Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into upstream-merge-26492
This commit is contained in:
@@ -13,6 +13,10 @@
|
||||
#define MC_AVERAGE_FAST(average, current) (0.7 * (average) + 0.3 * (current))
|
||||
#define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current))
|
||||
#define MC_AVERAGE_SLOW(average, current) (0.9 * (average) + 0.1 * (current))
|
||||
|
||||
#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
|
||||
#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
|
||||
|
||||
#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;}
|
||||
|
||||
#define START_PROCESSING(Processor, Datum) if (!Datum.isprocessing) {Datum.isprocessing = 1;Processor.processing += Datum}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#define ANTAG_DATUM_CULT /datum/antagonist/cult
|
||||
#define ANTAG_DATUM_CULT_MASTER /datum/antagonist/cult/master
|
||||
#define ANTAG_DATUM_CLOCKCULT /datum/antagonist/clockcult
|
||||
#define ANTAG_DATUM_CLOCKCULT_SILENT /datum/antagonist/clockcult/silent
|
||||
@@ -37,15 +37,15 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
#define JUDGEMENT_CV_REQ 300
|
||||
|
||||
//general component/cooldown things
|
||||
#define SLAB_PRODUCTION_TIME 900 //how long(deciseconds) slabs require to produce a single component; defaults to 1 minute 30 seconds
|
||||
#define SLAB_PRODUCTION_TIME 450 //how long(deciseconds) slabs require to produce a single component; defaults to 45 seconds
|
||||
|
||||
#define SLAB_SERVANT_SLOWDOWN 300 //how much each servant above 5 slows down slab-based generation; defaults to 30 seconds per sevant
|
||||
#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 2700 //maximum slowdown from additional servants; defaults to 4 minutes 30 seconds
|
||||
#define SLAB_SLOWDOWN_MAXIMUM 1350 //maximum slowdown from additional servants; defaults to 2 minutes 15 seconds
|
||||
|
||||
#define CACHE_PRODUCTION_TIME 600 //how long(deciseconds) caches require to produce a component; defaults to 1 minute
|
||||
#define CACHE_PRODUCTION_TIME 300 //how long(deciseconds) caches require to produce a component; defaults to 30 seconds
|
||||
|
||||
#define ACTIVE_CACHE_SLOWDOWN 100 //how many additional deciseconds caches take to produce a component for each linked cache; defaults to 10 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
|
||||
|
||||
@@ -87,9 +87,9 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
|
||||
#define GATEWAY_RATVAR_ARRIVAL 300 //when progress is at or above this, game over ratvar's here everybody go home
|
||||
|
||||
#define ARK_SUMMON_COST 3 //how many of each component an Ark costs to summon
|
||||
#define ARK_SUMMON_COST 5 //how many of each component an Ark costs to summon
|
||||
|
||||
#define ARK_CONSUME_COST 7 //how many of each component an Ark needs to consume to activate
|
||||
#define ARK_CONSUME_COST 15 //how many of each component an Ark needs to consume to activate
|
||||
|
||||
//Objective text define
|
||||
#define CLOCKCULT_OBJECTIVE "Construct the Ark of the Clockwork Justicar and free Ratvar."
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#define BOTANIST (1<<2)
|
||||
#define COOK (1<<3)
|
||||
#define JANITOR (1<<4)
|
||||
#define LIBRARIAN (1<<5)
|
||||
#define CURATOR (1<<5)
|
||||
#define QUARTERMASTER (1<<6)
|
||||
#define CARGOTECH (1<<7)
|
||||
#define MINER (1<<8)
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
#define NO_STUTTER 1
|
||||
#define TONGUELESS_SPEECH 2
|
||||
#define LANGUAGE_HIDE_ICON_IF_UNDERSTOOD 4
|
||||
#define LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD 8
|
||||
|
||||
#define LANGUAGE_KNOWN "language_known"
|
||||
#define LANGUAGE_SHADOWED "language_shadowed"
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
#define LIGHTING_BASE_MATRIX \
|
||||
list \
|
||||
( \
|
||||
LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
|
||||
LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
|
||||
LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
|
||||
LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
|
||||
1, 1, 1, 0, \
|
||||
1, 1, 1, 0, \
|
||||
1, 1, 1, 0, \
|
||||
1, 1, 1, 0, \
|
||||
0, 0, 0, 1 \
|
||||
) \
|
||||
|
||||
@@ -78,4 +78,11 @@
|
||||
#define DYNAMIC_LIGHTING_ENABLED 1 //dynamic lighting enabled
|
||||
#define DYNAMIC_LIGHTING_FORCED 2 //dynamic lighting enabled even if the area doesn't require power
|
||||
#define DYNAMIC_LIGHTING_IFSTARLIGHT 3 //dynamic lighting enabled only if starlight is.
|
||||
#define IS_DYNAMIC_LIGHTING(A) A.dynamic_lighting
|
||||
#define IS_DYNAMIC_LIGHTING(A) A.dynamic_lighting
|
||||
|
||||
|
||||
//code assumes higher numbers override lower numbers.
|
||||
#define LIGHTING_NO_UPDATE 0
|
||||
#define LIGHTING_VIS_UPDATE 1
|
||||
#define LIGHTING_CHECK_UPDATE 2
|
||||
#define LIGHTING_FORCE_UPDATE 3
|
||||
@@ -23,6 +23,7 @@
|
||||
#define MECHFAB 16 //Remember, objects utilising this flag should have construction_time and construction_cost vars.
|
||||
#define BIOGENERATOR 32 //Uses biomass
|
||||
#define LIMBGROWER 64 //Uses synthetic flesh
|
||||
#define SMELTER 128 //uses various minerals
|
||||
//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
|
||||
|
||||
//Modular computer/NTNet defines
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#define CHECKBOX_NONE 0
|
||||
#define CHECKBOX_GROUP 1
|
||||
#define CHECKBOX_TOGGLE 2
|
||||
@@ -201,6 +201,21 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
|
||||
#define BLOOD_STATE_XENO "xeno"
|
||||
#define BLOOD_STATE_OIL "oil"
|
||||
#define BLOOD_STATE_NOT_BLOODY "no blood whatsoever"
|
||||
|
||||
//suit sensors: sensor_mode defines
|
||||
|
||||
#define SENSOR_OFF 0
|
||||
#define SENSOR_LIVING 1
|
||||
#define SENSOR_VITALS 2
|
||||
#define SENSOR_COORDS 3
|
||||
|
||||
//suit sensors: has_sensor defines
|
||||
|
||||
#define BROKEN_SENSORS -1
|
||||
#define NO_SENSORS 0
|
||||
#define HAS_SENSORS 1
|
||||
#define LOCKED_SENSORS 2
|
||||
|
||||
//Turf wet states
|
||||
#define TURF_DRY 0
|
||||
#define TURF_WET_WATER 1
|
||||
|
||||
@@ -31,5 +31,10 @@
|
||||
/////////////
|
||||
|
||||
#define STATUS_EFFECT_SIGILMARK /datum/status_effect/sigil_mark
|
||||
#define STATUS_EFFECT_BELLIGERENT /datum/status_effect/belligerent //forces the affected to walk, doing damage if they try to run
|
||||
|
||||
#define STATUS_EFFECT_MANIAMOTOR /datum/status_effect/maniamotor //disrupts, damages, and confuses the affected as long as they're in range of the motor
|
||||
#define MAX_MANIA_SEVERITY 100 //how high the mania severity can go
|
||||
#define MANIA_DAMAGE_TO_CONVERT 90 //how much damage is required before it'll convert affected targets
|
||||
|
||||
#define STATUS_EFFECT_HISWRATH /datum/status_effect/his_wrath //His Wrath.
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#define INIT_ORDER_TICKER 13
|
||||
#define INIT_ORDER_MAPPING 12
|
||||
#define INIT_ORDER_ATOMS 11
|
||||
#define INIT_ORDER_LANGUAGE 10
|
||||
#define INIT_ORDER_MACHINES 9
|
||||
#define INIT_ORDER_SHUTTLE 3
|
||||
#define INIT_ORDER_TIMER 1
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
diff a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm (rejected hunks)
|
||||
@@ -26,4 +26,13 @@
|
||||
|
||||
#define INITIALIZE_HINT_NORMAL 0 //Nothing happens
|
||||
#define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize
|
||||
-#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom
|
||||
\ No newline at end of file
|
||||
+#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom
|
||||
+
|
||||
+//type and all subtypes should always call Initialize in New()
|
||||
+#define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\
|
||||
+ ..();\
|
||||
+ if(!initialized) {\
|
||||
+ args[1] = TRUE;\
|
||||
+ SSatoms.InitAtom(src, args);\
|
||||
+ }\
|
||||
+}
|
||||
\ No newline at end of file
|
||||
@@ -457,6 +457,7 @@
|
||||
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
|
||||
#define LAZYLEN(L) length(L)
|
||||
#define LAZYCLEARLIST(L) if(L) L.Cut()
|
||||
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
|
||||
|
||||
/* Definining a counter as a series of key -> numeric value entries
|
||||
|
||||
|
||||
+17
-20
@@ -20,13 +20,13 @@
|
||||
/proc/log_admin(text)
|
||||
GLOB.admin_log.Add(text)
|
||||
if (config.log_admin)
|
||||
GLOB.diary << "\[[time_stamp()]]ADMIN: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ADMIN: [text]"
|
||||
|
||||
//Items using this proc are stripped from public logs - use with caution
|
||||
/proc/log_admin_private(text)
|
||||
GLOB.admin_log.Add(text)
|
||||
if (config.log_admin)
|
||||
GLOB.diary << "\[[time_stamp()]]ADMINPRIVATE: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ADMINPRIVATE: [text]"
|
||||
|
||||
/proc/log_adminsay(text)
|
||||
if (config.log_adminchat)
|
||||
@@ -38,67 +38,64 @@
|
||||
|
||||
/proc/log_game(text)
|
||||
if (config.log_game)
|
||||
GLOB.diary << "\[[time_stamp()]]GAME: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]GAME: [text]"
|
||||
|
||||
/proc/log_vote(text)
|
||||
if (config.log_vote)
|
||||
GLOB.diary << "\[[time_stamp()]]VOTE: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]VOTE: [text]"
|
||||
|
||||
/proc/log_access(text)
|
||||
if (config.log_access)
|
||||
GLOB.diary << "\[[time_stamp()]]ACCESS: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ACCESS: [text]"
|
||||
|
||||
/proc/log_say(text)
|
||||
if (config.log_say)
|
||||
GLOB.diary << "\[[time_stamp()]]SAY: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]SAY: [text]"
|
||||
|
||||
/proc/log_prayer(text)
|
||||
if (config.log_prayer)
|
||||
GLOB.diary << "\[[time_stamp()]]PRAY: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]PRAY: [text]"
|
||||
|
||||
/proc/log_law(text)
|
||||
if (config.log_law)
|
||||
GLOB.diary << "\[[time_stamp()]]LAW: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]LAW: [text]"
|
||||
|
||||
/proc/log_ooc(text)
|
||||
if (config.log_ooc)
|
||||
GLOB.diary << "\[[time_stamp()]]OOC: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]OOC: [text]"
|
||||
|
||||
/proc/log_whisper(text)
|
||||
if (config.log_whisper)
|
||||
GLOB.diary << "\[[time_stamp()]]WHISPER: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]WHISPER: [text]"
|
||||
|
||||
/proc/log_emote(text)
|
||||
if (config.log_emote)
|
||||
GLOB.diary << "\[[time_stamp()]]EMOTE: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]EMOTE: [text]"
|
||||
|
||||
/proc/log_attack(text)
|
||||
if (config.log_attack)
|
||||
GLOB.diaryofmeanpeople << "\[[time_stamp()]]ATTACK: [text]"
|
||||
GLOB.world_attack_log << "\[[time_stamp()]]ATTACK: [text]"
|
||||
|
||||
/proc/log_pda(text)
|
||||
if (config.log_pda)
|
||||
GLOB.diary << "\[[time_stamp()]]PDA: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]PDA: [text]"
|
||||
|
||||
/proc/log_comment(text)
|
||||
if (config.log_pda)
|
||||
//reusing the PDA option because I really don't think news comments are worth a config option
|
||||
GLOB.diary << "\[[time_stamp()]]COMMENT: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]COMMENT: [text]"
|
||||
|
||||
/proc/log_chat(text)
|
||||
if (config.log_pda)
|
||||
GLOB.diary << "\[[time_stamp()]]CHAT: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]CHAT: [text]"
|
||||
|
||||
/proc/log_sql(text)
|
||||
if(config.sql_enabled)
|
||||
GLOB.diary << "\[[time_stamp()]]SQL: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]SQL: [text]"
|
||||
|
||||
//This replaces world.log so it displays both in DD and the file
|
||||
/proc/log_world(text)
|
||||
if(config && config.log_runtimes)
|
||||
world.log = GLOB.runtime_diary
|
||||
world.log << text
|
||||
world.log = null
|
||||
GLOB.world_runtime_log << text
|
||||
world.log << text
|
||||
|
||||
// Helper procs for building detailed log lines
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#define YOUNG 4
|
||||
|
||||
|
||||
/client/proc/join_date_check(y,m,d)
|
||||
var/datum/DBQuery/query_datediff = SSdbcore.NewQuery("SELECT DATEDIFF(Now(),'[y]-[m]-[d]')")
|
||||
|
||||
if(!query_datediff.Execute())
|
||||
return FALSE
|
||||
|
||||
if(query_datediff.NextRow())
|
||||
var/diff = text2num(query_datediff.item[1])
|
||||
if(config.use_account_age_for_jobs)
|
||||
player_age = max(0,diff) //So job code soesn't freak out if they are time traveling.
|
||||
if(diff < YOUNG)
|
||||
var/msg = "(IP: [address], ID: [computer_id]) is a new BYOND account made on [y]-[m]-[d]."
|
||||
if(diff < 0)
|
||||
msg += " They are also apparently from the future."
|
||||
message_admins("[key_name_admin(src)] [msg]")
|
||||
return TRUE
|
||||
#undef YOUNG
|
||||
|
||||
|
||||
/client/proc/findJoinDate()
|
||||
var/http[] = world.Export("http://byond.com/members/[src.ckey]?format=text")
|
||||
if(!http)
|
||||
log_world("Failed to connect to byond age check for [src.ckey]")
|
||||
return FALSE
|
||||
|
||||
var/F = file2text(http["CONTENT"])
|
||||
if(F)
|
||||
var/regex/R = regex("joined = \"(\\d{4})-(\\d{2})-(\\d{2})\"")
|
||||
if(!R.Find(F))
|
||||
CRASH("Age check regex failed")
|
||||
var/y = R.group[1]
|
||||
var/m = R.group[2]
|
||||
var/d = R.group[3]
|
||||
return join_date_check(y,m,d)
|
||||
+97
-32
@@ -6,6 +6,7 @@
|
||||
)
|
||||
|
||||
#define Z_TURFS(ZLEVEL) block(locate(1,1,ZLEVEL), locate(world.maxx, world.maxy, ZLEVEL))
|
||||
#define CULT_POLL_WAIT 2400
|
||||
|
||||
/proc/get_area(atom/A)
|
||||
if (!istype(A))
|
||||
@@ -313,10 +314,10 @@
|
||||
|
||||
// Will return a list of active candidates. It increases the buffer 5 times until it finds a candidate which is active within the buffer.
|
||||
|
||||
/proc/get_candidates(be_special_type, afk_bracket = config.inactivity_period, jobbanType)
|
||||
/proc/get_candidates(be_special_type, afk_bracket = config.inactivity_period, jobbanType)
|
||||
var/list/candidates = list()
|
||||
// Keep looping until we find a non-afk candidate within the time bracket (we limit the bracket to 10 minutes (6000))
|
||||
while(!candidates.len && afk_bracket < config.afk_period)
|
||||
while(!candidates.len && afk_bracket < config.afk_period)
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(G.client != null)
|
||||
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
|
||||
@@ -414,68 +415,83 @@
|
||||
|
||||
return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y)
|
||||
|
||||
/proc/showCandidatePollWindow(mob/dead/observer/G, poll_time, Question, list/candidates, ignore_category, time_passed, flashwindow = TRUE)
|
||||
/proc/showCandidatePollWindow(mob/M, poll_time, Question, list/candidates, ignore_category, time_passed, flashwindow = TRUE)
|
||||
set waitfor = 0
|
||||
|
||||
G << 'sound/misc/notice2.ogg' //Alerting them to their consideration
|
||||
M << 'sound/misc/notice2.ogg' //Alerting them to their consideration
|
||||
if(flashwindow)
|
||||
window_flash(G.client)
|
||||
switch(ignore_category ? askuser(G,Question,"Please answer in [poll_time/10] seconds!","Yes","No","Never for this round", StealFocus=0, Timeout=poll_time) : askuser(G,Question,"Please answer in [poll_time/10] seconds!","Yes","No", StealFocus=0, Timeout=poll_time))
|
||||
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))
|
||||
if(1)
|
||||
to_chat(G, "<span class='notice'>Choice registered: Yes.</span>")
|
||||
to_chat(M, "<span class='notice'>Choice registered: Yes.</span>")
|
||||
if((world.time-time_passed)>poll_time)
|
||||
to_chat(G, "<span class='danger'>Sorry, you were too late for the consideration!</span>")
|
||||
G << 'sound/machines/buzz-sigh.ogg'
|
||||
to_chat(M, "<span class='danger'>Sorry, you answered too late to be considered!</span>")
|
||||
M << 'sound/machines/buzz-sigh.ogg'
|
||||
candidates -= M
|
||||
else
|
||||
candidates += G
|
||||
candidates += M
|
||||
if(2)
|
||||
to_chat(G, "<span class='danger'>Choice registered: No.</span>")
|
||||
to_chat(M, "<span class='danger'>Choice registered: No.</span>")
|
||||
candidates -= M
|
||||
if(3)
|
||||
var/list/L = GLOB.poll_ignore[ignore_category]
|
||||
if(!L)
|
||||
GLOB.poll_ignore[ignore_category] = list()
|
||||
GLOB.poll_ignore[ignore_category] += G.ckey
|
||||
to_chat(G, "<span class='danger'>Choice registered: Never for this round.</span>")
|
||||
GLOB.poll_ignore[ignore_category] += M.ckey
|
||||
to_chat(M, "<span class='danger'>Choice registered: Never for this round.</span>")
|
||||
candidates -= M
|
||||
else
|
||||
candidates -= M
|
||||
|
||||
/proc/pollCandidates(var/Question, var/jobbanType, var/datum/game_mode/gametypeCheck, var/be_special_flag = 0, var/poll_time = 300, var/ignore_category = null, flashwindow = TRUE)
|
||||
var/list/mob/dead/observer/candidates = list()
|
||||
/proc/pollGhostCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE)
|
||||
var/list/candidates = list()
|
||||
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
candidates += G
|
||||
|
||||
pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category, flashwindow, candidates)
|
||||
|
||||
return candidates
|
||||
|
||||
/proc/pollCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE, list/group = null)
|
||||
var/time_passed = world.time
|
||||
if (!Question)
|
||||
Question = "Would you like to be a special role?"
|
||||
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(!G.key || !G.client || (ignore_category && GLOB.poll_ignore[ignore_category] && G.ckey in GLOB.poll_ignore[ignore_category]))
|
||||
for(var/m in group)
|
||||
var/mob/M = m
|
||||
if(!M.key || !M.client || (ignore_category && GLOB.poll_ignore[ignore_category] && M.ckey in GLOB.poll_ignore[ignore_category]))
|
||||
continue
|
||||
if(be_special_flag)
|
||||
if(!(G.client.prefs) || !(be_special_flag in G.client.prefs.be_special))
|
||||
if(!(M.client.prefs) || !(be_special_flag in M.client.prefs.be_special))
|
||||
continue
|
||||
if (gametypeCheck)
|
||||
if(!gametypeCheck.age_check(G.client))
|
||||
if(gametypeCheck)
|
||||
if(!gametypeCheck.age_check(M.client))
|
||||
continue
|
||||
if (jobbanType)
|
||||
if(jobban_isbanned(G, jobbanType) || jobban_isbanned(G, "Syndicate"))
|
||||
if(jobbanType)
|
||||
if(jobban_isbanned(M, jobbanType) || jobban_isbanned(M, "Syndicate"))
|
||||
continue
|
||||
|
||||
showCandidatePollWindow(G, poll_time, Question, candidates, ignore_category, time_passed, flashwindow)
|
||||
showCandidatePollWindow(M, poll_time, Question, group, ignore_category, time_passed, flashwindow)
|
||||
sleep(poll_time)
|
||||
|
||||
//Check all our candidates, to make sure they didn't log off during the wait period.
|
||||
for(var/mob/dead/observer/G in candidates)
|
||||
if(!G.key || !G.client)
|
||||
candidates.Remove(G)
|
||||
//Check all our candidates, to make sure they didn't log off or get deleted during the wait period.
|
||||
for(var/mob/M in group)
|
||||
if(!M.key || !M.client)
|
||||
group -= M
|
||||
|
||||
listclearnulls(candidates)
|
||||
listclearnulls(group)
|
||||
|
||||
return candidates
|
||||
return group
|
||||
|
||||
/proc/pollCandidatesForMob(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, mob/M, ignore_category = null)
|
||||
var/list/L = pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
|
||||
var/list/L = pollGhostCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
|
||||
if(!M || QDELETED(M) || !M.loc)
|
||||
return list()
|
||||
return L
|
||||
|
||||
/proc/pollCandidatesForMobs(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, list/mobs, ignore_category = null)
|
||||
var/list/L = pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
|
||||
var/list/L = pollGhostCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
|
||||
var/i=1
|
||||
for(var/v in mobs)
|
||||
var/atom/A = v
|
||||
@@ -485,6 +501,55 @@
|
||||
++i
|
||||
return L
|
||||
|
||||
/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.")
|
||||
return
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current)
|
||||
B.current.verbs -= /mob/living/proc/cult_master
|
||||
if(!B.current.incapacitated())
|
||||
B.current << 'sound/hallucinations/im_here1.ogg'
|
||||
to_chat(B.current, "<span class='cultlarge'>Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.</span>")
|
||||
sleep(250)
|
||||
var/list/asked_cultists = list()
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current && B.current != Nominee && !B.current.incapacitated())
|
||||
B.current << 'sound/magic/exit_blood.ogg'
|
||||
asked_cultists += B.current
|
||||
var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 1200, group = asked_cultists)
|
||||
sleep(300)
|
||||
if(QDELETED(Nominee) || Nominee.incapacitated())
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current)
|
||||
B.current.verbs += /mob/living/proc/cult_master
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current,"<span class='cultlarge'>[Nominee] has died in the process of attempting to win the cult's support!")
|
||||
return FALSE
|
||||
if(!Nominee.mind)
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current)
|
||||
B.current.verbs += /mob/living/proc/cult_master
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current,"<span class='cultlarge'>[Nominee] has gone insane and catatonic in the process of attempting to win the cult's support!")
|
||||
return FALSE
|
||||
if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current)
|
||||
B.current.verbs += /mob/living/proc/cult_master
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current, "<span class='cultlarge'>[Nominee] could not win the cult's support and shall continue to serve as an acolyte.")
|
||||
return FALSE
|
||||
SSticker.mode.remove_cultist(Nominee.mind, FALSE)
|
||||
Nominee.mind.add_antag_datum(ANTAG_DATUM_CULT_MASTER)
|
||||
GLOB.cult_mastered = TRUE
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current,"<span class='cultlarge'>[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!")
|
||||
return TRUE
|
||||
|
||||
/proc/poll_helper(var/mob/living/M)
|
||||
|
||||
/proc/makeBody(mob/dead/observer/G_found) // Uses stripped down and bastardized code from respawn character
|
||||
if(!G_found || !G_found.key)
|
||||
return
|
||||
@@ -513,7 +578,7 @@
|
||||
winset(C, "mainwindow", "flash=5")
|
||||
|
||||
/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank)
|
||||
if(SSticker.current_state != GAME_STATE_PLAYING || !character)
|
||||
if(!SSticker.IsRoundInProgress() || !character)
|
||||
return
|
||||
var/area/A = get_area(character)
|
||||
var/message = "<span class='game deadsay'><span class='name'>\
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
//doesn't have an object argument because this is "Stacking" with the animate call above
|
||||
//3 billion% intentional
|
||||
|
||||
|
||||
//Dumps the matrix data in format a-f
|
||||
/matrix/proc/tolist()
|
||||
. = list()
|
||||
|
||||
@@ -24,4 +24,4 @@ GLOBAL_LIST_EMPTY(whitelisted_species_list)
|
||||
|
||||
/proc/log_mentor(text)
|
||||
GLOB.mentor_log.Add(text)
|
||||
GLOB.diary << "\[[time_stamp()]]MENTOR: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]MENTOR: [text]"
|
||||
@@ -1342,6 +1342,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
//This prevents RCEs from badmins
|
||||
//kevinz000 if you touch this I will hunt you down
|
||||
GLOBAL_VAR_INIT(valid_HTTPSGet, FALSE)
|
||||
GLOBAL_PROTECT(valid_HTTPSGet)
|
||||
/proc/HTTPSGet(url)
|
||||
if(findtext(url, "\""))
|
||||
GLOB.valid_HTTPSGet = FALSE
|
||||
|
||||
@@ -3,3 +3,12 @@ GLOBAL_VAR_INIT(secret_force_mode, "secret") // if this is anything but "secret"
|
||||
|
||||
GLOBAL_VAR_INIT(wavesecret, 0) // meteor mode, delays wave progression, terrible name
|
||||
GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report
|
||||
|
||||
// Cult, needs to be global so admin cultists are functional
|
||||
GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master
|
||||
GLOBAL_DATUM(blood_target_image, /image)
|
||||
GLOBAL_DATUM(sac_mind, /datum/mind)
|
||||
GLOBAL_VAR_INIT(sac_image, null)
|
||||
GLOBAL_VAR_INIT(cult_mastered, FALSE)
|
||||
GLOBAL_VAR_INIT(reckoning_complete, FALSE)
|
||||
GLOBAL_VAR_INIT(sac_complete, FALSE)
|
||||
@@ -104,5 +104,6 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
|
||||
/obj/item/weapon/storage/secure/briefcase = 3,
|
||||
/obj/item/weapon/storage/toolbox/artistic = 2,
|
||||
/obj/item/toy/eightball = 1,
|
||||
/obj/item/weapon/storage/daki = 3,
|
||||
"" = 3
|
||||
))
|
||||
|
||||
@@ -11,6 +11,7 @@ GLOBAL_LIST_EMPTY(stealthminID) //reference list with IDs that store ckeys,
|
||||
|
||||
GLOBAL_LIST_EMPTY(player_list) //all mobs **with clients attached**. Excludes /mob/dead/new_player
|
||||
GLOBAL_LIST_EMPTY(mob_list) //all mobs, including clientless
|
||||
GLOBAL_LIST_EMPTY(mob_directory) //mob_id -> mob
|
||||
GLOBAL_LIST_EMPTY(living_mob_list) //all alive mobs, including clientless. Excludes /mob/dead/new_player
|
||||
GLOBAL_LIST_EMPTY(dead_mob_list) //all dead mobs, including clientless. Excludes /mob/dead/new_player
|
||||
GLOBAL_LIST_EMPTY(joined_player_list) //all clients that have joined the game at round-start or as a latejoin.
|
||||
@@ -18,5 +19,7 @@ GLOBAL_LIST_EMPTY(silicon_mobs) //all silicon mobs
|
||||
GLOBAL_LIST_EMPTY(ai_list)
|
||||
GLOBAL_LIST_EMPTY(pai_list)
|
||||
GLOBAL_LIST_EMPTY(available_ai_shells)
|
||||
GLOBAL_LIST_EMPTY(language_datums)
|
||||
GLOBAL_LIST_EMPTY(simple_animals)
|
||||
GLOBAL_LIST_EMPTY(simple_animals)
|
||||
|
||||
GLOBAL_LIST_EMPTY(language_datum_instances)
|
||||
GLOBAL_LIST_EMPTY(all_languages)
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
GLOBAL_LIST_INIT(ai_names, world.file2list("config/names/ai.txt"))
|
||||
GLOBAL_LIST_INIT(wizard_first, world.file2list("config/names/wizardfirst.txt"))
|
||||
GLOBAL_LIST_INIT(wizard_second, world.file2list("config/names/wizardsecond.txt"))
|
||||
GLOBAL_LIST_INIT(ninja_titles, world.file2list("config/names/ninjatitle.txt"))
|
||||
GLOBAL_LIST_INIT(ninja_names, world.file2list("config/names/ninjaname.txt"))
|
||||
GLOBAL_LIST_INIT(commando_names, world.file2list("config/names/death_commando.txt"))
|
||||
GLOBAL_LIST_INIT(first_names_male, world.file2list("config/names/first_male.txt"))
|
||||
GLOBAL_LIST_INIT(first_names_female, world.file2list("config/names/first_female.txt"))
|
||||
GLOBAL_LIST_INIT(last_names, world.file2list("config/names/last.txt"))
|
||||
GLOBAL_LIST_INIT(lizard_names_male, world.file2list("config/names/lizard_male.txt"))
|
||||
GLOBAL_LIST_INIT(lizard_names_female, world.file2list("config/names/lizard_female.txt"))
|
||||
GLOBAL_LIST_INIT(clown_names, world.file2list("config/names/clown.txt"))
|
||||
GLOBAL_LIST_INIT(mime_names, world.file2list("config/names/mime.txt"))
|
||||
GLOBAL_LIST_INIT(carp_names, world.file2list("config/names/carp.txt"))
|
||||
GLOBAL_LIST_INIT(golem_names, world.file2list("config/names/golem.txt"))
|
||||
GLOBAL_LIST_INIT(plasmaman_names, world.file2list("config/names/plasmaman.txt"))
|
||||
GLOBAL_LIST_INIT(posibrain_names, list("PBU","HIU","SINA","ARMA","OSI","HBL","MSO","RR","CHRI","CDB","HG","XSI","ORNG","GUN","KOR","MET","FRE","XIS","SLI","PKP","HOG","RZH","GOOF","MRPR","JJR","FIRC","INC","PHL","BGB","ANTR","MIW","WJ","JRD","CHOC","ANCL","JLLO","JNLG","KOS","TKRG","XAL","STLP","CBOS","DUNC","FXMC","DRSD","COI"))
|
||||
GLOBAL_LIST_INIT(ai_names, world.file2list("strings/names/ai.txt"))
|
||||
GLOBAL_LIST_INIT(wizard_first, world.file2list("strings/names/wizardfirst.txt"))
|
||||
GLOBAL_LIST_INIT(wizard_second, world.file2list("strings/names/wizardsecond.txt"))
|
||||
GLOBAL_LIST_INIT(ninja_titles, world.file2list("strings/names/ninjatitle.txt"))
|
||||
GLOBAL_LIST_INIT(ninja_names, world.file2list("strings/names/ninjaname.txt"))
|
||||
GLOBAL_LIST_INIT(commando_names, world.file2list("strings/names/death_commando.txt"))
|
||||
GLOBAL_LIST_INIT(first_names_male, world.file2list("strings/names/first_male.txt"))
|
||||
GLOBAL_LIST_INIT(first_names_female, world.file2list("strings/names/first_female.txt"))
|
||||
GLOBAL_LIST_INIT(last_names, world.file2list("strings/names/last.txt"))
|
||||
GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt"))
|
||||
GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt"))
|
||||
GLOBAL_LIST_INIT(clown_names, world.file2list("strings/names/clown.txt"))
|
||||
GLOBAL_LIST_INIT(mime_names, world.file2list("strings/names/mime.txt"))
|
||||
GLOBAL_LIST_INIT(carp_names, world.file2list("strings/names/carp.txt"))
|
||||
GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt"))
|
||||
GLOBAL_LIST_INIT(plasmaman_names, world.file2list("strings/names/plasmaman.txt"))
|
||||
GLOBAL_LIST_INIT(posibrain_names, world.file2list("strings/names/posibrain.txt"))
|
||||
|
||||
|
||||
GLOBAL_LIST_INIT(verbs, world.file2list("config/names/verbs.txt"))
|
||||
GLOBAL_LIST_INIT(adjectives, world.file2list("config/names/adjectives.txt"))
|
||||
GLOBAL_LIST_INIT(verbs, world.file2list("strings/names/verbs.txt"))
|
||||
GLOBAL_LIST_INIT(adjectives, world.file2list("strings/names/adjectives.txt"))
|
||||
//loaded on startup because of "
|
||||
//would include in rsc if ' was used
|
||||
|
||||
@@ -29,6 +29,7 @@ GLOBAL_LIST_EMPTY(zombie_infection_list) // A list of all zombie_infection org
|
||||
GLOBAL_LIST_EMPTY(meteor_list) // List of all meteors.
|
||||
GLOBAL_LIST_EMPTY(active_jammers) // List of active radio jammers
|
||||
GLOBAL_LIST_EMPTY(ladders)
|
||||
GLOBAL_LIST_EMPTY(trophy_cases)
|
||||
|
||||
GLOBAL_LIST_EMPTY(wire_color_directory)
|
||||
GLOBAL_LIST_EMPTY(wire_name_directory)
|
||||
@@ -5,5 +5,6 @@
|
||||
#define POLL_IGNORE_POSSESSED_BLADE "possessed_blade"
|
||||
#define POLL_IGNORE_ALIEN_LARVA "alien_larva"
|
||||
#define POLL_IGNORE_CLOCKWORK_MARAUDER "clockwork_marauder"
|
||||
#define POLL_IGNORE_SYNDICATE "syndicate"
|
||||
|
||||
GLOBAL_LIST_EMPTY(poll_ignore)
|
||||
|
||||
+33
-27
@@ -1,28 +1,34 @@
|
||||
GLOBAL_VAR(diary)
|
||||
GLOBAL_PROTECT(diary)
|
||||
GLOBAL_VAR(runtime_diary)
|
||||
GLOBAL_PROTECT(runtime_diary)
|
||||
GLOBAL_VAR(diaryofmeanpeople)
|
||||
GLOBAL_PROTECT(diaryofmeanpeople)
|
||||
GLOBAL_VAR(href_logfile)
|
||||
GLOBAL_PROTECT(href_logfile)
|
||||
|
||||
GLOBAL_LIST_EMPTY(bombers)
|
||||
GLOBAL_PROTECT(bombers)
|
||||
GLOBAL_LIST_EMPTY(admin_log)
|
||||
GLOBAL_PROTECT(admin_log)
|
||||
GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
|
||||
GLOBAL_PROTECT(lastsignalers)
|
||||
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
|
||||
GLOBAL_PROTECT(lawchanges)
|
||||
|
||||
GLOBAL_LIST_EMPTY(combatlog)
|
||||
GLOBAL_PROTECT(combatlog)
|
||||
GLOBAL_LIST_EMPTY(IClog)
|
||||
GLOBAL_PROTECT(IClog)
|
||||
GLOBAL_LIST_EMPTY(OOClog)
|
||||
GLOBAL_PROTECT(OOClog)
|
||||
GLOBAL_LIST_EMPTY(adminlog)
|
||||
GLOBAL_PROTECT(adminlog)
|
||||
|
||||
GLOBAL_VAR(log_directory)
|
||||
GLOBAL_PROTECT(log_directory)
|
||||
GLOBAL_VAR(world_game_log)
|
||||
GLOBAL_PROTECT(world_game_log)
|
||||
GLOBAL_VAR(world_runtime_log)
|
||||
GLOBAL_PROTECT(world_runtime_log)
|
||||
GLOBAL_VAR(world_attack_log)
|
||||
GLOBAL_PROTECT(world_attack_log)
|
||||
GLOBAL_VAR(world_href_log)
|
||||
GLOBAL_PROTECT(world_href_log)
|
||||
GLOBAL_VAR(round_id)
|
||||
GLOBAL_PROTECT(round_id)
|
||||
GLOBAL_VAR(config_error_log)
|
||||
GLOBAL_PROTECT(config_error_log)
|
||||
|
||||
GLOBAL_LIST_EMPTY(bombers)
|
||||
GLOBAL_PROTECT(bombers)
|
||||
GLOBAL_LIST_EMPTY(admin_log)
|
||||
GLOBAL_PROTECT(admin_log)
|
||||
GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
|
||||
GLOBAL_PROTECT(lastsignalers)
|
||||
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
|
||||
GLOBAL_PROTECT(lawchanges)
|
||||
|
||||
GLOBAL_LIST_EMPTY(combatlog)
|
||||
GLOBAL_PROTECT(combatlog)
|
||||
GLOBAL_LIST_EMPTY(IClog)
|
||||
GLOBAL_PROTECT(IClog)
|
||||
GLOBAL_LIST_EMPTY(OOClog)
|
||||
GLOBAL_PROTECT(OOClog)
|
||||
GLOBAL_LIST_EMPTY(adminlog)
|
||||
GLOBAL_PROTECT(adminlog)
|
||||
|
||||
GLOBAL_LIST_EMPTY(active_turfs_startlist)
|
||||
+80
-47
@@ -107,64 +107,112 @@
|
||||
|
||||
var/obj/item/W = get_active_held_item()
|
||||
|
||||
|
||||
if(W == A)
|
||||
W.attack_self(src)
|
||||
update_inv_hands()
|
||||
return
|
||||
|
||||
// operate three levels deep here (item in backpack in src; item in box in backpack in src, not any deeper)
|
||||
if(A.ClickAccessible(src, depth=INVENTORY_DEPTH))
|
||||
// No adjacency needed
|
||||
|
||||
//These are always reachable.
|
||||
//User itself, current loc, and user inventory
|
||||
if(DirectAccess(A))
|
||||
if(W)
|
||||
melee_item_attack_chain(src, W, A, params)
|
||||
melee_item_attack_chain(src,W,A,params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A)
|
||||
return
|
||||
|
||||
if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that
|
||||
|
||||
//Can't reach anything else in lockers or other weirdness
|
||||
if(!loc.AllowClick())
|
||||
return
|
||||
|
||||
// Allows you to click on a box's contents, if that box is on the ground, but no deeper than that
|
||||
if(isturf(A) || isturf(A.loc) || (A.loc && isturf(A.loc.loc)))
|
||||
if(Adjacent(A) || (W && CheckReach(src, A, W.reach))) //Adjacent or reaching attacks
|
||||
if(W)
|
||||
melee_item_attack_chain(src, W, A, params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A, 1)
|
||||
return
|
||||
else // non-adjacent click
|
||||
if(W)
|
||||
W.afterattack(A,src,0,params) // 0: not Adjacent
|
||||
else
|
||||
RangedAttack(A, params)
|
||||
//Standard reach turf to turf or reaching inside storage
|
||||
if(CanReach(A,W))
|
||||
if(W)
|
||||
melee_item_attack_chain(src,W,A,params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A,1)
|
||||
else
|
||||
if(W)
|
||||
W.afterattack(A,src,0,params)
|
||||
else
|
||||
RangedAttack(A,params)
|
||||
|
||||
/atom/movable/proc/CanReach(atom/target,obj/item/tool,view_only = FALSE)
|
||||
if(isturf(target) || isturf(target.loc) || DirectAccess(target)) //Directly accessible atoms
|
||||
if(Adjacent(target) || (tool && CheckToolReach(src, target, tool.reach))) //Adjacent or reaching attacks
|
||||
return TRUE
|
||||
else
|
||||
//Things inside storage insde another storage
|
||||
//Eg Contents of a box in a backpack
|
||||
var/atom/outer_storage = get_atom_on_turf(target)
|
||||
if(outer_storage == target) //whatever that is we don't want infinite loop.
|
||||
return FALSE
|
||||
if(outer_storage && CanReach(outer_storage,tool) && outer_storage.CanReachStorage(target,src,view_only ? STORAGE_VIEW_DEPTH : INVENTORY_DEPTH))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Can [target] in this container be reached by [user], can't be more than [depth] levels deep
|
||||
/atom/proc/CanReachStorage(atom/target,user,depth)
|
||||
return FALSE
|
||||
|
||||
/obj/item/weapon/storage/CanReachStorage(atom/target,user,depth)
|
||||
while(target && depth > 0)
|
||||
target = target.loc
|
||||
depth--
|
||||
if(target == src)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/atom/movable/proc/DirectAccess(atom/target)
|
||||
if(target == src)
|
||||
return TRUE
|
||||
if(target == loc)
|
||||
return TRUE
|
||||
|
||||
/mob/DirectAccess(atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
if(target in contents) //This could probably use moving down and restricting to inventory only
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/DirectAccess(atom/target)
|
||||
if(..()) //Lightweight checks first
|
||||
return TRUE
|
||||
if(target in GetAllContents())
|
||||
return TRUE
|
||||
|
||||
/atom/proc/AllowClick()
|
||||
return FALSE
|
||||
|
||||
/turf/AllowClick()
|
||||
return TRUE
|
||||
|
||||
/proc/CheckReach(atom/movable/here, atom/movable/there, reach)
|
||||
/proc/CheckToolReach(atom/movable/here, atom/movable/there, reach)
|
||||
if(!here || !there)
|
||||
return
|
||||
switch(reach)
|
||||
if(0)
|
||||
return here.loc == there.loc
|
||||
return FALSE
|
||||
if(1)
|
||||
return here.Adjacent(there)
|
||||
return FALSE //here.Adjacent(there)
|
||||
if(2 to INFINITY)
|
||||
var/obj/dummy = new(get_turf(here)) //We'll try to move this every tick, failing if we can't
|
||||
var/obj/dummy = new(get_turf(here))
|
||||
dummy.pass_flags |= PASSTABLE
|
||||
dummy.invisibility = INVISIBILITY_ABSTRACT
|
||||
for(var/i in 1 to reach) //Limit it to that many tries
|
||||
var/turf/T = get_step(dummy, get_dir(dummy, there))
|
||||
if(dummy.loc == there.loc)
|
||||
if(dummy.CanReach(there))
|
||||
qdel(dummy)
|
||||
return 1
|
||||
if(there.density && dummy in range(1, there)) //For windows and suchlike
|
||||
qdel(dummy)
|
||||
return 1
|
||||
return TRUE
|
||||
if(!dummy.Move(T)) //we're blocked!
|
||||
qdel(dummy)
|
||||
return
|
||||
qdel(dummy)
|
||||
|
||||
// Default behavior: ignore double clicks (the second click that makes the doubleclick call already calls for a normal click)
|
||||
/mob/proc/DblClickOn(atom/A, params)
|
||||
@@ -304,21 +352,6 @@
|
||||
/atom/proc/CtrlShiftClick(mob/user)
|
||||
return
|
||||
|
||||
/*
|
||||
Helper to check can the mob click/access an item.
|
||||
Used by mob inventory and storage items.
|
||||
*/
|
||||
/atom/proc/ClickAccessible(mob/user, depth=1)
|
||||
if(src == user.loc || (src in user.contents))
|
||||
return TRUE
|
||||
|
||||
if(loc && depth > 1)
|
||||
return loc.ClickAccessible(user, depth-1)
|
||||
|
||||
/turf/ClickAccessible(mob/user, depth=1)
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
Misc helpers
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define ui_inventory "WEST:6,SOUTH:5"
|
||||
|
||||
//Middle left indicators
|
||||
#define ui_lingchemdisplay "WEST:6,CENTER-1:15"
|
||||
#define ui_lingchemdisplay "WEST,CENTER-1:15"
|
||||
#define ui_lingstingdisplay "WEST:6,CENTER-3:11"
|
||||
#define ui_crafting "12:-10,1:5"
|
||||
#define ui_building "12:-10,1:21"
|
||||
@@ -104,12 +104,17 @@
|
||||
#define ui_health "EAST-1:28,CENTER-1:15"
|
||||
#define ui_internal "EAST-1:28,CENTER:17"
|
||||
|
||||
//borgs and aliens
|
||||
#define ui_alien_nightvision "EAST-1:28,CENTER:17"
|
||||
//borgs
|
||||
#define ui_borg_health "EAST-1:28,CENTER-1:15" //borgs have the health display where humans have the pressure damage indicator.
|
||||
#define ui_alien_health "EAST-1:28,CENTER-1:15" //aliens have the health display where humans have the pressure damage indicator.
|
||||
#define ui_alienplasmadisplay "EAST-1:28,CENTER-2:15"
|
||||
#define ui_alien_queen_finder "EAST-1:28,CENTER-3:15"
|
||||
|
||||
//aliens
|
||||
#define ui_alien_health "EAST,CENTER-1:15" //aliens have the health display where humans have the pressure damage indicator.
|
||||
#define ui_alienplasmadisplay "EAST,CENTER-2:15"
|
||||
#define ui_alien_queen_finder "EAST,CENTER-3:15"
|
||||
|
||||
//constructs
|
||||
#define ui_construct_pull "EAST,CENTER-2:15"
|
||||
#define ui_construct_health "EAST,CENTER:15" //same as borgs and humans
|
||||
|
||||
// AI
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
thealert.override_alerts = override
|
||||
if(override)
|
||||
thealert.timeout = null
|
||||
thealert.mob_viewer = src
|
||||
|
||||
if(new_master)
|
||||
var/old_layer = new_master.layer
|
||||
@@ -96,6 +97,7 @@
|
||||
var/severity = 0
|
||||
var/alerttooltipstyle = ""
|
||||
var/override_alerts = FALSE //If it is overriding other alerts of the same type
|
||||
var/mob/mob_viewer //the mob viewing this alert
|
||||
|
||||
|
||||
/obj/screen/alert/MouseEntered(location,control,params)
|
||||
@@ -256,6 +258,102 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
icon_state = "blobbernaut_nofactory"
|
||||
alerttooltipstyle = "blob"
|
||||
|
||||
// BLOODCULT
|
||||
|
||||
/obj/screen/alert/bloodsense
|
||||
name = "Blood Sense"
|
||||
desc = "Allows you to sense blood that is manipulated by dark magicks."
|
||||
icon_state = "cult_sense"
|
||||
alerttooltipstyle = "cult"
|
||||
var/static/image/narnar
|
||||
var/angle = 0
|
||||
var/mob/living/simple_animal/hostile/construct/Cviewer = null
|
||||
|
||||
/obj/screen/alert/bloodsense/Initialize()
|
||||
. = ..()
|
||||
if(!narnar)
|
||||
narnar = new('icons/mob/screen_alert.dmi', "mini_nar")
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/screen/alert/bloodsense/Destroy()
|
||||
Cviewer = null
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
return ..()
|
||||
|
||||
/obj/screen/alert/bloodsense/process()
|
||||
var/atom/blood_target
|
||||
if(GLOB.blood_target)
|
||||
if(!get_turf(GLOB.blood_target))
|
||||
GLOB.blood_target = null
|
||||
else
|
||||
blood_target = GLOB.blood_target
|
||||
if(Cviewer)
|
||||
if(Cviewer.seeking && Cviewer.master)
|
||||
blood_target = Cviewer.master
|
||||
if(!blood_target && !GLOB.sac_complete)
|
||||
if(icon_state == "runed_sense0")
|
||||
return
|
||||
animate(src, transform = null, time = 1, loop = 0)
|
||||
angle = 0
|
||||
cut_overlays()
|
||||
icon_state = "runed_sense0"
|
||||
desc = "Nar-Sie demands that [GLOB.sac_mind] be sacrificed before the summoning ritual can begin."
|
||||
add_overlay(GLOB.sac_image)
|
||||
return
|
||||
if(!blood_target && GLOB.sac_complete)
|
||||
if(icon_state == "runed_sense1")
|
||||
return
|
||||
animate(src, transform = null, time = 1, loop = 0)
|
||||
angle = 0
|
||||
cut_overlays()
|
||||
icon_state = "runed_sense1"
|
||||
desc = "The sacrifice is complete, prepare to summon Nar-Sie!"
|
||||
add_overlay(narnar)
|
||||
return
|
||||
if(!blood_target)
|
||||
return
|
||||
var/turf/P = get_turf(blood_target)
|
||||
var/turf/Q = get_turf(mob_viewer)
|
||||
var/area/A = get_area(P)
|
||||
if(P.z != Q.z) //The target is on a different Z level, we cannot sense that far.
|
||||
return
|
||||
desc = "You are currently tracking [blood_target] in [A.name]."
|
||||
var/target_angle = Get_Angle(Q, P)
|
||||
var/target_dist = get_dist(P, Q)
|
||||
cut_overlays()
|
||||
switch(target_dist)
|
||||
if(0 to 1)
|
||||
icon_state = "runed_sense2"
|
||||
if(2 to 8)
|
||||
icon_state = "arrow8"
|
||||
if(9 to 15)
|
||||
icon_state = "arrow7"
|
||||
if(16 to 22)
|
||||
icon_state = "arrow6"
|
||||
if(23 to 29)
|
||||
icon_state = "arrow5"
|
||||
if(30 to 36)
|
||||
icon_state = "arrow4"
|
||||
if(37 to 43)
|
||||
icon_state = "arrow3"
|
||||
if(44 to 50)
|
||||
icon_state = "arrow2"
|
||||
if(51 to 57)
|
||||
icon_state = "arrow1"
|
||||
if(58 to 64)
|
||||
icon_state = "arrow0"
|
||||
if(65 to 400)
|
||||
icon_state = "arrow"
|
||||
var/difference = target_angle - angle
|
||||
angle = target_angle
|
||||
if(!difference)
|
||||
return
|
||||
var/matrix/final = matrix(transform)
|
||||
final.Turn(difference)
|
||||
animate(src, transform = final, time = 5, loop = 0)
|
||||
|
||||
|
||||
|
||||
// CLOCKCULT
|
||||
/obj/screen/alert/clockwork
|
||||
alerttooltipstyle = "clockcult"
|
||||
@@ -393,6 +491,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
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>"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
/datum/hud/construct
|
||||
ui_style_icon = 'icons/mob/screen_construct.dmi'
|
||||
|
||||
/datum/hud/construct/New(mob/owner)
|
||||
..()
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style_icon
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.screen_loc = ui_pull_resist
|
||||
static_inventory += pull_icon
|
||||
|
||||
healths = new /obj/screen/healths/construct()
|
||||
infodisplay += healths
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/create_mob_hud()
|
||||
if(client && !hud_used)
|
||||
hud_used = new /datum/hud/construct(src)
|
||||
@@ -68,6 +68,10 @@
|
||||
using.screen_loc = ui_ghost_pai
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/language_menu
|
||||
using.icon = ui_style
|
||||
static_inventory += using
|
||||
|
||||
/datum/hud/ghost/show_hud(version = 0, mob/viewmob)
|
||||
..()
|
||||
if(!mymob.client.prefs.ghost_hud)
|
||||
|
||||
@@ -208,7 +208,6 @@
|
||||
mymob.reload_fullscreen()
|
||||
update_parallax_pref(screenmob)
|
||||
|
||||
|
||||
/datum/hud/human/show_hud(version = 0,mob/viewmob)
|
||||
..()
|
||||
hidden_inventory_update(viewmob)
|
||||
@@ -266,3 +265,6 @@
|
||||
E.screen_loc = ui_equip_position(mymob)
|
||||
if(mymob.hud_used)
|
||||
show_hud(HUD_STYLE_STANDARD,mymob)
|
||||
|
||||
/datum/hud/proc/update_locked_slots()
|
||||
return
|
||||
+12
-14
@@ -124,7 +124,6 @@
|
||||
inv_box.icon = ui_style
|
||||
inv_box.slot_id = slot_w_uniform
|
||||
inv_box.icon_state = "uniform"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_iclothing
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
@@ -133,7 +132,6 @@
|
||||
inv_box.icon = ui_style
|
||||
inv_box.slot_id = slot_wear_suit
|
||||
inv_box.icon_state = "suit"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_oclothing
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
@@ -155,7 +153,6 @@
|
||||
inv_box.name = "id"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "id"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_id
|
||||
inv_box.slot_id = slot_wear_id
|
||||
static_inventory += inv_box
|
||||
@@ -164,7 +161,6 @@
|
||||
inv_box.name = "mask"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "mask"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_mask
|
||||
inv_box.slot_id = slot_wear_mask
|
||||
toggleable_inventory += inv_box
|
||||
@@ -173,7 +169,6 @@
|
||||
inv_box.name = "neck"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "neck"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_neck
|
||||
inv_box.slot_id = slot_neck
|
||||
toggleable_inventory += inv_box
|
||||
@@ -182,7 +177,6 @@
|
||||
inv_box.name = "back"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "back"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_back
|
||||
inv_box.slot_id = slot_back
|
||||
static_inventory += inv_box
|
||||
@@ -191,7 +185,6 @@
|
||||
inv_box.name = "storage1"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "pocket"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_storage1
|
||||
inv_box.slot_id = slot_l_store
|
||||
static_inventory += inv_box
|
||||
@@ -200,7 +193,6 @@
|
||||
inv_box.name = "storage2"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "pocket"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_storage2
|
||||
inv_box.slot_id = slot_r_store
|
||||
static_inventory += inv_box
|
||||
@@ -209,7 +201,6 @@
|
||||
inv_box.name = "suit storage"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "suit_storage"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_sstore1
|
||||
inv_box.slot_id = slot_s_store
|
||||
static_inventory += inv_box
|
||||
@@ -233,7 +224,6 @@
|
||||
inv_box.name = "gloves"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "gloves"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_gloves
|
||||
inv_box.slot_id = slot_gloves
|
||||
toggleable_inventory += inv_box
|
||||
@@ -242,7 +232,6 @@
|
||||
inv_box.name = "eyes"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "glasses"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_glasses
|
||||
inv_box.slot_id = slot_glasses
|
||||
toggleable_inventory += inv_box
|
||||
@@ -251,7 +240,6 @@
|
||||
inv_box.name = "ears"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "ears"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_ears
|
||||
inv_box.slot_id = slot_ears
|
||||
toggleable_inventory += inv_box
|
||||
@@ -260,7 +248,6 @@
|
||||
inv_box.name = "head"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "head"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_head
|
||||
inv_box.slot_id = slot_head
|
||||
toggleable_inventory += inv_box
|
||||
@@ -269,7 +256,6 @@
|
||||
inv_box.name = "shoes"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "shoes"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_shoes
|
||||
inv_box.slot_id = slot_shoes
|
||||
toggleable_inventory += inv_box
|
||||
@@ -327,6 +313,18 @@
|
||||
inv_slots[inv.slot_id] = inv
|
||||
inv.update_icon()
|
||||
|
||||
/datum/hud/human/update_locked_slots()
|
||||
if(!mymob)
|
||||
return
|
||||
var/mob/living/carbon/human/H = mymob
|
||||
var/datum/species/S = H.dna.species
|
||||
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
|
||||
if(inv.slot_id)
|
||||
if(inv.slot_id in S.no_equip)
|
||||
inv.alpha = 128
|
||||
else
|
||||
inv.alpha = initial(inv.alpha)
|
||||
|
||||
/datum/hud/human/hidden_inventory_update(mob/viewer)
|
||||
if(!mymob)
|
||||
return
|
||||
|
||||
@@ -91,10 +91,9 @@
|
||||
screen_loc = ui_language_menu
|
||||
|
||||
/obj/screen/language_menu/Click()
|
||||
var/mob/living/L = usr
|
||||
if(!istype(L))
|
||||
return
|
||||
L.open_language_menu(usr)
|
||||
var/mob/M = usr
|
||||
var/datum/language_holder/H = M.get_language_holder()
|
||||
H.open_language_menu(usr)
|
||||
|
||||
/obj/screen/inventory
|
||||
var/slot_id // The indentifier for the slot. It has nothing to do with ID cards.
|
||||
@@ -532,6 +531,12 @@
|
||||
screen_loc = ui_health
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/screen/healths/construct
|
||||
icon = 'icons/mob/screen_construct.dmi'
|
||||
icon_state = "artificer_health0"
|
||||
screen_loc = ui_construct_health
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/screen/healthdoll
|
||||
name = "health doll"
|
||||
screen_loc = ui_healthdoll
|
||||
|
||||
@@ -117,7 +117,7 @@ GLOBAL_VAR_INIT(dlooc_allowed, 1)
|
||||
prefs.chat_toggles ^= CHAT_LOOC
|
||||
prefs.save_preferences()
|
||||
src << "You will [(prefs.chat_toggles & CHAT_LOOC) ? "now" : "no longer"] see messages on the LOOC channel."
|
||||
feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
SSblackbox.add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/togglelooc()
|
||||
set category = "Server"
|
||||
@@ -126,7 +126,7 @@ GLOBAL_VAR_INIT(dlooc_allowed, 1)
|
||||
toggle_looc()
|
||||
log_admin("[key_name(usr)] toggled LOOC.")
|
||||
message_admins("[key_name_admin(usr)] toggled LOOC.")
|
||||
feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
SSblackbox.add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/proc/toggle_looc(toggle = null)
|
||||
if(toggle != null) //if we're specifically en/disabling ooc
|
||||
@@ -146,7 +146,7 @@ GLOBAL_VAR_INIT(dlooc_allowed, 1)
|
||||
|
||||
log_admin("[key_name(usr)] toggled Dead LOOC.")
|
||||
message_admins("[key_name_admin(usr)] toggled Dead LOOC.")
|
||||
feedback_add_details("admin_verb","TDLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
SSblackbox.add_details("admin_verb","TDLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/mob/living/carbon/proc/has_penis()
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
/obj/item/organ/genital/Initialize()
|
||||
. = ..()
|
||||
reagents = create_reagents(fluid_max_volume)
|
||||
if(!reagents)
|
||||
create_reagents(fluid_max_volume)
|
||||
update()
|
||||
|
||||
/obj/item/organ/genital/Destroy()
|
||||
|
||||
@@ -45,9 +45,9 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick)
|
||||
switch(controller)
|
||||
if("Master")
|
||||
Recreate_MC()
|
||||
feedback_add_details("admin_verb","Restart Master Controller")
|
||||
SSblackbox.add_details("admin_verb","Restart Master Controller")
|
||||
if("Failsafe")
|
||||
new /datum/controller/failsafe()
|
||||
feedback_add_details("admin_verb","Restart Failsafe Controller")
|
||||
SSblackbox.add_details("admin_verb","Restart Failsafe Controller")
|
||||
|
||||
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
|
||||
|
||||
@@ -43,10 +43,8 @@
|
||||
var/log_attack = 0 // log attack messages
|
||||
var/log_adminchat = 0 // log admin chat messages
|
||||
var/log_pda = 0 // log pda messages
|
||||
var/log_hrefs = 0 // log all links clicked in-game. Could be used for debugging and tracking down exploits
|
||||
var/log_twitter = 0 // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
|
||||
var/log_world_topic = 0 // log all world.Topic() calls
|
||||
var/log_runtimes = FALSE // log runtimes into a file
|
||||
var/sql_enabled = 0 // for sql switching
|
||||
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
|
||||
var/allow_vote_restart = 0 // allow votes to restart
|
||||
@@ -66,9 +64,9 @@
|
||||
var/respawn = 1
|
||||
var/guest_jobban = 1
|
||||
var/usewhitelist = 0
|
||||
var/inactivity_period = 3000 //time in ds until a player is considered inactive
|
||||
var/afk_period = 6000 //time in ds until a player is considered afk and kickable
|
||||
var/kick_inactive = FALSE //force disconnect for inactive players
|
||||
var/inactivity_period = 3000 //time in ds until a player is considered inactive
|
||||
var/afk_period = 6000 //time in ds until a player is considered afk and kickable
|
||||
var/kick_inactive = FALSE //force disconnect for inactive players
|
||||
var/load_jobs_from_txt = 0
|
||||
var/automute_on = 0 //enables automuting/spam prevention
|
||||
var/minimal_access_threshold = 0 //If the number of players is larger than this threshold, minimal access will be turned on.
|
||||
@@ -129,6 +127,7 @@
|
||||
var/forbid_peaceborg = 0
|
||||
var/panic_bunker = 0 // prevents new people it hasn't seen before from connecting
|
||||
var/notify_new_player_age = 0 // how long do we notify admins of a new player
|
||||
var/notify_new_player_account_age = 0 // how long do we notify admins of a new byond account
|
||||
var/irc_first_connection_alert = 0 // do we notify the irc channel when somebody is connecting for the first time?
|
||||
|
||||
var/traitor_scaling_coeff = 6 //how much does the amount of players get divided by to determine traitors
|
||||
@@ -269,7 +268,7 @@
|
||||
|
||||
if(M.config_tag)
|
||||
if(!(M.config_tag in modes)) // ensure each mode is added only once
|
||||
GLOB.diary << "Adding game mode [M.name] ([M.config_tag]) to configuration."
|
||||
GLOB.config_error_log << "Adding game mode [M.name] ([M.config_tag]) to configuration."
|
||||
modes += M.config_tag
|
||||
mode_names[M.config_tag] = M.name
|
||||
probabilities[M.config_tag] = M.probability
|
||||
@@ -291,7 +290,7 @@
|
||||
GLOB.abandon_allowed = respawn
|
||||
|
||||
/datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist
|
||||
var/list/Lines = world.file2list(filename)
|
||||
var/list/Lines = world.file2list(filename)
|
||||
|
||||
for(var/t in Lines)
|
||||
if(!t)
|
||||
@@ -358,8 +357,6 @@
|
||||
log_adminchat = 1
|
||||
if("log_pda")
|
||||
log_pda = 1
|
||||
if("log_hrefs")
|
||||
log_hrefs = 1
|
||||
if("log_twitter")
|
||||
log_twitter = 1
|
||||
if("log_world_topic")
|
||||
@@ -410,12 +407,12 @@
|
||||
usewhitelist = TRUE
|
||||
if("allow_metadata")
|
||||
allow_Metadata = 1
|
||||
if("inactivity_period")
|
||||
inactivity_period = text2num(value) * 10 //documented as seconds in config.txt
|
||||
if("afk_period")
|
||||
afk_period = text2num(value) * 10 // ^^^
|
||||
if("inactivity_period")
|
||||
inactivity_period = text2num(value) * 10 //documented as seconds in config.txt
|
||||
if("afk_period")
|
||||
afk_period = text2num(value) * 10 // ^^^
|
||||
if("kick_inactive")
|
||||
kick_inactive = TRUE
|
||||
kick_inactive = TRUE
|
||||
if("load_jobs_from_txt")
|
||||
load_jobs_from_txt = 1
|
||||
if("forbid_singulo_possession")
|
||||
@@ -476,6 +473,8 @@
|
||||
panic_bunker = 1
|
||||
if("notify_new_player_age")
|
||||
notify_new_player_age = text2num(value)
|
||||
if("notify_new_player_account_age")
|
||||
notify_new_player_account_age = text2num(value)
|
||||
if("irc_first_connection_alert")
|
||||
irc_first_connection_alert = 1
|
||||
if("check_randomizer")
|
||||
@@ -493,12 +492,6 @@
|
||||
ipintel_save_bad = text2num(value)
|
||||
if("aggressive_changelog")
|
||||
aggressive_changelog = 1
|
||||
if("log_runtimes")
|
||||
log_runtimes = TRUE
|
||||
var/newlog = file("data/logs/runtimes/runtime-[time2text(world.realtime, "YYYY-MM-DD")].log")
|
||||
if(GLOB.runtime_diary != newlog)
|
||||
world.log << "Now logging runtimes to data/logs/runtimes/runtime-[time2text(world.realtime, "YYYY-MM-DD")].log"
|
||||
GLOB.runtime_diary = newlog
|
||||
if("autoconvert_notes")
|
||||
autoconvert_notes = 1
|
||||
if("allow_webclient")
|
||||
@@ -542,7 +535,7 @@
|
||||
if("error_msg_delay")
|
||||
error_msg_delay = text2num(value)
|
||||
else
|
||||
GLOB.diary << "Unknown setting in configuration: '[name]'"
|
||||
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
|
||||
|
||||
else if(type == "game_options")
|
||||
switch(name)
|
||||
@@ -605,13 +598,13 @@
|
||||
if(mode_name in modes)
|
||||
continuous[mode_name] = 1
|
||||
else
|
||||
GLOB.diary << "Unknown continuous configuration definition: [mode_name]."
|
||||
GLOB.config_error_log << "Unknown continuous configuration definition: [mode_name]."
|
||||
if("midround_antag")
|
||||
var/mode_name = lowertext(value)
|
||||
if(mode_name in modes)
|
||||
midround_antag[mode_name] = 1
|
||||
else
|
||||
GLOB.diary << "Unknown midround antagonist configuration definition: [mode_name]."
|
||||
GLOB.config_error_log << "Unknown midround antagonist configuration definition: [mode_name]."
|
||||
if("midround_antag_time_check")
|
||||
midround_antag_time_check = text2num(value)
|
||||
if("midround_antag_life_check")
|
||||
@@ -627,9 +620,9 @@
|
||||
if(mode_name in modes)
|
||||
min_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
GLOB.diary << "Unknown minimum population configuration definition: [mode_name]."
|
||||
GLOB.config_error_log << "Unknown minimum population configuration definition: [mode_name]."
|
||||
else
|
||||
GLOB.diary << "Incorrect minimum population configuration definition: [mode_name] [mode_value]."
|
||||
GLOB.config_error_log << "Incorrect minimum population configuration definition: [mode_name] [mode_value]."
|
||||
if("max_pop")
|
||||
var/pop_pos = findtext(value, " ")
|
||||
var/mode_name = null
|
||||
@@ -641,9 +634,9 @@
|
||||
if(mode_name in modes)
|
||||
max_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
GLOB.diary << "Unknown maximum population configuration definition: [mode_name]."
|
||||
GLOB.config_error_log << "Unknown maximum population configuration definition: [mode_name]."
|
||||
else
|
||||
GLOB.diary << "Incorrect maximum population configuration definition: [mode_name] [mode_value]."
|
||||
GLOB.config_error_log << "Incorrect maximum population configuration definition: [mode_name] [mode_value]."
|
||||
if("shuttle_refuel_delay")
|
||||
shuttle_refuel_delay = text2num(value)
|
||||
if("show_game_type_odds")
|
||||
@@ -671,9 +664,9 @@
|
||||
if(prob_name in modes)
|
||||
probabilities[prob_name] = text2num(prob_value)
|
||||
else
|
||||
GLOB.diary << "Unknown game mode probability configuration definition: [prob_name]."
|
||||
GLOB.config_error_log << "Unknown game mode probability configuration definition: [prob_name]."
|
||||
else
|
||||
GLOB.diary << "Incorrect probability configuration definition: [prob_name] [prob_value]."
|
||||
GLOB.config_error_log << "Incorrect probability configuration definition: [prob_name] [prob_value]."
|
||||
|
||||
if("protect_roles_from_antagonist")
|
||||
protect_roles_from_antagonist = 1
|
||||
@@ -720,7 +713,7 @@
|
||||
// Value is in the form "LAWID,NUMBER"
|
||||
var/list/L = splittext(value, ",")
|
||||
if(L.len != 2)
|
||||
GLOB.diary << "Invalid LAW_WEIGHT: " + t
|
||||
GLOB.config_error_log << "Invalid LAW_WEIGHT: " + t
|
||||
continue
|
||||
var/lawid = L[1]
|
||||
var/weight = text2num(L[2])
|
||||
@@ -776,8 +769,8 @@
|
||||
mentors_mobname_only = 1
|
||||
if ("mentor_legacy_system")
|
||||
mentor_legacy_system = 1
|
||||
else
|
||||
GLOB.diary << "Unknown setting in configuration: '[name]'"
|
||||
// else
|
||||
// GLOB.config_error_log << "Adding game mode [M.name] ([M.config_tag]) to configuration."
|
||||
|
||||
fps = round(fps)
|
||||
if(fps <= 0)
|
||||
@@ -785,7 +778,7 @@
|
||||
|
||||
|
||||
/datum/configuration/proc/loadmaplist(filename)
|
||||
var/list/Lines = world.file2list(filename)
|
||||
var/list/Lines = world.file2list(filename)
|
||||
|
||||
var/datum/map_config/currentmap = null
|
||||
for(var/t in Lines)
|
||||
@@ -831,11 +824,11 @@
|
||||
maplist[currentmap.map_name] = currentmap
|
||||
currentmap = null
|
||||
else
|
||||
GLOB.diary << "Unknown command in map vote config: '[command]'"
|
||||
GLOB.config_error_log << "Unknown command in map vote config: '[command]'"
|
||||
|
||||
|
||||
/datum/configuration/proc/loadsql(filename)
|
||||
var/list/Lines = world.file2list(filename)
|
||||
var/list/Lines = world.file2list(filename)
|
||||
for(var/t in Lines)
|
||||
if(!t)
|
||||
continue
|
||||
@@ -875,7 +868,7 @@
|
||||
if("feedback_tableprefix")
|
||||
global.sqlfdbktableprefix = value
|
||||
else
|
||||
GLOB.diary << "Unknown setting in configuration: '[name]'"
|
||||
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
|
||||
|
||||
/datum/configuration/proc/pick_mode(mode_name)
|
||||
// I wish I didn't have to instance the game modes in order to look up
|
||||
|
||||
@@ -52,6 +52,12 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
|
||||
/datum/controller/global_vars/Initialize()
|
||||
gvars_datum_init_order = list()
|
||||
gvars_datum_protected_varlist = list("gvars_datum_protected_varlist")
|
||||
|
||||
//See https://github.com/tgstation/tgstation/issues/26954
|
||||
for(var/I in typesof(/datum/controller/global_vars/proc))
|
||||
var/CLEANBOT_RETURNS = "[I]"
|
||||
pass(CLEANBOT_RETURNS)
|
||||
|
||||
for(var/I in vars - gvars_datum_in_built_vars)
|
||||
var/start_tick = world.time
|
||||
call(src, "InitGlobal[I]")()
|
||||
|
||||
+18
-13
@@ -48,7 +48,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
|
||||
var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
|
||||
// Has round started? (So we know what subsystems to run)
|
||||
var/round_started = 0
|
||||
var/local_round_started = FALSE //Don't read this var, use SSticker.HasRoundStarted() instead
|
||||
|
||||
// The type of the last subsystem to be process()'d.
|
||||
var/last_type_processed
|
||||
@@ -189,7 +189,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
|
||||
// Notify the MC that the round has started.
|
||||
/datum/controller/master/proc/RoundStart()
|
||||
round_started = 1
|
||||
local_round_started = TRUE
|
||||
var/timer = world.time
|
||||
for (var/datum/controller/subsystem/SS in subsystems)
|
||||
if (SS.flags & SS_FIRE_IN_LOBBY || SS.flags & SS_TICKER)
|
||||
@@ -222,7 +222,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
// local vars rock
|
||||
|
||||
// Schedule the first run of the Subsystems.
|
||||
round_started = world.has_round_started()
|
||||
local_round_started = world.has_round_started()
|
||||
//all this shit is here so that flag edits can be refreshed by restarting the MC. (and for speed)
|
||||
var/list/tickersubsystems = list()
|
||||
var/list/normalsubsystems = list()
|
||||
@@ -245,7 +245,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
lobbysubsystems += SS
|
||||
timer += world.tick_lag * rand(1, 5)
|
||||
SS.next_fire = timer
|
||||
else if (round_started)
|
||||
else if (local_round_started)
|
||||
timer += world.tick_lag * rand(1, 5)
|
||||
SS.next_fire = timer
|
||||
normalsubsystems += SS
|
||||
@@ -280,7 +280,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
// because sleeps are processed in the order received, so longer sleeps are more likely to run first
|
||||
if (world.tick_usage > TICK_LIMIT_MC)
|
||||
sleep_delta += 2
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.5)
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING * 0.5
|
||||
sleep(world.tick_lag * (processing + sleep_delta))
|
||||
continue
|
||||
|
||||
@@ -296,7 +296,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
if (!Failsafe || (Failsafe.processing_interval > 0 && (Failsafe.lasttick+(Failsafe.processing_interval*5)) < world.time))
|
||||
new/datum/controller/failsafe() // (re)Start the failsafe.
|
||||
if (!queue_head || !(iteration % 3))
|
||||
if (round_started)
|
||||
if (local_round_started)
|
||||
subsystems_to_check = normalsubsystems
|
||||
else
|
||||
subsystems_to_check = lobbysubsystems
|
||||
@@ -421,26 +421,31 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
else
|
||||
tick_precentage = tick_remaining
|
||||
|
||||
GLOB.CURRENT_TICKLIMIT = world.tick_usage + tick_precentage
|
||||
tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun)
|
||||
|
||||
GLOB.CURRENT_TICKLIMIT = round(world.tick_usage + tick_precentage)
|
||||
|
||||
if (!(queue_node_flags & SS_TICKER))
|
||||
ran_non_ticker = TRUE
|
||||
ran = TRUE
|
||||
tick_usage = world.tick_usage
|
||||
|
||||
queue_node_paused = (queue_node.state == SS_PAUSED || queue_node.state == SS_PAUSING)
|
||||
last_type_processed = queue_node
|
||||
|
||||
queue_node.state = SS_RUNNING
|
||||
|
||||
tick_usage = world.tick_usage
|
||||
var/state = queue_node.ignite(queue_node_paused)
|
||||
tick_usage = world.tick_usage - tick_usage
|
||||
|
||||
if (state == SS_RUNNING)
|
||||
state = SS_IDLE
|
||||
current_tick_budget -= queue_node_priority
|
||||
tick_usage = world.tick_usage - tick_usage
|
||||
|
||||
|
||||
if (tick_usage < 0)
|
||||
tick_usage = 0
|
||||
|
||||
queue_node.tick_overrun = max(0, MC_AVG_FAST_UP_SLOW_DOWN(queue_node.tick_overrun, tick_usage-tick_precentage))
|
||||
queue_node.state = state
|
||||
|
||||
if (state == SS_PAUSED)
|
||||
@@ -467,13 +472,13 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
queue_node.times_fired++
|
||||
|
||||
if (queue_node_flags & SS_TICKER)
|
||||
queue_node.next_fire = world.time + (world.tick_lag * queue_node.wait)
|
||||
queue_node.next_fire = world.time + (world.tick_lag * (queue_node.wait + (queue_node.tick_overrun/100)))
|
||||
else if (queue_node_flags & SS_POST_FIRE_TIMING)
|
||||
queue_node.next_fire = world.time + queue_node.wait
|
||||
queue_node.next_fire = world.time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
|
||||
else if (queue_node_flags & SS_KEEP_TIMING)
|
||||
queue_node.next_fire += queue_node.wait
|
||||
else
|
||||
queue_node.next_fire = queue_node.queued_time + queue_node.wait
|
||||
queue_node.next_fire = queue_node.queued_time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
|
||||
|
||||
queue_node.queued_time = 0
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
var/next_fire = 0 //scheduled world.time for next fire()
|
||||
var/cost = 0 //average time to execute
|
||||
var/tick_usage = 0 //average tick usage
|
||||
var/tick_overrun = 0 //average tick overrun
|
||||
var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc.
|
||||
var/paused_ticks = 0 //ticks this ss is taking to run right now.
|
||||
var/paused_tick_usage //total tick_usage of all of our runs while pausing this run
|
||||
@@ -168,7 +169,7 @@
|
||||
|
||||
|
||||
if(can_fire && !(SS_NO_FIRE in flags))
|
||||
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%|[round(ticks,0.1)]\t[msg]"
|
||||
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]"
|
||||
else
|
||||
msg = "OFFLINE\t[msg]"
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
diff a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm (rejected hunks)
|
||||
@@ -12,6 +12,7 @@ SUBSYSTEM_DEF(atoms)
|
||||
var/old_initialized
|
||||
|
||||
var/list/late_loaders
|
||||
+ var/list/created_atoms
|
||||
|
||||
var/list/BadInitializeCalls = list()
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
GLOBAL_DATUM_INIT(blackbox, /datum/feedback, new)
|
||||
|
||||
//the feedback datum; stores all feedback
|
||||
/datum/feedback
|
||||
var/list/messages = list()
|
||||
var/list/messages_admin = list()
|
||||
SUBSYSTEM_DEF(blackbox)
|
||||
name = "Blackbox"
|
||||
wait = 6000
|
||||
flags = SS_NO_TICK_CHECK
|
||||
|
||||
var/list/msg_common = list()
|
||||
var/list/msg_science = list()
|
||||
@@ -15,21 +13,48 @@ GLOBAL_DATUM_INIT(blackbox, /datum/feedback, new)
|
||||
var/list/msg_syndicate = list()
|
||||
var/list/msg_service = list()
|
||||
var/list/msg_cargo = list()
|
||||
var/list/msg_other = list()
|
||||
|
||||
var/list/datum/feedback_variable/feedback = new()
|
||||
var/list/feedback = list() //list of datum/feedback_variable
|
||||
|
||||
/datum/feedback/proc/find_feedback_datum(variable)
|
||||
for (var/datum/feedback_variable/FV in feedback)
|
||||
if (FV.get_variable() == variable)
|
||||
return FV
|
||||
var/datum/feedback_variable/FV = new(variable)
|
||||
feedback += FV
|
||||
return FV
|
||||
//poll population
|
||||
/datum/controller/subsystem/blackbox/fire()
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
var/playercount = 0
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.client)
|
||||
playercount += 1
|
||||
var/admincount = GLOB.admins.len
|
||||
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON('[world.internet_address]'), '[world.port]')")
|
||||
query_record_playercount.Execute()
|
||||
|
||||
/datum/feedback/proc/get_round_feedback()
|
||||
return feedback
|
||||
/datum/controller/subsystem/blackbox/Recover()
|
||||
msg_common = SSblackbox.msg_common
|
||||
msg_science = SSblackbox.msg_science
|
||||
msg_command = SSblackbox.msg_command
|
||||
msg_medical = SSblackbox.msg_medical
|
||||
msg_engineering = SSblackbox.msg_engineering
|
||||
msg_security = SSblackbox.msg_security
|
||||
msg_deathsquad = SSblackbox.msg_deathsquad
|
||||
msg_syndicate = SSblackbox.msg_syndicate
|
||||
msg_service = SSblackbox.msg_service
|
||||
msg_cargo = SSblackbox.msg_cargo
|
||||
msg_other = SSblackbox.msg_other
|
||||
|
||||
/datum/feedback/proc/round_end_data_gathering()
|
||||
|
||||
feedback = SSblackbox.feedback
|
||||
|
||||
//no touchie
|
||||
/datum/controller/subsystem/blackbox/can_vv_get(var_name)
|
||||
if(var_name == "feedback")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
/datum/controller/subsystem/blackbox/Shutdown()
|
||||
var/pda_msg_amt = 0
|
||||
var/rc_msg_amt = 0
|
||||
|
||||
@@ -39,41 +64,26 @@ GLOBAL_DATUM_INIT(blackbox, /datum/feedback, new)
|
||||
if (MS.rc_msgs.len > rc_msg_amt)
|
||||
rc_msg_amt = MS.rc_msgs.len
|
||||
|
||||
feedback_set_details("radio_usage","")
|
||||
set_details("radio_usage","")
|
||||
|
||||
feedback_add_details("radio_usage","COM-[msg_common.len]")
|
||||
feedback_add_details("radio_usage","SCI-[msg_science.len]")
|
||||
feedback_add_details("radio_usage","HEA-[msg_command.len]")
|
||||
feedback_add_details("radio_usage","MED-[msg_medical.len]")
|
||||
feedback_add_details("radio_usage","ENG-[msg_engineering.len]")
|
||||
feedback_add_details("radio_usage","SEC-[msg_security.len]")
|
||||
feedback_add_details("radio_usage","DTH-[msg_deathsquad.len]")
|
||||
feedback_add_details("radio_usage","SYN-[msg_syndicate.len]")
|
||||
feedback_add_details("radio_usage","SRV-[msg_service.len]")
|
||||
feedback_add_details("radio_usage","CAR-[msg_cargo.len]")
|
||||
feedback_add_details("radio_usage","OTH-[messages.len]")
|
||||
feedback_add_details("radio_usage","PDA-[pda_msg_amt]")
|
||||
feedback_add_details("radio_usage","RC-[rc_msg_amt]")
|
||||
add_details("radio_usage","COM-[msg_common.len]")
|
||||
add_details("radio_usage","SCI-[msg_science.len]")
|
||||
add_details("radio_usage","HEA-[msg_command.len]")
|
||||
add_details("radio_usage","MED-[msg_medical.len]")
|
||||
add_details("radio_usage","ENG-[msg_engineering.len]")
|
||||
add_details("radio_usage","SEC-[msg_security.len]")
|
||||
add_details("radio_usage","DTH-[msg_deathsquad.len]")
|
||||
add_details("radio_usage","SYN-[msg_syndicate.len]")
|
||||
add_details("radio_usage","SRV-[msg_service.len]")
|
||||
add_details("radio_usage","CAR-[msg_cargo.len]")
|
||||
add_details("radio_usage","OTH-[msg_other.len]")
|
||||
add_details("radio_usage","PDA-[pda_msg_amt]")
|
||||
add_details("radio_usage","RC-[rc_msg_amt]")
|
||||
|
||||
feedback_set_details("round_end","[time2text(world.realtime)]") //This one MUST be the last one that gets set.
|
||||
set_details("round_end","[time2text(world.realtime)]") //This one MUST be the last one that gets set.
|
||||
|
||||
//This proc is only to be called at round end.
|
||||
/datum/feedback/proc/save_all_data_to_sql()
|
||||
if (!feedback) return
|
||||
|
||||
round_end_data_gathering() //round_end time logging and some other data processing
|
||||
if (!SSdbcore.Connect()) return
|
||||
var/round_id
|
||||
|
||||
var/datum/DBQuery/query_feedback_max_id = SSdbcore.NewQuery("SELECT MAX(round_id) AS round_id FROM [format_table_name("feedback")]")
|
||||
if(!query_feedback_max_id.Execute())
|
||||
if (!SSdbcore.Connect())
|
||||
return
|
||||
while (query_feedback_max_id.NextRow())
|
||||
round_id = query_feedback_max_id.item[1]
|
||||
|
||||
if (!isnum(round_id))
|
||||
round_id = text2num(round_id)
|
||||
round_id++
|
||||
|
||||
var/sqlrowlist = ""
|
||||
|
||||
@@ -81,7 +91,7 @@ GLOBAL_DATUM_INIT(blackbox, /datum/feedback, new)
|
||||
if (sqlrowlist != "")
|
||||
sqlrowlist += ", " //a comma (,) at the start of the first row to insert will trigger a SQL error
|
||||
|
||||
sqlrowlist += "(null, Now(), [round_id], \"[sanitizeSQL(FV.get_variable())]\", [FV.get_value()], \"[sanitizeSQL(FV.get_details())]\")"
|
||||
sqlrowlist += "(null, Now(), [GLOB.round_id], \"[sanitizeSQL(FV.get_variable())]\", [FV.get_value()], \"[sanitizeSQL(FV.get_details())]\")"
|
||||
|
||||
if (sqlrowlist == "")
|
||||
return
|
||||
@@ -89,69 +99,99 @@ GLOBAL_DATUM_INIT(blackbox, /datum/feedback, new)
|
||||
var/datum/DBQuery/query_feedback_save = SSdbcore.NewQuery("INSERT DELAYED IGNORE INTO [format_table_name("feedback")] VALUES " + sqlrowlist)
|
||||
query_feedback_save.Execute()
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/LogBroadcast(blackbox_msg, freq)
|
||||
switch(freq)
|
||||
if(1459)
|
||||
msg_common += blackbox_msg
|
||||
if(1351)
|
||||
msg_science += blackbox_msg
|
||||
if(1353)
|
||||
msg_command += blackbox_msg
|
||||
if(1355)
|
||||
msg_medical += blackbox_msg
|
||||
if(1357)
|
||||
msg_engineering += blackbox_msg
|
||||
if(1359)
|
||||
msg_security += blackbox_msg
|
||||
if(1441)
|
||||
msg_deathsquad += blackbox_msg
|
||||
if(1213)
|
||||
msg_syndicate += blackbox_msg
|
||||
if(1349)
|
||||
msg_service += blackbox_msg
|
||||
if(1347)
|
||||
msg_cargo += blackbox_msg
|
||||
else
|
||||
msg_other += blackbox_msg
|
||||
|
||||
/proc/feedback_set(variable,value)
|
||||
if(!GLOB.blackbox)
|
||||
return
|
||||
/datum/controller/subsystem/blackbox/proc/find_feedback_datum(variable)
|
||||
for(var/datum/feedback_variable/FV in feedback)
|
||||
if(FV.get_variable() == variable)
|
||||
return FV
|
||||
|
||||
var/datum/feedback_variable/FV = GLOB.blackbox.find_feedback_datum(variable)
|
||||
|
||||
if(!FV)
|
||||
return
|
||||
var/datum/feedback_variable/FV = new(variable)
|
||||
feedback += FV
|
||||
return FV
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/set_val(variable, value)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.set_value(value)
|
||||
|
||||
/proc/feedback_inc(variable,value)
|
||||
if(!GLOB.blackbox)
|
||||
return
|
||||
|
||||
var/datum/feedback_variable/FV = GLOB.blackbox.find_feedback_datum(variable)
|
||||
|
||||
if(!FV)
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/inc(variable, value)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.inc(value)
|
||||
|
||||
/proc/feedback_dec(variable,value)
|
||||
if(!GLOB.blackbox)
|
||||
return
|
||||
|
||||
var/datum/feedback_variable/FV = GLOB.blackbox.find_feedback_datum(variable)
|
||||
|
||||
if(!FV)
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/dec(variable,value)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.dec(value)
|
||||
|
||||
/proc/feedback_set_details(variable,details)
|
||||
if(!GLOB.blackbox)
|
||||
return
|
||||
|
||||
var/datum/feedback_variable/FV = GLOB.blackbox.find_feedback_datum(variable)
|
||||
|
||||
if(!FV)
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/set_details(variable,details)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.set_details(details)
|
||||
|
||||
/proc/feedback_add_details(variable,details)
|
||||
if(!GLOB.blackbox)
|
||||
return
|
||||
|
||||
var/datum/feedback_variable/FV = GLOB.blackbox.find_feedback_datum(variable)
|
||||
|
||||
if(!FV)
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/add_details(variable,details)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.add_details(details)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
if(!L || !L.key || !L.mind)
|
||||
return
|
||||
var/turf/T = get_turf(L)
|
||||
var/area/placeofdeath = get_area(T.loc)
|
||||
var/sqlname = sanitizeSQL(L.real_name)
|
||||
var/sqlkey = sanitizeSQL(L.ckey)
|
||||
var/sqljob = sanitizeSQL(L.mind.assigned_role)
|
||||
var/sqlspecial = sanitizeSQL(L.mind.special_role)
|
||||
var/sqlpod = sanitizeSQL(placeofdeath.name)
|
||||
var/laname
|
||||
var/lakey
|
||||
if(L.lastattacker && ismob(L.lastattacker))
|
||||
var/mob/LA = L.lastattacker
|
||||
laname = sanitizeSQL(LA.real_name)
|
||||
lakey = sanitizeSQL(LA.key)
|
||||
var/sqlgender = sanitizeSQL(L.gender)
|
||||
var/sqlbrute = sanitizeSQL(L.getBruteLoss())
|
||||
var/sqlfire = sanitizeSQL(L.getFireLoss())
|
||||
var/sqlbrain = sanitizeSQL(L.getBrainLoss())
|
||||
var/sqloxy = sanitizeSQL(L.getOxyLoss())
|
||||
var/sqltox = sanitizeSQL(L.getStaminaLoss())
|
||||
var/sqlclone = sanitizeSQL(L.getStaminaLoss())
|
||||
var/sqlstamina = sanitizeSQL(L.getStaminaLoss())
|
||||
var/coord = sanitizeSQL("[L.x], [L.y], [L.z]")
|
||||
var/map = sanitizeSQL(SSmapping.config.map_name)
|
||||
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss, coord, mapname, server_ip, server_port) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[SQLtime()]', '[laname]', '[lakey]', '[sqlgender]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina], '[coord]', '[map]', INET_ATON('[world.internet_address]'), '[world.port]')")
|
||||
query_report_death.Execute()
|
||||
|
||||
|
||||
//feedback variable datum, for storing all kinds of data
|
||||
/datum/feedback_variable
|
||||
var/variable
|
||||
var/value
|
||||
var/details
|
||||
|
||||
/datum/feedback_variable/New(var/param_variable,var/param_value = 0)
|
||||
/datum/feedback_variable/New(param_variable, param_value = 0)
|
||||
variable = param_variable
|
||||
value = param_value
|
||||
|
||||
@@ -204,50 +244,3 @@ GLOBAL_DATUM_INIT(blackbox, /datum/feedback, new)
|
||||
|
||||
/datum/feedback_variable/proc/get_parsed()
|
||||
return list(variable,value,details)
|
||||
|
||||
//sql reporting procs
|
||||
/proc/sql_poll_population()
|
||||
if(!config.sql_enabled)
|
||||
return
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
var/playercount = 0
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.client)
|
||||
playercount += 1
|
||||
var/admincount = GLOB.admins.len
|
||||
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON('[world.internet_address]'), '[world.port]')")
|
||||
query_record_playercount.Execute()
|
||||
|
||||
/proc/sql_report_death(mob/living/L)
|
||||
if(!config.sql_enabled)
|
||||
return
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
if(!L || !L.key || !L.mind)
|
||||
return
|
||||
var/turf/T = get_turf(L)
|
||||
var/area/placeofdeath = get_area(T.loc)
|
||||
var/sqlname = sanitizeSQL(L.real_name)
|
||||
var/sqlkey = sanitizeSQL(L.ckey)
|
||||
var/sqljob = sanitizeSQL(L.mind.assigned_role)
|
||||
var/sqlspecial = sanitizeSQL(L.mind.special_role)
|
||||
var/sqlpod = sanitizeSQL(placeofdeath.name)
|
||||
var/laname
|
||||
var/lakey
|
||||
if(L.lastattacker && ismob(L.lastattacker))
|
||||
var/mob/LA = L.lastattacker
|
||||
laname = sanitizeSQL(LA.real_name)
|
||||
lakey = sanitizeSQL(LA.key)
|
||||
var/sqlgender = sanitizeSQL(L.gender)
|
||||
var/sqlbrute = sanitizeSQL(L.getBruteLoss())
|
||||
var/sqlfire = sanitizeSQL(L.getFireLoss())
|
||||
var/sqlbrain = sanitizeSQL(L.getBrainLoss())
|
||||
var/sqloxy = sanitizeSQL(L.getOxyLoss())
|
||||
var/sqltox = sanitizeSQL(L.getStaminaLoss())
|
||||
var/sqlclone = sanitizeSQL(L.getStaminaLoss())
|
||||
var/sqlstamina = sanitizeSQL(L.getStaminaLoss())
|
||||
var/coord = sanitizeSQL("[L.x], [L.y], [L.z]")
|
||||
var/map = sanitizeSQL(SSmapping.config.map_name)
|
||||
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss, coord, mapname, server_ip, server_port) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[SQLtime()]', '[laname]', '[lakey]', '[sqlgender]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina], '[coord]', '[map]', INET_ATON('[world.internet_address]'), '[world.port]')")
|
||||
query_report_death.Execute()
|
||||
@@ -308,7 +308,6 @@ SUBSYSTEM_DEF(job)
|
||||
Debug("DO non-human failed, Player: [player], Job:[job.title]")
|
||||
continue
|
||||
|
||||
|
||||
// If the player wants that job on this level, then try give it to him.
|
||||
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
|
||||
|
||||
@@ -319,6 +318,7 @@ SUBSYSTEM_DEF(job)
|
||||
unassigned -= player
|
||||
break
|
||||
|
||||
|
||||
// Hand out random jobs to the people who didn't get any in the last check
|
||||
// Also makes sure that they got their preference correct
|
||||
for(var/mob/dead/new_player/player in unassigned)
|
||||
@@ -483,7 +483,7 @@ SUBSYSTEM_DEF(job)
|
||||
else level4++ //not selected
|
||||
|
||||
tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|YOUNG=[level6]|-"
|
||||
feedback_add_details("job_preferences",tmp_str)
|
||||
SSblackbox.add_details("job_preferences",tmp_str)
|
||||
|
||||
/datum/controller/subsystem/job/proc/PopcapReached()
|
||||
if(config.hard_popcap || config.extreme_popcap)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
SUBSYSTEM_DEF(language)
|
||||
name = "Language"
|
||||
init_order = INIT_ORDER_LANGUAGE
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
/datum/controller/subsystem/language/Initialize(timeofday)
|
||||
for(var/L in subtypesof(/datum/language))
|
||||
var/datum/language/language = L
|
||||
if(!initial(language.key))
|
||||
continue
|
||||
|
||||
GLOB.all_languages += language
|
||||
|
||||
var/datum/language/instance = new language
|
||||
|
||||
GLOB.language_datum_instances[language] = instance
|
||||
|
||||
return ..()
|
||||
@@ -36,18 +36,10 @@ SUBSYSTEM_DEF(lighting)
|
||||
for (i in 1 to GLOB.lighting_update_lights.len)
|
||||
var/datum/light_source/L = GLOB.lighting_update_lights[i]
|
||||
|
||||
if (L.check() || QDELETED(L) || L.force_update)
|
||||
L.remove_lum()
|
||||
if (!QDELETED(L))
|
||||
L.apply_lum()
|
||||
L.update_corners()
|
||||
|
||||
else if (L.vis_update) //We smartly update only tiles that became (in) visible to use.
|
||||
L.smart_vis_update()
|
||||
L.needs_update = LIGHTING_NO_UPDATE
|
||||
|
||||
L.vis_update = FALSE
|
||||
L.force_update = FALSE
|
||||
L.needs_update = FALSE
|
||||
|
||||
if(init_tick_checks)
|
||||
CHECK_TICK
|
||||
else if (MC_TICK_CHECK)
|
||||
|
||||
@@ -119,7 +119,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
INIT_ANNOUNCE("Loading [config.map_name]...")
|
||||
TryLoadZ(config.GetFullMapPath(), FailedZs, ZLEVEL_STATION)
|
||||
INIT_ANNOUNCE("Loaded station in [(REALTIMEOFDAY - start_time)/10]s!")
|
||||
feedback_add_details("map_name", config.map_name)
|
||||
SSblackbox.add_details("map_name", config.map_name)
|
||||
|
||||
if(config.minetype != "lavaland")
|
||||
INIT_ANNOUNCE("WARNING: A map without lavaland set as it's minetype was loaded! This is being ignored! Update the maploader code!")
|
||||
|
||||
@@ -150,7 +150,7 @@ SUBSYSTEM_DEF(pai)
|
||||
if(!(ROLE_PAI in G.client.prefs.be_special))
|
||||
continue
|
||||
//G << 'sound/misc/server-ready.ogg' //Alerting them to their consideration
|
||||
to_chat(G, "<span class='ghostalert'>Someone is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>")
|
||||
to_chat(G, "<span class='ghostalert'>[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>")
|
||||
addtimer(CALLBACK(src, .proc/spam_again), spam_delay)
|
||||
var/list/available = list()
|
||||
for(var/datum/paiCandidate/c in SSpai.candidates)
|
||||
|
||||
@@ -9,12 +9,15 @@ SUBSYSTEM_DEF(persistence)
|
||||
|
||||
var/list/obj/structure/chisel_message/chisel_messages = list()
|
||||
var/list/saved_messages = list()
|
||||
var/savefile/chisel_messages_sav
|
||||
|
||||
var/savefile/trophy_sav
|
||||
var/list/saved_trophies = list()
|
||||
|
||||
/datum/controller/subsystem/persistence/Initialize()
|
||||
LoadSatchels()
|
||||
LoadPoly()
|
||||
LoadChiselMessages()
|
||||
LoadTrophies()
|
||||
..()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadSatchels()
|
||||
@@ -71,14 +74,14 @@ SUBSYSTEM_DEF(persistence)
|
||||
break //Who's been duping the bird?!
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadChiselMessages()
|
||||
chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
|
||||
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
|
||||
var/saved_json
|
||||
chisel_messages_sav[SSmapping.config.map_name] >> saved_json
|
||||
|
||||
if(!saved_json)
|
||||
return
|
||||
|
||||
var/saved_messages = json_decode(saved_json)
|
||||
var/list/saved_messages = json_decode(saved_json)
|
||||
|
||||
for(var/item in saved_messages)
|
||||
if(!islist(item))
|
||||
@@ -100,15 +103,57 @@ SUBSYSTEM_DEF(persistence)
|
||||
|
||||
var/obj/structure/chisel_message/M = new(T)
|
||||
|
||||
M.unpack(item)
|
||||
if(!M.loc)
|
||||
M.persists = FALSE
|
||||
qdel(M)
|
||||
if(!QDELETED(M))
|
||||
M.unpack(item)
|
||||
|
||||
log_world("Loaded [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadTrophies()
|
||||
trophy_sav = new /savefile("data/npc_saves/TrophyItems.sav")
|
||||
var/saved_json
|
||||
trophy_sav >> saved_json
|
||||
|
||||
if(!saved_json)
|
||||
return
|
||||
|
||||
var/decoded_json = json_decode(saved_json)
|
||||
|
||||
if(!islist(decoded_json))
|
||||
return
|
||||
|
||||
saved_trophies = decoded_json
|
||||
|
||||
SetUpTrophies(saved_trophies.Copy())
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
|
||||
for(var/A in GLOB.trophy_cases)
|
||||
var/obj/structure/displaycase/trophy/T = A
|
||||
T.added_roundstart = TRUE
|
||||
|
||||
var/trophy_data = pick_n_take(trophy_items)
|
||||
|
||||
if(!islist(trophy_data))
|
||||
continue
|
||||
|
||||
var/list/chosen_trophy = trophy_data
|
||||
|
||||
if(!chosen_trophy || isemptylist(chosen_trophy)) //Malformed
|
||||
continue
|
||||
|
||||
var/path = text2path(chosen_trophy["path"]) //If the item no longer exist, this returns null
|
||||
if(!path)
|
||||
continue
|
||||
|
||||
T.showpiece = new /obj/item/showpiece_dummy(T, path)
|
||||
T.trophy_message = chosen_trophy["message"]
|
||||
T.placer_key = chosen_trophy["placer_key"]
|
||||
T.update_icon()
|
||||
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectData()
|
||||
CollectChiselMessages()
|
||||
CollectSecretSatchels()
|
||||
CollectTrophies()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
|
||||
for(var/A in new_secret_satchels)
|
||||
@@ -129,10 +174,26 @@ SUBSYSTEM_DEF(persistence)
|
||||
secret_satchels[SSmapping.config.map_name] << old_secret_satchels
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
|
||||
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
|
||||
|
||||
for(var/obj/structure/chisel_message/M in chisel_messages)
|
||||
saved_messages += list(M.pack())
|
||||
|
||||
log_world("Saved [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
|
||||
|
||||
chisel_messages_sav[SSmapping.config.map_name] << json_encode(saved_messages)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
|
||||
saved_messages += list(M.pack()) // dm eats one list.
|
||||
saved_messages += list(M.pack()) // dm eats one list
|
||||
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectTrophies()
|
||||
trophy_sav << json_encode(saved_trophies)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
|
||||
if(!T.added_roundstart && T.showpiece)
|
||||
var/list/data = list()
|
||||
data["path"] = T.showpiece.type
|
||||
data["message"] = T.trophy_message
|
||||
data["placer_key"] = T.placer_key
|
||||
saved_trophies += list(data)
|
||||
|
||||
@@ -3,14 +3,20 @@
|
||||
SUBSYSTEM_DEF(ping)
|
||||
name = "Ping"
|
||||
wait = 6
|
||||
flags = SS_NO_INIT|SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
|
||||
flags = SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
|
||||
priority = 10
|
||||
var/list/currentrun
|
||||
|
||||
/datum/controller/subsystem/ping/Initialize()
|
||||
if (config.hub)
|
||||
world.visibility = 1
|
||||
..()
|
||||
|
||||
/datum/controller/subsystem/ping/fire(resumed = FALSE)
|
||||
if (!resumed)
|
||||
src.currentrun = GLOB.clients.Copy()
|
||||
|
||||
var/round_started = Master.round_started
|
||||
var/list/currentrun = src.currentrun
|
||||
while (length(currentrun))
|
||||
var/client/C = currentrun[currentrun.len]
|
||||
@@ -19,7 +25,15 @@ SUBSYSTEM_DEF(ping)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
|
||||
if(round_started && C.is_afk(INACTIVITY_KICK))
|
||||
if(!istype(C.mob, /mob/dead))
|
||||
log_access("AFK: [key_name(C)]")
|
||||
to_chat(C, "<span class='danger'>You have been inactive for more than 10 minutes and have been disconnected.</span>")
|
||||
qdel(C)
|
||||
|
||||
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*world.tick_usage/100]")
|
||||
|
||||
if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check
|
||||
return
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ PROCESSING_SUBSYSTEM_DEF(flightpacks)
|
||||
stat_tag = "FM"
|
||||
flags = SS_NO_INIT|SS_TICKER|SS_KEEP_TIMING
|
||||
|
||||
var/flightsuit_processing = FLIGHTSUIT_PROCESSING_FULL
|
||||
var/flightsuit_processing = FLIGHTSUIT_PROCESSING_NONE
|
||||
|
||||
/datum/controller/subsystem/processing/flightpacks/Initialize()
|
||||
sync_flightsuit_processing()
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
#define PING_BUFFER_TIME 25
|
||||
|
||||
SUBSYSTEM_DEF(server_maint)
|
||||
name = "Server Tasks"
|
||||
wait = 6000
|
||||
flags = SS_NO_TICK_CHECK
|
||||
wait = 6
|
||||
flags = SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
|
||||
priority = 10
|
||||
var/list/currentrun
|
||||
|
||||
/datum/controller/subsystem/server_maint/Initialize(timeofday)
|
||||
if (config.hub)
|
||||
world.visibility = 1
|
||||
..()
|
||||
|
||||
/datum/controller/subsystem/server_maint/fire()
|
||||
//handle kicking inactive players
|
||||
if(config.kick_inactive)
|
||||
for(var/client/C in GLOB.clients)
|
||||
/datum/controller/subsystem/server_maint/fire(resumed = FALSE)
|
||||
if(!resumed)
|
||||
src.currentrun = GLOB.clients.Copy()
|
||||
|
||||
var/list/currentrun = src.currentrun
|
||||
var/round_started = SSticker.HasRoundStarted()
|
||||
|
||||
for(var/I in currentrun)
|
||||
var/client/C = I
|
||||
//handle kicking inactive players
|
||||
if(round_started && config.kick_inactive)
|
||||
if(C.is_afk(config.afk_period))
|
||||
var/cmob = C.mob
|
||||
if(!(istype(cmob, /mob/dead/observer) || (istype(cmob, /mob/dead) && C.holder)))
|
||||
@@ -19,5 +30,10 @@ SUBSYSTEM_DEF(server_maint)
|
||||
to_chat(C, "<span class='danger'>You have been inactive for more than [config.afk_period / 600] minutes and have been disconnected.</span>")
|
||||
qdel(C)
|
||||
|
||||
if(config.sql_enabled)
|
||||
sql_poll_population()
|
||||
if (!(!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1)))
|
||||
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*world.tick_usage/100]")
|
||||
|
||||
if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check
|
||||
return
|
||||
|
||||
#undef PING_BUFFER_TIME
|
||||
|
||||
@@ -243,7 +243,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
send2irc("Server", "Round of [hide_mode ? "secret":"[mode.name]"] has started[allmins.len ? ".":" with no active admins online!"]")
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/cb)
|
||||
if(current_state < GAME_STATE_PLAYING)
|
||||
if(!HasRoundStarted())
|
||||
LAZYADD(round_start_events, cb)
|
||||
else
|
||||
cb.InvokeAsync()
|
||||
@@ -625,8 +625,8 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(selected_tip)
|
||||
m = selected_tip
|
||||
else
|
||||
var/list/randomtips = world.file2list("config/tips.txt")
|
||||
var/list/memetips = world.file2list("config/sillytips.txt")
|
||||
var/list/randomtips = world.file2list("strings/tips.txt")
|
||||
var/list/memetips = world.file2list("strings/sillytips.txt")
|
||||
if(randomtips.len && prob(95))
|
||||
m = pick(randomtips)
|
||||
else if(memetips.len)
|
||||
@@ -672,15 +672,16 @@ SUBSYSTEM_DEF(ticker)
|
||||
return
|
||||
INVOKE_ASYNC(SSmapping, /datum/controller/subsystem/mapping/.proc/maprotate)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/HasRoundStarted()
|
||||
return current_state >= GAME_STATE_PLAYING
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/IsRoundInProgress()
|
||||
return current_state == GAME_STATE_PLAYING
|
||||
|
||||
/proc/send_gamemode_vote()
|
||||
SSticker.modevoted = TRUE
|
||||
SSvote.initiate_vote("roundtype","server")
|
||||
|
||||
/world/proc/has_round_started()
|
||||
if (SSticker && SSticker.current_state >= GAME_STATE_PLAYING)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/controller/subsystem/ticker/Recover()
|
||||
current_state = SSticker.current_state
|
||||
force_ending = SSticker.force_ending
|
||||
|
||||
@@ -124,7 +124,7 @@ SUBSYSTEM_DEF(vote)
|
||||
if("gamemode")
|
||||
if(GLOB.master_mode != .)
|
||||
world.save_mode(.)
|
||||
if(SSticker && SSticker.mode)
|
||||
if(SSticker.HasRoundStarted())
|
||||
restart = 1
|
||||
else
|
||||
GLOB.master_mode = .
|
||||
|
||||
@@ -482,6 +482,7 @@
|
||||
/datum/action/language_menu/Trigger()
|
||||
if(!..())
|
||||
return FALSE
|
||||
if(isliving(owner))
|
||||
var/mob/living/L = owner
|
||||
L.open_language_menu(usr)
|
||||
if(ismob(owner))
|
||||
var/mob/M = owner
|
||||
var/datum/language_holder/H = M.get_language_holder()
|
||||
H.open_language_menu(usr)
|
||||
|
||||
@@ -1,87 +1,62 @@
|
||||
//The Datum, Antagonist. Handles various antag things via a datum.
|
||||
/datum/antagonist
|
||||
var/mob/living/owner //who's our owner and accordingly an antagonist
|
||||
var/some_flufftext = "yer an antag larry"
|
||||
var/prevented_antag_datum_type //the type of antag datum that this datum can't coexist with; should probably be a list
|
||||
var/silent_update = FALSE //if we suppress messages during on_gain, apply_innate_effects, remove_innate_effects, and on_remove
|
||||
var/name = "Antagonist"
|
||||
|
||||
/datum/antagonist/New()
|
||||
if(!prevented_antag_datum_type)
|
||||
prevented_antag_datum_type = type
|
||||
var/datum/mind/owner //Mind that owns this datum
|
||||
|
||||
var/silent = FALSE //Silent will prevent the gain/lose texts to show
|
||||
|
||||
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
|
||||
var/list/typecache_datum_blacklist = list() //List of datums this type can't coexist with
|
||||
|
||||
/datum/antagonist/New(datum/mind/new_owner)
|
||||
typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
|
||||
if(new_owner)
|
||||
owner = new_owner
|
||||
|
||||
/datum/antagonist/Destroy()
|
||||
if(owner)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/proc/can_be_owned(mob/living/new_body)
|
||||
return new_body && !new_body.has_antag_datum(prevented_antag_datum_type, TRUE)
|
||||
/datum/antagonist/proc/can_be_owned(datum/mind/new_owner)
|
||||
. = TRUE
|
||||
if(owner.has_antag_datum(type))
|
||||
return FALSE
|
||||
for(var/i in owner.antag_datums)
|
||||
var/datum/antagonist/A = i
|
||||
if(is_type_in_typecache(src, A.typecache_datum_blacklist))
|
||||
return FALSE
|
||||
|
||||
/datum/antagonist/proc/give_to_body(mob/living/new_body) //tries to give an antag datum to a mob. cancels out if it can't be owned by the new body
|
||||
if(new_body && can_be_owned(new_body))
|
||||
new_body.antag_datums += src
|
||||
owner = new_body
|
||||
on_gain()
|
||||
. = src //return the datum if successful
|
||||
else
|
||||
qdel(src)
|
||||
. = FALSE
|
||||
/datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body)
|
||||
remove_innate_effects(old_body)
|
||||
apply_innate_effects(new_body)
|
||||
|
||||
/datum/antagonist/proc/on_gain() //on initial gain of antag datum, do this. should only be called once per datum
|
||||
apply_innate_effects()
|
||||
if(!silent_update && some_flufftext)
|
||||
to_chat(owner, some_flufftext)
|
||||
//This handles the application of antag huds/special abilities
|
||||
/datum/antagonist/proc/apply_innate_effects(mob/living/mob_override)
|
||||
return
|
||||
|
||||
/datum/antagonist/proc/apply_innate_effects() //applies innate effects to the owner, may be called multiple times due to mind transferral, but should only be called once per mob
|
||||
//antag huds would go here if antag huds were less completely unworkable as-is
|
||||
//This handles the removal of antag huds/special abilities
|
||||
/datum/antagonist/proc/remove_innate_effects(mob/living/mob_override)
|
||||
return
|
||||
|
||||
/datum/antagonist/proc/remove_innate_effects() //removes innate effects from the owner, may be called multiple times due to mind transferral, but should only be called once per mob
|
||||
//also antag huds but see above antag huds a shit
|
||||
//Proc called when the datum is given to a mind.
|
||||
/datum/antagonist/proc/on_gain()
|
||||
if(owner && owner.current)
|
||||
if(!silent)
|
||||
greet()
|
||||
apply_innate_effects()
|
||||
|
||||
/datum/antagonist/proc/on_remove() //totally removes the antag datum from the owner; can only be called once per owner
|
||||
/datum/antagonist/proc/on_removal()
|
||||
remove_innate_effects()
|
||||
owner.antag_datums -= src
|
||||
if(owner)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
if(!silent && owner.current)
|
||||
farewell()
|
||||
qdel(src)
|
||||
|
||||
/datum/antagonist/proc/transfer_to_new_body(mob/living/new_body)
|
||||
remove_innate_effects()
|
||||
if(!islist(new_body.antag_datums))
|
||||
new_body.antag_datums = list()
|
||||
new_body.antag_datums += src
|
||||
owner.antag_datums -= src
|
||||
owner = new_body
|
||||
apply_innate_effects()
|
||||
/datum/antagonist/proc/greet()
|
||||
return
|
||||
|
||||
//mob var and helper procs/Destroy override
|
||||
/mob/living
|
||||
var/list/antag_datums
|
||||
|
||||
/mob/living/Destroy() //TODO: merge this with the living/Destroy() in code\modules\mob\living\living.dm (currently line 29)
|
||||
if(islist(antag_datums))
|
||||
for(var/i in antag_datums)
|
||||
qdel(i)
|
||||
antag_datums = null
|
||||
return ..()
|
||||
|
||||
/mob/living/proc/can_have_antag_datum(datum_type) //if we can have this specific antagonist datum; neccessary, but requires creating a new antag datum each time.
|
||||
var/datum/antagonist/D = new datum_type()
|
||||
. = D.can_be_owned(src) //we can't exactly cache the results, either, because conditions might change. avoid use? TODO: better proc
|
||||
qdel(D)
|
||||
|
||||
/mob/living/proc/gain_antag_datum(datum_type) //tries to give a mob a specific antagonist datum; returns the datum if successful.
|
||||
if(!islist(antag_datums))
|
||||
antag_datums = list()
|
||||
var/datum/antagonist/D = new datum_type()
|
||||
. = D.give_to_body(src)
|
||||
|
||||
/mob/living/proc/has_antag_datum(type, check_subtypes) //checks this mob for if it has the antagonist datum. can either check specific type or subtypes
|
||||
if(!islist(antag_datums))
|
||||
return FALSE
|
||||
for(var/i in antag_datums)
|
||||
var/datum/antagonist/D = i
|
||||
if(check_subtypes)
|
||||
if(istype(D, type))
|
||||
return D //if it finds the datum, will return it so you can mess with it
|
||||
else
|
||||
if(D.type == type)
|
||||
return D
|
||||
return FALSE
|
||||
/datum/antagonist/proc/farewell()
|
||||
return
|
||||
|
||||
@@ -1,79 +1,75 @@
|
||||
//CLOCKCULT PROOF OF CONCEPT
|
||||
|
||||
/datum/antagonist/clockcultist
|
||||
prevented_antag_datum_type = /datum/antagonist/clockcultist
|
||||
some_flufftext = null
|
||||
/datum/antagonist/clockcult
|
||||
var/datum/action/innate/hierophant/hierophant_network = new()
|
||||
|
||||
/datum/antagonist/clockcultist/silent
|
||||
silent_update = TRUE
|
||||
/datum/antagonist/clockcult/silent
|
||||
silent = TRUE
|
||||
|
||||
/datum/antagonist/clockcultist/Destroy()
|
||||
/datum/antagonist/clockcult/Destroy()
|
||||
qdel(hierophant_network)
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/clockcultist/can_be_owned(mob/living/new_body)
|
||||
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
|
||||
. = ..()
|
||||
if(.)
|
||||
. = is_eligible_servant(new_body)
|
||||
if(iscyborg(new_owner.current))
|
||||
var/mob/living/silicon/robot/R = new_owner.current
|
||||
if(R.deployed)
|
||||
var/mob/living/silicon/ai/AI = R.mainframe
|
||||
R.undeploy()
|
||||
to_chat(AI, "<span class='userdanger'>Anomaly Detected. Returned to core!</span>") //The AI needs to be in its core to properly be converted
|
||||
. = is_eligible_servant(new_owner.current)
|
||||
if(!silent && new_owner.current)
|
||||
if(issilicon(new_owner.current))
|
||||
to_chat(new_owner.current, "<span class='heavy_brass'>You are unable to compute this truth. Your vision glows a brilliant yellow, and all at once it comes to you. Ratvar, the \
|
||||
Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm.</span>")
|
||||
else
|
||||
to_chat(new_owner.current, "<span class='heavy_brass'>[iscarbon(new_owner.current) ? "Your mind is racing! Your body feels incredibly light! ":""]Your world glows a brilliant \
|
||||
yellow! All at once it comes to you. Ratvar, the Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm.</span>")
|
||||
if(!.)
|
||||
new_owner.current.visible_message("<span class='boldwarning'>[new_owner.current] seems to resist an unseen force!</span>")
|
||||
to_chat(new_owner.current, "<span class='userdanger'>And yet, you somehow push it all away.</span>")
|
||||
|
||||
/datum/antagonist/clockcultist/give_to_body(mob/living/new_body)
|
||||
if(iscyborg(new_body))
|
||||
var/mob/living/silicon/robot/R = new_body
|
||||
if(R.deployed)
|
||||
var/mob/living/silicon/ai/AI = R.mainframe
|
||||
R.undeploy()
|
||||
var/converted = add_servant_of_ratvar(AI, silent_update)
|
||||
to_chat(AI, "<span class='userdanger'>Anomaly Detected. Returned to core!</span>") //The AI needs to be in its core to properly be converted
|
||||
return converted
|
||||
if(!silent_update)
|
||||
if(issilicon(new_body))
|
||||
to_chat(new_body, "<span class='heavy_brass'>You are unable to compute this truth. Your vision glows a brilliant yellow, and all at once it comes to you. Ratvar, the Clockwork Justiciar, \
|
||||
lies in exile, derelict and forgotten in an unseen realm.</span>")
|
||||
else
|
||||
to_chat(new_body, "<span class='heavy_brass'>[iscarbon(new_body) ? "Your mind is racing! Your body feels incredibly light! ":""]Your world glows a brilliant yellow! All at once it comes to you. \
|
||||
Ratvar, the Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm.</span>")
|
||||
. = ..()
|
||||
if(!silent_update && new_body)
|
||||
if(.)
|
||||
new_body.visible_message("<span class='heavy_brass'>[new_body]'s eyes glow a blazing yellow!</span>")
|
||||
to_chat(new_body, "<span class='heavy_brass'>Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork Justiciar above all else. \
|
||||
Perform his every whim without hesitation.</span>")
|
||||
else
|
||||
new_body.visible_message("<span class='boldwarning'>[new_body] seems to resist an unseen force!</span>")
|
||||
to_chat(new_body, "<span class='userdanger'>And yet, you somehow push it all away.</span>")
|
||||
/datum/antagonist/clockcult/greet()
|
||||
if(!owner.current || silent)
|
||||
return
|
||||
owner.current.visible_message("<span class='heavy_brass'>[owner.current]'s eyes glow a blazing yellow!</span>")
|
||||
to_chat(owner.current, "<span class='heavy_brass'>Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork \
|
||||
Justiciar above all else. Perform his every whim without hesitation.</span>")
|
||||
|
||||
/datum/antagonist/clockcultist/on_gain()
|
||||
if(SSticker && SSticker.mode && owner.mind)
|
||||
SSticker.mode.servants_of_ratvar += owner.mind
|
||||
SSticker.mode.update_servant_icons_added(owner.mind)
|
||||
if(jobban_isbanned(owner, ROLE_SERVANT_OF_RATVAR))
|
||||
INVOKE_ASYNC(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, owner, ROLE_SERVANT_OF_RATVAR, ROLE_SERVANT_OF_RATVAR)
|
||||
if(owner.mind)
|
||||
owner.mind.special_role = "Servant of Ratvar"
|
||||
owner.log_message("<font color=#BE8700>Has been converted to the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(issilicon(owner))
|
||||
var/mob/living/silicon/S = owner
|
||||
if(iscyborg(S) && !silent_update)
|
||||
to_chat(S, "<span class='boldwarning'>You have been desynced from your master AI.\n\
|
||||
In addition, your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.</span>")
|
||||
if(isAI(S))
|
||||
to_chat(S, "<span class='boldwarning'>You are able to use your cameras to listen in on conversations.</span>")
|
||||
to_chat(S, "<span class='heavy_brass'>You can communicate with other servants by using the Hierophant Network action button in the upper left.</span>")
|
||||
else if(isbrain(owner) || isclockmob(owner))
|
||||
to_chat(owner, "<span class='nezbere'>You can communicate with other servants by using the Hierophant Network action button in the upper left.</span>")
|
||||
/datum/antagonist/clockcult/on_gain()
|
||||
var/mob/living/current = owner.current
|
||||
SSticker.mode.servants_of_ratvar += owner
|
||||
SSticker.mode.update_servant_icons_added(owner)
|
||||
if(jobban_isbanned(current, ROLE_SERVANT_OF_RATVAR))
|
||||
addtimer(CALLBACK(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, current, ROLE_SERVANT_OF_RATVAR, ROLE_SERVANT_OF_RATVAR), 0)
|
||||
owner.special_role = "Servant of Ratvar"
|
||||
owner.current.log_message("<font color=#BE8700>Has been converted to the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(issilicon(current))
|
||||
if(iscyborg(current) && !silent)
|
||||
to_chat(current, "<span class='boldwarning'>You have been desynced from your master AI.</span>")
|
||||
to_chat(current, "<span class='boldwarning'>In addition, your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.</span>")
|
||||
if(isAI(current))
|
||||
to_chat(current, "<span class='boldwarning'>You are able to use your cameras to listen in on conversations.</span>")
|
||||
to_chat(current, "<span class='heavy_brass'>You can communicate with other servants by using the Hierophant Network action button in the upper left.</span>")
|
||||
else if(isbrain(current) || isclockmob(current))
|
||||
to_chat(current, "<span class='nezbere'>You can communicate with other servants by using the Hierophant Network action button in the upper left.</span>")
|
||||
..()
|
||||
if(istype(SSticker.mode, /datum/game_mode/clockwork_cult))
|
||||
var/datum/game_mode/clockwork_cult/C = SSticker.mode
|
||||
C.present_tasks(owner) //Memorize the objectives
|
||||
|
||||
/datum/antagonist/clockcultist/apply_innate_effects()
|
||||
GLOB.all_clockwork_mobs += owner
|
||||
owner.faction |= "ratvar"
|
||||
owner.grant_language(/datum/language/ratvar)
|
||||
owner.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
|
||||
if(issilicon(owner))
|
||||
var/mob/living/silicon/S = owner
|
||||
/datum/antagonist/clockcult/apply_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
if(istype(mob_override))
|
||||
current = mob_override
|
||||
GLOB.all_clockwork_mobs += current
|
||||
current.faction |= "ratvar"
|
||||
current.grant_language(/datum/language/ratvar)
|
||||
current.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
|
||||
if(issilicon(current))
|
||||
var/mob/living/silicon/S = current
|
||||
if(iscyborg(S))
|
||||
var/mob/living/silicon/robot/R = S
|
||||
if(!R.shell)
|
||||
@@ -106,31 +102,33 @@
|
||||
hierophant_network.title = "Silicon"
|
||||
hierophant_network.span_for_name = "nezbere"
|
||||
hierophant_network.span_for_message = "brass"
|
||||
else if(isbrain(owner))
|
||||
hierophant_network.Grant(owner)
|
||||
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(owner))
|
||||
hierophant_network.Grant(owner)
|
||||
else if(isclockmob(current))
|
||||
hierophant_network.Grant(current)
|
||||
hierophant_network.title = "Construct"
|
||||
hierophant_network.span_for_name = "nezbere"
|
||||
hierophant_network.span_for_message = "brass"
|
||||
owner.throw_alert("clockinfo", /obj/screen/alert/clockwork/infodump)
|
||||
current.throw_alert("clockinfo", /obj/screen/alert/clockwork/infodump)
|
||||
if(!GLOB.clockwork_gateway_activated)
|
||||
owner.throw_alert("scripturereq", /obj/screen/alert/clockwork/scripture_reqs)
|
||||
..()
|
||||
current.throw_alert("scripturereq", /obj/screen/alert/clockwork/scripture_reqs)
|
||||
|
||||
/datum/antagonist/clockcultist/remove_innate_effects()
|
||||
GLOB.all_clockwork_mobs -= owner
|
||||
owner.faction -= "ratvar"
|
||||
owner.remove_language(/datum/language/ratvar)
|
||||
owner.clear_alert("clockinfo")
|
||||
owner.clear_alert("scripturereq")
|
||||
for(var/datum/action/innate/function_call/F in owner.actions) //Removes any bound Ratvarian spears
|
||||
/datum/antagonist/clockcult/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/current = owner.current
|
||||
if(istype(mob_override))
|
||||
current = mob_override
|
||||
GLOB.all_clockwork_mobs -= current
|
||||
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)
|
||||
if(issilicon(owner))
|
||||
var/mob/living/silicon/S = owner
|
||||
if(issilicon(current))
|
||||
var/mob/living/silicon/S = current
|
||||
if(isAI(S))
|
||||
var/mob/living/silicon/ai/A = S
|
||||
A.can_be_carded = initial(A.can_be_carded)
|
||||
@@ -139,7 +137,7 @@
|
||||
S.make_laws()
|
||||
S.update_icons()
|
||||
S.show_laws()
|
||||
var/mob/living/temp_owner = owner
|
||||
var/mob/living/temp_owner = current
|
||||
..()
|
||||
if(iscyborg(temp_owner))
|
||||
var/mob/living/silicon/robot/R = temp_owner
|
||||
@@ -147,17 +145,15 @@
|
||||
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
|
||||
|
||||
/datum/antagonist/clockcultist/on_remove()
|
||||
if(!silent_update)
|
||||
owner.visible_message("<span class='big'>[owner] seems to have remembered their true allegiance!</span>", \
|
||||
/datum/antagonist/clockcult/on_removal()
|
||||
SSticker.mode.servants_of_ratvar -= owner
|
||||
SSticker.mode.update_servant_icons_removed(owner)
|
||||
if(!silent)
|
||||
owner.current.visible_message("<span class='big'>[owner] seems to have remembered their true allegiance!</span>", \
|
||||
"<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
|
||||
if(SSticker && SSticker.mode && owner.mind)
|
||||
SSticker.mode.servants_of_ratvar -= owner.mind
|
||||
SSticker.mode.update_servant_icons_removed(owner.mind)
|
||||
if(owner.mind)
|
||||
owner.mind.wipe_memory()
|
||||
owner.mind.special_role = null
|
||||
owner.log_message("<font color=#BE8700>Has renounced the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(iscyborg(owner))
|
||||
to_chat(owner, "<span class='warning'>Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.</span>")
|
||||
..()
|
||||
owner.current.log_message("<font color=#BE8700>Has renounced the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
owner.wipe_memory()
|
||||
owner.special_role = null
|
||||
if(iscyborg(owner.current))
|
||||
to_chat(owner.current, "<span class='warning'>Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.</span>")
|
||||
. = ..()
|
||||
|
||||
@@ -1,50 +1,148 @@
|
||||
/datum/antagonist/cultist
|
||||
prevented_antag_datum_type = /datum/antagonist/cultist
|
||||
some_flufftext = null
|
||||
var/datum/action/innate/cultcomm/communion = new()
|
||||
/datum/antagonist/cult
|
||||
var/datum/action/innate/cultcomm/communion = new
|
||||
|
||||
/datum/antagonist/cultist/Destroy()
|
||||
qdel(communion)
|
||||
/datum/antagonist/cult/Destroy()
|
||||
QDEL_NULL(communion)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/cultist/can_be_owned(mob/living/new_body)
|
||||
/datum/antagonist/cult/proc/add_objectives()
|
||||
var/list/target_candidates = list()
|
||||
for(var/mob/living/carbon/human/player in GLOB.player_list)
|
||||
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && (player != owner) && player.stat != DEAD)
|
||||
target_candidates += player.mind
|
||||
if(target_candidates.len == 0)
|
||||
message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
|
||||
for(var/mob/living/carbon/human/player in GLOB.player_list)
|
||||
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && (player != owner) && player.stat != DEAD)
|
||||
target_candidates += player.mind
|
||||
listclearnulls(target_candidates)
|
||||
if(LAZYLEN(target_candidates))
|
||||
GLOB.sac_mind = pick(target_candidates)
|
||||
if(!GLOB.sac_mind)
|
||||
message_admins("Cult Sacrifice: ERROR - Null target chosen!")
|
||||
else
|
||||
var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
|
||||
var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
|
||||
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
|
||||
reshape.Shift(SOUTH, 4)
|
||||
reshape.Shift(EAST, 1)
|
||||
reshape.Crop(7,4,26,31)
|
||||
reshape.Crop(-5,-3,26,30)
|
||||
GLOB.sac_image = reshape
|
||||
else
|
||||
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
|
||||
GLOB.sac_complete = TRUE
|
||||
SSticker.mode.cult_objectives += "sacrifice"
|
||||
SSticker.mode.cult_objectives += "eldergod"
|
||||
|
||||
/datum/antagonist/cult/proc/cult_memorization(datum/mind/cult_mind)
|
||||
var/mob/living/current = cult_mind.current
|
||||
for(var/obj_count = 1,obj_count <= SSticker.mode.cult_objectives.len,obj_count++)
|
||||
var/explanation
|
||||
switch(SSticker.mode.cult_objectives[obj_count])
|
||||
if("sacrifice")
|
||||
if(GLOB.sac_mind)
|
||||
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
|
||||
else
|
||||
explanation = "The veil has already been weakened here, proceed to the final objective."
|
||||
if("eldergod")
|
||||
explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie' with nine acolytes on it. You must do this after sacrificing your target."
|
||||
if(!silent)
|
||||
to_chat(current, "<B>Objective #[obj_count]</B>: [explanation]")
|
||||
cult_mind.memory += "<B>Objective #[obj_count]</B>: [explanation]<BR>"
|
||||
|
||||
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
|
||||
. = ..()
|
||||
if(.)
|
||||
. = is_convertable_to_cult(new_body)
|
||||
. = is_convertable_to_cult(new_owner.current)
|
||||
|
||||
/datum/antagonist/cultist/on_gain()
|
||||
if(SSticker && SSticker.mode && owner.mind)
|
||||
SSticker.mode.cult += owner.mind
|
||||
SSticker.mode.update_cult_icons_added(owner.mind)
|
||||
if(istype(SSticker.mode, /datum/game_mode/cult))
|
||||
var/datum/game_mode/cult/C = SSticker.mode
|
||||
C.memorize_cult_objectives(owner.mind)
|
||||
if(jobban_isbanned(owner, ROLE_CULTIST))
|
||||
INVOKE_ASYNC(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, owner, ROLE_CULTIST, ROLE_CULTIST)
|
||||
if(owner.mind)
|
||||
owner.mind.special_role = "Cultist"
|
||||
owner.log_message("<font color=#960000>Has been converted to the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
..()
|
||||
/datum/antagonist/cult/on_gain()
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
if(!LAZYLEN(SSticker.mode.cult_objectives))
|
||||
add_objectives()
|
||||
SSticker.mode.cult += owner // Only add after they've been given objectives
|
||||
cult_memorization(owner)
|
||||
if(jobban_isbanned(current, ROLE_CULTIST))
|
||||
addtimer(CALLBACK(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, current, ROLE_CULTIST, ROLE_CULTIST), 0)
|
||||
SSticker.mode.update_cult_icons_added(owner)
|
||||
current.log_message("<font color=#960000>Has been converted to the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(GLOB.blood_target && GLOB.blood_target_image && current.client)
|
||||
current.client.images += GLOB.blood_target_image
|
||||
|
||||
/datum/antagonist/cultist/apply_innate_effects()
|
||||
owner.faction |= "cult"
|
||||
owner.verbs += /mob/living/proc/cult_help
|
||||
communion.Grant(owner)
|
||||
..()
|
||||
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
if(mob_override)
|
||||
current = mob_override
|
||||
current.faction |= "cult"
|
||||
current.verbs += /mob/living/proc/cult_help
|
||||
if(!GLOB.cult_mastered)
|
||||
current.verbs += /mob/living/proc/cult_master
|
||||
communion.Grant(current)
|
||||
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
|
||||
|
||||
/datum/antagonist/cultist/remove_innate_effects()
|
||||
owner.faction -= "cult"
|
||||
owner.verbs -= /mob/living/proc/cult_help
|
||||
..()
|
||||
/datum/antagonist/cult/remove_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
if(mob_override)
|
||||
current = mob_override
|
||||
current.faction -= "cult"
|
||||
current.verbs -= /mob/living/proc/cult_help
|
||||
communion.Remove(current)
|
||||
owner.current.verbs -= /mob/living/proc/cult_master
|
||||
for(var/datum/action/innate/cultmast/H in owner.current.actions)
|
||||
qdel(H)
|
||||
current.clear_alert("bloodsense")
|
||||
|
||||
/datum/antagonist/cultist/on_remove()
|
||||
if(owner.mind)
|
||||
owner.mind.wipe_memory()
|
||||
if(SSticker && SSticker.mode)
|
||||
SSticker.mode.cult -= owner.mind
|
||||
SSticker.mode.update_cult_icons_removed(owner.mind)
|
||||
to_chat(owner, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Dark One and all your memories as its servant.</span>")
|
||||
owner.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(!silent_update)
|
||||
owner.visible_message("<span class='big'>[owner] looks like [owner.p_they()] just reverted to their old faith!</span>")
|
||||
..()
|
||||
/datum/antagonist/cult/on_removal()
|
||||
owner.wipe_memory()
|
||||
SSticker.mode.cult -= owner
|
||||
SSticker.mode.update_cult_icons_removed(owner)
|
||||
if(!silent)
|
||||
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
|
||||
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
owner.current.visible_message("<span class='big'>[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!</span>")
|
||||
if(GLOB.blood_target && GLOB.blood_target_image && owner.current.client)
|
||||
owner.current.client.images -= GLOB.blood_target_image
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/cult/master
|
||||
var/datum/action/innate/cultmast/finalreck/reckoning = new
|
||||
var/datum/action/innate/cultmast/cultmark/bloodmark = new
|
||||
|
||||
/datum/antagonist/cult/master/Destroy()
|
||||
QDEL_NULL(reckoning)
|
||||
QDEL_NULL(bloodmark)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/cult/master/on_gain()
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
SSticker.mode.set_antag_hud(current, "cultmaster")
|
||||
|
||||
/datum/antagonist/cult/master/greet()
|
||||
to_chat(owner.current, "<span class='cultlarge'>You are the cult's Master</span>. As the cult's Master, you have a unique title and loud voice when communicating, are capable of marking \
|
||||
targets, such as a location or a noncultist, to direct the cult to them, and, finally, you are capable of summoning the entire living cult to your location <b><i>once</i></b>.")
|
||||
to_chat(owner.current, "Use these abilities to direct the cult to victory at any cost.")
|
||||
|
||||
/datum/antagonist/cult/master/apply_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
if(mob_override)
|
||||
current = mob_override
|
||||
if(!GLOB.reckoning_complete)
|
||||
reckoning.Grant(current)
|
||||
bloodmark.Grant(current)
|
||||
current.update_action_buttons_icon()
|
||||
current.apply_status_effect(/datum/status_effect/cult_master)
|
||||
|
||||
/datum/antagonist/cult/master/remove_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
if(mob_override)
|
||||
current = mob_override
|
||||
reckoning.Remove(current)
|
||||
bloodmark.Remove(current)
|
||||
current.update_action_buttons_icon()
|
||||
current.remove_status_effect(/datum/status_effect/cult_master)
|
||||
|
||||
+13
-15
@@ -27,7 +27,7 @@
|
||||
. += "---"
|
||||
.["Call Proc"] = "?_src_=vars;proc_call=\ref[src]"
|
||||
.["Mark Object"] = "?_src_=vars;mark_object=\ref[src]"
|
||||
.["Delete"] = "?_src_=vars;delete=\ref[src]"
|
||||
.["Delete"] = "?_src_=vars;delete=\ref[src]"
|
||||
|
||||
|
||||
/datum/proc/on_reagent_change()
|
||||
@@ -94,7 +94,6 @@
|
||||
CLONE:<font size='1'><a href='?_src_=vars;mobToDamage=[refid];adjustDamage=clone'>[M.getCloneLoss()]</a>
|
||||
BRAIN:<font size='1'><a href='?_src_=vars;mobToDamage=[refid];adjustDamage=brain'>[M.getBrainLoss()]</a>
|
||||
STAMINA:<font size='1'><a href='?_src_=vars;mobToDamage=[refid];adjustDamage=stamina'>[M.getStaminaLoss()]</a>
|
||||
AROUSAL:<font size='1'><a href='?_src_=vars;mobToDamage=[refid];adjustDamage=arousal'>[M.getArousalLoss()]</a>
|
||||
</font>
|
||||
"}
|
||||
else
|
||||
@@ -447,7 +446,7 @@
|
||||
var/list/L = value
|
||||
var/list/items = list()
|
||||
|
||||
if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? 50 : 150)))
|
||||
if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? 50 : 150)))
|
||||
for (var/i in 1 to L.len)
|
||||
var/key = L[i]
|
||||
var/val
|
||||
@@ -527,16 +526,16 @@
|
||||
if(T)
|
||||
callproc_datum(T)
|
||||
|
||||
else if(href_list["delete"])
|
||||
if(!check_rights(R_DEBUG, 0))
|
||||
return
|
||||
|
||||
var/datum/D = locate(href_list["delete"])
|
||||
if(!D)
|
||||
to_chat(usr, "Unable to locate item!")
|
||||
admin_delete(D)
|
||||
href_list["datumrefresh"] = href_list["delete"]
|
||||
|
||||
else if(href_list["delete"])
|
||||
if(!check_rights(R_DEBUG, 0))
|
||||
return
|
||||
|
||||
var/datum/D = locate(href_list["delete"])
|
||||
if(!D)
|
||||
to_chat(usr, "Unable to locate item!")
|
||||
admin_delete(D)
|
||||
href_list["datumrefresh"] = href_list["delete"]
|
||||
|
||||
else if(href_list["regenerateicons"])
|
||||
if(!check_rights(0))
|
||||
return
|
||||
@@ -1166,8 +1165,6 @@
|
||||
L.adjustCloneLoss(amount)
|
||||
if("stamina")
|
||||
L.adjustStaminaLoss(amount)
|
||||
if("arousal")
|
||||
L.adjustArousalLoss(amount)
|
||||
else
|
||||
to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]")
|
||||
return
|
||||
@@ -1178,3 +1175,4 @@
|
||||
message_admins(msg)
|
||||
admin_ticket_log(L, msg)
|
||||
href_list["datumrefresh"] = href_list["mobToDamage"]
|
||||
|
||||
|
||||
@@ -35,10 +35,6 @@
|
||||
var/msg = select_message_type(user)
|
||||
if(params && message_param)
|
||||
msg = select_param(user, params)
|
||||
if(findtext(msg, "their"))
|
||||
msg = replacetext(msg, "their", user.p_their())
|
||||
if(findtext(msg, "them"))
|
||||
msg = replacetext(msg, "them", user.p_them())
|
||||
if(findtext(msg, "%s"))
|
||||
msg = replacetext(msg, "%s", user.p_s())
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
for(var/line in testmerge)
|
||||
if(line)
|
||||
log_world("Test merge active of PR #[line]")
|
||||
feedback_add_details("testmerged_prs","[line]")
|
||||
SSblackbox.add_details("testmerged_prs","[line]")
|
||||
log_world("Based off master commit [parentcommit]")
|
||||
else
|
||||
log_world(parentcommit)
|
||||
@@ -75,10 +75,12 @@
|
||||
|
||||
if(GLOB.revdata.parentcommit)
|
||||
to_chat(src, "<b>Server revision compiled on:</b> [GLOB.revdata.date]")
|
||||
var/prefix = ""
|
||||
if(GLOB.revdata.testmerge.len)
|
||||
to_chat(src, GLOB.revdata.GetTestMergeInfo())
|
||||
to_chat(src, "Based off master commit:")
|
||||
to_chat(src, "<a href='[config.githuburl]/commit/[GLOB.revdata.parentcommit]'>[GLOB.revdata.parentcommit]</a>")
|
||||
prefix = "Based off master commit: "
|
||||
var/pc = GLOB.revdata.parentcommit
|
||||
to_chat(src, "[prefix]<a href='[config.githuburl]/commit/[pc]'>[copytext(pc, 1, min(length(pc), 7))]</a>")
|
||||
else
|
||||
to_chat(src, "Revision unknown")
|
||||
to_chat(src, "<b>Current Infomational Settings:</b>")
|
||||
@@ -89,7 +91,7 @@
|
||||
to_chat(src, "Enforce Continuous Rounds: [config.continuous.len] of [config.modes.len] roundtypes")
|
||||
to_chat(src, "Allow Midround Antagonists: [config.midround_antag.len] of [config.modes.len] roundtypes")
|
||||
if(config.show_game_type_odds)
|
||||
if(SSticker.current_state == GAME_STATE_PLAYING)
|
||||
if(SSticker.IsRoundInProgress())
|
||||
var/prob_sum = 0
|
||||
var/current_odds_differ = FALSE
|
||||
var/list/probs = list()
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
|
||||
#define HOLOPAD_MAX_DIAL_TIME 200
|
||||
|
||||
/mob/camera/aiEye/remote/holo/setLoc()
|
||||
. = ..()
|
||||
var/obj/machinery/holopad/H = origin
|
||||
H.move_hologram(eye_user, loc)
|
||||
|
||||
//this datum manages it's own references
|
||||
|
||||
/datum/holocall
|
||||
var/mob/living/user //the one that called
|
||||
var/obj/machinery/holopad/calling_holopad //the one that sent the call
|
||||
var/obj/machinery/holopad/connected_holopad //the one that answered the call (may be null)
|
||||
var/list/dialed_holopads //all things called, will be cleared out to just connected_holopad once answered
|
||||
|
||||
var/mob/camera/aiEye/remote/holo/eye //user's eye, once connected
|
||||
var/obj/effect/overlay/holo_pad_hologram/hologram //user's hologram, once connected
|
||||
|
||||
var/call_start_time
|
||||
|
||||
//creates a holocall made by `caller` from `calling_pad` to `callees`
|
||||
/datum/holocall/New(mob/living/caller, obj/machinery/holopad/calling_pad, list/callees)
|
||||
call_start_time = world.time
|
||||
user = caller
|
||||
calling_pad.outgoing_call = src
|
||||
calling_holopad = calling_pad
|
||||
dialed_holopads = list()
|
||||
|
||||
for(var/I in callees)
|
||||
var/obj/machinery/holopad/H = I
|
||||
if(!QDELETED(H) && H.is_operational())
|
||||
dialed_holopads += H
|
||||
LAZYADD(H.holo_calls, src)
|
||||
|
||||
if(!dialed_holopads.len)
|
||||
calling_pad.say("Connection failure.")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
testing("Holocall started")
|
||||
|
||||
//cleans up ALL references :)
|
||||
/datum/holocall/Destroy()
|
||||
QDEL_NULL(eye)
|
||||
|
||||
user.reset_perspective()
|
||||
|
||||
user = null
|
||||
hologram.HC = null
|
||||
hologram = null
|
||||
calling_holopad.outgoing_call = null
|
||||
|
||||
for(var/I in dialed_holopads)
|
||||
var/obj/machinery/holopad/H = I
|
||||
LAZYREMOVE(H.holo_calls, src)
|
||||
dialed_holopads.Cut()
|
||||
|
||||
if(calling_holopad)
|
||||
calling_holopad.SetLightsAndPower()
|
||||
calling_holopad = null
|
||||
if(connected_holopad)
|
||||
connected_holopad.SetLightsAndPower()
|
||||
connected_holopad = null
|
||||
|
||||
testing("Holocall destroyed")
|
||||
|
||||
return ..()
|
||||
|
||||
//Gracefully disconnects a holopad `H` from a call. Pads not in the call are ignored. Notifies participants of the disconnection
|
||||
/datum/holocall/proc/Disconnect(obj/machinery/holopad/H)
|
||||
testing("Holocall disconnect")
|
||||
if(H == connected_holopad)
|
||||
calling_holopad.say("[usr] disconnected.")
|
||||
else if(H == calling_holopad && connected_holopad)
|
||||
connected_holopad.say("[usr] disconnected.")
|
||||
|
||||
ConnectionFailure(H, TRUE)
|
||||
|
||||
//Forcefully disconnects a holopad `H` from a call. Pads not in the call are ignored.
|
||||
/datum/holocall/proc/ConnectionFailure(obj/machinery/holopad/H, graceful = FALSE)
|
||||
testing("Holocall connection failure: graceful [graceful]")
|
||||
if(H == connected_holopad || H == calling_holopad)
|
||||
if(!graceful)
|
||||
calling_holopad.say("Connection failure.")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
LAZYREMOVE(H.holo_calls, src)
|
||||
dialed_holopads -= H
|
||||
if(!dialed_holopads.len)
|
||||
if(graceful)
|
||||
calling_holopad.say("Call rejected.")
|
||||
testing("No recipients, terminating")
|
||||
qdel(src)
|
||||
|
||||
//Answers a call made to a holopad `H` which cannot be the calling holopad. Pads not in the call are ignored
|
||||
/datum/holocall/proc/Answer(obj/machinery/holopad/H)
|
||||
testing("Holocall answer")
|
||||
if(H == calling_holopad)
|
||||
CRASH("How cute, a holopad tried to answer itself.")
|
||||
|
||||
if(!(H in dialed_holopads))
|
||||
return
|
||||
|
||||
if(connected_holopad)
|
||||
CRASH("Multi-connection holocall")
|
||||
|
||||
for(var/I in dialed_holopads)
|
||||
if(I == H)
|
||||
continue
|
||||
Disconnect(I)
|
||||
|
||||
for(var/I in H.holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC != src)
|
||||
HC.Disconnect(H)
|
||||
|
||||
connected_holopad = H
|
||||
|
||||
if(!Check())
|
||||
return
|
||||
|
||||
hologram = H.activate_holo(user)
|
||||
hologram.HC = src
|
||||
|
||||
//eyeobj code is horrid, this is the best copypasta I could make
|
||||
eye = new
|
||||
eye.origin = H
|
||||
eye.eye_initialized = TRUE
|
||||
eye.eye_user = user
|
||||
eye.name = "Camera Eye ([user.name])"
|
||||
user.remote_control = eye
|
||||
user.reset_perspective(eye)
|
||||
eye.setLoc(H.loc)
|
||||
|
||||
//Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise
|
||||
/datum/holocall/proc/Check()
|
||||
for(var/I in dialed_holopads)
|
||||
var/obj/machinery/holopad/H = I
|
||||
if(!H.is_operational())
|
||||
ConnectionFailure(H)
|
||||
|
||||
if(QDELETED(src))
|
||||
return FALSE
|
||||
|
||||
. = !QDELETED(user) && !user.incapacitated() && !QDELETED(calling_holopad) && calling_holopad.is_operational() && user.loc == calling_holopad.loc
|
||||
|
||||
if(.)
|
||||
if(connected_holopad)
|
||||
. = !QDELETED(connected_holopad) && connected_holopad.is_operational()
|
||||
else
|
||||
. = world.time < (call_start_time + HOLOPAD_MAX_DIAL_TIME)
|
||||
if(!.)
|
||||
calling_holopad.say("No answer recieved.")
|
||||
calling_holopad.temp = ""
|
||||
|
||||
if(!.)
|
||||
testing("Holocall Check fail")
|
||||
qdel(src)
|
||||
@@ -136,7 +136,7 @@
|
||||
return FALSE
|
||||
|
||||
//For spawning mineral sheets; internal use only
|
||||
/datum/material_container/proc/retrieve(sheet_amt, datum/material/M)
|
||||
/datum/material_container/proc/retrieve(sheet_amt, datum/material/M, target = null)
|
||||
if(!M.sheet_type)
|
||||
return 0
|
||||
if(sheet_amt > 0)
|
||||
@@ -149,26 +149,28 @@
|
||||
use_amount_type(sheet_amt * MINERAL_MATERIAL_AMOUNT, M.id)
|
||||
sheet_amt -= MAX_STACK_SIZE
|
||||
if(round((sheet_amt * MINERAL_MATERIAL_AMOUNT) / MINERAL_MATERIAL_AMOUNT))
|
||||
new M.sheet_type(get_turf(owner), sheet_amt)
|
||||
var/obj/item/stack/sheet/s = new M.sheet_type(get_turf(owner), sheet_amt)
|
||||
if(target)
|
||||
s.forceMove(target)
|
||||
count += sheet_amt
|
||||
use_amount_type(sheet_amt * MINERAL_MATERIAL_AMOUNT, M.id)
|
||||
return count
|
||||
return 0
|
||||
|
||||
/datum/material_container/proc/retrieve_sheets(sheet_amt, id)
|
||||
/datum/material_container/proc/retrieve_sheets(sheet_amt, id, target = null)
|
||||
if(materials[id])
|
||||
return retrieve(sheet_amt, materials[id])
|
||||
return retrieve(sheet_amt, materials[id], target)
|
||||
return 0
|
||||
|
||||
/datum/material_container/proc/retrieve_amount(amt, id)
|
||||
return retrieve_sheets(amount2sheet(amt), id)
|
||||
/datum/material_container/proc/retrieve_amount(amt, id, target)
|
||||
return retrieve_sheets(amount2sheet(amt), id, target)
|
||||
|
||||
/datum/material_container/proc/retrieve_all()
|
||||
/datum/material_container/proc/retrieve_all(target = null)
|
||||
var/result = 0
|
||||
var/datum/material/M
|
||||
for(var/MAT in materials)
|
||||
M = materials[MAT]
|
||||
result += retrieve_sheets(amount2sheet(M.amount), MAT)
|
||||
result += retrieve_sheets(amount2sheet(M.amount), MAT, target)
|
||||
return result
|
||||
|
||||
/datum/material_container/proc/has_space(amt = 0)
|
||||
|
||||
+73
-29
@@ -44,9 +44,7 @@
|
||||
var/datum/job/assigned_job
|
||||
|
||||
var/list/datum/objective/objectives = list()
|
||||
var/list/datum/objective/special_verbs = list()
|
||||
|
||||
var/list/cult_words = list()
|
||||
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
|
||||
|
||||
var/datum/faction/faction //associated faction
|
||||
@@ -54,6 +52,7 @@
|
||||
var/linglink
|
||||
|
||||
var/miming = 0 // Mime's vow of silence
|
||||
var/list/antag_datums
|
||||
var/antag_hud_icon_state = null //this mind's ANTAG_HUD should have this icon_state
|
||||
var/datum/atom_hud/antag/antag_hud = null //this mind's antag HUD
|
||||
var/datum/gang/gang_datum //Which gang this mind belongs to, if any
|
||||
@@ -64,19 +63,36 @@
|
||||
|
||||
var/mob/living/enslaved_to //If this mind's master is another mob (i.e. adamantine golems)
|
||||
|
||||
var/datum/language_holder/language_holder
|
||||
|
||||
/datum/mind/New(var/key)
|
||||
src.key = key
|
||||
soulOwner = src
|
||||
|
||||
/datum/mind/Destroy()
|
||||
SSticker.minds -= src
|
||||
if(islist(antag_datums))
|
||||
for(var/i in antag_datums)
|
||||
qdel(i)
|
||||
antag_datums = null
|
||||
return ..()
|
||||
|
||||
/datum/mind/proc/get_language_holder()
|
||||
if(!language_holder)
|
||||
var/datum/language_holder/L = current.get_language_holder(shadow=FALSE)
|
||||
language_holder = L.copy(src)
|
||||
|
||||
return language_holder
|
||||
|
||||
/datum/mind/proc/transfer_to(mob/new_character, var/force_key_move = 0)
|
||||
if(current) // remove ourself from our old body's mind variable
|
||||
current.mind = null
|
||||
SStgui.on_transfer(current, new_character)
|
||||
|
||||
if(!language_holder)
|
||||
var/datum/language_holder/mob_holder = new_character.get_language_holder(shadow = FALSE)
|
||||
language_holder = mob_holder.copy(src)
|
||||
|
||||
if(key)
|
||||
if(new_character.key != key) //if we're transfering into a body with a key associated which is not ours
|
||||
new_character.ghostize(1) //we'll need to ghostize so that key isn't mobless.
|
||||
@@ -86,13 +102,13 @@
|
||||
if(new_character.mind) //disassociate any mind currently in our new body's mind variable
|
||||
new_character.mind.current = null
|
||||
|
||||
if(istype(current) && islist(current.antag_datums)) //wow apparently current isn't always living good fucking job SOMEONE
|
||||
for(var/i in current.antag_datums)
|
||||
var/datum/antagonist/D = i
|
||||
D.transfer_to_new_body(new_character)
|
||||
var/datum/atom_hud/antag/hud_to_transfer = antag_hud//we need this because leave_hud() will clear this list
|
||||
var/mob/living/old_current = current
|
||||
current = new_character //associate ourself with our new body
|
||||
new_character.mind = src //and associate our new body with ourself
|
||||
for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body
|
||||
var/datum/antagonist/A = a
|
||||
A.on_body_transfer(old_current, current)
|
||||
if(iscarbon(new_character))
|
||||
var/mob/living/carbon/C = new_character
|
||||
C.last_mind = src
|
||||
@@ -108,6 +124,41 @@
|
||||
/datum/mind/proc/wipe_memory()
|
||||
memory = null
|
||||
|
||||
// Datum antag mind procs
|
||||
/datum/mind/proc/add_antag_datum(datum_type)
|
||||
if(!datum_type)
|
||||
return
|
||||
var/datum/antagonist/A = new datum_type(src)
|
||||
if(!A.can_be_owned(src))
|
||||
qdel(A)
|
||||
return
|
||||
LAZYADD(antag_datums, A)
|
||||
A.on_gain()
|
||||
return A
|
||||
|
||||
/datum/mind/proc/remove_antag_datum(datum_type)
|
||||
if(!datum_type)
|
||||
return
|
||||
var/datum/antagonist/A = has_antag_datum(datum_type)
|
||||
if(A)
|
||||
A.on_removal()
|
||||
return TRUE
|
||||
|
||||
/datum/mind/proc/remove_all_antag_datums() //For the Lazy amongst us.
|
||||
for(var/a in antag_datums)
|
||||
var/datum/antagonist/A = a
|
||||
A.on_removal()
|
||||
|
||||
/datum/mind/proc/has_antag_datum(datum_type, check_subtypes = TRUE)
|
||||
if(!datum_type)
|
||||
return
|
||||
. = FALSE
|
||||
for(var/a in antag_datums)
|
||||
var/datum/antagonist/A = a
|
||||
if(check_subtypes && istype(A, datum_type))
|
||||
return A
|
||||
else if(A.type == datum_type)
|
||||
return A
|
||||
|
||||
/*
|
||||
Removes antag type's references from a mind.
|
||||
@@ -234,7 +285,7 @@
|
||||
creator.faction |= current.faction
|
||||
|
||||
if(creator.mind.special_role)
|
||||
message_admins("[key_name_admin(current)](<A HREF='?_src_=holder;adminmoreinfo=\ref[current]'>?</A>) has been created by [key_name_admin(creator)](<A HREF='?_src_=holder;adminmoreinfo=\ref[creator]'>?</A>), an antagonist.")
|
||||
message_admins("[ADMIN_LOOKUPFLW(current)] has been created by [ADMIN_LOOKUPFLW(creator)], an antagonist.")
|
||||
to_chat(current, "<span class='userdanger'>Despite your creators current allegiances, your true master remains [creator.real_name]. If their loyalities change, so do yours. This will never change unless your creator's body is destroyed.</span>")
|
||||
|
||||
/datum/mind/proc/show_memory(mob/recipient, window=1)
|
||||
@@ -255,7 +306,7 @@
|
||||
to_chat(recipient, "<i>[output]</i>")
|
||||
|
||||
/datum/mind/proc/edit_memory()
|
||||
if(!SSticker || !SSticker.mode)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
alert("Not before round-start!", "Alert")
|
||||
return
|
||||
|
||||
@@ -1143,7 +1194,7 @@
|
||||
log_admin("[key_name_admin(usr)] has made [current] unable to ascend as a devil.")
|
||||
return
|
||||
if(!ishuman(current) && !iscyborg(current))
|
||||
to_chat(usr, "<span class='warning'>This only works on humans and cyborgs!</span>")
|
||||
to_chat(usr, "<span class='warning'>This only works on humans and cyborgs!</span>")
|
||||
return
|
||||
SSticker.mode.devils += src
|
||||
special_role = "devil"
|
||||
@@ -1192,17 +1243,17 @@
|
||||
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>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = current
|
||||
if(!ishuman(current))
|
||||
to_chat(usr, "<span class='warning'>This only works on humans!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = current
|
||||
var/gear = alert("Agent or Scientist Gear","Gear","Agent","Scientist")
|
||||
if(gear)
|
||||
if(gear=="Agent")
|
||||
H.equipOutfit(/datum/outfit/abductor/agent)
|
||||
H.equipOutfit(/datum/outfit/abductor/agent)
|
||||
else
|
||||
H.equipOutfit(/datum/outfit/abductor/scientist)
|
||||
H.equipOutfit(/datum/outfit/abductor/scientist)
|
||||
|
||||
else if (href_list["monkey"])
|
||||
var/mob/living/L = current
|
||||
@@ -1399,15 +1450,8 @@
|
||||
special_role = "Cultist"
|
||||
to_chat(current, "<font color=\"purple\"><b><i>You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of Nar-Sie.</b></i></font>")
|
||||
to_chat(current, "<font color=\"purple\"><b><i>Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.</b></i></font>")
|
||||
var/datum/game_mode/cult/cult = SSticker.mode
|
||||
|
||||
if (istype(cult))
|
||||
cult.memorize_cult_objectives(src)
|
||||
else
|
||||
var/explanation = "Summon Nar-Sie via the use of the appropriate rune (Hell join self). It will only work if nine cultists stand on and around it."
|
||||
to_chat(current, "<B>Objective #1</B>: [explanation]")
|
||||
memory += "<B>Objective #1</B>: [explanation]<BR>"
|
||||
|
||||
var/datum/antagonist/cult/C
|
||||
C.cult_memorization(src)
|
||||
var/mob/living/carbon/human/H = current
|
||||
if (!SSticker.mode.equip_cultist(current))
|
||||
to_chat(H, "Spawning an amulet from your Master failed.")
|
||||
@@ -1471,8 +1515,8 @@
|
||||
H.set_species(/datum/species/abductor)
|
||||
var/datum/species/abductor/S = H.dna.species
|
||||
|
||||
if(role == "Scientist")
|
||||
S.scientist = TRUE
|
||||
if(role == "Scientist")
|
||||
S.scientist = TRUE
|
||||
S.team = team
|
||||
|
||||
var/list/obj/effect/landmark/abductor/agent_landmarks = new
|
||||
@@ -1491,8 +1535,8 @@
|
||||
if("Agent")
|
||||
L = agent_landmarks[team]
|
||||
if("Scientist")
|
||||
L = scientist_landmarks[team]
|
||||
H.forceMove(L.loc)
|
||||
L = scientist_landmarks[team]
|
||||
H.forceMove(L.loc)
|
||||
|
||||
/datum/mind/proc/AddSpell(obj/effect/proc_holder/spell/S)
|
||||
spell_list += S
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
However, all the inhabitants seem to do is grow drugs and guns."
|
||||
suffix = "lavaland_surface_seed_vault.dmm"
|
||||
cost = 10
|
||||
allow_duplicates = FALSE
|
||||
|
||||
/datum/map_template/ruin/lavaland/ash_walker
|
||||
name = "Ash Walker Nest"
|
||||
|
||||
@@ -43,6 +43,13 @@
|
||||
name = "Asteroid 5"
|
||||
description = "Oh my god, another giant rock!"
|
||||
|
||||
/datum/map_template/ruin/space/deep_storage
|
||||
id = "deep-storage"
|
||||
suffix = "deepstorage.dmm"
|
||||
name = "Survivalist Bunker"
|
||||
description = "Assume the best, prepare for the worst. Generally, you should do so by digging a three man heavily fortified bunker into a giant unused asteroid. \
|
||||
Then make it self sufficient, mask any evidence of construction, hook it covertly into the telecommunications network and hope for the best."
|
||||
|
||||
/datum/map_template/ruin/space/bigderelict1
|
||||
id = "bigderelict1"
|
||||
suffix = "bigderelict1.dmm"
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
/datum/map_template/shuttle/emergency/meteor
|
||||
suffix = "meteor"
|
||||
name = "An Asteroid With Engines Strapped To It"
|
||||
name = "Asteroid With Engines Strapped To It"
|
||||
description = "A hollowed out asteroid with engines strapped to it. Due to its size and difficulty in steering it, this shuttle may damage the docking area."
|
||||
admin_notes = "This shuttle will likely crush escape, killing anyone there."
|
||||
credit_cost = -5000
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
/datum/status_effect/shadow_mend/on_apply()
|
||||
owner.visible_message("<span class='notice'>Violet light wraps around [owner]'s body!</span>", "<span class='notice'>Violet light wraps around your body!</span>")
|
||||
playsound(owner, 'sound/magic/Teleport_app.ogg', 50, 1)
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/shadow_mend/tick()
|
||||
owner.adjustBruteLoss(-15)
|
||||
@@ -72,9 +73,12 @@
|
||||
add_logs(owner, null, "gained Vanguard stun immunity")
|
||||
owner.add_stun_absorption("vanguard", 200, 1, "'s yellow aura momentarily intensifies!", "Your ward absorbs the stun!", " radiating with a soft yellow light!")
|
||||
owner.visible_message("<span class='warning'>[owner] begins to faintly glow!</span>", "<span class='brass'>You will absorb all stuns for the next twenty seconds.</span>")
|
||||
owner.SetStunned(0, FALSE)
|
||||
owner.SetWeakened(0)
|
||||
progbar = new(owner, duration, owner)
|
||||
progbar.bar.color = list("#FAE48C", "#FAE48C", "#FAE48C", rgb(0,0,0))
|
||||
progbar.update(duration - world.time)
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/vanguard_shield/tick()
|
||||
progbar.update(duration - world.time)
|
||||
@@ -127,6 +131,7 @@
|
||||
animate(owner, color = oldcolor, time = 150, easing = EASE_IN)
|
||||
addtimer(CALLBACK(owner, /atom/proc/update_atom_colour), 150)
|
||||
playsound(owner, 'sound/magic/Ethereal_Enter.ogg', 50, 1)
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/inathneqs_endowment/on_remove()
|
||||
add_logs(owner, null, "lost Inath-neq's invulnerability")
|
||||
@@ -178,6 +183,7 @@
|
||||
/datum/status_effect/his_grace/on_apply()
|
||||
add_logs(owner, null, "gained His Grace's stun immunity")
|
||||
owner.add_stun_absorption("hisgrace", INFINITY, 3, null, "His Grace protects you from the stun!")
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/his_grace/tick()
|
||||
bloodlust = 0
|
||||
@@ -211,6 +217,7 @@
|
||||
|
||||
/datum/status_effect/wish_granters_gift/on_apply()
|
||||
to_chat(owner, "<span class='notice'>Death is not your end! The Wish Granter's energy suffuses you, and you begin to rise...</span>")
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/wish_granters_gift/on_remove()
|
||||
owner.revive(full_heal = 1, admin_revive = 1)
|
||||
@@ -221,3 +228,32 @@
|
||||
name = "Wish Granter's Immortality"
|
||||
desc = "You are being resurrected!"
|
||||
icon_state = "wish_granter"
|
||||
|
||||
/datum/status_effect/cult_master
|
||||
id = "The Cult Master"
|
||||
duration = -1
|
||||
tick_interval = 100
|
||||
alert_type = null
|
||||
var/alive = TRUE
|
||||
|
||||
/datum/status_effect/cult_master/proc/deathrattle()
|
||||
var/area/A = get_area(owner)
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(isliving(B.current))
|
||||
var/mob/living/M = B.current
|
||||
M << 'sound/hallucinations/veryfar_noise.ogg'
|
||||
to_chat(M, "<span class='cultlarge'>The Cult's Master, [owner], has fallen in the [A]!")
|
||||
|
||||
|
||||
/datum/status_effect/cult_master/tick()
|
||||
if(owner.stat != DEAD && !alive)
|
||||
alive = TRUE
|
||||
return
|
||||
if(owner.stat == DEAD && alive)
|
||||
alive = FALSE
|
||||
deathrattle()
|
||||
|
||||
/datum/status_effect/cult_master/on_remove()
|
||||
deathrattle()
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -29,3 +29,136 @@
|
||||
owner.adjustBruteLoss(0.1)
|
||||
owner.adjustFireLoss(0.1)
|
||||
owner.adjustToxLoss(0.2, TRUE, TRUE)
|
||||
|
||||
/datum/status_effect/belligerent
|
||||
id = "belligerent"
|
||||
duration = 70
|
||||
tick_interval = 0 //tick as fast as possible
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
alert_type = /obj/screen/alert/status_effect/belligerent
|
||||
var/leg_damage_on_toggle = 2 //damage on initial application and when the owner tries to toggle to run
|
||||
var/cultist_damage_on_toggle = 10 //damage on initial application and when the owner tries to toggle to run, but to cultists
|
||||
|
||||
/obj/screen/alert/status_effect/belligerent
|
||||
name = "Belligerent"
|
||||
desc = "<b><font color=#880020>Kneel, her-eti'c.</font></b>"
|
||||
icon_state = "belligerent"
|
||||
alerttooltipstyle = "clockcult"
|
||||
|
||||
/datum/status_effect/belligerent/on_apply()
|
||||
return do_movement_toggle(TRUE)
|
||||
|
||||
/datum/status_effect/belligerent/tick()
|
||||
if(!do_movement_toggle())
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/belligerent/proc/do_movement_toggle(force_damage)
|
||||
var/number_legs = owner.get_num_legs()
|
||||
if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.null_rod_check() && number_legs)
|
||||
if(force_damage || owner.m_intent != MOVE_INTENT_WALK)
|
||||
if(GLOB.ratvar_awakens)
|
||||
owner.Weaken(1)
|
||||
if(iscultist(owner))
|
||||
owner.apply_damage(cultist_damage_on_toggle * 0.5, BURN, "l_leg")
|
||||
owner.apply_damage(cultist_damage_on_toggle * 0.5, BURN, "r_leg")
|
||||
else
|
||||
owner.apply_damage(leg_damage_on_toggle * 0.5, BURN, "l_leg")
|
||||
owner.apply_damage(leg_damage_on_toggle * 0.5, BURN, "r_leg")
|
||||
if(owner.m_intent != MOVE_INTENT_WALK)
|
||||
if(!iscultist(owner))
|
||||
to_chat(owner, "<span class='warning'>Your leg[number_legs > 1 ? "s shiver":" shivers"] with pain!</span>")
|
||||
else //Cultists take extra burn damage
|
||||
to_chat(owner, "<span class='warning'>Your leg[number_legs > 1 ? "s burn":" burns"] with pain!</span>")
|
||||
owner.toggle_move_intent()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/status_effect/belligerent/on_remove()
|
||||
if(owner.m_intent == MOVE_INTENT_WALK)
|
||||
owner.toggle_move_intent()
|
||||
|
||||
|
||||
/datum/status_effect/maniamotor
|
||||
id = "maniamotor"
|
||||
duration = -1
|
||||
tick_interval = 10
|
||||
status_type = STATUS_EFFECT_MULTIPLE
|
||||
alert_type = null
|
||||
var/obj/structure/destructible/clockwork/powered/mania_motor/motor
|
||||
var/severity = 0 //goes up to a maximum of MAX_MANIA_SEVERITY
|
||||
var/warned_turnoff = FALSE //if we've warned that the motor is off
|
||||
var/warned_outofsight = FALSE //if we've warned that the target is out of sight of the motor
|
||||
var/static/list/mania_messages = list("Go nuts.", "Take a crack at crazy.", "Make a bid for insanity.", "Get kooky.", "Move towards mania.", "Become bewildered.", "Wax wild.", \
|
||||
"Go round the bend.", "Land in lunacy.", "Try dementia.", "Strive to get a screw loose.", "Advance forward.", "Approach the transmitter.", "Touch the antennae.", \
|
||||
"Move towards the mania motor.", "Come closer.", "Get over here already!", "Keep your eyes on the motor.")
|
||||
var/static/list/flee_messages = list("Oh, NOW you flee.", "Get back here!", "If you were smarter, you'd come back.", "Only fools run.", "You'll be back.")
|
||||
var/static/list/turnoff_messages = list("Why would they turn it-", "What are these idi-", "Fools, fools, all of-", "Are they trying to c-", "All this effort just f-")
|
||||
var/static/list/powerloss_messages = list("\"Oh, the id**ts di***t s***e en**** pow**...\"", "\"D*dn't **ey mak* an **te***c*i*n le**?\"", "\"The** f**ls for**t t* make a ***** *f-\"", \
|
||||
"\"No, *O, you **re so cl***-\"", "You hear a yell of frustration, cut off by static.")
|
||||
|
||||
/datum/status_effect/maniamotor/Destroy()
|
||||
motor = null
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/maniamotor/tick()
|
||||
var/is_servant = is_servant_of_ratvar(owner)
|
||||
var/span_part = severity > 50 ? "" : "_small" //let's save like one check
|
||||
if(QDELETED(motor))
|
||||
if(!is_servant)
|
||||
to_chat(owner, "<span class='sevtug[span_part]'>You feel a frustrated voice quietly fade from your mind...</span>")
|
||||
qdel(src)
|
||||
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)
|
||||
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(turnoff_messages))]\"</span>")
|
||||
else
|
||||
to_chat(owner, "<span class='sevtug[span_part]'>[text2ratvar(pick(powerloss_messages))]</span>")
|
||||
warned_turnoff = TRUE
|
||||
severity = max(severity - 2, 0)
|
||||
if(!severity)
|
||||
qdel(src)
|
||||
return
|
||||
else
|
||||
if(prob(severity * 2))
|
||||
warned_turnoff = FALSE
|
||||
if(!(owner in viewers(7, motor))) //not being in range makes it fall off slightly faster
|
||||
if(!is_servant && !warned_outofsight)
|
||||
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(flee_messages))]\"</span>")
|
||||
warned_outofsight = TRUE
|
||||
severity = max(severity - 1, 0)
|
||||
if(!severity)
|
||||
qdel(src)
|
||||
return
|
||||
else if(prob(severity * 2))
|
||||
warned_outofsight = FALSE
|
||||
if(is_servant) //heals servants of braindamage, hallucination, druggy, dizziness, and confusion
|
||||
if(owner.hallucination)
|
||||
owner.hallucination = 0
|
||||
if(owner.druggy)
|
||||
owner.adjust_drugginess(-owner.druggy)
|
||||
if(owner.dizziness)
|
||||
owner.dizziness = 0
|
||||
if(owner.confused)
|
||||
owner.confused = 0
|
||||
severity = 0
|
||||
else if(!owner.null_rod_check() && owner.stat != DEAD && severity)
|
||||
var/static/hum = get_sfx('sound/effects/screech.ogg') //same sound for every proc call
|
||||
if(owner.getToxLoss() > MANIA_DAMAGE_TO_CONVERT)
|
||||
if(is_eligible_servant(owner))
|
||||
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar("You are mine and his, now.")]\"</span>")
|
||||
add_servant_of_ratvar(owner)
|
||||
owner.Paralyse(5)
|
||||
else
|
||||
if(prob(severity * 0.15))
|
||||
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(mania_messages))]\"</span>")
|
||||
owner.playsound_local(get_turf(motor), hum, severity, 1)
|
||||
owner.adjust_drugginess(Clamp(max(severity * 0.075, 1), 0, max(0, 50 - owner.druggy))) //7.5% of severity per second, minimum 1
|
||||
if(owner.hallucination < 50)
|
||||
owner.hallucination = min(owner.hallucination + max(severity * 0.075, 1), 50) //7.5% of severity per second, minimum 1
|
||||
if(owner.dizziness < 50)
|
||||
owner.dizziness = min(owner.dizziness + round(severity * 0.05, 1), 50) //5% of severity per second above 10 severity
|
||||
if(owner.confused < 25)
|
||||
owner.confused = min(owner.confused + round(severity * 0.025, 1), 25) //2.5% of severity per second above 20 severity
|
||||
owner.adjustToxLoss(severity * 0.02, TRUE, TRUE) //2% of severity per second
|
||||
severity--
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
cube = icon('icons/effects/freeze.dmi', "ice_cube")
|
||||
owner.add_overlay(cube)
|
||||
owner.update_canmove()
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/freon/tick()
|
||||
owner.update_canmove()
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second.
|
||||
var/mob/living/owner //The mob affected by the status effect.
|
||||
var/status_type = STATUS_EFFECT_UNIQUE //How many of the effect can be on one mob, and what happens when you try to add another
|
||||
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
|
||||
var/alert_type = /obj/screen/alert/status_effect //the alert thrown by the status effect, contains name and description
|
||||
var/obj/screen/alert/status_effect/linked_alert = null //the alert itself, if it exists
|
||||
|
||||
/datum/status_effect/New(mob/living/new_owner)
|
||||
if(new_owner)
|
||||
@@ -21,23 +23,24 @@
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
if(owner)
|
||||
owner.clear_alert(id)
|
||||
on_remove()
|
||||
LAZYREMOVE(owner.status_effects, src)
|
||||
on_remove()
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/proc/start_ticking()
|
||||
if(!src)
|
||||
return
|
||||
if(!owner)
|
||||
if(!owner || !on_apply())
|
||||
qdel(src)
|
||||
return
|
||||
on_apply()
|
||||
if(duration != -1)
|
||||
duration = world.time + initial(duration)
|
||||
tick_interval = world.time + initial(tick_interval)
|
||||
if(alert_type)
|
||||
var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type)
|
||||
A.attached_effect = src //so the alert can reference us, if it needs to
|
||||
linked_alert = A //so we can reference the alert, if we need to
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/datum/status_effect/process()
|
||||
@@ -51,9 +54,11 @@
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/proc/on_apply() //Called whenever the buff is applied.
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/proc/tick() //Called every tick.
|
||||
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed.
|
||||
/datum/status_effect/proc/be_replaced() //Called instead of on_remove when a status effect is replaced by itself
|
||||
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null
|
||||
/datum/status_effect/proc/be_replaced() //Called instead of on_remove when a status effect is replaced by itself or when a status effect with on_remove_on_mob_delete = FALSE has its mob deleted
|
||||
owner.clear_alert(id)
|
||||
LAZYREMOVE(owner.status_effects, src)
|
||||
owner = null
|
||||
@@ -101,3 +106,11 @@
|
||||
for(var/datum/status_effect/S in status_effects)
|
||||
if(initial(S1.id) == S.id)
|
||||
return S
|
||||
|
||||
/mob/living/proc/has_status_effect_list(effect) //returns a list of effects with matching IDs that the mod owns; use for effects there can be multiple of
|
||||
. = list()
|
||||
if(status_effects)
|
||||
var/datum/status_effect/S1 = effect
|
||||
for(var/datum/status_effect/S in status_effects)
|
||||
if(initial(S1.id) == S.id)
|
||||
. += S
|
||||
|
||||
@@ -96,16 +96,15 @@
|
||||
/area/holodeck/rec_center/kobayashi
|
||||
name = "Holodeck - Kobayashi Maru"
|
||||
|
||||
/area/holodeck/rec_center/winterwonderland
|
||||
name = "Holodeck - Winter Wonderland"
|
||||
|
||||
// Bad programs
|
||||
|
||||
/area/holodeck/rec_center/burn
|
||||
name = "Holodeck - Atmospheric Burn Test"
|
||||
restricted = 1
|
||||
|
||||
/area/holodeck/rec_center/winterwonderland
|
||||
name = "Holodeck - Winter Wonderland"
|
||||
restricted = 1
|
||||
|
||||
/area/holodeck/rec_center/wildlife
|
||||
name = "Holodeck - Wildlife Simulation"
|
||||
restricted = 1
|
||||
|
||||
+2
-1
@@ -43,7 +43,7 @@
|
||||
if(SSatoms.InitAtom(src, args))
|
||||
//we were deleted
|
||||
return
|
||||
|
||||
|
||||
var/list/created = SSatoms.created_atoms
|
||||
if(created)
|
||||
created += src
|
||||
@@ -274,6 +274,7 @@
|
||||
return
|
||||
|
||||
/atom/proc/ex_act(severity, target)
|
||||
set waitfor = FALSE
|
||||
contents_explosion(severity, target)
|
||||
|
||||
/atom/proc/blob_act(obj/structure/blob/B)
|
||||
|
||||
+52
-27
@@ -13,9 +13,9 @@
|
||||
var/throw_speed = 2 //How many tiles to move per ds when being thrown. Float values are fully supported
|
||||
var/throw_range = 7
|
||||
var/mob/pulledby = null
|
||||
var/list/languages
|
||||
var/list/initial_languages = list(/datum/language/common)
|
||||
var/only_speaks_language = null
|
||||
var/initial_language_holder = /datum/language_holder
|
||||
var/datum/language_holder/language_holder
|
||||
var/datum/language_menu/language_menu = null
|
||||
var/verb_say = "says"
|
||||
var/verb_ask = "asks"
|
||||
var/verb_exclaim = "exclaims"
|
||||
@@ -44,10 +44,6 @@
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/atom/movable/Initialize(mapload)
|
||||
. = ..()
|
||||
for(var/L in initial_languages)
|
||||
grant_language(L)
|
||||
|
||||
/atom/movable/Move(atom/newloc, direct = 0)
|
||||
if(!loc || !newloc) return 0
|
||||
@@ -120,7 +116,7 @@
|
||||
|
||||
if(flags & CLEAN_ON_MOVE)
|
||||
clean_on_move()
|
||||
|
||||
|
||||
var/datum/proximity_monitor/proximity_monitor = src.proximity_monitor
|
||||
if(proximity_monitor)
|
||||
proximity_monitor.HandleMove()
|
||||
@@ -177,6 +173,7 @@
|
||||
STOP_PROCESSING(SSinbounds, src)
|
||||
|
||||
QDEL_NULL(proximity_monitor)
|
||||
QDEL_NULL(language_holder)
|
||||
|
||||
. = ..()
|
||||
if(loc)
|
||||
@@ -576,44 +573,70 @@
|
||||
|
||||
|
||||
/* Language procs */
|
||||
/atom/movable/proc/get_language_holder(shadow=TRUE)
|
||||
if(language_holder)
|
||||
return language_holder
|
||||
else
|
||||
language_holder = new initial_language_holder(src)
|
||||
return language_holder
|
||||
|
||||
|
||||
/atom/movable/proc/grant_language(datum/language/dt)
|
||||
LAZYINITLIST(languages)
|
||||
languages[dt] = TRUE
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
H.grant_language(dt)
|
||||
|
||||
/atom/movable/proc/grant_all_languages(omnitongue=FALSE)
|
||||
for(var/la in subtypesof(/datum/language))
|
||||
grant_language(la)
|
||||
|
||||
if(omnitongue)
|
||||
SET_SECONDARY_FLAG(src, OMNITONGUE)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
H.grant_all_languages(omnitongue)
|
||||
|
||||
/atom/movable/proc/get_random_understood_language()
|
||||
var/list/possible = list()
|
||||
for(var/dt in languages)
|
||||
possible += dt
|
||||
. = safepick(possible)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
. = H.get_random_understood_language()
|
||||
|
||||
/atom/movable/proc/remove_language(datum/language/dt)
|
||||
LAZYREMOVE(languages, dt)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
H.remove_language(dt)
|
||||
|
||||
/atom/movable/proc/remove_all_languages()
|
||||
LAZYCLEARLIST(languages)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
H.remove_all_languages()
|
||||
|
||||
/atom/movable/proc/has_language(datum/language/dt)
|
||||
. = is_type_in_typecache(dt, languages)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
. = H.has_language(dt)
|
||||
|
||||
// Whether an AM can speak in a language or not, independent of whether
|
||||
// it KNOWS the language
|
||||
/atom/movable/proc/could_speak_in_language(datum/language/dt)
|
||||
. = TRUE
|
||||
|
||||
/atom/movable/proc/can_speak_in_language(datum/language/dt)
|
||||
. = has_language(dt)
|
||||
if(only_speaks_language && !HAS_SECONDARY_FLAG(src, OMNITONGUE))
|
||||
. = . && ispath(only_speaks_language, dt)
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
|
||||
if(!H.has_language(dt))
|
||||
return FALSE
|
||||
else if(H.omnitongue || could_speak_in_language(dt))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/atom/movable/proc/get_default_language()
|
||||
// if no language is specified, and we want to say() something, which
|
||||
// language do we use?
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
|
||||
if(H.selected_default_language)
|
||||
if(H.has_language(H.selected_default_language))
|
||||
return H.selected_default_language
|
||||
else
|
||||
H.selected_default_language = null
|
||||
|
||||
|
||||
|
||||
var/datum/language/chosen_langtype
|
||||
var/highest_priority
|
||||
|
||||
for(var/lt in languages)
|
||||
for(var/lt in H.languages)
|
||||
var/datum/language/langtype = lt
|
||||
if(!can_speak_in_language(langtype))
|
||||
continue
|
||||
@@ -622,8 +645,10 @@
|
||||
if(!highest_priority || (pri > highest_priority))
|
||||
chosen_langtype = langtype
|
||||
highest_priority = pri
|
||||
|
||||
H.selected_default_language = .
|
||||
. = chosen_langtype
|
||||
|
||||
/* End language procs */
|
||||
/atom/movable/proc/ConveyorMove(movedir)
|
||||
set waitfor = FALSE
|
||||
if(!anchored && has_gravity())
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
if(!istype(H)) return 0
|
||||
var/obj/item/clothing/under/U = H.w_uniform
|
||||
if(!istype(U)) return 0
|
||||
if(U.sensor_mode <= 2) return 0
|
||||
if(U.sensor_mode <= SENSOR_VITALS) return 0
|
||||
return 1
|
||||
|
||||
/datum/atom_hud/data/human/medical/basic/add_to_single_hud(mob/M, mob/living/carbon/H)
|
||||
|
||||
@@ -155,7 +155,8 @@
|
||||
if(!(check_usability(user)))
|
||||
return
|
||||
|
||||
var/list/nuke_candidates = pollCandidatesForMob("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, src)
|
||||
to_chat(user, "<span class='notice'>You activate [src] and wait for confirmation.</span>")
|
||||
var/list/nuke_candidates = pollCandidatesForMob("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE, src)
|
||||
if(nuke_candidates.len)
|
||||
if(!(check_usability(user)))
|
||||
return
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
if(round_converted) //So badmin blobs later don't step on the dead natural blobs metaphorical toes
|
||||
..()
|
||||
if(blobwincount <= GLOB.blobs_legit.len)
|
||||
feedback_set_details("round_end_result","win - blob took over")
|
||||
SSblackbox.set_details("round_end_result","win - blob took over")
|
||||
to_chat(world, "<FONT size = 3><B>The blob has taken over the station!</B></FONT>")
|
||||
to_chat(world, "<B>The entire station was eaten by the Blob!</B>")
|
||||
log_game("Blob mode completed with a blob victory.")
|
||||
@@ -28,7 +28,7 @@
|
||||
SSticker.news_report = BLOB_WIN
|
||||
|
||||
else if(station_was_nuked)
|
||||
feedback_set_details("round_end_result","halfwin - nuke")
|
||||
SSblackbox.set_details("round_end_result","halfwin - nuke")
|
||||
to_chat(world, "<FONT size = 3><B>Partial Win: The station has been destroyed!</B></FONT>")
|
||||
to_chat(world, "<B>Directive 7-12 has been successfully carried out, preventing the Blob from spreading.</B>")
|
||||
log_game("Blob mode completed with a tie (station destroyed).")
|
||||
@@ -36,7 +36,7 @@
|
||||
SSticker.news_report = BLOB_NUKE
|
||||
|
||||
else if(!GLOB.blob_cores.len)
|
||||
feedback_set_details("round_end_result","loss - blob eliminated")
|
||||
SSblackbox.set_details("round_end_result","loss - blob eliminated")
|
||||
to_chat(world, "<FONT size = 3><B>The staff has won!</B></FONT>")
|
||||
to_chat(world, "<B>The alien organism has been eradicated from the station!</B>")
|
||||
log_game("Blob mode completed with a crew victory.")
|
||||
|
||||
@@ -254,19 +254,19 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
|
||||
for(var/datum/objective/objective in changeling.objectives)
|
||||
if(objective.check_completion())
|
||||
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <font color='green'><b>Success!</b></font>"
|
||||
feedback_add_details("changeling_objective","[objective.type]|SUCCESS")
|
||||
SSblackbox.add_details("changeling_objective","[objective.type]|SUCCESS")
|
||||
else
|
||||
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='danger'>Fail.</span>"
|
||||
feedback_add_details("changeling_objective","[objective.type]|FAIL")
|
||||
SSblackbox.add_details("changeling_objective","[objective.type]|FAIL")
|
||||
changelingwin = 0
|
||||
count++
|
||||
|
||||
if(changelingwin)
|
||||
text += "<br><font color='green'><b>The changeling was successful!</b></font>"
|
||||
feedback_add_details("changeling_success","SUCCESS")
|
||||
SSblackbox.add_details("changeling_success","SUCCESS")
|
||||
else
|
||||
text += "<br><span class='boldannounce'>The changeling has failed.</span>"
|
||||
feedback_add_details("changeling_success","FAIL")
|
||||
SSblackbox.add_details("changeling_success","FAIL")
|
||||
text += "<br>"
|
||||
|
||||
to_chat(world, text)
|
||||
|
||||
@@ -13,15 +13,13 @@
|
||||
var/req_dna = 0 //amount of dna needed to use this ability. Changelings always have atleast 1
|
||||
var/req_human = 0 //if you need to be human to use this ability
|
||||
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
|
||||
var/genetic_damage = 0 // genetic damage caused by using the sting. Nothing to do with cloneloss.
|
||||
var/max_genetic_damage = 100 // hard counter for spamming abilities. Not used/balanced much yet.
|
||||
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
|
||||
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec)
|
||||
if(!is_respec)
|
||||
feedback_add_details("changeling_power_purchase",name)
|
||||
SSblackbox.add_details("changeling_power_purchase",name)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_refund(mob/user)
|
||||
return
|
||||
@@ -37,9 +35,9 @@
|
||||
return
|
||||
var/datum/changeling/c = user.mind.changeling
|
||||
if(sting_action(user, target))
|
||||
feedback_add_details("changeling_powers",name)
|
||||
SSblackbox.add_details("changeling_powers",name)
|
||||
sting_feedback(user, target)
|
||||
take_chemical_cost(c)
|
||||
c.chem_charges -= chemical_cost
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_action(mob/user, mob/target)
|
||||
return 0
|
||||
@@ -47,10 +45,6 @@
|
||||
/obj/effect/proc_holder/changeling/proc/sting_feedback(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/take_chemical_cost(datum/changeling/changeling)
|
||||
changeling.chem_charges -= chemical_cost
|
||||
changeling.geneticdamage += genetic_damage
|
||||
|
||||
//Fairly important to remember to return 1 on success >.<
|
||||
/obj/effect/proc_holder/changeling/proc/can_sting(mob/user, mob/target)
|
||||
if(!ishuman(user) && !ismonkey(user)) //typecast everything from mob to carbon from this point onwards
|
||||
@@ -71,9 +65,6 @@
|
||||
if((user.status_flags & FAKEDEATH) && (!ignores_fakedeath))
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
if(c.geneticdamage > max_genetic_damage)
|
||||
to_chat(user, "<span class='warning'>Our genomes are still reassembling. We need time to recover first.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//used in /mob/Stat()
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
mind.changeling.purchasedpowers+=S
|
||||
S.on_purchase(src, is_respec)
|
||||
if(is_respec)
|
||||
feedback_add_details("changeling_power_purchase","Readapt")
|
||||
SSblackbox.add_details("changeling_power_purchase","Readapt")
|
||||
|
||||
var/mob/living/carbon/C = src //only carbons have dna now, so we have to typecaste
|
||||
if(ishuman(C))
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
chemical_cost = 0
|
||||
dna_cost = 0
|
||||
req_human = 1
|
||||
max_genetic_damage = 100
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/can_sting(mob/living/carbon/user)
|
||||
if(!..())
|
||||
@@ -42,13 +41,13 @@
|
||||
to_chat(target, "<span class='userdanger'>You feel a sharp stabbing pain!</span>")
|
||||
target.take_overall_damage(40)
|
||||
|
||||
feedback_add_details("changeling_powers","Absorb DNA|[i]")
|
||||
SSblackbox.add_details("changeling_powers","Absorb DNA|[i]")
|
||||
if(!do_mob(user, target, 150))
|
||||
to_chat(user, "<span class='warning'>Our absorption of [target] has been interrupted!</span>")
|
||||
changeling.isabsorbing = 0
|
||||
return
|
||||
|
||||
feedback_add_details("changeling_powers","Absorb DNA|4")
|
||||
SSblackbox.add_details("changeling_powers","Absorb DNA|4")
|
||||
user.visible_message("<span class='danger'>[user] sucks the fluids from [target]!</span>", "<span class='notice'>We have absorbed [target].</span>")
|
||||
to_chat(target, "<span class='userdanger'>You are absorbed by the changeling!</span>")
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
chemical_cost = 30 //High cost to prevent spam
|
||||
dna_cost = 2
|
||||
req_human = 1
|
||||
genetic_damage = 10
|
||||
max_genetic_damage = 0
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/sting_action(mob/living/carbon/human/user)
|
||||
var/used = FALSE // only one form of shackles removed per use
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
dna_cost = 2
|
||||
chemical_cost = 25
|
||||
req_human = 1
|
||||
genetic_damage = 10
|
||||
max_genetic_damage = 50
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/chameleon_skin/sting_action(mob/user)
|
||||
var/mob/living/carbon/human/H = user //SHOULD always be human, because req_human = 1
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
dna_cost = 0
|
||||
req_dna = 1
|
||||
req_stat = DEAD
|
||||
max_genetic_damage = 100
|
||||
|
||||
|
||||
//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay.
|
||||
/obj/effect/proc_holder/changeling/fakedeath/sting_action(mob/living/user)
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
name = "Human Form"
|
||||
desc = "We change into a human."
|
||||
chemical_cost = 5
|
||||
genetic_damage = 3
|
||||
req_dna = 1
|
||||
max_genetic_damage = 3
|
||||
|
||||
|
||||
//Transform into a human.
|
||||
/obj/effect/proc_holder/changeling/humanform/sting_action(mob/living/carbon/user)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
desc = "We debase ourselves and become lesser. We become a monkey."
|
||||
chemical_cost = 5
|
||||
dna_cost = 1
|
||||
genetic_damage = 3
|
||||
req_human = 1
|
||||
|
||||
//Transform into a monkey.
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
chemical_cost = 0
|
||||
dna_cost = 0
|
||||
req_human = 1
|
||||
max_genetic_damage = 100
|
||||
|
||||
/obj/effect/proc_holder/changeling/linglink/can_sting(mob/living/carbon/user)
|
||||
if(!..())
|
||||
@@ -56,7 +55,7 @@
|
||||
to_chat(target, "<font color=#800040><span class='boldannounce'>You can now communicate in the changeling hivemind, say \":g message\" to communicate!</span>")
|
||||
target.reagents.add_reagent("salbutamol", 40) // So they don't choke to death while you interrogate them
|
||||
sleep(1800)
|
||||
feedback_add_details("changeling_powers","Hivemind Link|[i]")
|
||||
SSblackbox.add_details("changeling_powers","Hivemind Link|[i]")
|
||||
if(!do_mob(user, target, 20))
|
||||
to_chat(user, "<span class='warning'>Our link with [target] has ended!</span>")
|
||||
changeling.islinking = 0
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
helptext = "Yell at Miauw and/or Perakp"
|
||||
chemical_cost = 1000
|
||||
dna_cost = -1
|
||||
genetic_damage = 1000
|
||||
|
||||
var/silent = FALSE
|
||||
var/weapon_type
|
||||
@@ -67,7 +66,6 @@
|
||||
helptext = "Yell at Miauw and/or Perakp"
|
||||
chemical_cost = 1000
|
||||
dna_cost = -1
|
||||
genetic_damage = 1000
|
||||
|
||||
var/helmet_type = /obj/item
|
||||
var/suit_type = /obj/item
|
||||
@@ -89,7 +87,7 @@
|
||||
return 1
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.wear_suit, suit_type) || istype(H.head, helmet_type))
|
||||
H.visible_message("<span class='warning'>[H] casts off their [suit_name_simple]!</span>", "<span class='warning'>We cast off our [suit_name_simple][genetic_damage > 0 ? ", temporarily weakening our genomes." : "."]</span>", "<span class='italics'>You hear the organic matter ripping and tearing!</span>")
|
||||
H.visible_message("<span class='warning'>[H] casts off their [suit_name_simple]!</span>", "<span class='warning'>We cast off our [suit_name_simple].</span>", "<span class='italics'>You hear the organic matter ripping and tearing!</span>")
|
||||
H.temporarilyRemoveItemFromInventory(H.head, TRUE) //The qdel on dropped() takes care of it
|
||||
H.temporarilyRemoveItemFromInventory(H.wear_suit, TRUE)
|
||||
H.update_inv_wear_suit()
|
||||
@@ -100,7 +98,6 @@
|
||||
H.add_splatter_floor()
|
||||
playsound(H.loc, 'sound/effects/splat.ogg', 50, 1) //So real sounds
|
||||
|
||||
changeling.geneticdamage += genetic_damage //Casting off a space suit leaves you weak for a few seconds.
|
||||
changeling.chem_recharge_slowdown -= recharge_slowdown
|
||||
return 1
|
||||
|
||||
@@ -139,9 +136,7 @@
|
||||
helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form."
|
||||
chemical_cost = 20
|
||||
dna_cost = 2
|
||||
genetic_damage = 10
|
||||
req_human = 1
|
||||
max_genetic_damage = 20
|
||||
weapon_type = /obj/item/weapon/melee/arm_blade
|
||||
weapon_name_simple = "blade"
|
||||
|
||||
@@ -217,9 +212,7 @@
|
||||
and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form."
|
||||
chemical_cost = 10
|
||||
dna_cost = 2
|
||||
genetic_damage = 5
|
||||
req_human = 1
|
||||
max_genetic_damage = 10
|
||||
weapon_type = /obj/item/weapon/gun/magic/tentacle
|
||||
weapon_name_simple = "tentacle"
|
||||
silent = TRUE
|
||||
@@ -381,9 +374,7 @@
|
||||
helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
genetic_damage = 12
|
||||
req_human = 1
|
||||
max_genetic_damage = 20
|
||||
|
||||
weapon_type = /obj/item/weapon/shield/changeling
|
||||
weapon_name_simple = "shield"
|
||||
@@ -430,12 +421,10 @@
|
||||
/obj/effect/proc_holder/changeling/suit/organic_space_suit
|
||||
name = "Organic Space Suit"
|
||||
desc = "We grow an organic suit to protect ourselves from space exposure."
|
||||
helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Retreating the suit damages our genomes. Cannot be used in lesser form."
|
||||
helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form."
|
||||
chemical_cost = 20
|
||||
dna_cost = 2
|
||||
genetic_damage = 8
|
||||
req_human = 1
|
||||
max_genetic_damage = 20
|
||||
|
||||
suit_type = /obj/item/clothing/suit/space/changeling
|
||||
helmet_type = /obj/item/clothing/head/helmet/space/changeling
|
||||
@@ -477,12 +466,10 @@
|
||||
/obj/effect/proc_holder/changeling/suit/armor
|
||||
name = "Chitinous Armor"
|
||||
desc = "We turn our skin into tough chitin to protect us from damage."
|
||||
helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Retreating the armor damages our genomes. Cannot be used in lesser form."
|
||||
helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
genetic_damage = 11
|
||||
req_human = 1
|
||||
max_genetic_damage = 20
|
||||
recharge_slowdown = 0.25
|
||||
|
||||
suit_type = /obj/item/clothing/suit/armor/changeling
|
||||
|
||||
@@ -40,10 +40,9 @@
|
||||
return
|
||||
if(!AStar(user, target.loc, /turf/proc/Distance, user.mind.changeling.sting_range, simulated_only = 0))
|
||||
return
|
||||
if(target.mind && target.mind.changeling)
|
||||
sting_feedback(user,target)
|
||||
take_chemical_cost(user.mind.changeling)
|
||||
return
|
||||
if(target.mind && target.mind.changeling)
|
||||
sting_feedback(user, target)
|
||||
user.mind.changeling.chem_charges -= chemical_cost
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/sting_feedback(mob/user, mob/target)
|
||||
@@ -62,7 +61,6 @@
|
||||
sting_icon = "sting_transform"
|
||||
chemical_cost = 40
|
||||
dna_cost = 3
|
||||
genetic_damage = 100
|
||||
var/datum/changelingprofile/selected_dna = null
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/Click()
|
||||
@@ -117,8 +115,6 @@
|
||||
sting_icon = "sting_armblade"
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
genetic_damage = 20
|
||||
max_genetic_damage = 10
|
||||
|
||||
/obj/item/weapon/melee/arm_blade/false
|
||||
desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless."
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
dna_cost = 0
|
||||
req_dna = 1
|
||||
req_human = 1
|
||||
max_genetic_damage = 3
|
||||
|
||||
/obj/item/clothing/glasses/changeling
|
||||
name = "flesh"
|
||||
|
||||
@@ -46,7 +46,7 @@ Credit where due:
|
||||
///////////
|
||||
|
||||
/proc/is_servant_of_ratvar(mob/living/M)
|
||||
return istype(M) && M.has_antag_datum(/datum/antagonist/clockcultist, TRUE)
|
||||
return istype(M) && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_CLOCKCULT)
|
||||
|
||||
/proc/is_eligible_servant(mob/living/M)
|
||||
if(!istype(M))
|
||||
@@ -65,17 +65,21 @@ Credit where due:
|
||||
return FALSE
|
||||
|
||||
/proc/add_servant_of_ratvar(mob/living/L, silent = FALSE)
|
||||
var/update_type = /datum/antagonist/clockcultist
|
||||
if(!L || !L.mind)
|
||||
return
|
||||
var/update_type = ANTAG_DATUM_CLOCKCULT
|
||||
if(silent)
|
||||
update_type = /datum/antagonist/clockcultist/silent
|
||||
. = L.gain_antag_datum(update_type)
|
||||
update_type = ANTAG_DATUM_CLOCKCULT_SILENT
|
||||
. = L.mind.add_antag_datum(update_type)
|
||||
|
||||
/proc/remove_servant_of_ratvar(mob/living/L, silent = FALSE)
|
||||
var/datum/antagonist/clockcultist/clock_datum = L.has_antag_datum(/datum/antagonist/clockcultist, TRUE)
|
||||
if(!L || !L.mind)
|
||||
return
|
||||
var/datum/antagonist/clockcult/clock_datum = L.mind.has_antag_datum(/datum/antagonist/clockcult)
|
||||
if(!clock_datum)
|
||||
return FALSE
|
||||
clock_datum.silent_update = silent
|
||||
clock_datum.on_remove()
|
||||
clock_datum.silent = silent
|
||||
clock_datum.on_removal()
|
||||
return TRUE
|
||||
|
||||
///////////////
|
||||
@@ -194,7 +198,7 @@ Credit where due:
|
||||
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>"
|
||||
feedback_set_details("round_end_result", "win - servants completed their objective (summon ratvar)")
|
||||
SSblackbox.set_details("round_end_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
|
||||
@@ -203,10 +207,10 @@ Credit where due:
|
||||
if(half_victory)
|
||||
text += "<span class='large_brass'><b>The crew escaped before Ratvar could rise, but the gateway \
|
||||
was successfully constructed!</b></span>"
|
||||
feedback_set_details("round_end_result", "halfwin - servants constructed the gateway but their objective was not completed (summon ratvar)")
|
||||
SSblackbox.set_details("round_end_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>"
|
||||
feedback_set_details("round_end_result", "loss - servants failed their objective (summon ratvar)")
|
||||
SSblackbox.set_details("round_end_result", "loss - servants failed their objective (summon ratvar)")
|
||||
text += "<br><b>The servants' objective was:</b> <br>[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>"
|
||||
|
||||
@@ -54,8 +54,11 @@
|
||||
clockwork_desc = "A sigil that will stun the next non-Servant to cross it."
|
||||
icon_state = "sigildull"
|
||||
layer = HIGH_SIGIL_LAYER
|
||||
alpha = 60
|
||||
alpha = 75
|
||||
color = "#FAE48C"
|
||||
light_range = 1.4
|
||||
light_power = 1
|
||||
light_color = "#FAE48C"
|
||||
sigil_name = "Sigil of Transgression"
|
||||
|
||||
/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L)
|
||||
@@ -93,10 +96,6 @@
|
||||
sigil_name = "Sigil of Submission"
|
||||
var/glow_type
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/New()
|
||||
..()
|
||||
update_light()
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/proc/post_channel(mob/living/L)
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
|
||||
@@ -202,6 +201,21 @@
|
||||
and <b>[structure_number]</b> Clockwork Structure[structure_number == 1 ? "":"s"] [structure_number == 1 ? "is":"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>[POWER_FLOOR]W</b> power.</span>")
|
||||
if(!GLOB.ratvar_awakens)
|
||||
to_chat(user, "<span class='brass'>You can recharge Clockwork Proselytizers 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>[B.amount * POWER_FLOOR]W</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/sigil_effects(mob/living/L)
|
||||
if(is_servant_of_ratvar(L))
|
||||
@@ -214,9 +228,7 @@
|
||||
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))
|
||||
return
|
||||
if(!cyborg_checks(cyborg))
|
||||
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))
|
||||
@@ -228,23 +240,27 @@
|
||||
animate(cyborg, color = previous_color, time = 100)
|
||||
addtimer(CALLBACK(cyborg, /atom/proc/update_atom_colour), 100)
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/cyborg_checks(mob/living/silicon/robot/cyborg)
|
||||
/obj/effect/clockwork/sigil/transmission/proc/cyborg_checks(mob/living/silicon/robot/cyborg, silent)
|
||||
if(!cyborg.cell)
|
||||
to_chat(cyborg, "<span class='warning'>You have no cell!</span>")
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>You have no cell!</span>")
|
||||
return FALSE
|
||||
if(!power_charge)
|
||||
to_chat(cyborg, "<span class='warning'>The [sigil_name] has no stored power!</span>")
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>The [sigil_name] has no stored power!</span>")
|
||||
return FALSE
|
||||
if(cyborg.cell.charge > cyborg.cell.maxcharge - MIN_CLOCKCULT_POWER)
|
||||
to_chat(cyborg, "<span class='warning'>You are already at maximum charge!</span>")
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>You are already at maximum charge!</span>")
|
||||
return FALSE
|
||||
if(cyborg.has_status_effect(STATUS_EFFECT_POWERREGEN))
|
||||
to_chat(cyborg, "<span class='warning'>You are already regenerating power!</span>")
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>You are already regenerating power!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/New()
|
||||
..()
|
||||
/obj/effect/clockwork/sigil/transmission/Initialize()
|
||||
. = ..()
|
||||
update_glow()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/modify_charge(amount)
|
||||
@@ -265,7 +281,7 @@
|
||||
if(!power_charge)
|
||||
set_light(0)
|
||||
else
|
||||
set_light(round(alpha*0.02, 1), round(alpha*0.005, 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
|
||||
@@ -299,8 +315,7 @@
|
||||
if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active)
|
||||
return
|
||||
visible_message("<span class='warning'>[src] begins to glow bright blue!</span>")
|
||||
animate(src, alpha = 255, time = 10)
|
||||
addtimer(CALLBACK(src, .proc/update_alpha), 10)
|
||||
animate(src, alpha = 255, time = 10, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay.
|
||||
sleep(10)
|
||||
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
|
||||
while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (GLOB.ratvar_awakens || vitality))) && get_turf(L) == get_turf(src))
|
||||
@@ -369,12 +384,4 @@
|
||||
animation_number = initial(animation_number)
|
||||
sigil_active = FALSE
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
if(sigil_active || alpha == 255)
|
||||
animate(src, alpha = initial(alpha), time = 10)
|
||||
addtimer(CALLBACK(src, .proc/update_alpha), 10)
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality/proc/update_alpha()
|
||||
if(sigil_active)
|
||||
alpha = 255
|
||||
else
|
||||
alpha = initial(alpha)
|
||||
animate(src, alpha = initial(alpha), time = 10, flags = ANIMATION_END_NOW)
|
||||
|
||||
@@ -15,9 +15,8 @@
|
||||
var/obj/effect/clockwork/spatial_gateway/linked_gateway //The gateway linked to this one
|
||||
var/timerid
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/New()
|
||||
..()
|
||||
update_light()
|
||||
/obj/effect/clockwork/spatial_gateway/Initialize()
|
||||
. = ..()
|
||||
addtimer(CALLBACK(src, .proc/check_setup), 1)
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/Destroy()
|
||||
@@ -99,12 +98,12 @@
|
||||
if(severity == 1 && uses)
|
||||
uses = 0
|
||||
visible_message("<span class='warning'>[src] is disrupted!</span>")
|
||||
animate(src, alpha = 0, transform = matrix()*2, time = 10)
|
||||
animate(src, alpha = 0, transform = matrix()*2, time = 10, flags = ANIMATION_END_NOW)
|
||||
deltimer(timerid)
|
||||
timerid = QDEL_IN(src, 10)
|
||||
linked_gateway.uses = 0
|
||||
linked_gateway.visible_message("<span class='warning'>[linked_gateway] is disrupted!</span>")
|
||||
animate(linked_gateway, alpha = 0, transform = matrix()*2, time = 10)
|
||||
animate(linked_gateway, alpha = 0, transform = matrix()*2, time = 10, flags = ANIMATION_END_NOW)
|
||||
deltimer(linked_gateway.timerid)
|
||||
linked_gateway.timerid = QDEL_IN(linked_gateway, 10)
|
||||
return TRUE
|
||||
@@ -131,9 +130,9 @@
|
||||
playsound(src, 'sound/effects/EMPulse.ogg', 50, 1)
|
||||
playsound(linked_gateway, 'sound/effects/EMPulse.ogg', 50, 1)
|
||||
transform = matrix() * 1.5
|
||||
animate(src, transform = matrix() / 1.5, time = 10)
|
||||
animate(src, transform = matrix() / 1.5, time = 10, flags = ANIMATION_END_NOW)
|
||||
linked_gateway.transform = matrix() * 1.5
|
||||
animate(linked_gateway, transform = matrix() / 1.5, time = 10)
|
||||
animate(linked_gateway, transform = matrix() / 1.5, time = 10, flags = ANIMATION_END_NOW)
|
||||
A.forceMove(get_turf(linked_gateway))
|
||||
if(!no_cost)
|
||||
uses = max(0, uses - 1)
|
||||
@@ -181,17 +180,26 @@
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
var/istargetobelisk = istype(target, /obj/structure/destructible/clockwork/powered/clockwork_obelisk)
|
||||
var/issrcobelisk = istype(src, /obj/structure/destructible/clockwork/powered/clockwork_obelisk)
|
||||
if(issrcobelisk && !anchored)
|
||||
to_chat(invoker, "<span class='warning'>[src] is no longer secured!</span>")
|
||||
return FALSE
|
||||
if(issrcobelisk)
|
||||
if(!anchored)
|
||||
to_chat(invoker, "<span class='warning'>[src] is no longer secured!</span>")
|
||||
return FALSE
|
||||
var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/CO = src //foolish as I am, how I set this proc up makes substypes unfeasible
|
||||
if(CO.active)
|
||||
to_chat(invoker, "<span class='warning'>[src] is now sustaining a gateway!</span>")
|
||||
return FALSE
|
||||
if(istargetobelisk)
|
||||
if(!target.anchored)
|
||||
to_chat(invoker, "<span class='warning'>That [target.name] is no longer secured!</span>")
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/CO = target
|
||||
if(CO.active)
|
||||
to_chat(invoker, "<span class='warning'>That [target.name] is sustaining a gateway, and cannot recieve another!</span>")
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
var/efficiency = CO.get_efficiency_mod()
|
||||
gateway_uses = round(gateway_uses * (2 * efficiency), 1)
|
||||
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>")
|
||||
var/obj/effect/clockwork/spatial_gateway/S1 = new(issrcobelisk ? get_turf(src) : get_step(get_turf(invoker), invoker.dir))
|
||||
|
||||
@@ -22,6 +22,12 @@
|
||||
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
|
||||
@@ -37,6 +43,8 @@
|
||||
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)
|
||||
@@ -51,6 +59,8 @@
|
||||
return "RA"
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return "HA"
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a component id from a component name
|
||||
/proc/get_component_id(name)
|
||||
@@ -65,6 +75,8 @@
|
||||
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)
|
||||
@@ -121,6 +133,8 @@
|
||||
return /obj/effect/overlay/temp/ratvar/component/alloy
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return /obj/effect/overlay/temp/ratvar/component/ansible
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a type for a component from a component id
|
||||
/proc/get_component_type(id)
|
||||
@@ -134,4 +148,6 @@
|
||||
if(REPLICANT_ALLOY)
|
||||
return /obj/item/clockwork/component/replicant_alloy
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return /obj/item/clockwork/component/hierophant_ansible
|
||||
return /obj/item/clockwork/component/hierophant_ansible
|
||||
else
|
||||
return null
|
||||
@@ -286,6 +286,28 @@
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.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/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
var/list/charge_values = list()
|
||||
if(!proselytizer.sigil_charge_checks(charge_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts draining glowing orange energy from [src]...</span>", \
|
||||
"<span class='alloy'>You start recharging your [proselytizer.name]...</span>")
|
||||
proselytizer.recharging = src
|
||||
while(proselytizer && user && src)
|
||||
if(!do_after(user, 10, target = src, extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/sigil_charge_checks, charge_values, src, user, TRUE)))
|
||||
break
|
||||
modify_charge(charge_values["power_gain"])
|
||||
proselytizer.modify_stored_power(charge_values["power_gain"])
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', charge_values["power_gain"] * 0.1, 1)
|
||||
|
||||
if(proselytizer)
|
||||
proselytizer.recharging = null
|
||||
if(user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops draining glowing orange energy from [src].</span>", \
|
||||
"<span class='alloy'>You finish recharging your [proselytizer.name]. It now contains <b>[proselytizer.get_power()]W/[proselytizer.get_max_power()]W</b> power.</span>")
|
||||
|
||||
//Proselytizer mob heal proc, to avoid as much copypaste as possible.
|
||||
/mob/living/proc/proselytizer_heal(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/list/repair_values = list()
|
||||
|
||||
@@ -106,6 +106,6 @@ List of nuances:
|
||||
if(!whisper)
|
||||
L.say(message, "clock", spans, language=/datum/language/common)
|
||||
else
|
||||
L.whisper(message)
|
||||
L.whisper(message, "clock", spans, language=/datum/language/common)
|
||||
else
|
||||
AM.say(message, language=/datum/language/common)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
var/uses_power = TRUE
|
||||
var/metal_to_power = FALSE
|
||||
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 proselytizer 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
|
||||
@@ -140,10 +141,11 @@
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/attack_self(mob/living/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
if(!can_use_power(POWER_WALL_TOTAL))
|
||||
to_chat(user, "<span class='warning'>[src] requires <b>[POWER_WALL_TOTAL]W</b> of power to produce brass sheets!</span>")
|
||||
return
|
||||
modify_stored_power(-POWER_WALL_TOTAL)
|
||||
if(uses_power)
|
||||
if(!can_use_power(POWER_WALL_TOTAL))
|
||||
to_chat(user, "<span class='warning'>[src] requires <b>[POWER_WALL_TOTAL]W</b> of power to produce brass sheets!</span>")
|
||||
return
|
||||
modify_stored_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 user [stored_power ? "some":"all"] of [src]'s power to produce some brass sheets. It now stores <b>[get_power()]W/[get_max_power()]W</b> of power.</span>")
|
||||
@@ -182,6 +184,9 @@
|
||||
if(repairing)
|
||||
to_chat(user, "<span class='warning'>You are currently repairing [repairing] with [src]!</span>")
|
||||
return FALSE
|
||||
if(recharging)
|
||||
to_chat(user, "<span class='warning'>You are currently recharging [src] from the [recharging.sigil_name]!</span>")
|
||||
return FALSE
|
||||
var/list/proselytize_values = target.proselytize_vals(user, src) //relevant values for proselytizing stuff, given as an associated list
|
||||
if(!islist(proselytize_values))
|
||||
if(proselytize_values != TRUE) //if we get true, fail, but don't send a message for whatever reason
|
||||
@@ -237,7 +242,7 @@
|
||||
/obj/item/clockwork/clockwork_proselytizer/proc/proselytize_checks(list/proselytize_values, atom/target, expected_type, mob/user, silent) //checked constantly while proselytizing
|
||||
if(!islist(proselytize_values) || !target || QDELETED(target) || !user)
|
||||
return FALSE
|
||||
if(repairing)
|
||||
if(repairing || recharging)
|
||||
return FALSE
|
||||
if(target.type != expected_type)
|
||||
return FALSE
|
||||
@@ -296,3 +301,20 @@
|
||||
<b>[round(repair_values["amount_to_heal"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]W</b> to fully repair [target == user ? "yourself" : "[target.p_them()]"]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//checked constantly while charging from a sigil
|
||||
/obj/item/clockwork/clockwork_proselytizer/proc/sigil_charge_checks(list/charge_values, obj/effect/clockwork/sigil/transmission/sigil, mob/user, silent)
|
||||
if(!islist(charge_values) || !sigil || QDELETED(sigil) || !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
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
/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/fellowship_armory, /datum/clockwork_scripture/create_object/mending_motor)
|
||||
/datum/clockwork_scripture/create_object/vitality_matrix, /datum/clockwork_scripture/channeled/mending_mantra, /datum/clockwork_scripture/fellowship_armory)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/security //four scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/channeled/taunting_tirade, \
|
||||
@@ -326,13 +326,19 @@
|
||||
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/production_text = "<b>[round(production_time)] minute\s"
|
||||
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
|
||||
production_text += " and [round(production_time, 1)] second\s"
|
||||
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>Chetr nyy hagehguf-naq-ubabe Ratvar.</center></b></font><br>\
|
||||
\
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
apply_eye_damage(H)
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/wraith_spectacles/tick()
|
||||
if(!ishuman(owner))
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
verb_ask = "requests"
|
||||
verb_exclaim = "proclaims"
|
||||
verb_yell = "harangues"
|
||||
initial_languages = list(/datum/language/common, /datum/language/ratvar)
|
||||
only_speaks_language = /datum/language/ratvar
|
||||
initial_language_holder = /datum/language_holder/clockmob
|
||||
bubble_icon = "clock"
|
||||
light_color = "#E42742"
|
||||
death_sound = 'sound/magic/clockwork/anima_fragment_death.ogg'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user