Merge branch 'master' into language-tab
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
/*! Actionspeed modification datums.
|
||||
|
||||
How action speed for mobs works
|
||||
|
||||
Action speed is now calculated by using modifier datums which are added to mobs. Some of them (nonvariable ones) are globally cached, the variable ones are instanced and changed based on need.
|
||||
|
||||
This gives us the ability to have multiple sources of actionspeed, reliabily keep them applied and remove them when they should be
|
||||
|
||||
THey can have unique sources and a bunch of extra fancy flags that control behaviour
|
||||
|
||||
Previously trying to update action speed was a shot in the dark that usually meant mobs got stuck going faster or slower
|
||||
|
||||
Actionspeed modification list is a simple key = datum system. Key will be the datum's ID if it is overridden to not be null, or type if it is not.
|
||||
|
||||
DO NOT override datum IDs unless you are going to have multiple types that must overwrite each other. It's more efficient to use types, ID functionality is only kept for cases where dynamic creation of modifiers need to be done.
|
||||
|
||||
When update actionspeed is called, the list of items is iterated, according to flags priority and a bunch of conditions
|
||||
this spits out a final calculated value which is used as a modifer to last_move + modifier for calculating when a mob
|
||||
can next move
|
||||
|
||||
*/
|
||||
|
||||
/datum/actionspeed_modifier
|
||||
/// Whether or not this is a variable modifier. Variable modifiers can NOT be ever auto-cached. ONLY CHECKED VIA INITIAL(), EFFECTIVELY READ ONLY (and for very good reason)
|
||||
var/variable = FALSE
|
||||
|
||||
/// Unique ID. You can never have different modifications with the same ID. By default, this SHOULD NOT be set. Only set it for cases where you're dynamically making modifiers/need to have two types overwrite each other. If unset, uses path (converted to text) as ID.
|
||||
var/id
|
||||
|
||||
/// Higher ones override lower priorities. This is NOT used for ID, ID must be unique, if it isn't unique the newer one overwrites automatically if overriding.
|
||||
var/priority = 0
|
||||
var/flags = NONE
|
||||
|
||||
/// Multiplicative slowdown
|
||||
var/multiplicative_slowdown = 0
|
||||
|
||||
/// Other modification datums this conflicts with.
|
||||
var/conflicts_with
|
||||
|
||||
/datum/actionspeed_modifier/New()
|
||||
. = ..()
|
||||
if(!id)
|
||||
id = "[type]" //We turn the path into a string.
|
||||
|
||||
GLOBAL_LIST_EMPTY(actionspeed_modification_cache)
|
||||
|
||||
/// Grabs a STATIC MODIFIER datum from cache. YOU MUST NEVER EDIT THESE DATUMS, OR IT WILL AFFECT ANYTHING ELSE USING IT TOO!
|
||||
/proc/get_cached_actionspeed_modifier(modtype)
|
||||
if(!ispath(modtype, /datum/actionspeed_modifier))
|
||||
CRASH("[modtype] is not a actionspeed modification typepath.")
|
||||
var/datum/actionspeed_modifier/actionspeed_mod = modtype
|
||||
if(initial(actionspeed_mod.variable))
|
||||
CRASH("[modtype] is a variable modifier, and can never be cached.")
|
||||
actionspeed_mod = GLOB.actionspeed_modification_cache[modtype]
|
||||
if(!actionspeed_mod)
|
||||
actionspeed_mod = GLOB.actionspeed_modification_cache[modtype] = new modtype
|
||||
return actionspeed_mod
|
||||
|
||||
///Add a action speed modifier to a mob. If a variable subtype is passed in as the first argument, it will make a new datum. If ID conflicts, it will overwrite the old ID.
|
||||
/mob/proc/add_actionspeed_modifier(datum/actionspeed_modifier/type_or_datum, update = TRUE)
|
||||
if(ispath(type_or_datum))
|
||||
if(!initial(type_or_datum.variable))
|
||||
type_or_datum = get_cached_actionspeed_modifier(type_or_datum)
|
||||
else
|
||||
type_or_datum = new type_or_datum
|
||||
var/datum/actionspeed_modifier/existing = LAZYACCESS(actionspeed_modification, type_or_datum.id)
|
||||
if(existing)
|
||||
if(existing == type_or_datum) //same thing don't need to touch
|
||||
return TRUE
|
||||
remove_actionspeed_modifier(existing, FALSE)
|
||||
if(length(actionspeed_modification))
|
||||
BINARY_INSERT(type_or_datum.id, actionspeed_modification, /datum/actionspeed_modifier, type_or_datum, priority, COMPARE_VALUE)
|
||||
LAZYSET(actionspeed_modification, type_or_datum.id, type_or_datum)
|
||||
if(update)
|
||||
update_actionspeed()
|
||||
return TRUE
|
||||
|
||||
/// Remove a action speed modifier from a mob, whether static or variable.
|
||||
/mob/proc/remove_actionspeed_modifier(datum/actionspeed_modifier/type_id_datum, update = TRUE)
|
||||
var/key
|
||||
if(ispath(type_id_datum))
|
||||
key = initial(type_id_datum.id) || "[type_id_datum]" //id if set, path set to string if not.
|
||||
else if(!istext(type_id_datum)) //if it isn't text it has to be a datum, as it isn't a type.
|
||||
key = type_id_datum.id
|
||||
else //assume it's an id
|
||||
key = type_id_datum
|
||||
if(!LAZYACCESS(actionspeed_modification, key))
|
||||
return FALSE
|
||||
LAZYREMOVE(actionspeed_modification, key)
|
||||
if(update)
|
||||
update_actionspeed(FALSE)
|
||||
return TRUE
|
||||
|
||||
/*! Used for variable slowdowns like hunger/health loss/etc, works somewhat like the old list-based modification adds. Returns the modifier datum if successful
|
||||
How this SHOULD work is:
|
||||
1. Ensures type_id_datum one way or another refers to a /variable datum. This makes sure it can't be cached. This includes if it's already in the modification list.
|
||||
2. Instantiate a new datum if type_id_datum isn't already instantiated + in the list, using the type. Obviously, wouldn't work for ID only.
|
||||
3. Add the datum if necessary using the regular add proc
|
||||
4. If any of the rest of the args are not null (see: multiplicative slowdown), modify the datum
|
||||
5. Update if necessary
|
||||
*/
|
||||
/mob/proc/add_or_update_variable_actionspeed_modifier(datum/actionspeed_modifier/type_id_datum, update = TRUE, multiplicative_slowdown)
|
||||
var/modified = FALSE
|
||||
var/inject = FALSE
|
||||
var/datum/actionspeed_modifier/final
|
||||
if(istext(type_id_datum))
|
||||
final = LAZYACCESS(actionspeed_modification, type_id_datum)
|
||||
if(!final)
|
||||
CRASH("Couldn't find existing modification when provided a text ID.")
|
||||
else if(ispath(type_id_datum))
|
||||
if(!initial(type_id_datum.variable))
|
||||
CRASH("Not a variable modifier")
|
||||
final = LAZYACCESS(actionspeed_modification, initial(type_id_datum.id) || "[type_id_datum]")
|
||||
if(!final)
|
||||
final = new type_id_datum
|
||||
inject = TRUE
|
||||
modified = TRUE
|
||||
else
|
||||
if(!initial(type_id_datum.variable))
|
||||
CRASH("Not a variable modifier")
|
||||
final = type_id_datum
|
||||
if(!LAZYACCESS(actionspeed_modification, final.id))
|
||||
inject = TRUE
|
||||
modified = TRUE
|
||||
if(!isnull(multiplicative_slowdown))
|
||||
final.multiplicative_slowdown = multiplicative_slowdown
|
||||
modified = TRUE
|
||||
if(inject)
|
||||
add_actionspeed_modifier(final, FALSE)
|
||||
if(update && modified)
|
||||
update_actionspeed(TRUE)
|
||||
return final
|
||||
|
||||
///Is there a actionspeed modifier for this mob
|
||||
/mob/proc/has_actionspeed_modifier(datum/actionspeed_modifier/datum_type_id)
|
||||
var/key
|
||||
if(ispath(datum_type_id))
|
||||
key = initial(datum_type_id.id) || "[datum_type_id]"
|
||||
else if(istext(datum_type_id))
|
||||
key = datum_type_id
|
||||
else
|
||||
key = datum_type_id.id
|
||||
return LAZYACCESS(actionspeed_modification, key)
|
||||
|
||||
/// Go through the list of actionspeed modifiers and calculate a final actionspeed. ANY ADD/REMOVE DONE IN UPDATE_actionspeed MUST HAVE THE UPDATE ARGUMENT SET AS FALSE!
|
||||
/mob/proc/update_actionspeed()
|
||||
. = 0
|
||||
var/list/conflict_tracker = list()
|
||||
for(var/key in get_actionspeed_modifiers())
|
||||
var/datum/actionspeed_modifier/M = actionspeed_modification[key]
|
||||
var/conflict = M.conflicts_with
|
||||
var/amt = M.multiplicative_slowdown
|
||||
if(conflict)
|
||||
// Conflicting modifiers prioritize the larger slowdown or the larger speedup
|
||||
// We purposefuly don't handle mixing speedups and slowdowns on the same id
|
||||
if(abs(conflict_tracker[conflict]) < abs(amt))
|
||||
conflict_tracker[conflict] = amt
|
||||
else
|
||||
continue
|
||||
. += amt
|
||||
cached_multiplicative_actions_slowdown = .
|
||||
|
||||
///Adds a default action speed
|
||||
/mob/proc/initialize_actionspeed()
|
||||
add_or_update_variable_actionspeed_modifier(/datum/actionspeed_modifier/base, multiplicative_slowdown = 1)
|
||||
|
||||
/// Get the action speed modifiers list of the mob
|
||||
/mob/proc/get_actionspeed_modifiers()
|
||||
. = LAZYCOPY(actionspeed_modification)
|
||||
for(var/id in actionspeed_mod_immunities)
|
||||
. -= id
|
||||
|
||||
/// Checks if a action speed modifier is valid and not missing any data
|
||||
/proc/actionspeed_data_null_check(datum/actionspeed_modifier/M) //Determines if a data list is not meaningful and should be discarded.
|
||||
. = !(M.multiplicative_slowdown)
|
||||
@@ -0,0 +1,2 @@
|
||||
/datum/actionspeed_modifier/base
|
||||
variable = TRUE
|
||||
@@ -0,0 +1,7 @@
|
||||
/datum/actionspeed_modifier/low_sanity
|
||||
multiplicative_slowdown = 0.25
|
||||
id = ACTIONSPEED_ID_SANITY
|
||||
|
||||
/datum/actionspeed_modifier/high_sanity
|
||||
multiplicative_slowdown = -0.1
|
||||
id = ACTIONSPEED_ID_SANITY
|
||||
@@ -0,0 +1,5 @@
|
||||
/datum/actionspeed_modifier/timecookie
|
||||
multiplicative_slowdown = -0.05
|
||||
|
||||
/datum/actionspeed_modifier/blunt_wound
|
||||
variable = TRUE
|
||||
@@ -226,6 +226,14 @@
|
||||
key_cache[key] = 0
|
||||
return .
|
||||
|
||||
/proc/restore_stickybans()
|
||||
for (var/banned_ckey in GLOB.stickybanadmintexts)
|
||||
world.SetConfig("ban", banned_ckey, GLOB.stickybanadmintexts[banned_ckey])
|
||||
GLOB.stickybanadminexemptions = list()
|
||||
GLOB.stickybanadmintexts = list()
|
||||
if (GLOB.stickbanadminexemptiontimerid)
|
||||
deltimer(GLOB.stickbanadminexemptiontimerid)
|
||||
GLOB.stickbanadminexemptiontimerid = null
|
||||
|
||||
#undef STICKYBAN_MAX_MATCHES
|
||||
#undef STICKYBAN_MAX_EXISTING_USER_MATCHES
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////Panels
|
||||
|
||||
/datum/admins/proc/show_player_panel(mob/M in GLOB.mob_list)
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Show Player Panel"
|
||||
set desc="Edit player (respawn, ban, heal, etc)"
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
|
||||
|
||||
/datum/admins/proc/access_news_network() //MARKER
|
||||
set category = "Fun"
|
||||
set category = "Admin.Events"
|
||||
set name = "Access Newscaster Network"
|
||||
set desc = "Allows you to view, add and edit news feeds."
|
||||
|
||||
@@ -679,8 +679,8 @@
|
||||
set category = "Server"
|
||||
set desc="Respawn basically"
|
||||
set name="Toggle Respawn"
|
||||
var/new_nores = !CONFIG_GET(flag/norespawn)
|
||||
CONFIG_SET(flag/norespawn, new_nores)
|
||||
var/new_nores = CONFIG_GET(flag/respawns_enabled)
|
||||
CONFIG_SET(flag/respawns_enabled, !new_nores)
|
||||
if (!new_nores)
|
||||
to_chat(world, "<B>You may now respawn.</B>", confidential = TRUE)
|
||||
else
|
||||
@@ -783,10 +783,11 @@
|
||||
if(ispath(chosen, /turf))
|
||||
T.ChangeTurf(chosen)
|
||||
else
|
||||
var/obj/structure/closet/supplypod/centcompod/pod = new()
|
||||
var/area/pod_storage_area = locate(/area/centcom/supplypod/podStorage) in GLOB.sortedAreas
|
||||
var/obj/structure/closet/supplypod/centcompod/pod = new(pick(get_area_turfs(pod_storage_area))) //Lets just have it in the pod bay for a moment instead of runtiming
|
||||
var/atom/A = new chosen(pod)
|
||||
A.flags_1 |= ADMIN_SPAWNED_1
|
||||
new /obj/effect/abstract/DPtarget(T, pod)
|
||||
new /obj/effect/pod_landingzone(T, pod)
|
||||
|
||||
log_admin("[key_name(usr)] pod-spawned [chosen] at [AREACOORD(usr)]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Podspawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/client/proc/investigate_show()
|
||||
set name = "Investigate"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
if(!holder)
|
||||
return
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
/datum/admin_rank/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
/datum/admin_rank/CanProcCall(procname)
|
||||
. = ..()
|
||||
if(!check_rights(R_SENSITIVE))
|
||||
return FALSE
|
||||
|
||||
/proc/admin_keyword_to_flag(word, previous_rights=0)
|
||||
var/flag = 0
|
||||
switch(ckey(word))
|
||||
@@ -79,6 +84,8 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
flag = R_AUTOLOGIN
|
||||
if("dbranks")
|
||||
flag = R_DBRANKS
|
||||
if("sensitive")
|
||||
flag = R_SENSITIVE
|
||||
if("@","prev")
|
||||
flag = previous_rights
|
||||
return flag
|
||||
|
||||
@@ -78,8 +78,11 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/mark_datum_mapview,
|
||||
/client/proc/hide_verbs, /*hides all our adminverbs*/
|
||||
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
|
||||
/datum/admins/proc/open_borgopanel
|
||||
/datum/admins/proc/open_borgopanel,
|
||||
/client/proc/admin_cmd_respawn_return_to_lobby,
|
||||
/client/proc/admin_cmd_remove_ghost_respawn_timer
|
||||
)
|
||||
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/DB_ban_panel, /client/proc/stickybanpanel))
|
||||
GLOBAL_PROTECT(admin_verbs_ban)
|
||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/manual_play_web_sound, /client/proc/set_round_end_sound))
|
||||
@@ -348,7 +351,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
|
||||
|
||||
/client/proc/admin_ghost()
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Aghost"
|
||||
if(!holder)
|
||||
return FALSE
|
||||
@@ -379,7 +382,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
|
||||
/client/proc/invisimin()
|
||||
set name = "Invisimin"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set desc = "Toggles ghost-like invisibility (Don't abuse this)"
|
||||
if(holder && mob)
|
||||
if(mob.invisibility == INVISIBILITY_OBSERVER)
|
||||
@@ -391,7 +394,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
|
||||
/client/proc/check_antagonists()
|
||||
set name = "Check Antagonists"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
if(holder)
|
||||
holder.check_antagonists()
|
||||
log_admin("[key_name(usr)] checked antagonists.") //for tsar~
|
||||
@@ -411,14 +414,14 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
|
||||
/client/proc/game_panel()
|
||||
set name = "Game Panel"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
if(holder)
|
||||
holder.Game()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Game Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/secrets()
|
||||
set name = "Secrets"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
if (holder)
|
||||
holder.Secrets()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Secrets Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
@@ -472,7 +475,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Stealth Mode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/drop_bomb()
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Drop Bomb"
|
||||
set desc = "Cause an explosion of varying strength at your location."
|
||||
|
||||
@@ -514,7 +517,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Bomb") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/drop_dynex_bomb()
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Drop DynEx Bomb"
|
||||
set desc = "Cause an explosion of varying strength at your location."
|
||||
|
||||
@@ -561,7 +564,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
message_admins("[key_name_admin(usr)] has modified Dynamic Explosion Scale: [ex_scale]")
|
||||
|
||||
/client/proc/give_spell(mob/T in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Give Spell"
|
||||
set desc = "Gives a spell to a mob."
|
||||
|
||||
@@ -585,7 +588,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
message_admins("<span class='danger'>Spells given to mindless mobs will not be transferred in mindswap or cloning!</span>")
|
||||
|
||||
/client/proc/remove_spell(mob/T in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Remove Spell"
|
||||
set desc = "Remove a spell from the selected mob."
|
||||
|
||||
@@ -598,7 +601,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Remove Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/give_disease(mob/living/T in GLOB.mob_living_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Give Disease"
|
||||
set desc = "Gives a Disease to a mob."
|
||||
if(!istype(T))
|
||||
@@ -613,7 +616,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name(T)] the disease [D].</span>")
|
||||
|
||||
/client/proc/object_say(obj/O in world)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
set name = "OSay"
|
||||
set desc = "Makes an object say something."
|
||||
var/message = input(usr, "What do you want the message to be?", "Make Sound") as text | null
|
||||
@@ -625,7 +628,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Object Say") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/client/proc/togglebuildmodeself()
|
||||
set name = "Toggle Build Mode Self"
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
if (!(holder.rank.rights & R_BUILDMODE))
|
||||
return
|
||||
if(src.mob)
|
||||
@@ -634,7 +637,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
|
||||
/client/proc/check_ai_laws()
|
||||
set name = "Check AI Laws"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
if(holder)
|
||||
src.holder.output_ai_laws()
|
||||
|
||||
@@ -717,7 +720,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
|
||||
/client/proc/toggle_AI_interact()
|
||||
set name = "Toggle Admin AI Interact"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set desc = "Allows you to interact with most machines as an AI would as a ghost"
|
||||
|
||||
AI_Interact = !AI_Interact
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/datum/verbs/menu/Admin/verb/playerpanel()
|
||||
set name = "Player Panel"
|
||||
set desc = "Player Panel"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
if(usr.client.holder)
|
||||
usr.client.holder.player_panel_new()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Player Panel New") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -212,4 +212,4 @@
|
||||
dat += build_antag_listing()
|
||||
|
||||
dat += "</body></html>"
|
||||
usr << browse(dat.Join(), "window=roundstatus;size=500x500")
|
||||
usr << browse(dat.Join(), "window=roundstatus;size=500x500")
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
H.saved_socks = H.socks
|
||||
|
||||
// Mutant randomizing, doesn't affect the mob appearance unless it's the specific mutant.
|
||||
H.dna.features["mcolor"] = random_short_color()
|
||||
H.dna.features["mcolor"] = sanitize_hexcolor(random_short_color(), 6)
|
||||
H.dna.features["mcolor2"] = sanitize_hexcolor(random_short_color(), 6)
|
||||
H.dna.features["mcolor3"] = sanitize_hexcolor(random_short_color(), 6)
|
||||
H.dna.features["tail_lizard"] = pick(GLOB.tails_list_lizard)
|
||||
H.dna.features["snout"] = pick(GLOB.snouts_list)
|
||||
H.dna.features["horns"] = pick(GLOB.horns_list)
|
||||
@@ -43,6 +45,9 @@
|
||||
H.dna.features["insect_wings"] = pick(GLOB.insect_wings_list)
|
||||
H.dna.features["deco_wings"] = pick(GLOB.deco_wings_list)
|
||||
H.dna.features["insect_fluff"] = pick(GLOB.insect_fluffs_list)
|
||||
H.dna.features["arachnid_legs"] = pick(GLOB.arachnid_legs_list)
|
||||
H.dna.features["arachnid_spinneret"] = pick(GLOB.arachnid_spinneret_list)
|
||||
H.dna.features["arachnid_mandibles"] = pick(GLOB.arachnid_mandibles_list)
|
||||
H.dna.features["flavor_text"] = "" //Oh no.
|
||||
H.dna.features["body_model"] = H.gender
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
var/deadmined
|
||||
|
||||
/datum/admins/CanProcCall(procname)
|
||||
. = ..()
|
||||
if(!check_rights(R_SENSITIVE))
|
||||
return FALSE
|
||||
|
||||
/datum/admins/New(datum/admin_rank/R, ckey, force_active = FALSE, protected)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
@@ -147,6 +152,8 @@ GLOBAL_PROTECT(href_token)
|
||||
return 0
|
||||
|
||||
/datum/admins/vv_edit_var(var_name, var_value)
|
||||
if(var_name == NAMEOF(src, fakekey))
|
||||
return ..()
|
||||
return FALSE //nice try trialmin
|
||||
|
||||
/*
|
||||
|
||||
@@ -287,7 +287,7 @@
|
||||
R = rank_names[new_rank]
|
||||
if(!R) //rank with that name doesn't exist yet - make it
|
||||
if(D)
|
||||
R = new(new_rank, D.rank.rights) //duplicate our previous admin_rank but with a new name
|
||||
R = new(new_rank, D.rank.rights, D.rank.exclude_rights, D.rank.can_edit_rights) //duplicate our previous admin_rank but with a new name
|
||||
else
|
||||
R = new(new_rank) //blank new admin_rank
|
||||
GLOB.admin_ranks += R
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
for(var/mob/living/mob in thunderdome)
|
||||
qdel(mob) //Clear mobs
|
||||
for(var/obj/obj in thunderdome)
|
||||
if(!istype(obj, /obj/machinery/camera))
|
||||
if(!istype(obj, /obj/machinery/camera) && !istype(obj, /obj/effect/abstract/proximity_checker))
|
||||
qdel(obj) //Clear objects
|
||||
|
||||
var/area/template = locate(/area/tdome/arena_source)
|
||||
|
||||
@@ -52,11 +52,9 @@
|
||||
edit_emitter(user)
|
||||
|
||||
/obj/effect/sound_emitter/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(check_rights_for(user.client, R_SOUNDS))
|
||||
activate(user)
|
||||
to_chat(user, "<span class='notice'>Sound emitter activated.</span>")
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>Sound emitter activated.</span>", confidential = TRUE)
|
||||
|
||||
/obj/effect/sound_emitter/proc/edit_emitter(mob/user)
|
||||
var/dat = ""
|
||||
@@ -84,20 +82,20 @@
|
||||
if(!new_label)
|
||||
return
|
||||
maptext = new_label
|
||||
to_chat(user, "<span class='notice'>Label set to [maptext].</span>")
|
||||
to_chat(user, "<span class='notice'>Label set to [maptext].</span>", confidential = TRUE)
|
||||
if(href_list["edit_sound_file"])
|
||||
var/new_file = input(user, "Choose a sound file.", "Sound Emitter") as null|sound
|
||||
if(!new_file)
|
||||
return
|
||||
sound_file = new_file
|
||||
to_chat(user, "<span class='notice'>New sound file set to [sound_file].</span>")
|
||||
to_chat(user, "<span class='notice'>New sound file set to [sound_file].</span>", confidential = TRUE)
|
||||
if(href_list["edit_volume"])
|
||||
var/new_volume = input(user, "Choose a volume.", "Sound Emitter", sound_volume) as null|num
|
||||
if(isnull(new_volume))
|
||||
return
|
||||
new_volume = clamp(new_volume, 0, 100)
|
||||
sound_volume = new_volume
|
||||
to_chat(user, "<span class='notice'>Volume set to [sound_volume]%.</span>")
|
||||
to_chat(user, "<span class='notice'>Volume set to [sound_volume]%.</span>", confidential = TRUE)
|
||||
if(href_list["edit_mode"])
|
||||
var/new_mode
|
||||
var/mode_list = list("Local (normal sound)" = SOUND_EMITTER_LOCAL, "Direct (not affected by environment/location)" = SOUND_EMITTER_DIRECT)
|
||||
@@ -105,7 +103,7 @@
|
||||
if(!new_mode)
|
||||
return
|
||||
motus_operandi = mode_list[new_mode]
|
||||
to_chat(user, "<span class='notice'>Mode set to [motus_operandi].</span>")
|
||||
to_chat(user, "<span class='notice'>Mode set to [motus_operandi].</span>", confidential = TRUE)
|
||||
if(href_list["edit_range"])
|
||||
var/new_range
|
||||
var/range_list = list("Radius (all mobs within a radius)" = SOUND_EMITTER_RADIUS, "Z-Level (all mobs on the same z)" = SOUND_EMITTER_ZLEVEL, "Global (all players)" = SOUND_EMITTER_GLOBAL)
|
||||
@@ -113,14 +111,14 @@
|
||||
if(!new_range)
|
||||
return
|
||||
emitter_range = range_list[new_range]
|
||||
to_chat(user, "<span class='notice'>Range set to [emitter_range].</span>")
|
||||
to_chat(user, "<span class='notice'>Range set to [emitter_range].</span>", confidential = TRUE)
|
||||
if(href_list["edit_radius"])
|
||||
var/new_radius = input(user, "Choose a radius.", "Sound Emitter", sound_volume) as null|num
|
||||
if(isnull(new_radius))
|
||||
return
|
||||
new_radius = clamp(new_radius, 0, 127)
|
||||
play_radius = new_radius
|
||||
to_chat(user, "<span class='notice'>Audible radius set to [play_radius].</span>")
|
||||
to_chat(user, "<span class='notice'>Audible radius set to [play_radius].</span>", confidential = TRUE)
|
||||
if(href_list["play"])
|
||||
activate(user)
|
||||
edit_emitter(user) //Refresh the UI to see our changes
|
||||
|
||||
@@ -298,7 +298,9 @@
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
qdel(query_find_message_secret)
|
||||
|
||||
/proc/browse_messages(type, target_ckey, index, linkless = FALSE, filter, agegate = FALSE)
|
||||
/proc/browse_messages(type, target_ckey, index, linkless = FALSE, filter, agegate = FALSE, override = FALSE)
|
||||
if((!override || IsAdminAdvancedProcCall()) && !check_rights(R_SENSITIVE))
|
||||
return
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
|
||||
+318
-55
@@ -7,7 +7,7 @@
|
||||
if ("add")
|
||||
var/list/ban = list()
|
||||
var/ckey
|
||||
ban["admin"] = usr.key
|
||||
ban["admin"] = usr.ckey
|
||||
ban["type"] = list("sticky")
|
||||
ban["reason"] = "(InGameBan)([usr.key])" //this will be displayed in dd only
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
ban["ckey"] = ckey
|
||||
|
||||
if (get_stickyban_from_ckey(ckey))
|
||||
to_chat(usr, "<span class='adminnotice'>Error: Can not add a stickyban: User already has a current sticky ban</span>")
|
||||
to_chat(usr, "<span class='adminnotice'>Error: Can not add a stickyban: User already has a current sticky ban</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
if (data["reason"])
|
||||
ban["message"] = data["reason"]
|
||||
@@ -31,7 +32,26 @@
|
||||
return
|
||||
ban["message"] = "[reason]"
|
||||
|
||||
if(SSdbcore.Connect()) // todo: second wave
|
||||
// var/datum/db_query/query_create_stickyban = SSdbcore.NewQuery({"
|
||||
// INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin)
|
||||
// VALUES (:ckey, :message, :banning_admin)
|
||||
// "}, list("ckey" = ckey, "message" = ban["message"], "banning_admin" = usr.ckey))
|
||||
var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin)
|
||||
VALUES ([ckey], [ban["message"]], [usr.ckey])
|
||||
"})
|
||||
if (query_create_stickyban.warn_execute())
|
||||
ban["fromdb"] = TRUE
|
||||
qdel(query_create_stickyban)
|
||||
|
||||
world.SetConfig("ban",ckey,list2stickyban(ban))
|
||||
ban = stickyban2list(list2stickyban(ban))
|
||||
ban["matches_this_round"] = list()
|
||||
ban["existing_user_matches_this_round"] = list()
|
||||
ban["admin_matches_this_round"] = list()
|
||||
ban["pending_matches_this_round"] = list()
|
||||
SSstickyban.cache[ckey] = ban
|
||||
|
||||
log_admin_private("[key_name(usr)] has stickybanned [ckey].\nReason: [ban["message"]]")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has stickybanned [ckey].\nReason: [ban["message"]]</span>")
|
||||
@@ -43,14 +63,29 @@
|
||||
|
||||
var/ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>")
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
|
||||
return
|
||||
if (alert("Are you sure you want to remove the sticky ban on [ckey]?","Are you sure","Yes","No") == "No")
|
||||
return
|
||||
if (!get_stickyban_from_ckey(ckey))
|
||||
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>")
|
||||
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
|
||||
return
|
||||
world.SetConfig("ban",ckey, null)
|
||||
SSstickyban.cache -= ckey
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// SSdbcore.QuerySelect(list(
|
||||
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = :ckey", list("ckey" = ckey)),
|
||||
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey", list("ckey" = ckey)),
|
||||
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = :ckey", list("ckey" = ckey)),
|
||||
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = :ckey", list("ckey" = ckey))
|
||||
// ), warn = TRUE, qdel = TRUE)
|
||||
SSdbcore.QuerySelect(list(
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = [ckey]"),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey]"),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = [ckey]"),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = [ckey]")
|
||||
), warn = TRUE, qdel = TRUE)
|
||||
|
||||
log_admin_private("[key_name(usr)] removed [ckey]'s stickyban")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed [ckey]'s stickyban</span>")
|
||||
@@ -64,42 +99,45 @@
|
||||
var/alt = ckey(data["alt"])
|
||||
var/ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>")
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/found = 0
|
||||
//we have to do it this way because byond keeps the case in its sticky ban matches WHY!!!
|
||||
for (var/key in ban["keys"])
|
||||
if (ckey(key) == alt)
|
||||
found = 1
|
||||
break
|
||||
|
||||
if (!found)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: [alt] is not linked to [ckey]'s sticky ban!</span>")
|
||||
var/key = LAZYACCESS(ban["keys"], alt)
|
||||
if (!key)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: [alt] is not linked to [ckey]'s sticky ban!</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them","Are you sure","Yes","No") == "No")
|
||||
if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them, Use \[E] to exempt them","Are you sure","Yes","No") == "No")
|
||||
return
|
||||
|
||||
//we have to do this again incase something changes
|
||||
ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>")
|
||||
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
found = 0
|
||||
for (var/key in ban["keys"])
|
||||
if (ckey(key) == alt)
|
||||
ban["keys"] -= key
|
||||
found = 1
|
||||
break
|
||||
key = LAZYACCESS(ban["keys"], alt)
|
||||
|
||||
if (!found)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: [alt] link to [ckey]'s sticky ban disappeared.</span>")
|
||||
if (!key)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: [alt] link to [ckey]'s sticky ban disappeared.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
LAZYREMOVE(ban["keys"], alt)
|
||||
world.SetConfig("ban",ckey,list2stickyban(ban))
|
||||
|
||||
SSstickyban.cache[ckey] = ban
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// var/datum/db_query/query_remove_stickyban_alt = SSdbcore.NewQuery(
|
||||
// "DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey AND matched_ckey = :alt",
|
||||
// list("ckey" = ckey, "alt" = alt)
|
||||
// )
|
||||
var/datum/DBQuery/query_remove_stickyban_alt = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey] AND matched_ckey = [alt]"
|
||||
)
|
||||
query_remove_stickyban_alt.warn_execute()
|
||||
qdel(query_remove_stickyban_alt)
|
||||
|
||||
log_admin_private("[key_name(usr)] has disassociated [alt] from [ckey]'s sticky ban")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has disassociated [alt] from [ckey]'s sticky ban</span>")
|
||||
|
||||
@@ -109,7 +147,7 @@
|
||||
var/ckey = data["ckey"]
|
||||
var/ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>")
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
|
||||
return
|
||||
var/oldreason = ban["message"]
|
||||
var/reason = input(usr,"Reason","Reason","[ban["message"]]") as text|null
|
||||
@@ -118,28 +156,203 @@
|
||||
//we have to do this again incase something changed while we waited for input
|
||||
ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>")
|
||||
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
|
||||
return
|
||||
ban["message"] = "[reason]"
|
||||
|
||||
world.SetConfig("ban",ckey,list2stickyban(ban))
|
||||
|
||||
SSstickyban.cache[ckey] = ban
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// var/datum/db_query/query_edit_stickyban = SSdbcore.NewQuery(
|
||||
// "UPDATE [format_table_name("stickyban")] SET reason = :reason WHERE ckey = :ckey",
|
||||
// list("reason" = reason, "ckey" = ckey)
|
||||
// )
|
||||
var/datum/DBQuery/query_edit_stickyban = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("stickyban")] SET reason = [reason] WHERE ckey = [ckey]"
|
||||
)
|
||||
query_edit_stickyban.warn_execute()
|
||||
qdel(query_edit_stickyban)
|
||||
|
||||
log_admin_private("[key_name(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]</span>")
|
||||
|
||||
if ("exempt")
|
||||
if (!data["ckey"])
|
||||
return
|
||||
var/ckey = data["ckey"]
|
||||
if (!data["alt"])
|
||||
return
|
||||
var/alt = ckey(data["alt"])
|
||||
var/ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/key = LAZYACCESS(ban["keys"], alt)
|
||||
if (!key)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: [alt] is not linked to [ckey]'s sticky ban!</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
if (alert("Are you sure you want to exempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No")
|
||||
return
|
||||
|
||||
//we have to do this again incase something changes
|
||||
ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
key = LAZYACCESS(ban["keys"], alt)
|
||||
|
||||
if (!key)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: [alt]'s link to [ckey]'s sticky ban disappeared.</span>", confidential = TRUE)
|
||||
return
|
||||
LAZYREMOVE(ban["keys"], alt)
|
||||
key["exempt"] = TRUE
|
||||
LAZYSET(ban["whitelist"], alt, key)
|
||||
|
||||
world.SetConfig("ban",ckey,list2stickyban(ban))
|
||||
|
||||
SSstickyban.cache[ckey] = ban
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// var/datum/db_query/query_exempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
// "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = :ckey AND matched_ckey = :alt",
|
||||
// list("ckey" = ckey, "alt" = alt)
|
||||
// )
|
||||
var/datum/DBQuery/query_exempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = [ckey] AND matched_ckey = [alt]"
|
||||
)
|
||||
query_exempt_stickyban_alt.warn_execute()
|
||||
qdel(query_exempt_stickyban_alt)
|
||||
|
||||
log_admin_private("[key_name(usr)] has exempted [alt] from [ckey]'s sticky ban")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has exempted [alt] from [ckey]'s sticky ban</span>")
|
||||
|
||||
if ("unexempt")
|
||||
if (!data["ckey"])
|
||||
return
|
||||
var/ckey = data["ckey"]
|
||||
if (!data["alt"])
|
||||
return
|
||||
var/alt = ckey(data["alt"])
|
||||
var/ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/key = LAZYACCESS(ban["whitelist"], alt)
|
||||
if (!key)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: [alt] is not exempt from [ckey]'s sticky ban!</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
if (alert("Are you sure you want to unexempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No")
|
||||
return
|
||||
|
||||
//we have to do this again incase something changes
|
||||
ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
key = LAZYACCESS(ban["whitelist"], alt)
|
||||
if (!key)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: [alt]'s exemption from [ckey]'s sticky ban disappeared.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
LAZYREMOVE(ban["whitelist"], alt)
|
||||
key["exempt"] = FALSE
|
||||
LAZYSET(ban["keys"], alt, key)
|
||||
|
||||
world.SetConfig("ban",ckey,list2stickyban(ban))
|
||||
|
||||
SSstickyban.cache[ckey] = ban
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// var/datum/db_query/query_unexempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
// "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = :ckey AND matched_ckey = :alt",
|
||||
// list("ckey" = ckey, "alt" = alt)
|
||||
// )
|
||||
var/datum/DBQuery/query_unexempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = [ckey] AND matched_ckey = [alt]"
|
||||
)
|
||||
query_unexempt_stickyban_alt.warn_execute()
|
||||
qdel(query_unexempt_stickyban_alt)
|
||||
|
||||
log_admin_private("[key_name(usr)] has unexempted [alt] from [ckey]'s sticky ban")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has unexempted [alt] from [ckey]'s sticky ban</span>")
|
||||
|
||||
if ("timeout")
|
||||
if (!data["ckey"])
|
||||
return
|
||||
if (!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='adminnotice'>No database connection!</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/ckey = data["ckey"]
|
||||
|
||||
if (alert("Are you sure you want to put [ckey]'s stickyban on timeout until next round (or removed)?","Are you sure","Yes","No") == "No")
|
||||
return
|
||||
var/ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
ban["timeout"] = TRUE
|
||||
|
||||
world.SetConfig("ban", ckey, null)
|
||||
|
||||
var/cachedban = SSstickyban.cache[ckey]
|
||||
if (cachedban)
|
||||
cachedban["timeout"] = TRUE
|
||||
|
||||
log_admin_private("[key_name(usr)] has put [ckey]'s sticky ban on timeout.")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has put [ckey]'s sticky ban on timeout.</span>")
|
||||
|
||||
if ("untimeout")
|
||||
if (!data["ckey"])
|
||||
return
|
||||
if (!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='adminnotice'>No database connection!</span>", confidential = TRUE)
|
||||
return
|
||||
var/ckey = data["ckey"]
|
||||
|
||||
if (alert("Are you sure you want to lift the timeout on [ckey]'s stickyban?","Are you sure","Yes","No") == "No")
|
||||
return
|
||||
|
||||
var/ban = get_stickyban_from_ckey(ckey)
|
||||
var/cachedban = SSstickyban.cache[ckey]
|
||||
if (cachedban)
|
||||
cachedban["timeout"] = FALSE
|
||||
if (!ban)
|
||||
if (!cachedban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
|
||||
return
|
||||
ban = cachedban
|
||||
|
||||
ban["timeout"] = FALSE
|
||||
|
||||
world.SetConfig("ban",ckey,list2stickyban(ban))
|
||||
|
||||
log_admin_private("[key_name(usr)] has taken [ckey]'s sticky ban off of timeout.")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has taken [ckey]'s sticky ban off of timeout.</span>")
|
||||
|
||||
|
||||
if ("revert")
|
||||
if (!data["ckey"])
|
||||
return
|
||||
var/ckey = data["ckey"]
|
||||
if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start?","Are you sure","Yes","No") == "No")
|
||||
if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start (or last edit)?","Are you sure","Yes","No") == "No")
|
||||
return
|
||||
var/ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>")
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
|
||||
return
|
||||
var/cached_ban = SSstickyban.cache[ckey]
|
||||
if (!cached_ban)
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No cached sticky ban for [ckey] found!</span>")
|
||||
to_chat(usr, "<span class='adminnotice'>Error: No cached sticky ban for [ckey] found!</span>", confidential = TRUE)
|
||||
world.SetConfig("ban",ckey,null)
|
||||
|
||||
log_admin_private("[key_name(usr)] has reverted [ckey]'s sticky ban to its state at round start.")
|
||||
@@ -150,14 +363,22 @@
|
||||
world.SetConfig("ban",ckey,list2stickyban(cached_ban))
|
||||
|
||||
|
||||
/datum/admins/proc/stickyban_gethtml(ckey, ban)
|
||||
. = {"
|
||||
/datum/admins/proc/stickyban_gethtml(ckey)
|
||||
var/ban = get_stickyban_from_ckey(ckey)
|
||||
if (!ban)
|
||||
return
|
||||
var/timeout
|
||||
if (SSdbcore.Connect())
|
||||
timeout = "<a href='?_src_=holder;[HrefToken()];stickyban=[(ban["timeout"] ? "untimeout" : "timeout")]&ckey=[ckey]'>\[[(ban["timeout"] ? "untimeout" : "timeout" )]\]</a>"
|
||||
else
|
||||
timeout = "<a href='?_src_=holder;[HrefToken()];stickyban=revert&ckey=[ckey]'>\[revert\]</a>"
|
||||
. = list({"
|
||||
<a href='?_src_=holder;[HrefToken()];stickyban=remove&ckey=[ckey]'>\[-\]</a>
|
||||
<a href='?_src_=holder;[HrefToken()];stickyban=revert&ckey=[ckey]'>\[revert\]</a>
|
||||
[timeout]
|
||||
<b>[ckey]</b>
|
||||
<br />"
|
||||
[ban["message"]] <b><a href='?_src_=holder;[HrefToken()];stickyban=edit&ckey=[ckey]'>\[Edit\]</a></b><br />
|
||||
"}
|
||||
"})
|
||||
if (ban["admin"])
|
||||
. += "[ban["admin"]]<br />"
|
||||
else
|
||||
@@ -166,19 +387,24 @@
|
||||
for (var/key in ban["keys"])
|
||||
if (ckey(key) == ckey)
|
||||
continue
|
||||
. += "<li><a href='?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]</li>"
|
||||
. += "<li><a href='?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]<a href='?_src_=holder;[HrefToken()];stickyban=exempt&ckey=[ckey]&alt=[ckey(key)]'>\[E\]</a></li>"
|
||||
|
||||
for (var/key in ban["whitelist"])
|
||||
if (ckey(key) == ckey)
|
||||
continue
|
||||
. += "<li><a href='?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]<a href='?_src_=holder;[HrefToken()];stickyban=unexempt&ckey=[ckey]&alt=[ckey(key)]'>\[UE\]</a></li>"
|
||||
|
||||
. += "</ol>\n"
|
||||
|
||||
/datum/admins/proc/stickyban_show()
|
||||
if(!check_rights(R_BAN))
|
||||
return
|
||||
var/list/bans = sortList(world.GetConfig("ban"))
|
||||
var/banhtml = ""
|
||||
var/list/bans = sticky_banned_ckeys()
|
||||
var/list/banhtml = list()
|
||||
for(var/key in bans)
|
||||
var/ckey = ckey(key)
|
||||
var/ban = stickyban2list(world.GetConfig("ban",key))
|
||||
banhtml += "<br /><hr />\n"
|
||||
banhtml += stickyban_gethtml(ckey,ban)
|
||||
banhtml += stickyban_gethtml(ckey)
|
||||
|
||||
var/html = {"
|
||||
<head>
|
||||
@@ -186,22 +412,49 @@
|
||||
</head>
|
||||
<body>
|
||||
<h2>All Sticky Bans:</h2> <a href='?_src_=holder;[HrefToken()];stickyban=add'>\[+\]</a><br>
|
||||
[banhtml]
|
||||
[banhtml.Join("")]
|
||||
</body>
|
||||
"}
|
||||
usr << browse(html,"window=stickybans;size=700x400")
|
||||
|
||||
/proc/get_stickyban_from_ckey(var/ckey)
|
||||
/proc/sticky_banned_ckeys()
|
||||
if (SSdbcore.Connect() || length(SSstickyban.dbcache))
|
||||
if (SSstickyban.dbcacheexpire < world.time)
|
||||
SSstickyban.Populatedbcache()
|
||||
if (SSstickyban.dbcacheexpire)
|
||||
return SSstickyban.dbcache.Copy()
|
||||
|
||||
return sortList(world.GetConfig("ban"))
|
||||
|
||||
|
||||
/proc/get_stickyban_from_ckey(ckey)
|
||||
. = list()
|
||||
if (!ckey)
|
||||
return null
|
||||
ckey = ckey(ckey)
|
||||
. = null
|
||||
for (var/key in world.GetConfig("ban"))
|
||||
if (ckey(key) == ckey)
|
||||
. = stickyban2list(world.GetConfig("ban",key))
|
||||
break
|
||||
if (SSdbcore.Connect() || length(SSstickyban.dbcache))
|
||||
if (SSstickyban.dbcacheexpire < world.time)
|
||||
SSstickyban.Populatedbcache()
|
||||
if (SSstickyban.dbcacheexpire)
|
||||
. = SSstickyban.dbcache[ckey]
|
||||
//reset the cache incase its a newer ban (but only if we didn't update the cache recently)
|
||||
if (!. && SSstickyban.dbcacheexpire != world.time+STICKYBAN_DB_CACHE_TIME)
|
||||
SSstickyban.dbcacheexpire = 1
|
||||
SSstickyban.Populatedbcache()
|
||||
. = SSstickyban.dbcache[ckey]
|
||||
if (.)
|
||||
var/list/cachedban = SSstickyban.cache["[ckey]"]
|
||||
if (cachedban)
|
||||
.["timeout"] = cachedban["timeout"]
|
||||
|
||||
/proc/stickyban2list(var/ban)
|
||||
.["fromdb"] = TRUE
|
||||
return
|
||||
|
||||
. = stickyban2list(world.GetConfig("ban", ckey)) || stickyban2list(world.GetConfig("ban", ckey(ckey))) || list()
|
||||
|
||||
if (!length(.))
|
||||
return null
|
||||
|
||||
/proc/stickyban2list(ban, strictdb = TRUE)
|
||||
if (!ban)
|
||||
return null
|
||||
. = params2list(ban)
|
||||
@@ -212,30 +465,40 @@
|
||||
var/ckey = ckey(key)
|
||||
ckeys[ckey] = ckey //to make searching faster.
|
||||
.["keys"] = ckeys
|
||||
if (.["whitelist"])
|
||||
var/keys = splittext(.["whitelist"], ",")
|
||||
var/ckeys = list()
|
||||
for (var/key in keys)
|
||||
var/ckey = ckey(key)
|
||||
ckeys[ckey] = ckey //to make searching faster.
|
||||
.["whitelist"] = ckeys
|
||||
.["type"] = splittext(.["type"], ",")
|
||||
.["IP"] = splittext(.["IP"], ",")
|
||||
.["computer_id"] = splittext(.["computer_id"], ",")
|
||||
. -= "fromdb"
|
||||
|
||||
|
||||
/proc/list2stickyban(var/list/ban)
|
||||
/proc/list2stickyban(list/ban)
|
||||
if (!ban || !islist(ban))
|
||||
return null
|
||||
. = ban.Copy()
|
||||
if (.["keys"])
|
||||
.["keys"] = jointext(.["keys"], ",")
|
||||
if (.["IP"])
|
||||
.["IP"] = jointext(.["IP"], ",")
|
||||
if (.["computer_id"])
|
||||
.["computer_id"] = jointext(.["computer_id"], ",")
|
||||
if (.["whitelist"])
|
||||
.["whitelist"] = jointext(.["whitelist"], ",")
|
||||
if (.["type"])
|
||||
.["type"] = jointext(.["type"], ",")
|
||||
|
||||
//internal tracking only, shouldn't be stored
|
||||
. -= "reverting"
|
||||
. -= "matches_this_round"
|
||||
. -= "existing_user_matches_this_round"
|
||||
. -= "admin_matches_this_round"
|
||||
. -= "matches_this_round"
|
||||
. -= "reverting"
|
||||
. -= "pending_matches_this_round"
|
||||
|
||||
//storing these can sometimes cause sticky bans to start matching everybody
|
||||
// and isn't even needed for sticky ban matching, as the hub tracks these separately
|
||||
. -= "IP"
|
||||
. -= "computer_id"
|
||||
|
||||
. = list2params(.)
|
||||
|
||||
|
||||
@@ -257,9 +257,8 @@
|
||||
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.ckey == banckey)
|
||||
playermob = M
|
||||
break
|
||||
|
||||
if(!playermob || M.client) // prioritise mobs with a client to stop the 'oops the dead body with no client got forwarded'
|
||||
playermob = M
|
||||
|
||||
banreason = "(MANUAL BAN) "+banreason
|
||||
|
||||
@@ -508,7 +507,7 @@
|
||||
if("constructwraith")
|
||||
M.change_mob_type( /mob/living/simple_animal/hostile/construct/wraith , null, null, delmob )
|
||||
if("shade")
|
||||
M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob )
|
||||
M.change_mob_type( /mob/living/simple_animal/hostile/construct/shade , null, null, delmob )
|
||||
|
||||
|
||||
/////////////////////////////////////new ban stuff
|
||||
@@ -936,6 +935,12 @@
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_MIND_TRANSFER];jobban4=[REF(M)]'>Mind Transfer Potion</a></td>"
|
||||
|
||||
//Respawns
|
||||
if(jobban_isbanned(M, ROLE_RESPAWN))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_RESPAWN];jobban4=[REF(M)]'><font color=red>Respawns</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_RESPAWN];jobban4=[REF(M)]'>Respawns</a></td>"
|
||||
|
||||
dat += "</tr></table>"
|
||||
usr << browse(dat, "window=jobban2;size=800x450")
|
||||
return
|
||||
@@ -1799,12 +1804,15 @@
|
||||
if(alert(usr, "Send [key_name(M)] back to Lobby?", "Message", "Yes", "No") != "Yes")
|
||||
return
|
||||
|
||||
log_admin("[key_name(usr)] has sent [key_name(M)] back to the Lobby.")
|
||||
message_admins("[key_name(usr)] has sent [key_name(M)] back to the Lobby.")
|
||||
log_admin("[key_name(usr)] has sent [key_name(M)] back to the Lobby, removing their respawn restrictions if they existed.")
|
||||
message_admins("[key_name(usr)] has sent [key_name(M)] back to the Lobby, removing their respawn restrictions if they existed.")
|
||||
|
||||
var/mob/dead/new_player/NP = new()
|
||||
NP.ckey = M.ckey
|
||||
qdel(M)
|
||||
if(GLOB.preferences_datums[NP.ckey])
|
||||
var/datum/preferences/P = GLOB.preferences_datums[NP.ckey]
|
||||
P.respawn_restrictions_active = FALSE
|
||||
|
||||
else if(href_list["tdome1"])
|
||||
if(!check_rights(R_FUN))
|
||||
@@ -2475,7 +2483,7 @@
|
||||
R.activate_module(I)
|
||||
|
||||
if(pod)
|
||||
new /obj/effect/abstract/DPtarget(target, pod)
|
||||
new /obj/effect/pod_landingzone(target, pod)
|
||||
|
||||
if (number == 1)
|
||||
log_admin("[key_name(usr)] created a [english_list(paths)]")
|
||||
|
||||
@@ -782,7 +782,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
if(temp.vars.Find(v))
|
||||
temp.vars[v] = SDQL_expression(d, set_list[sets])
|
||||
else
|
||||
temp.vv_edit_var(v, SDQL_expression(d, set_list[sets]))
|
||||
temp.vv_edit_var(v, SDQL_expression(d, set_list[sets]), TRUE)
|
||||
break
|
||||
if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client)))
|
||||
temp = temp.vars[v]
|
||||
|
||||
@@ -174,7 +174,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
//is_bwoink is TRUE if this ticket was started by an admin PM
|
||||
/datum/admin_help/New(msg, client/C, is_bwoink)
|
||||
//clean the input msg
|
||||
msg = sanitize(copytext_char(msg,1,MAX_MESSAGE_LEN))
|
||||
msg = copytext_char(msg,1,MAX_MESSAGE_LEN)
|
||||
if(!msg || !C || !C.mob)
|
||||
qdel(src)
|
||||
return
|
||||
@@ -263,7 +263,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
//message from the initiator without a target, all admins will see this
|
||||
//won't bug irc
|
||||
/datum/admin_help/proc/MessageNoRecipient(msg)
|
||||
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
|
||||
msg = copytext_char(msg, 1, MAX_MESSAGE_LEN)
|
||||
var/ref_src = "[REF(src)]"
|
||||
//Message to be sent to all admins
|
||||
var/admin_msg = "<span class='adminnotice'><span class='adminhelp'>Ticket [TicketHref("#[id]", ref_src)]</span><b>: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]:</b> <span class='linkify'>[keywords_lookup(msg)]</span></span>"
|
||||
@@ -523,7 +523,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
if(handle_spam_prevention(msg,MUTE_ADMINHELP))
|
||||
return
|
||||
|
||||
msg = trim(msg)
|
||||
msg = sanitize(trim(msg))
|
||||
|
||||
if(!msg)
|
||||
return
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/client/proc/jumptoarea(area/A in GLOB.sortedAreas)
|
||||
set name = "Jump to Area"
|
||||
set desc = "Area to jump to"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
if(!src.holder)
|
||||
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
|
||||
return
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
/client/proc/jumptoturf(turf/T in world)
|
||||
set name = "Jump to Turf"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
if(!src.holder)
|
||||
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
|
||||
return
|
||||
@@ -40,7 +40,7 @@
|
||||
return
|
||||
|
||||
/client/proc/jumptomob(mob/M in GLOB.mob_list)
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Jump to Mob"
|
||||
|
||||
if(!src.holder)
|
||||
@@ -59,7 +59,7 @@
|
||||
to_chat(A, "This mob is not located in the game world.", confidential = TRUE)
|
||||
|
||||
/client/proc/jumptocoord(tx as num, ty as num, tz as num)
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Jump to Coordinate"
|
||||
|
||||
if (!holder)
|
||||
@@ -74,7 +74,7 @@
|
||||
message_admins("[key_name_admin(usr)] jumped to coordinates [tx], [ty], [tz]")
|
||||
|
||||
/client/proc/jumptokey()
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Jump to Key"
|
||||
|
||||
if(!src.holder)
|
||||
@@ -97,7 +97,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Key") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/Getmob(mob/M in GLOB.mob_list - GLOB.dummy_mob_list)
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Get Mob"
|
||||
set desc = "Mob to teleport"
|
||||
if(!src.holder)
|
||||
@@ -113,7 +113,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Get Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/Getkey()
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Get Key"
|
||||
set desc = "Key to teleport"
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Get Key") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/sendmob(mob/M in sortmobs())
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Send Mob"
|
||||
if(!src.holder)
|
||||
to_chat(src, "Only administrators may use this command.", confidential = TRUE)
|
||||
@@ -158,3 +158,19 @@
|
||||
else
|
||||
to_chat(src, "Failed to move mob to a valid location.", confidential = TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Send Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/// Proc to hook user-enacted teleporting behavior and keep logging of the event.
|
||||
/atom/movable/proc/admin_teleport(atom/new_location, message = TRUE)
|
||||
if(isnull(new_location))
|
||||
log_admin("[key_name(usr)] teleported [key_name(src)] to nullspace")
|
||||
moveToNullspace()
|
||||
else
|
||||
log_admin("[key_name(usr)] teleported [key_name(src)] to [AREACOORD(loc)]")
|
||||
forceMove(new_location)
|
||||
|
||||
/mob/admin_teleport(atom/new_location, message = TRUE)
|
||||
var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(src)] to [isnull(new_location) ? "nullspace" : ADMIN_VERBOSEJMP(loc)]"
|
||||
if(message)
|
||||
message_admins(msg)
|
||||
admin_ticket_log(src, msg)
|
||||
return ..()
|
||||
|
||||
@@ -113,7 +113,6 @@
|
||||
to_chat(src, "<span class='danger'>Error: Use the admin IRC/Discord channel, nerd.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
|
||||
else
|
||||
//get message text, limit it's length.and clean/escape html
|
||||
if(!msg)
|
||||
@@ -128,11 +127,16 @@
|
||||
else
|
||||
if(holder)
|
||||
to_chat(src, "<span class='danger'>Error: Admin-PM: Client not found.</span>", confidential = TRUE)
|
||||
to_chat(src, "<span class='danger'><b>Message not sent:</b></span><br>[msg]", confidential = TRUE)
|
||||
to_chat(src, "<span class='danger'><b>Message not sent:</b></span><br>[sanitize(msg)]", confidential = TRUE)
|
||||
if(recipient_ticket)
|
||||
recipient_ticket.AddInteraction("<b>No client found, message not sent:</b><br>[msg]")
|
||||
return
|
||||
else
|
||||
//clean the message if it's not sent by a high-rank admin
|
||||
if(!check_rights(R_SERVER|R_DEBUG,0)||external)//no sending html to the poor bots
|
||||
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
|
||||
if(!msg)
|
||||
return
|
||||
current_ticket.MessageNoRecipient(msg)
|
||||
return
|
||||
|
||||
@@ -141,7 +145,7 @@
|
||||
to_chat(src, "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
|
||||
if(src.handle_spam_prevention(msg,MUTE_ADMINHELP))
|
||||
return
|
||||
|
||||
//clean the message if it's not sent by a high-rank admin
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/datum/admins/proc/open_borgopanel(borgo in GLOB.silicon_mobs)
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Show Borg Panel"
|
||||
set desc = "Show borg panel"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/client/proc/cinematic()
|
||||
set name = "cinematic"
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set desc = "Shows a cinematic." // Intended for testing but I thought it might be nice for events on the rare occasion Feel free to comment it out if it's not wanted.
|
||||
set hidden = 1
|
||||
if(!SSticker)
|
||||
@@ -8,4 +8,4 @@
|
||||
|
||||
var/datum/cinematic/choice = input(src,"Cinematic","Choose",null) as anything in subtypesof(/datum/cinematic)
|
||||
if(choice)
|
||||
Cinematic(initial(choice.id),world,null)
|
||||
Cinematic(initial(choice.id),world,null)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/client/proc/dsay(msg as text)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Game"
|
||||
set name = "Dsay"
|
||||
set hidden = 1
|
||||
if(!holder)
|
||||
@@ -23,13 +23,6 @@
|
||||
|
||||
var/rendered = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <span class='name'>[uppertext(holder.rank)]([src.holder.fakekey ? pick(nicknames) : src.key])</span> says, <span class='message'>\"[emoji_parse(msg)]\"</span></span>"
|
||||
|
||||
// var/rank_name = holder.rank
|
||||
// var/admin_name = key
|
||||
// if(holder.fakekey)
|
||||
// rank_name = pick(strings("admin_nicknames.json", "ranks", "config")) please use this soon.
|
||||
// admin_name = pick(strings("admin_nicknames.json", "names", "config"))
|
||||
// var/rendered = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <span class='name'>[rank_name]([admin_name])</span> says, <span class='message'>\"[emoji_parse(msg)]\"</span></span>"
|
||||
|
||||
for (var/mob/M in GLOB.player_list)
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Air Status In Location") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_robotize(mob/M in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Make Robot"
|
||||
|
||||
if(!SSticker.HasRoundStarted())
|
||||
@@ -43,7 +43,7 @@
|
||||
alert("Invalid mob")
|
||||
|
||||
/client/proc/cmd_admin_blobize(mob/M in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Make Blob"
|
||||
|
||||
if(!SSticker.HasRoundStarted())
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
|
||||
/client/proc/cmd_admin_animalize(mob/M in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Make Simple Animal"
|
||||
|
||||
if(!SSticker.HasRoundStarted())
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
|
||||
/client/proc/makepAI(turf/T in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Make pAI"
|
||||
set desc = "Specify a location to spawn a pAI device, then specify a key to play that pAI"
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Make pAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_alienize(mob/M in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Make Alien"
|
||||
|
||||
if(!SSticker.HasRoundStarted())
|
||||
@@ -121,7 +121,7 @@
|
||||
alert("Invalid mob")
|
||||
|
||||
/client/proc/cmd_admin_slimeize(mob/M in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Make slime"
|
||||
|
||||
if(!SSticker.HasRoundStarted())
|
||||
@@ -211,7 +211,7 @@
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has granted [M.key] full access.</span>")
|
||||
|
||||
/client/proc/cmd_assume_direct_control(mob/M in GLOB.mob_list)
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Assume direct control"
|
||||
set desc = "Direct intervention"
|
||||
|
||||
@@ -229,6 +229,33 @@
|
||||
qdel(adminmob)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Assume Direct Control") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_give_direct_control(mob/M in GLOB.mob_list)
|
||||
set category = "Admin.Game"
|
||||
set name = "Give direct control"
|
||||
|
||||
if(!M)
|
||||
return
|
||||
if(M.ckey)
|
||||
if(alert("This mob is being controlled by [M.key]. Are you sure you wish to give someone else control of it? [M.key] will be made a ghost.",,"Yes","No") != "Yes")
|
||||
return
|
||||
var/client/newkey = input(src, "Pick the player to put in control.", "New player") as null|anything in sortList(GLOB.clients)
|
||||
var/mob/oldmob = newkey.mob
|
||||
var/delmob = FALSE
|
||||
if((isobserver(oldmob) || alert("Do you want to delete [newkey]'s old mob?","Delete?","Yes","No") != "No"))
|
||||
delmob = TRUE
|
||||
if(!M || QDELETED(M))
|
||||
to_chat(usr, "<span class='warning'>The target mob no longer exists, aborting.</span>")
|
||||
return
|
||||
if(M.ckey)
|
||||
M.ghostize(FALSE)
|
||||
M.ckey = newkey.key
|
||||
M.client?.init_verbs()
|
||||
if(delmob)
|
||||
qdel(oldmob)
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave away direct control of [M] to [newkey].</span>")
|
||||
log_admin("[key_name(usr)] gave away direct control of [M] to [newkey].")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Direct Control") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_test_atmos_controllers()
|
||||
set category = "Mapping"
|
||||
set name = "Test Atmos Monitoring Consoles"
|
||||
@@ -455,7 +482,7 @@
|
||||
cmd_admin_areatest(FALSE)
|
||||
|
||||
/client/proc/cmd_admin_dress(mob/M in GLOB.mob_list)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Events"
|
||||
set name = "Select equipment"
|
||||
if(!(ishuman(M) || isobserver(M)))
|
||||
alert("Invalid mob")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/client/proc/roll_dices()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Roll Dice"
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
browseserverlogs("[GLOB.log_directory]/")
|
||||
|
||||
/client/proc/browseserverlogs(path = "data/logs/")
|
||||
if(!check_rights(R_SENSITIVE))
|
||||
return
|
||||
path = browse_files(path)
|
||||
if(!path)
|
||||
return
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
var/ntype = text2num(type)
|
||||
|
||||
//Add client links
|
||||
var/dat = ""
|
||||
var/list/dat = list()
|
||||
if(M.client)
|
||||
dat += "<center><p>Client</p></center>"
|
||||
dat += "<center>"
|
||||
@@ -46,22 +46,27 @@
|
||||
var/log_source = M.logging;
|
||||
if(source == LOGSRC_CLIENT && M.client) //if client doesn't exist just fall back to the mob log
|
||||
log_source = M.client.player_details.logging //should exist, if it doesn't that's a bug, don't check for it not existing
|
||||
|
||||
var/list/concatenated_logs = list()
|
||||
for(var/log_type in log_source)
|
||||
var/nlog_type = text2num(log_type)
|
||||
if(nlog_type & ntype)
|
||||
var/list/reversed = log_source[log_type]
|
||||
if(islist(reversed))
|
||||
reversed = reverseRange(reversed.Copy())
|
||||
for(var/entry in reversed)
|
||||
dat += "<font size=2px><b>[entry]</b><br>[reversed[entry]]</font><br>"
|
||||
dat += "<hr>"
|
||||
var/list/all_the_entrys = log_source[log_type]
|
||||
for(var/entry in all_the_entrys)
|
||||
concatenated_logs += "<b>[entry]</b><br>[all_the_entrys[entry]]"
|
||||
if(length(concatenated_logs))
|
||||
sortTim(concatenated_logs, cmp = /proc/cmp_text_dsc) //Sort by timestamp.
|
||||
dat += "<font size=2px>"
|
||||
dat += concatenated_logs.Join("<br>")
|
||||
dat += "</font>"
|
||||
|
||||
usr << browse(dat, "window=invidual_logging_[key_name(M)];size=600x480")
|
||||
var/datum/browser/popup = new(usr, "invidual_logging_[key_name(M)]", "Individual Logs", 600, 600)
|
||||
popup.set_content(dat.Join())
|
||||
popup.open()
|
||||
|
||||
/proc/individual_logging_panel_link(mob/M, log_type, log_src, label, selected_src, selected_type)
|
||||
var/slabel = label
|
||||
if(selected_type == log_type && selected_src == log_src)
|
||||
slabel = "<b>\[[label]\]</b>"
|
||||
|
||||
return "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[log_type];log_src=[log_src]'>[slabel]</a>"
|
||||
//This is necessary because num2text drops digits and rounds on big numbers. If more defines get added in the future it could break again.
|
||||
log_type = num2text(log_type, MAX_BITFLAG_DIGITS)
|
||||
return "<a href='?_src_=holder;[HrefToken()];individuallog=[REF(M)];log_type=[log_type];log_src=[log_src]'>[slabel]</a>"
|
||||
|
||||
@@ -41,4 +41,4 @@
|
||||
message_admins("[key_name_admin(usr)] is changing the map to [VM.map_name]")
|
||||
log_admin("[key_name(usr)] is changing the map to [VM.map_name]")
|
||||
if (SSmapping.changemap(VM) == 0)
|
||||
message_admins("[key_name_admin(usr)] has changed the map to [VM.map_name]")
|
||||
message_admins("[key_name_admin(usr)] has changed the map to [VM.map_name]")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/client/proc/one_click_antag()
|
||||
set name = "Create Antagonist"
|
||||
set desc = "Auto-create an antagonist of your choice"
|
||||
set category = "Admin"
|
||||
set category = "Admin.Events"
|
||||
|
||||
if(holder)
|
||||
holder.one_click_antag()
|
||||
|
||||
@@ -28,4 +28,4 @@ GLOBAL_VAR_INIT(highlander, FALSE)
|
||||
addtimer(CALLBACK(src, .proc/only_one), 420)
|
||||
|
||||
/mob/living/carbon/human/proc/make_scottish()
|
||||
mind.add_antag_datum(/datum/antagonist/highlander)
|
||||
mind.add_antag_datum(/datum/antagonist/highlander)
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
/client/proc/play_sound(S as sound)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Play Global Sound"
|
||||
if(!check_rights(R_SOUNDS))
|
||||
return
|
||||
|
||||
var/freq = 1
|
||||
var/vol = input(usr, "What volume would you like the sound to play at?",, 100) as null|num
|
||||
if(!vol)
|
||||
return
|
||||
var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num
|
||||
if(!freq)
|
||||
freq = 1
|
||||
vol = clamp(vol, 1, 100)
|
||||
|
||||
var/sound/admin_sound = new()
|
||||
@@ -18,14 +16,14 @@
|
||||
admin_sound.channel = CHANNEL_ADMIN
|
||||
admin_sound.frequency = freq
|
||||
admin_sound.wait = 1
|
||||
admin_sound.repeat = 0
|
||||
admin_sound.repeat = FALSE
|
||||
admin_sound.status = SOUND_STREAM
|
||||
admin_sound.volume = vol
|
||||
|
||||
var/res = alert(usr, "Show the title of this song to the players?",, "Yes","No", "Cancel")
|
||||
switch(res)
|
||||
if("Yes")
|
||||
to_chat(world, "<span class='boldannounce'>An admin played: [S]</span>")
|
||||
to_chat(world, "<span class='boldannounce'>An admin played: [S]</span>", confidential = TRUE)
|
||||
if("Cancel")
|
||||
return
|
||||
|
||||
@@ -42,18 +40,18 @@
|
||||
|
||||
|
||||
/client/proc/play_local_sound(S as sound)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Play Local Sound"
|
||||
if(!check_rights(R_SOUNDS))
|
||||
return
|
||||
|
||||
log_admin("[key_name(src)] played a local sound [S]")
|
||||
message_admins("[key_name_admin(src)] played a local sound [S]")
|
||||
playsound(get_turf(src.mob), S, 50, 0, 0)
|
||||
playsound(get_turf(src.mob), S, 50, FALSE, FALSE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Local Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/play_web_sound()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Play Internet Sound"
|
||||
if(!check_rights(R_SOUNDS))
|
||||
return
|
||||
@@ -136,7 +134,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Internet Sound")
|
||||
|
||||
/client/proc/manual_play_web_sound()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Manual Play Internet Sound"
|
||||
if(!check_rights(R_SOUNDS))
|
||||
return
|
||||
@@ -182,7 +180,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Manual Play Internet Sound")
|
||||
|
||||
/client/proc/set_round_end_sound(S as sound)
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Set Round End Sound"
|
||||
if(!check_rights(R_SOUNDS))
|
||||
return
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
if(C.prefs.toggles & SOUND_PRAYERS)
|
||||
if(usr.job == "Chaplain")
|
||||
SEND_SOUND(C, sound('sound/effects/pray.ogg'))
|
||||
else
|
||||
SEND_SOUND(C, sound('sound/effects/ding.ogg'))
|
||||
to_chat(usr, "<span class='info'>You pray to the gods: \"[msg_tmp]\"</span>")
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Prayer") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Everything") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_subtle_message(mob/M in GLOB.mob_list)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
set name = "Subtle Message"
|
||||
|
||||
if(!ismob(M))
|
||||
@@ -46,7 +46,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Subtle Message") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_headset_message(mob/M in GLOB.mob_list)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
set name = "Headset Message"
|
||||
|
||||
admin_headset_message(M)
|
||||
@@ -128,7 +128,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Modify Antagonist Reputation") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_world_narrate()
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
set name = "Global Narrate"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -144,7 +144,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Global Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_direct_narrate(mob/M)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
set name = "Direct Narrate"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -169,7 +169,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Direct Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_local_narrate(atom/A)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
set name = "Local Narrate"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -190,7 +190,7 @@
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Local Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Game"
|
||||
set name = "Godmode"
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
@@ -335,7 +335,7 @@ Works kind of like entering the game with a new character. Character receives a
|
||||
Traitors and the like can also be revived with the previous role mostly intact.
|
||||
/N */
|
||||
/client/proc/respawn_character()
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Game"
|
||||
set name = "Respawn Character"
|
||||
set desc = "Respawn a person that has been gibbed/dusted/killed. They must be a ghost for this to work and preferably should not have a body to go back into."
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -503,7 +503,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
return new_character
|
||||
|
||||
/client/proc/cmd_admin_add_freeform_ai_law()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Events"
|
||||
set name = "Add Custom AI law"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -546,7 +546,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Rejuvinate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_create_centcom_report()
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
set name = "Create Command Report"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -572,7 +572,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Create Command Report") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_change_command_name()
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
set name = "Change Command Name"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -595,7 +595,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
admin_delete(A)
|
||||
|
||||
/client/proc/cmd_admin_list_open_jobs()
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Manage Job Slots"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -604,7 +604,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Manage Job Slots") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in world)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Explosion"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -640,7 +640,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
return
|
||||
|
||||
/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in world)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Fun"
|
||||
set name = "EM Pulse"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -656,7 +656,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "EM Pulse") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_gib(mob/M in GLOB.mob_list)
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Gib"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -683,7 +683,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
|
||||
/client/proc/cmd_admin_gib_self()
|
||||
set name = "Gibself"
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
|
||||
var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No")
|
||||
if(confirm == "Yes")
|
||||
@@ -702,14 +702,14 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Contents") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/toggle_view_range()
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Game"
|
||||
set name = "Change View Range"
|
||||
set desc = "switches between 1x and custom views"
|
||||
|
||||
if(view == CONFIG_GET(string/default_view))
|
||||
change_view(input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,128))
|
||||
if(view_size.getView() == view_size.default)
|
||||
view_size.setTo(input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,128) - 7)
|
||||
else
|
||||
change_view(CONFIG_GET(string/default_view))
|
||||
view_size.resetToDefault(getScreenSize(prefs.widescreenpref))
|
||||
|
||||
log_admin("[key_name(usr)] changed their view range to [view].")
|
||||
//message_admins("\blue [key_name_admin(usr)] changed their view range to [view].") //why? removed by order of XSI
|
||||
@@ -717,8 +717,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Change View Range", "[view]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/admin_call_shuttle()
|
||||
|
||||
set category = "Admin"
|
||||
set category = "Admin.Events"
|
||||
set name = "Call Shuttle"
|
||||
|
||||
if(EMERGENCY_AT_LEAST_DOCKED)
|
||||
@@ -738,7 +737,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
return
|
||||
|
||||
/client/proc/admin_cancel_shuttle()
|
||||
set category = "Admin"
|
||||
set category = "Admin.Events"
|
||||
set name = "Cancel Shuttle"
|
||||
if(!check_rights(0))
|
||||
return
|
||||
@@ -754,9 +753,51 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] admin-recalled the emergency shuttle.</span>")
|
||||
|
||||
return
|
||||
/*
|
||||
/client/proc/admin_disable_shuttle()
|
||||
set category = "Admin.Events"
|
||||
set name = "Disable Shuttle"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_DISABLED)
|
||||
to_chat(usr, "<span class='warning'>Error, shuttle is already disabled.</span>")
|
||||
return
|
||||
if(alert(src, "You sure?", "Confirm", "Yes", "No") != "Yes")
|
||||
return
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] disabled the shuttle.</span>")
|
||||
SSshuttle.lastMode = SSshuttle.emergency.mode
|
||||
SSshuttle.lastCallTime = SSshuttle.emergency.timeLeft(1)
|
||||
SSshuttle.adminEmergencyNoRecall = TRUE
|
||||
SSshuttle.emergency.setTimer(0)
|
||||
SSshuttle.emergency.mode = SHUTTLE_DISABLED
|
||||
priority_announce("Warning: Emergency Shuttle uplink failure, shuttle disabled until further notice.", "Emergency Shuttle Uplink Alert", 'sound/misc/announce_dig.ogg')
|
||||
|
||||
/client/proc/admin_enable_shuttle()
|
||||
set category = "Admin - Events"
|
||||
set category = "Admin.Events"
|
||||
set name = "Enable Shuttle"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_DISABLED)
|
||||
to_chat(usr, "<span class='warning'>Error, shuttle not disabled.</span>")
|
||||
return
|
||||
if(alert(src, "You sure?", "Confirm", "Yes", "No") != "Yes")
|
||||
return
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] enabled the emergency shuttle.</span>")
|
||||
SSshuttle.adminEmergencyNoRecall = FALSE
|
||||
SSshuttle.emergencyNoRecall = FALSE
|
||||
if(SSshuttle.lastMode == SHUTTLE_DISABLED) //If everything goes to shit, fix it.
|
||||
SSshuttle.lastMode = SHUTTLE_IDLE
|
||||
SSshuttle.emergency.mode = SSshuttle.lastMode
|
||||
if(SSshuttle.lastCallTime < 10 SECONDS && SSshuttle.lastMode != SHUTTLE_IDLE)
|
||||
SSshuttle.lastCallTime = 10 SECONDS //Make sure no insta departures.
|
||||
SSshuttle.emergency.setTimer(SSshuttle.lastCallTime)
|
||||
priority_announce("Warning: Emergency Shuttle uplink reestablished, shuttle enabled.", "Emergency Shuttle Uplink Alert", 'sound/misc/announce_dig.ogg')
|
||||
*/
|
||||
/client/proc/everyone_random()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Make Everyone Random"
|
||||
set desc = "Make everyone have a random appearance. You can only use this before rounds!"
|
||||
|
||||
@@ -804,7 +845,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
|
||||
|
||||
/client/proc/admin_change_sec_level()
|
||||
set category = "Special Verbs"
|
||||
set category = "Admin.Events"
|
||||
set name = "Set Security Level"
|
||||
set desc = "Changes the security level. Announcement only, i.e. setting to Delta won't activate nuke"
|
||||
|
||||
@@ -821,7 +862,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
|
||||
/client/proc/toggle_nuke(obj/machinery/nuclearbomb/N in GLOB.nuke_list)
|
||||
set name = "Toggle Nuke"
|
||||
set category = "Fun"
|
||||
set category = "Admin.Events"
|
||||
set popup_menu = 0
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
@@ -1016,7 +1057,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
usr << browse(dat, "window=dressup;size=550x600")
|
||||
|
||||
/client/proc/toggle_combo_hud()
|
||||
set category = "Admin"
|
||||
set category = "Admin.Game"
|
||||
set name = "Toggle Combo HUD"
|
||||
set desc = "Toggles the Admin Combo HUD (antag, sci, med, eng)"
|
||||
|
||||
@@ -1051,7 +1092,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
|
||||
|
||||
/client/proc/run_weather()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Events"
|
||||
set name = "Run Weather"
|
||||
set desc = "Triggers a weather on the z-level you choose."
|
||||
|
||||
@@ -1075,7 +1116,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Run Weather")
|
||||
|
||||
/client/proc/mass_zombie_infection()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Mass Zombie Infection"
|
||||
set desc = "Infects all humans with a latent organ that will zombify \
|
||||
them on death."
|
||||
@@ -1095,7 +1136,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Mass Zombie Infection")
|
||||
|
||||
/client/proc/mass_zombie_cure()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Mass Zombie Cure"
|
||||
set desc = "Removes the zombie infection from all humans, returning them to normal."
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -1113,7 +1154,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Mass Zombie Cure")
|
||||
|
||||
/client/proc/polymorph_all()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Polymorph All"
|
||||
set desc = "Applies the effects of the bolt of change to every single mob."
|
||||
|
||||
@@ -1203,7 +1244,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggled Hub Visibility", "[GLOB.hub_visibility ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_toggle_fov()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
set name = "Enable/Disable Field of Vision"
|
||||
|
||||
var/static/busy_toggling_fov = FALSE
|
||||
@@ -1256,7 +1297,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
|
||||
/client/proc/smite(mob/living/carbon/human/target as mob)
|
||||
set name = "Smite"
|
||||
set category = "Fun"
|
||||
set category = "Admin.Fun"
|
||||
if(!check_rights(R_ADMIN) || !check_rights(R_FUN))
|
||||
return
|
||||
|
||||
@@ -1306,7 +1347,8 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
new /obj/effect/immovablerod(startT, endT,target)
|
||||
if(ADMIN_PUNISHMENT_SUPPLYPOD_QUICK)
|
||||
var/target_path = input(usr,"Enter typepath of an atom you'd like to send with the pod (type \"empty\" to send an empty pod):" ,"Typepath","/obj/item/reagent_containers/food/snacks/grown/harebell") as null|text
|
||||
var/obj/structure/closet/supplypod/centcompod/pod = new()
|
||||
var/area/pod_storage_area = locate(/area/centcom/supplypod/podStorage) in GLOB.sortedAreas
|
||||
var/obj/structure/closet/supplypod/centcompod/pod = new(pick(get_area_turfs(pod_storage_area))) //Lets not runtime
|
||||
pod.damage = 40
|
||||
pod.explosionSize = list(0,0,0,2)
|
||||
pod.effectStun = TRUE
|
||||
@@ -1319,7 +1361,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
if(!delivery)
|
||||
alert("ERROR: Incorrect / improper path given.")
|
||||
new delivery(pod)
|
||||
new /obj/effect/abstract/DPtarget(get_turf(target), pod)
|
||||
new /obj/effect/pod_landingzone(get_turf(target), pod)
|
||||
if(ADMIN_PUNISHMENT_SUPPLYPOD)
|
||||
var/datum/centcom_podlauncher/plaunch = new(usr)
|
||||
if(!holder)
|
||||
@@ -1331,7 +1373,6 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
plaunch.temp_pod.damage = 40//bring the mother fuckin ruckus
|
||||
plaunch.temp_pod.explosionSize = list(0,0,0,2)
|
||||
plaunch.temp_pod.effectStun = TRUE
|
||||
plaunch.ui_interact(usr)
|
||||
return //We return here because punish_log() is handled by the centcom_podlauncher datum
|
||||
|
||||
if(ADMIN_PUNISHMENT_MAZING)
|
||||
|
||||
@@ -27,4 +27,4 @@
|
||||
if(!SSdbcore.Connect())
|
||||
message_admins("Database connection failed: " + SSdbcore.ErrorMsg())
|
||||
else
|
||||
message_admins("Database connection re-established")
|
||||
message_admins("Database connection re-established")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/datum/admins/proc/open_shuttlepanel()
|
||||
set category = "Admin"
|
||||
set category = "Admin.Events"
|
||||
set name = "Shuttle Manipulator"
|
||||
set desc = "Opens the shuttle manipulator UI."
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/client/proc/triple_ai()
|
||||
set category = "Fun"
|
||||
set category = "Admin.Events"
|
||||
set name = "Create AI Triumvirate"
|
||||
|
||||
if(SSticker.current_state > GAME_STATE_PREGAME)
|
||||
|
||||
@@ -93,4 +93,4 @@
|
||||
|
||||
return "[header][item]</li>"
|
||||
|
||||
#undef VV_HTML_ENCODE
|
||||
#undef VV_HTML_ENCODE
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
if (!thing)
|
||||
continue
|
||||
var/datum/D = thing
|
||||
if (D.vv_edit_var(variable, initial(D.vars[variable])) != FALSE)
|
||||
if (D.vv_edit_var(variable, initial(D.vars[variable]), TRUE) != FALSE)
|
||||
accepted++
|
||||
else
|
||||
rejected++
|
||||
@@ -135,7 +135,7 @@
|
||||
for(var/V in varsvars)
|
||||
new_value = replacetext(new_value,"\[[V]]","[D.vars[V]]")
|
||||
|
||||
if (D.vv_edit_var(variable, new_value) != FALSE)
|
||||
if (D.vv_edit_var(variable, new_value, TRUE) != FALSE)
|
||||
accepted++
|
||||
else
|
||||
rejected++
|
||||
@@ -161,7 +161,7 @@
|
||||
if(many && !new_value)
|
||||
new_value = new type()
|
||||
|
||||
if (D.vv_edit_var(variable, new_value) != FALSE)
|
||||
if (D.vv_edit_var(variable, new_value, TRUE) != FALSE)
|
||||
accepted++
|
||||
else
|
||||
rejected++
|
||||
@@ -176,7 +176,7 @@
|
||||
if (!thing)
|
||||
continue
|
||||
var/datum/D = thing
|
||||
if (D.vv_edit_var(variable, new_value) != FALSE)
|
||||
if (D.vv_edit_var(variable, new_value, TRUE) != FALSE)
|
||||
accepted++
|
||||
else
|
||||
rejected++
|
||||
|
||||
@@ -109,7 +109,7 @@ GLOBAL_LIST_EMPTY(deletion_failures)
|
||||
set name = "Find References"
|
||||
set src in world
|
||||
|
||||
find_references(FALSE)
|
||||
find_references_legacy(FALSE)
|
||||
|
||||
|
||||
/datum/proc/find_references_legacy(skip_alert)
|
||||
@@ -164,7 +164,7 @@ GLOBAL_LIST_EMPTY(deletion_failures)
|
||||
|
||||
qdel(src, TRUE) //force a qdel
|
||||
if(!running_find_references)
|
||||
find_references(TRUE)
|
||||
find_references_legacy(TRUE)
|
||||
|
||||
|
||||
/datum/verb/qdel_then_if_fail_find_references()
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
L.adjustFireLoss(amount)
|
||||
newamt = L.getFireLoss()
|
||||
if("toxin")
|
||||
L.adjustToxLoss(amount)
|
||||
L.adjustToxLoss(amount, toxins_type = TOX_OMNI, forced = TRUE)
|
||||
newamt = L.getToxLoss()
|
||||
if("oxygen")
|
||||
L.adjustOxyLoss(amount)
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
continue
|
||||
var/datum/team/T = A.get_team()
|
||||
if(!team_type || istype(T,team_type))
|
||||
. |= T
|
||||
. |= T
|
||||
|
||||
@@ -50,4 +50,4 @@
|
||||
/datum/mind/proc/leave_all_antag_huds()
|
||||
for(var/datum/atom_hud/antag/hud in GLOB.huds)
|
||||
if(hud.hudusers[current])
|
||||
hud.leave_hud(current)
|
||||
hud.leave_hud(current)
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_ROBELESS]'>Robeless</A><BR>"
|
||||
dat += "<I>Your apprentice is training to cast spells without their robes. They know Knock and Mindswap.</I><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_MARTIAL]'>Martial Artist</a><BR>"
|
||||
dat += "<I>Your apprentice is training in ancient martial arts. They know the Plasmafist and Nuclear Fist.</I><BR>"
|
||||
dat += "<I>Your apprentice is training in ancient martial arts. They know an Inner Mantra and the Nuclear Fist technique.</I><BR>"
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
return
|
||||
|
||||
@@ -2,22 +2,27 @@
|
||||
name = "experimental organ replacement"
|
||||
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/incise, /datum/surgery_step/extract_organ, /datum/surgery_step/gland_insert)
|
||||
possible_locs = list(BODY_ZONE_CHEST)
|
||||
ignore_clothes = 1
|
||||
ignore_clothes = TRUE
|
||||
|
||||
/datum/surgery/organ_extraction/can_start(mob/user, mob/living/carbon/target)
|
||||
if(!ishuman(user))
|
||||
return 0
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.dna.species.id == "abductor")
|
||||
return 1
|
||||
return TRUE
|
||||
for(var/obj/item/implant/abductor/A in H.implants)
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/surgery/organ_extraction/mechanic
|
||||
name = "Prosthesis experimental organ replacement"
|
||||
requires_bodypart_type = BODYPART_ROBOTIC
|
||||
steps = list(/datum/surgery_step/mechanic_open, /datum/surgery_step/open_hatch, /datum/surgery_step/mechanic_unwrench, /datum/surgery_step/prepare_electronics, /datum/surgery_step/extract_organ, /datum/surgery_step/gland_insert)
|
||||
|
||||
|
||||
/datum/surgery_step/extract_organ
|
||||
name = "remove heart"
|
||||
accept_hand = 1
|
||||
accept_hand = TRUE
|
||||
time = 32
|
||||
var/obj/item/organ/IC = null
|
||||
var/list/organ_types = list(/obj/item/organ/heart)
|
||||
@@ -34,10 +39,10 @@
|
||||
user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "<span class='notice'>You pull [IC] out of [target]'s [target_zone].</span>")
|
||||
user.put_in_hands(IC)
|
||||
IC.Remove()
|
||||
return 1
|
||||
return TRUE
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You don't find anything in [target]'s [target_zone]!</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/surgery_step/gland_insert
|
||||
name = "insert gland"
|
||||
@@ -52,4 +57,4 @@
|
||||
user.temporarilyRemoveItemFromInventory(tool, TRUE)
|
||||
var/obj/item/organ/heart/gland/gland = tool
|
||||
gland.Insert(target, 2)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
@@ -110,4 +110,4 @@
|
||||
active = 0
|
||||
|
||||
/obj/item/organ/heart/gland/proc/activate()
|
||||
return
|
||||
return
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
/obj/item/organ/heart/gland/access/Remove(special = FALSE)
|
||||
if(!QDELETED(owner))
|
||||
UnregisterSignal(owner, COMSIG_MOB_ALLOWED)
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -15,4 +15,4 @@
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/datum/species/species = H.dna.species
|
||||
to_chat(H, "<span class='warning'>You feel your blood heat up for a moment.</span>")
|
||||
species.exotic_blood = get_random_reagent_id()
|
||||
species.exotic_blood = get_random_reagent_id()
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
var/chem_to_add = pick(possible_reagents)
|
||||
owner.reagents.add_reagent(chem_to_add, 2)
|
||||
owner.adjustToxLoss(-5, TRUE, TRUE)
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
/obj/item/organ/heart/gland/egg/activate()
|
||||
owner.visible_message("<span class='alertalien'>[owner] [pick(EGG_LAYING_MESSAGES)]</span>")
|
||||
var/turf/T = owner.drop_location()
|
||||
new /obj/item/reagent_containers/food/snacks/egg/gland(T)
|
||||
new /obj/item/reagent_containers/food/snacks/egg/gland(T)
|
||||
|
||||
@@ -24,4 +24,4 @@
|
||||
|
||||
/obj/item/organ/heart/gland/electric/proc/zap()
|
||||
tesla_zap(owner, 4, 8000, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN)
|
||||
playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, TRUE)
|
||||
playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, TRUE)
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
if(!limb)
|
||||
replace_limb(zone)
|
||||
return
|
||||
if((limb.get_damage() >= (limb.max_damage / 2)) || (limb.status == BODYPART_ROBOTIC))
|
||||
if((limb.get_damage() >= (limb.max_damage / 2)) || limb.is_robotic_limb(FALSE))
|
||||
replace_limb(zone, limb)
|
||||
return
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/chest/chest = owner.get_bodypart(BODY_ZONE_CHEST)
|
||||
if((chest.get_damage() >= (chest.max_damage / 4)) || (chest.status == BODYPART_ROBOTIC))
|
||||
if((chest.get_damage() >= (chest.max_damage / 4)) || chest.is_robotic_limb(FALSE))
|
||||
replace_chest(chest)
|
||||
return
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
addtimer(CALLBACK(src, .proc/keep_replacing_blood), 30)
|
||||
|
||||
/obj/item/organ/heart/gland/heal/proc/replace_chest(obj/item/bodypart/chest/chest)
|
||||
if(chest.status == BODYPART_ROBOTIC)
|
||||
if(chest.is_robotic_limb(FALSE))
|
||||
owner.visible_message("<span class='warning'>[owner]'s [chest.name] rapidly expels its mechanical components, replacing them with flesh!</span>", "<span class='userdanger'>Your [chest.name] rapidly expels its mechanical components, replacing them with flesh!</span>")
|
||||
playsound(owner, 'sound/magic/clockwork/anima_fragment_attack.ogg', 50, TRUE)
|
||||
var/list/dirs = GLOB.alldirs.Copy()
|
||||
@@ -175,4 +175,4 @@
|
||||
|
||||
var/obj/item/bodypart/chest/new_chest = new(null)
|
||||
new_chest.replace_limb(owner, TRUE)
|
||||
qdel(chest)
|
||||
qdel(chest)
|
||||
|
||||
@@ -61,4 +61,4 @@
|
||||
to_chat(H, "<span class='userdanger'>You feel the compulsion fade, and you <i>completely forget</i> about your previous orders.</span>")
|
||||
H.clear_alert("mind_control")
|
||||
active_mind_control = FALSE
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
var/turf/open/T = get_turf(owner)
|
||||
if(istype(T))
|
||||
T.atmos_spawn_air("plasma=50;TEMP=[T20C]")
|
||||
owner.vomit()
|
||||
owner.vomit()
|
||||
|
||||
@@ -44,4 +44,4 @@
|
||||
if(active_mind_control)
|
||||
to_chat(entangled_mob, "<span class='userdanger'>You feel the compulsion fade, and you completely forget about your previous orders.</span>")
|
||||
entangled_mob.clear_alert("mind_control")
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -23,4 +23,4 @@
|
||||
|
||||
var/mob/living/simple_animal/slime/Slime = new(get_turf(owner), "grey")
|
||||
Slime.Friends = list(owner)
|
||||
Slime.Leader = owner
|
||||
Slime.Leader = owner
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
to_chat(owner, "<span class='warning'>You feel something crawling in your skin.</span>")
|
||||
owner.faction |= "spiders"
|
||||
var/obj/structure/spider/spiderling/S = new(owner.drop_location())
|
||||
S.directive = "Protect your nest inside [owner.real_name]."
|
||||
S.directive = "Protect your nest inside [owner.real_name]."
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
to_chat(owner, "<span class='notice'>You feel unlike yourself.</span>")
|
||||
randomize_human(owner)
|
||||
var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/insect, /datum/species/fly))
|
||||
owner.set_species(species)
|
||||
owner.set_species(species)
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
|
||||
/obj/item/organ/heart/gland/ventcrawling/activate()
|
||||
to_chat(owner, "<span class='notice'>You feel very stretchy.</span>")
|
||||
owner.ventcrawler = VENTCRAWLER_ALWAYS
|
||||
owner.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
|
||||
|
||||
@@ -31,4 +31,4 @@
|
||||
var/datum/symptom/S = new chosen_symptom
|
||||
A.symptoms += S
|
||||
A.Refresh() //just in case someone already made and named the same disease
|
||||
return A
|
||||
return A
|
||||
|
||||
@@ -69,6 +69,7 @@ GLOBAL_LIST_INIT(abductor_gear, subtypesof(/datum/abductor_gear))
|
||||
build_path = /obj/item/abductor_machine_beacon/chem_dispenser
|
||||
category = "Advanced Gear"
|
||||
|
||||
/*
|
||||
/datum/abductor_gear/shrink_ray
|
||||
name = "Shrink Ray Blaster"
|
||||
description = "This is a piece of frightening alien tech that enhances the magnetic pull of atoms in a localized space to temporarily make an object shrink. \
|
||||
@@ -77,3 +78,4 @@ GLOBAL_LIST_INIT(abductor_gear, subtypesof(/datum/abductor_gear))
|
||||
cost = 2
|
||||
build_path = /obj/item/gun/energy/shrink_ray
|
||||
category = "Advanced Gear"
|
||||
*/
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
/obj/structure/fluff/iced_abductor/Destroy()
|
||||
var/turf/T = get_turf(src)
|
||||
new /obj/effect/mob_spawn/human/abductor(T)
|
||||
. = ..()
|
||||
. = ..()
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
return
|
||||
flick("blob_resource_glow", src)
|
||||
if(overmind)
|
||||
overmind.add_points(1)
|
||||
overmind.add_points(2)
|
||||
resource_delay = world.time + 40 + overmind.resource_blobs.len * 2.5 //4 seconds plus a quarter second for each resource blob the overmind has
|
||||
else
|
||||
resource_delay = world.time + 40
|
||||
|
||||
@@ -45,8 +45,12 @@
|
||||
desc = "A solid wall of slightly twitching tendrils with a reflective glow."
|
||||
damaged_desc = "A wall of twitching tendrils with a reflective glow."
|
||||
icon_state = "blob_glow"
|
||||
flags_1 = DEFAULT_RICOCHET_1
|
||||
flags_ricochet = RICOCHET_SHINY
|
||||
point_return = 8
|
||||
max_integrity = 100
|
||||
brute_resist = 1
|
||||
explosion_block = 2
|
||||
|
||||
/obj/structure/blob/shield/reflective/check_projectile_ricochet(obj/item/projectile/P)
|
||||
return PROJECTILE_RICOCHET_FORCE
|
||||
|
||||
@@ -277,3 +277,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
|
||||
if(!B)
|
||||
mind.add_antag_datum(/datum/antagonist/blob)
|
||||
|
||||
//the same but it's forced to be allowed by default as cameras usually don't allow emoting
|
||||
/mob/camera/blob/emote(act, m_type=1, message = null, intentional = FALSE, forced = TRUE)
|
||||
. = ..()
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
set category = "Blob"
|
||||
set name = "Create Factory Blob (60)"
|
||||
set desc = "Create a spore tower that will spawn spores to harass your enemies."
|
||||
createSpecial(60, /obj/structure/blob/factory, 7, 1)
|
||||
createSpecial(60, /obj/structure/blob/factory, 5, 1)
|
||||
|
||||
/mob/camera/blob/verb/create_blobbernaut()
|
||||
set category = "Blob"
|
||||
@@ -195,6 +195,7 @@
|
||||
to_chat(blobber, "The <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> reagent [blobstrain.shortdesc ? "[blobstrain.shortdesc]" : "[blobstrain.description]"]")
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You could not conjure a sentience for your blobbernaut. Your points have been refunded. Try again later.</span>")
|
||||
B.naut = FALSE
|
||||
add_points(40)
|
||||
|
||||
/mob/camera/blob/verb/relocate_core()
|
||||
|
||||
@@ -81,4 +81,4 @@
|
||||
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/AssignRandomBane()
|
||||
return
|
||||
return
|
||||
|
||||
@@ -120,9 +120,14 @@
|
||||
if(bruteheal + fireheal + toxinheal > 0) // Just a check? Don't heal/spend, and return.
|
||||
if(mult == 0)
|
||||
return TRUE
|
||||
|
||||
// We have damage. Let's heal (one time)
|
||||
C.adjustBruteLoss(-bruteheal * mult, forced = TRUE)// Heal BRUTE / BURN in random portions throughout the body.
|
||||
C.adjustFireLoss(-fireheal * mult, forced = TRUE)
|
||||
var/list/damaged_parts = C.get_damaged_bodyparts(TRUE,TRUE, status = list(BODYPART_ORGANIC, BODYPART_HYBRID, BODYPART_NANITES))
|
||||
if(damaged_parts.len)
|
||||
for(var/obj/item/bodypart/part in damaged_parts) // Heal BRUTE / BURN equally distibuted over all damaged bodyparts.
|
||||
part.heal_damage((bruteheal * mult)/damaged_parts.len, (fireheal * mult)/damaged_parts.len, only_organic = FALSE, updating_health = FALSE)
|
||||
C.updatehealth()
|
||||
C.update_damage_overlays()
|
||||
C.adjustToxLoss(-toxinheal * mult * 2, forced = TRUE) //Toxin healing because vamps arent immune
|
||||
//C.heal_overall_damage(bruteheal * mult, fireheal * mult) // REMOVED: We need to FORCE this, because otherwise, vamps won't heal EVER. Swapped to above.
|
||||
AddBloodVolume((bruteheal * -0.5 + fireheal * -1 + toxinheal * -0.2) / mult * costMult) // Costs blood to heal
|
||||
@@ -276,7 +281,7 @@
|
||||
/datum/antagonist/bloodsucker/proc/FinalDeath()
|
||||
//Dont bother if we are already supposed to be dead
|
||||
if(FinalDeath)
|
||||
return
|
||||
return
|
||||
FinalDeath = TRUE //We are now supposed to die. Lets not spam it.
|
||||
if(!iscarbon(owner.current)) //Check for non carbons.
|
||||
owner.current.gib()
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
var/can_be_staked = FALSE // Only Feed can happen with a stake in you.
|
||||
var/cooldown_static = FALSE // Feed, Masquerade, and One-Shot powers don't improve their cooldown.
|
||||
//var/not_bloodsucker = FALSE // This goes to Vassals or Hunters, but NOT bloodsuckers.
|
||||
var/must_be_concious = TRUE //Can't use this ability while unconcious.
|
||||
|
||||
/datum/action/bloodsucker/New()
|
||||
if(bloodcost > 0)
|
||||
@@ -101,6 +102,11 @@
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Garlic in your blood is interfering with your powers!</span>")
|
||||
return FALSE
|
||||
if(must_be_concious)
|
||||
if(owner.stat != CONSCIOUS)
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>You can't do this while you are unconcious!</span>")
|
||||
return FALSE
|
||||
// Incap?
|
||||
if(must_be_capacitated)
|
||||
var/mob/living/L = owner
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
var/nightime_duration = 900 //15 Minutes
|
||||
|
||||
/obj/effect/sunlight/Initialize()
|
||||
countdown()
|
||||
hud_tick()
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/countdown)
|
||||
INVOKE_ASYNC(src, .proc/hud_tick)
|
||||
|
||||
/obj/effect/sunlight/proc/countdown()
|
||||
set waitfor = FALSE
|
||||
|
||||
@@ -113,4 +113,4 @@
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.open()
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
/datum/antagonist/vassal/greet()
|
||||
to_chat(owner, "<span class='userdanger'>You are now the mortal servant of [master.owner.current], a bloodsucking vampire!</span>")
|
||||
to_chat(owner, "<span class='boldannounce'>The power of [master.owner.current.p_their()] immortal blood compells you to obey [master.owner.current.p_them()] in all things, even offering your own life to prolong theirs.<br>\
|
||||
You are not required to obey any other Bloodsucker, for only [master.owner.current] is your master. The laws of Nanotransen do not apply to you now; only your vampiric master's word must be obeyed.<span>")
|
||||
You are not required to obey any other Bloodsucker, for only [master.owner.current] is your master. The laws of Nanotrasen do not apply to you now; only your vampiric master's word must be obeyed.<span>")
|
||||
// Effects...
|
||||
owner.current.playsound_local(null, 'sound/magic/mutate.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
//owner.store_memory("You became the mortal servant of [master.owner.current], a bloodsucking vampire!")
|
||||
|
||||
@@ -43,14 +43,13 @@
|
||||
// This exists so Hardened/Silver Stake can't have a welding torch used on them.
|
||||
|
||||
/obj/item/stake/basic/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weldingtool))
|
||||
if(W.tool_behaviour == TOOL_WELDER)
|
||||
//if (amWelded)
|
||||
// to_chat(user, "<span class='warning'>This stake has already been treated with fire.</span>")
|
||||
// return
|
||||
//amWelded = TRUE
|
||||
// Weld it
|
||||
var/obj/item/weldingtool/WT = W
|
||||
if(WT.use(0))//remove_fuel(0,user))
|
||||
if(W.use(0))//remove_fuel(0,user))
|
||||
user.visible_message("[user.name] scorched the pointy end of [src] with the welding tool.", \
|
||||
"<span class='notice'>You scorch the pointy end of [src] with the welding tool.</span>", \
|
||||
"<span class='italics'>You hear welding.</span>")
|
||||
|
||||
@@ -164,11 +164,11 @@
|
||||
if(istype(W, cutting_tool))
|
||||
to_chat(user, "<span class='notice'>This is a much more complex mechanical structure than you thought. You don't know where to begin cutting [src].</span>")
|
||||
return
|
||||
else if(anchored && istype(W, /obj/item/wrench)) // Can't unanchor unless owner.
|
||||
else if(anchored && W.tool_behaviour == TOOL_WRENCH) // Can't unanchor unless owner.
|
||||
to_chat(user, "<span class='danger'>The coffin won't come unanchored from the floor.</span>")
|
||||
return
|
||||
|
||||
if(locked && istype(W, /obj/item/crowbar))
|
||||
if(locked && W.tool_behaviour == TOOL_CROWBAR)
|
||||
var/pry_time = pryLidTimer * W.toolspeed // Pry speed must be affected by the speed of the tool.
|
||||
user.visible_message("<span class='notice'>[user] tries to pry the lid off of [src] with [W].</span>", \
|
||||
"<span class='notice'>You begin prying the lid off of [src] with [W]. This should take about [DisplayTimeText(pry_time)].</span>")
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
can_use_in_torpor = TRUE
|
||||
must_be_capacitated = TRUE
|
||||
can_be_immobilized = TRUE
|
||||
must_be_concious = FALSE
|
||||
|
||||
/datum/action/bloodsucker/gohome/CheckCanUse(display_error)
|
||||
. = ..()
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
warn_constant_cost = TRUE
|
||||
can_use_in_torpor = TRUE // Masquerade is maybe the only one that can do this. It stops your healing.
|
||||
cooldown_static = TRUE
|
||||
must_be_concious = FALSE
|
||||
|
||||
// NOTE: Firing off vulgar powers disables your Masquerade!
|
||||
|
||||
|
||||
@@ -149,8 +149,6 @@
|
||||
if(prob(50))
|
||||
if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len))
|
||||
add_objective(new/datum/objective/destroy, TRUE)
|
||||
else if(prob(30))
|
||||
add_objective(new/datum/objective/maroon, TRUE)
|
||||
else
|
||||
add_objective(new/datum/objective/assassinate, TRUE)
|
||||
else
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
var/list/stored_profiles = list() //list of datum/changelingprofile
|
||||
var/datum/changelingprofile/first_prof = null
|
||||
var/dna_max = 6 //How many extra DNA strands the changeling can store for transformation.
|
||||
var/absorbedcount = 0
|
||||
/// did we get succed by another changeling
|
||||
var/hostile_absorbed = FALSE
|
||||
@@ -38,8 +37,9 @@
|
||||
var/mimicing = ""
|
||||
var/canrespec = 0
|
||||
var/changeling_speak = 0
|
||||
var/loudfactor = 0 //Used for blood tests. At 4, blood tests will succeed. At 10, blood tests will result in an explosion.
|
||||
var/bloodtestwarnings = 0 //Used to track if the ling has been notified that they will pass blood tests.
|
||||
var/loudfactor = 0 //Used for blood tests. This is is the average loudness of the ling's abilities calculated with the below two vars
|
||||
var/loudtotal = 0 //Used to keep track of the sum of the ling's loudness
|
||||
var/totalpurchases = 0 //Used to keep track of how many purchases the ling's made after free abilities have been added
|
||||
var/datum/dna/chosen_dna
|
||||
var/obj/effect/proc_holder/changeling/sting/chosen_sting
|
||||
var/datum/cellular_emporium/cellular_emporium
|
||||
@@ -139,8 +139,6 @@
|
||||
/datum/antagonist/changeling/proc/reset_powers()
|
||||
if(purchasedpowers)
|
||||
remove_changeling_powers()
|
||||
loudfactor = 0
|
||||
bloodtestwarnings = 0
|
||||
//Repurchase free powers.
|
||||
for(var/path in all_powers)
|
||||
var/obj/effect/proc_holder/changeling/S = new path()
|
||||
@@ -148,6 +146,9 @@
|
||||
if(!has_sting(S))
|
||||
purchasedpowers += S
|
||||
S.on_purchase(owner.current,TRUE)
|
||||
loudfactor = 0
|
||||
loudtotal = 0
|
||||
totalpurchases = 0
|
||||
|
||||
/datum/antagonist/changeling/proc/has_sting(obj/effect/proc_holder/changeling/power)
|
||||
for(var/obj/effect/proc_holder/changeling/P in purchasedpowers)
|
||||
@@ -192,13 +193,18 @@
|
||||
geneticpoints -= thepower.dna_cost
|
||||
purchasedpowers += thepower
|
||||
thepower.on_purchase(owner.current)
|
||||
loudfactor += thepower.loudness
|
||||
if(loudfactor >= 4 && !bloodtestwarnings)
|
||||
to_chat(owner.current, "<span class='warning'>Our blood is growing flammable. Our blood will react violently to heat.</span>")
|
||||
bloodtestwarnings = 1
|
||||
if(loudfactor >= 10 && bloodtestwarnings < 2)
|
||||
to_chat(owner.current, "<span class='warning'>Our blood has grown extremely flammable. Our blood will react explosively to heat.</span>")
|
||||
bloodtestwarnings = 2
|
||||
loudtotal += thepower.loudness
|
||||
totalpurchases++
|
||||
var/oldloudness = loudfactor
|
||||
loudfactor = loudtotal/max(totalpurchases,1)
|
||||
if(loudfactor >= LINGBLOOD_DETECTION_THRESHOLD && oldloudness < LINGBLOOD_DETECTION_THRESHOLD)
|
||||
to_chat(owner.current, "<span class='warning'>Our blood has grown flammable. Our blood will now react violently to heat.</span>")
|
||||
else if(loudfactor < LINGBLOOD_DETECTION_THRESHOLD && oldloudness >= LINGBLOOD_DETECTION_THRESHOLD)
|
||||
to_chat(owner.current, "<span class='notice'>Our blood has stabilized, and will no longer react violently to heat.</span>")
|
||||
if(loudfactor > LINGBLOOD_EXPLOSION_THRESHOLD && oldloudness <= LINGBLOOD_EXPLOSION_THRESHOLD)
|
||||
to_chat(owner.current, "<span class='warning'>Our blood has grown extremely flammable. Our blood will now react explosively to heat.</span>")
|
||||
else if(loudfactor <= LINGBLOOD_EXPLOSION_THRESHOLD && oldloudness > LINGBLOOD_EXPLOSION_THRESHOLD)
|
||||
to_chat(owner.current, "<span class='notice'>Our blood has slightly stabilized, and will no longer explode when exposed to heat.</span>")
|
||||
|
||||
/datum/antagonist/changeling/proc/readapt()
|
||||
if(!ishuman(owner.current))
|
||||
@@ -207,7 +213,7 @@
|
||||
if(canrespec)
|
||||
to_chat(owner.current, "<span class='notice'>We have removed our evolutions from this form, and are now ready to readapt.</span>")
|
||||
reset_powers()
|
||||
playsound(get_turf(owner.current), 'sound/effects/lingreadapt.ogg', 75, TRUE, 5, soundenvwet = 0)
|
||||
playsound(get_turf(owner.current), 'sound/effects/lingreadapt.ogg', 75, TRUE, 5)
|
||||
canrespec = 0
|
||||
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, "Readapt")
|
||||
return 1
|
||||
@@ -245,12 +251,6 @@
|
||||
var/mob/living/carbon/user = owner.current
|
||||
if(!istype(user))
|
||||
return
|
||||
if(stored_profiles.len)
|
||||
var/datum/changelingprofile/prof = stored_profiles[1]
|
||||
if(prof.dna == user.dna && stored_profiles.len >= dna_max)//If our current DNA is the stalest, we gotta ditch it.
|
||||
if(verbose)
|
||||
to_chat(user, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
|
||||
return
|
||||
if(!target)
|
||||
return
|
||||
if(NO_DNA_COPY in target.dna.species.species_traits)
|
||||
@@ -310,9 +310,6 @@
|
||||
return prof
|
||||
|
||||
/datum/antagonist/changeling/proc/add_profile(datum/changelingprofile/prof)
|
||||
if(stored_profiles.len > dna_max)
|
||||
if(!push_out_profile())
|
||||
return
|
||||
|
||||
if(!first_prof)
|
||||
first_prof = prof
|
||||
@@ -333,19 +330,6 @@
|
||||
stored_profiles -= prof
|
||||
qdel(prof)
|
||||
|
||||
/datum/antagonist/changeling/proc/get_profile_to_remove()
|
||||
for(var/datum/changelingprofile/prof in stored_profiles)
|
||||
if(!prof.protected)
|
||||
return prof
|
||||
|
||||
/datum/antagonist/changeling/proc/push_out_profile()
|
||||
var/datum/changelingprofile/removeprofile = get_profile_to_remove()
|
||||
if(removeprofile)
|
||||
stored_profiles -= removeprofile
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/datum/antagonist/changeling/proc/create_initial_profile()
|
||||
var/mob/living/carbon/C = owner.current //only carbons have dna now, so we have to typecaste
|
||||
if(ishuman(C))
|
||||
@@ -449,30 +433,21 @@
|
||||
destroy_objective.find_target()
|
||||
objectives += destroy_objective
|
||||
else
|
||||
if(prob(70))
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
if(team_mode) //No backstabbing while in a team
|
||||
kill_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1)
|
||||
else
|
||||
kill_objective.find_target()
|
||||
objectives += kill_objective
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
if(team_mode) //No backstabbing while in a team
|
||||
kill_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1)
|
||||
else
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = owner
|
||||
if(team_mode)
|
||||
maroon_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1)
|
||||
else
|
||||
maroon_objective.find_target()
|
||||
objectives += maroon_objective
|
||||
kill_objective.find_target()
|
||||
objectives += kill_objective
|
||||
|
||||
if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible)
|
||||
var/datum/objective/escape/escape_with_identity/identity_theft = new
|
||||
identity_theft.owner = owner
|
||||
identity_theft.target = maroon_objective.target
|
||||
identity_theft.update_explanation_text()
|
||||
objectives += identity_theft
|
||||
escape_objective_possible = FALSE
|
||||
if(!(locate(/datum/objective/escape) in objectives) && escape_objective_possible && prob(50))
|
||||
var/datum/objective/escape/escape_with_identity/identity_theft = new
|
||||
identity_theft.owner = owner
|
||||
identity_theft.target = kill_objective.target
|
||||
identity_theft.update_explanation_text()
|
||||
objectives += identity_theft
|
||||
escape_objective_possible = FALSE
|
||||
|
||||
if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible)
|
||||
if(prob(50))
|
||||
|
||||
@@ -24,4 +24,4 @@
|
||||
/obj/effect/proc_holder/changeling/digitalcamo/on_refund(mob/user)
|
||||
action.Remove(user)
|
||||
user.digitalcamo = 0
|
||||
user.digitalinvis = 0
|
||||
user.digitalinvis = 0
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
if(user.stat != DEAD)
|
||||
user.emote("deathgasp")
|
||||
user.tod = STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)
|
||||
user.fakedeath("changeling") //play dead
|
||||
user.fakedeath("changeling", TRUE) //play dead
|
||||
user.update_stat()
|
||||
|
||||
addtimer(CALLBACK(src, .proc/ready_to_regenerate, user), LING_FAKEDEATH_TIME, TIMER_UNIQUE)
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
Shield
|
||||
Armor
|
||||
Tentacles
|
||||
Hatterhat Additions:
|
||||
claws! (glove slot)
|
||||
jagged (thieves') claws
|
||||
bone gauntlets for punching dudes
|
||||
*/
|
||||
|
||||
|
||||
@@ -17,6 +21,7 @@
|
||||
chemical_cost = 1000
|
||||
dna_cost = -1
|
||||
|
||||
var/recharge_slowdown = 0
|
||||
var/silent = FALSE
|
||||
var/weapon_type
|
||||
var/weapon_name_simple
|
||||
@@ -33,6 +38,8 @@
|
||||
if(!silent)
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms [user.p_their()] [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.chem_recharge_slowdown -= recharge_slowdown
|
||||
user.update_inv_hands()
|
||||
return 1
|
||||
|
||||
@@ -53,6 +60,8 @@
|
||||
user.put_in_hands(W)
|
||||
if(!silent)
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.chem_recharge_slowdown += recharge_slowdown
|
||||
return W
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/on_refund(mob/user)
|
||||
@@ -89,7 +98,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 [H.p_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.visible_message("<span class='warning'>[H] casts off [H.p_their()] [suit_name_simple]!</span>", "<span class='warning'>We cast off our [suit_name_simple].</span>", "<span class='italics'>You hear 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()
|
||||
@@ -137,10 +146,11 @@
|
||||
name = "Arm Blade"
|
||||
desc = "We reform one of our arms into a deadly blade."
|
||||
helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form. This ability is loud, and might cause our blood to react violently to heat."
|
||||
chemical_cost = 10
|
||||
chemical_cost = 5
|
||||
dna_cost = 2
|
||||
loudness = 2
|
||||
req_human = 1
|
||||
recharge_slowdown = 0.6
|
||||
weapon_type = /obj/item/melee/arm_blade
|
||||
weapon_name_simple = "blade"
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
@@ -461,7 +471,7 @@
|
||||
if(--remaining_uses < 1)
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
H.visible_message("<span class='warning'>With a sickening crunch, [H] reforms [H.p_their()] shield into an arm!</span>", "<span class='notice'>We assimilate our shield into our body</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
H.visible_message("<span class='warning'>With a sickening crunch, [H] reforms [H.p_their()] shield into an arm!</span>", "<span class='notice'>We assimilate our shield into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
qdel(src)
|
||||
|
||||
/***************************************\
|
||||
@@ -483,7 +493,7 @@
|
||||
helmet_type = /obj/item/clothing/head/helmet/space/changeling
|
||||
suit_name_simple = "flesh shell"
|
||||
helmet_name_simple = "space helmet"
|
||||
recharge_slowdown = 0.5
|
||||
recharge_slowdown = 0.6
|
||||
blood_on_castoff = 1
|
||||
|
||||
/obj/item/clothing/suit/space/changeling
|
||||
@@ -528,11 +538,11 @@
|
||||
name = "Chitinous Armor"
|
||||
desc = "We turn our skin into tough chitin to protect us from damage."
|
||||
helptext = "Upkeep of the armor requires a constant expenditure of chemicals, resulting in a reduced chemical generation. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form. This ability is loud, and might cause our blood to react violently to heat."
|
||||
chemical_cost = 20
|
||||
chemical_cost = 10
|
||||
dna_cost = 1
|
||||
loudness = 2
|
||||
req_human = 1
|
||||
recharge_slowdown = 0.5
|
||||
recharge_slowdown = 0.6
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_armor"
|
||||
action_background_icon_state = "bg_ling"
|
||||
@@ -570,3 +580,167 @@
|
||||
/obj/item/clothing/head/helmet/changeling/Initialize()
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
|
||||
|
||||
/***************************************\
|
||||
|*****************CLAWS*****************|
|
||||
\***************************************/
|
||||
|
||||
/obj/effect/proc_holder/changeling/gloves
|
||||
name = "Mangled Claws"
|
||||
desc = "Go tell a coder if you see this"
|
||||
helptext = "Yell at Hatterhat, for fucking up Miauw and/or Perakp's work"
|
||||
chemical_cost = 1000
|
||||
dna_cost = -1
|
||||
|
||||
var/glove_type = /obj/item
|
||||
var/glove_name_simple = " " // keep these plural bro
|
||||
var/recharge_slowdown = 0
|
||||
var/blood_on_castoff = 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/gloves/try_to_sting(mob/user, mob/target)
|
||||
if(check_gloves(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
..(H, target)
|
||||
|
||||
//checks if we already have claws and casts it off
|
||||
/obj/effect/proc_holder/changeling/gloves/proc/check_gloves(mob/user)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!ishuman(user) || !changeling)
|
||||
return 1
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.gloves, glove_type))
|
||||
H.visible_message("<span class='warning'>With a sickening crunch, [H] reforms [H.p_their()] [glove_name_simple] into hands!</span>", "<span class='warning'>We assimilate our [glove_name_simple].</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
H.temporarilyRemoveItemFromInventory(H.gloves, TRUE) //The qdel on dropped() takes care of it
|
||||
H.update_inv_gloves()
|
||||
playsound(H.loc, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
if(blood_on_castoff)
|
||||
H.add_splatter_floor()
|
||||
playsound(H.loc, 'sound/effects/splat.ogg', 50, 1) //So real sounds
|
||||
|
||||
changeling.chem_recharge_slowdown -= recharge_slowdown
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/gloves/on_refund(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
action.Remove(user)
|
||||
var/mob/living/carbon/human/H = user
|
||||
check_gloves(H)
|
||||
|
||||
/obj/effect/proc_holder/changeling/gloves/sting_action(mob/living/carbon/human/user)
|
||||
if(!user.canUnEquip(user.gloves))
|
||||
to_chat(user, "\the [user.gloves] is stuck to your body, you cannot grow [glove_name_simple] over it!")
|
||||
return
|
||||
|
||||
user.dropItemToGround(user.gloves)
|
||||
|
||||
user.equip_to_slot_if_possible(new glove_type(user), SLOT_GLOVES, 1, 1, 1)
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.chem_recharge_slowdown += recharge_slowdown
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/gloves/claws
|
||||
name = "claws of doing nothing"
|
||||
desc = "These shouldn't be here."
|
||||
icon_state = "bracers"
|
||||
item_state = "bracers"
|
||||
transfer_prints = TRUE
|
||||
body_parts_covered = HANDS
|
||||
cold_protection = HANDS
|
||||
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
|
||||
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
|
||||
armor = list("melee" = 20, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 35, "bio" = 35, "rad" = 35, "fire" = 0, "acid" = 0)
|
||||
|
||||
/obj/item/clothing/gloves/claws/Initialize()
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
/obj/item/clothing/gloves/claws/vulture // prying shit off dead/soon to be dead dudes!
|
||||
name = "jagged claws"
|
||||
desc = "Good for prying things off of people and looking incredibly creepy."
|
||||
strip_mod = 2
|
||||
|
||||
/obj/effect/proc_holder/changeling/gloves/gauntlets
|
||||
name = "Bone Gauntlets"
|
||||
desc = "We turn our hands into solid bone and chitin, sacrificing dexterity for raw strength."
|
||||
helptext = "These grotesque, bone-and-chitin gauntlets are remarkably good at beating victims senseless, and cannot be used in lesser form. This ability is loud, and might cause our blood to react violently to heat."
|
||||
chemical_cost = 5 // same cost as armblade because its a sidegrade (sacrifice utility for punching people violently)
|
||||
dna_cost = 2
|
||||
loudness = 2
|
||||
req_human = 1
|
||||
recharge_slowdown = 0.6
|
||||
action_icon = 'icons/mob/actions/actions_changeling.dmi'
|
||||
action_icon_state = "ling_gauntlets"
|
||||
action_background_icon_state = "bg_ling"
|
||||
|
||||
glove_type = /obj/item/clothing/gloves/fingerless/pugilist/cling // just punch his head off dude
|
||||
glove_name_simple = "bone gauntlets"
|
||||
|
||||
/obj/item/clothing/gloves/fingerless/pugilist/cling // switches between lesser GotNS and Big Punchy Rib Breaky Hands
|
||||
name = "hewn bone gauntlets"
|
||||
icon_state = "ling_gauntlets"
|
||||
item_state = "ling_gauntlets"
|
||||
desc = "Rough bone and chitin, pulsing with an abomination barely called \"life\". Good for punching people, not so much for firearms."
|
||||
transfer_prints = TRUE
|
||||
item_flags = DROPDEL // whoops
|
||||
body_parts_covered = ARMS|HANDS
|
||||
cold_protection = ARMS|HANDS
|
||||
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
|
||||
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
|
||||
armor = list("melee" = 20, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 35, "bio" = 35, "rad" = 35, "fire" = 0, "acid" = 0)
|
||||
enhancement = 6 // first, do harm. all of it. all of the harm. just fuck em up.
|
||||
wound_enhancement = 6
|
||||
var/fast_enhancement = 6
|
||||
var/fast_wound_enhancement = 6
|
||||
var/slow_enhancement = 12
|
||||
var/slow_wound_enhancement = 15
|
||||
silent = TRUE
|
||||
inherited_trait = TRAIT_CHUNKYFINGERS // how do you expect to shoot anyone with bone covered hands
|
||||
secondary_trait = TRAIT_MAULER // just punch them idiot
|
||||
var/fasthands = TRUE
|
||||
|
||||
/obj/item/clothing/gloves/fingerless/pugilist/cling/examine(mob/user)
|
||||
. = ..()
|
||||
. += "[src] are shaped for [fasthands ? "fast, precise strikes" : "crippling, damaging blows"]."
|
||||
. += "Alt-click them to change between rapid strikes and strong blows."
|
||||
|
||||
/obj/item/clothing/gloves/fingerless/pugilist/cling/AltClick(mob/user)
|
||||
. = ..()
|
||||
use_buffs(user, FALSE) // reset
|
||||
fasthands = !fasthands
|
||||
if(fasthands)
|
||||
enhancement = fast_enhancement
|
||||
wound_enhancement = fast_wound_enhancement
|
||||
else
|
||||
enhancement = slow_enhancement // fuck em up kiddo
|
||||
wound_enhancement = slow_wound_enhancement // really. fuck em up.
|
||||
to_chat(user, "<span class='notice'>[src] are now formed to allow for [fasthands ? "fast, precise strikes" : "crippling, damaging blows"].</span>")
|
||||
addtimer(CALLBACK(src, .proc/use_buffs, user, TRUE), 0.1) // go fuckin get em
|
||||
|
||||
/obj/item/clothing/gloves/fingerless/pugilist/cling/Initialize()
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
/obj/item/clothing/gloves/fingerless/pugilist/cling/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(current_equipped_slot == SLOT_GLOVES)
|
||||
to_chat(user, "<span class='notice'>With [src] formed around our arms, we are ready to fight.</span>")
|
||||
|
||||
/obj/item/clothing/gloves/fingerless/pugilist/cling/dropped(mob/user)
|
||||
. = ..()
|
||||
if(wornonce)
|
||||
to_chat(user, "<span class='warning'>With [src] assimilated, we feel less ready to punch things.</span>")
|
||||
|
||||
/obj/item/clothing/gloves/fingerless/pugilist/cling/Touch(atom/target, proximity = TRUE)
|
||||
if(!isliving(target))
|
||||
return
|
||||
var/mob/living/M = loc
|
||||
if(fasthands)
|
||||
M.SetNextAction(CLICK_CD_RANGE) // fast punches
|
||||
else
|
||||
M.SetNextAction(CLICK_CD_GRABBING) // strong punches
|
||||
return NO_AUTO_CLICKDELAY_HANDLING | ATTACK_IGNORE_ACTION
|
||||
|
||||
@@ -57,4 +57,4 @@
|
||||
|
||||
/obj/screen/alert/status_effect/agent_pinpointer/changeling
|
||||
name = "Pheromone Scent"
|
||||
desc = "The nose always knows."
|
||||
desc = "The nose always knows."
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
for(var/obj/machinery/light/L in range(4, user))
|
||||
L.on = 1
|
||||
L.break_light_tube()
|
||||
playsound(get_turf(user), 'sound/effects/lingscreech.ogg', 75, TRUE, 5, soundenvwet = 0)
|
||||
playsound(get_turf(user), 'sound/effects/lingscreech.ogg', 75, TRUE, 5)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/dissonant_shriek
|
||||
@@ -49,5 +49,5 @@
|
||||
L.on = 1
|
||||
L.break_light_tube()
|
||||
empulse_using_range(get_turf(user), 8, TRUE)
|
||||
playsound(get_turf(user), 'sound/effects/lingempscreech.ogg', 75, TRUE, 5, soundenvwet = 0)
|
||||
playsound(get_turf(user), 'sound/effects/lingempscreech.ogg', 75, TRUE, 5)
|
||||
return TRUE
|
||||
|
||||
@@ -22,4 +22,4 @@
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
. = ..()
|
||||
desc = initial(desc)
|
||||
desc = initial(desc)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.z == z)
|
||||
if(get_dist(src, M) >= 7)
|
||||
M.playsound_local(src, 'sound/magic/blink.ogg', 10, FALSE, falloff = 10)
|
||||
M.playsound_local(src, 'sound/magic/blink.ogg', 10, FALSE)
|
||||
else
|
||||
M.playsound_local(src, 'sound/magic/blink.ogg', 50, FALSE)
|
||||
|
||||
|
||||
@@ -48,4 +48,4 @@
|
||||
plane = FLOOR_PLANE
|
||||
|
||||
/obj/effect/clockwork/overlay/floor/bloodcult //this is used by BLOOD CULT, it shouldn't use such a path...
|
||||
icon_state = "cult"
|
||||
icon_state = "cult"
|
||||
|
||||
@@ -216,6 +216,14 @@
|
||||
else if(get_clockwork_power())
|
||||
to_chat(L, "<span class='brass'>You feel a slight, static shock.</span>")
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/process()
|
||||
var/power_drained = 0
|
||||
var/power_mod = 0.005
|
||||
@@ -340,9 +348,9 @@
|
||||
L.dust()
|
||||
else if(L.health > min_drain_health)
|
||||
if(!GLOB.ratvar_awakens && L.stat == CONSCIOUS)
|
||||
vitality_drained = L.adjustToxLoss(1, forced = TRUE)
|
||||
vitality_drained = L.adjustToxLoss(1, forced = TRUE, toxins_type = TOX_OMNI)
|
||||
else
|
||||
vitality_drained = L.adjustToxLoss(1.5, forced = TRUE)
|
||||
vitality_drained = L.adjustToxLoss(1.5, forced = TRUE, toxins_type = TOX_OMNI)
|
||||
if(vitality_drained)
|
||||
GLOB.clockwork_vitality += vitality_drained
|
||||
else
|
||||
@@ -408,7 +416,7 @@
|
||||
|
||||
/obj/effect/clockwork/sigil/rite
|
||||
name = "radiant sigil"
|
||||
desc = "A glowing sigil glowing with barely-contained power."
|
||||
desc = "A sigil glowing with barely-contained power."
|
||||
clockwork_desc = "A sigil that will allow you to perform certain rites on it, provided you have access to sufficient power and materials."
|
||||
icon_state = "sigiltransmission" //am big lazy - recolored transmission sigil
|
||||
sigil_name = "Sigil of Rites"
|
||||
@@ -432,7 +440,8 @@
|
||||
return
|
||||
var/list/possible_rites = list()
|
||||
for(var/datum/clockwork_rite/R in GLOB.all_clockwork_rites)
|
||||
possible_rites[R] = R
|
||||
if(is_servant_of_ratvar(user, require_full_power = TRUE) || !R.requires_full_power)
|
||||
possible_rites[R] = R
|
||||
var/input_key = input(user, "Choose a rite", "Choosing a rite") as null|anything in possible_rites
|
||||
if(!input_key)
|
||||
return
|
||||
|
||||
@@ -287,4 +287,4 @@
|
||||
linked_gateway.visible_message("<span class='warning'>[linked_gateway] begins to destabilise!</span>")
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/stable/pass_through_gateway(atom/movable/A, no_cost = TRUE)
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -1,41 +1,57 @@
|
||||
//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
/atom/movable/proc/power_drain(clockcult_user, drain_weapons = FALSE) //This proc as of now is only in use for void volt
|
||||
/*
|
||||
horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
args:
|
||||
clockcult_user: If the user / source has to do with clockcult stuff
|
||||
drain_weapons: If this drains weaponry, such as batons and guns
|
||||
recursive: If this recurses through mob / storage contents. ONLY USE THIS IF IT'S NOT CALLED TOO FREQUENTLY, or I'm not liable for any lag / functional issues caused
|
||||
drain_amount: How much is drained by default; Influenced by a multiplier on most things depending on how much power they usually hold.
|
||||
*/
|
||||
/atom/movable/proc/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER) //This proc as of now is only in use for void volt and transmission sigils
|
||||
if(recursive)
|
||||
var/succ = 0
|
||||
for(var/V in contents)
|
||||
var/atom/movable/target = V
|
||||
succ += target.power_drain(clockcult_user, drain_weapons, recursive, drain_amount)
|
||||
return succ
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(cell)
|
||||
return cell.power_drain(clockcult_user)
|
||||
return cell.power_drain(clockcult_user, drain_weapons, recursive, drain_amount)
|
||||
return 0 //Returns 0 instead of FALSE to symbolise it returning the power amount in other cases, not TRUE aka 1
|
||||
|
||||
/obj/item/melee/baton/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
/obj/item/melee/baton/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
return ..()
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(cell)
|
||||
return cell.power_drain(clockcult_user, drain_weapons, recursive, drain_amount)
|
||||
return 0 //No need to recurse further in batons
|
||||
|
||||
/obj/item/gun/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
/obj/item/gun/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(!cell)
|
||||
return 0
|
||||
if(cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4) //Done snowflakey because guns have far smaller cells than batons / other equipment
|
||||
. = min(cell.charge, drain_amount*4) //Done snowflakey because guns have far smaller cells than batons / other equipment, also no need to recurse further in guns
|
||||
cell.use(.)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if(cell && cell.charge)
|
||||
playsound(src, "sparks", 50, 1)
|
||||
flick("apc-spark", src)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.) //Better than a power sink!
|
||||
. = min(cell.charge, drain_amount*4)
|
||||
cell.use(min(cell.charge, . * 4)) //Better than a power sink!
|
||||
if(!cell.charge && !shorted)
|
||||
shorted = 1
|
||||
visible_message("<span class='warning'>The [name]'s screen blurs with static.</span>")
|
||||
update()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*4)
|
||||
. = min(charge, drain_amount*4)
|
||||
charge -= . * 50
|
||||
if(!charge && !panel_open)
|
||||
panel_open = TRUE
|
||||
@@ -44,20 +60,26 @@
|
||||
visible_message("<span class='warning'>[src]'s panel flies open with a flurry of sparks!</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER * 4) //Done like this because normal cells are usually quite a bit bigger than the ones used in guns / APCs
|
||||
. = min(charge, drain_amount * 4) //Done like this because normal cells are usually quite a bit bigger than the ones used in guns / APCs
|
||||
use(min(charge, . * 10)) //Usually cell-powered equipment that is not a gun has at least ten times the capacity of a gun / 5 times the amount of an APC. This adjusts the drain to account for that.
|
||||
update_icon()
|
||||
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
. = min(cell.charge, drain_amount*8) //Silicons are very susceptible to Ratvar's might
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
|
||||
/obj/mecha/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if((!clockcult_user || (occupant && !is_servant_of_ratvar(occupant))) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
/obj/mecha/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if(!clockcult_user || (occupant && !is_servant_of_ratvar(occupant)))
|
||||
if(recursive)
|
||||
var/succ = 0
|
||||
for(var/atom/movable/target in contents) //Hiding in your mech won't save you.
|
||||
succ += target.power_drain(clockcult_user, drain_weapons, recursive, drain_amount)
|
||||
. = succ
|
||||
else if(cell && cell.charge)
|
||||
. = min(cell.charge, drain_amount*4)
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
//The base clockwork rite. This should never be visible
|
||||
/datum/clockwork_rite
|
||||
var/name = "Rite of THE frog" //The name of the rite
|
||||
var/desc = "This rite is used to summon the legendary frog whose-name-shall-not-be-spoken, ender of many worlds." //What does this rite do? Shown to cultists if they choose 'Show Info' after selecting the rite.
|
||||
var/desc = "This rite is used to summon the legendary frog whose-name-shall-not-be-spoken, ender of many worlds." //What does this rite do? Shown to servants if they choose 'Show Info' after selecting the rite.
|
||||
var/list/required_ingredients = list(/obj/item/clockwork) //What does this rite require?
|
||||
var/power_cost = 0 //How much power does this rite cost.. or does it even add power?
|
||||
var/requires_human = FALSE //Does the rite require a ../carbon/human on the rune?
|
||||
var/requires_human = FALSE //Does the rite require a ../carbon/human on the sigil?
|
||||
var/must_be_servant = TRUE //If the above is true, does the human need to be a servant?
|
||||
var/target_can_be_invoker = TRUE //Does this rite work if the invoker is also the target?
|
||||
var/requires_full_power = FALSE //Does the invoker need to be an actual full-on servant, or is this available to neutered ones aswell?
|
||||
var/cast_time = 0 //How long does the rite take to cast?
|
||||
var/limit = INFINITE //How often can this rite be used per round? Set this to INFINITE for unlimited, 0 for disallowed, anything above 0 for a limit
|
||||
var/times_used = 0 //How often has the rite already been used this shift?
|
||||
@@ -164,14 +165,16 @@
|
||||
/datum/clockwork_rite/treat_wounds/cast(var/mob/living/invoker, var/turf/T, var/mob/living/carbon/human/target)
|
||||
if(!target)
|
||||
return FALSE
|
||||
if(!target.all_wounds.len)
|
||||
if(!target.all_wounds || !target.all_wounds.len)
|
||||
to_chat(invoker, "<span class='inathneq_small'>This one does not require mending.</span>")
|
||||
return FALSE
|
||||
.= ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
target.adjustToxLoss(10 * target.all_wounds.len)
|
||||
QDEL_LIST(target.all_wounds)
|
||||
for(var/i in target.all_wounds)
|
||||
var/datum/wound/mended = i
|
||||
mended.remove_wound()
|
||||
to_chat(target, "<span class='warning'>You feel your wounds heal, but are overcome with deep nausea.</span>")
|
||||
new /obj/effect/temp_visual/ratvar/sigil/vitality(T)
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
if(totaldamage)
|
||||
L.heal_overall_damage(brutedamage, burndamage, only_organic = FALSE) //Maybe a machine god shouldn't murder augmented followers instead of healing them
|
||||
L.adjustOxyLoss(-oxydamage)
|
||||
L.adjustToxLoss(totaldamage * 0.5, TRUE, TRUE)
|
||||
L.adjustToxLoss(totaldamage * 0.5, TRUE, TRUE, toxins_type = TOX_OMNI)
|
||||
clockwork_say(ranged_ability_user, text2ratvar("[has_holy_water ? "Heal tainted" : "Mend wounded"] flesh!"))
|
||||
log_combat(ranged_ability_user, L, "healed with Sentinel's Compromise")
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], [has_holy_water ? "causing [L.p_them()] to briefly glow as it mends" : " mending"] [L.p_their()] bruises and burns!</span>", \
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
. = ..()
|
||||
desc = initial(desc)
|
||||
|
||||
obj/item/shield/riot/ratvarian/proc/calc_bash_mult()
|
||||
/obj/item/shield/riot/ratvarian/proc/calc_bash_mult()
|
||||
var/bash_mult = 0
|
||||
if(!dam_absorbed)
|
||||
return 1
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/ratvar_act()
|
||||
/obj/item/clockwork/slab/cyborg/ui_act()
|
||||
..()
|
||||
if(!GLOB.ratvar_awakens)
|
||||
SStgui.close_uis(src)
|
||||
@@ -203,10 +203,10 @@
|
||||
to_chat(user, "<span class='warning'>You need to hold the slab in your active hand to recite scripture!</span>")
|
||||
return FALSE
|
||||
var/initial_tier = initial(scripture.tier)
|
||||
if(initial_tier == SCRIPTURE_PERIPHERAL)
|
||||
if(initial_tier == SCRIPTURE_PERIPHERAL && !issilicon(user)) //Silicons use peripheral scripture & cannot open the slab.
|
||||
to_chat(user, "<span class='warning'>Nice try using href exploits</span>")
|
||||
return
|
||||
if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier])
|
||||
if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier] &&!issilicon(user)) //silicons can't choose their spells, so lets allow them to always cast their assigned ones.
|
||||
to_chat(user, "<span class='warning'>That scripture is not unlocked, and cannot be recited!</span>")
|
||||
return FALSE
|
||||
var/datum/clockwork_scripture/scripture_to_recite = new scripture
|
||||
|
||||
@@ -167,7 +167,7 @@ Judgement 5 converts
|
||||
set waitfor = FALSE
|
||||
chanting = TRUE
|
||||
for(var/invocation in invocations)
|
||||
sleep(channel_time / invocations.len)
|
||||
sleep(channel_time / (invocations.len + 1)) //So it always finishes the invocation
|
||||
if(QDELETED(src) || QDELETED(slab) || !chanting)
|
||||
return
|
||||
if(multiple_invokers_used)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
descname = "Powers Nearby Structures"
|
||||
name = "Sigil of Transmission"
|
||||
desc = "Places a sigil that can drain and will store energy to power clockwork structures."
|
||||
invocations = list("Divinity...", "...power our creations!")
|
||||
invocations = list("Divinity...", "...power our creations.")
|
||||
channel_time = 70
|
||||
power_cost = 200
|
||||
whispered = TRUE
|
||||
@@ -28,7 +28,7 @@
|
||||
descname = "Powered Structure, Delay Emergency Shuttles"
|
||||
name = "Prolonging Prism"
|
||||
desc = "Creates a mechanized prism which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost."
|
||||
invocations = list("May this prism...", "...grant us time to enact his will!")
|
||||
invocations = list("May this prism...", "...grant us time to enact his will.")
|
||||
channel_time = 80
|
||||
power_cost = 300
|
||||
object_path = /obj/structure/destructible/clockwork/powered/prolonging_prism
|
||||
@@ -60,7 +60,7 @@
|
||||
descname = "Powered Structure, Area Denial"
|
||||
name = "Mania Motor"
|
||||
desc = "Creates a mania motor which causes minor damage and a variety of negative mental effects in nearby non-Servant humans, potentially up to and including conversion."
|
||||
invocations = list("May this transmitter...", "...break the will of all who oppose us!")
|
||||
invocations = list("May this transmitter...", "...break the will of all who oppose us.")
|
||||
channel_time = 80
|
||||
power_cost = 750
|
||||
object_path = /obj/structure/destructible/clockwork/powered/mania_motor
|
||||
@@ -83,7 +83,7 @@
|
||||
descname = "Powered Structure, Teleportation Hub"
|
||||
name = "Clockwork Obelisk"
|
||||
desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living Servant or clockwork obelisk."
|
||||
invocations = list("May this obelisk...", "...take us to all places!")
|
||||
invocations = list("May this obelisk...", "...take us to all places.")
|
||||
channel_time = 80
|
||||
power_cost = 300
|
||||
object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk
|
||||
@@ -163,7 +163,7 @@
|
||||
descname = "Well-Rounded Combat Construct"
|
||||
name = "Clockwork Marauder"
|
||||
desc = "Creates a shell for a clockwork marauder, a balanced frontline construct that can deflect projectiles with its shield."
|
||||
invocations = list("Arise, avatar of Arbiter!", "Defend the Ark with vengeful zeal.")
|
||||
invocations = list("Arise, avatar of Arbiter!", "Defend the Ark with vengeful zeal!")
|
||||
channel_time = 80
|
||||
power_cost = 8000
|
||||
creator_message = "<span class='brass'>Your slab disgorges several chunks of replicant alloy that form into a suit of thrumming armor.</span>"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
descname = "Generates Power From Starlight"
|
||||
name = "Stargazer"
|
||||
desc = "Forms a weak structure that generates power every second while within three tiles of starlight."
|
||||
invocations = list("Capture their inferior light for us!")
|
||||
invocations = list("Capture their inferior light for us.")
|
||||
channel_time = 50
|
||||
power_cost = 200
|
||||
object_path = /obj/structure/destructible/clockwork/stargazer
|
||||
@@ -16,6 +16,7 @@
|
||||
usage_tip = "For obvious reasons, make sure to place this near a window or somewhere else that can see space!"
|
||||
tier = SCRIPTURE_DRIVER
|
||||
one_per_tile = TRUE
|
||||
whispered = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
@@ -34,7 +35,7 @@
|
||||
descname = "Power Generation"
|
||||
name = "Integration Cog"
|
||||
desc = "Fabricates an integration cog, which can be used on an open APC to replace its innards and passively siphon its power."
|
||||
invocations = list("Take that which sustains them!")
|
||||
invocations = list("Take that which sustains them.")
|
||||
channel_time = 10
|
||||
power_cost = 10
|
||||
whispered = TRUE
|
||||
@@ -55,7 +56,7 @@
|
||||
descname = "Trap, Stunning"
|
||||
name = "Sigil of Transgression"
|
||||
desc = "Wards a tile with a sigil, which will briefly stun the next non-Servant to cross it and apply Belligerent to them."
|
||||
invocations = list("Divinity, smite...", "...those who trespass here!")
|
||||
invocations = list("Divinity, smite...", "...those who trespass here.")
|
||||
channel_time = 50
|
||||
power_cost = 50
|
||||
whispered = TRUE
|
||||
@@ -75,7 +76,7 @@
|
||||
descname = "Trap, Conversion"
|
||||
name = "Sigil of Submission"
|
||||
desc = "Places a luminous sigil that will convert any non-Servants that remain on it for 8 seconds."
|
||||
invocations = list("Divinity, enlighten...", "...those who trespass here!")
|
||||
invocations = list("Divinity, enlighten...", "...those who trespass here.")
|
||||
channel_time = 60
|
||||
power_cost = 125
|
||||
whispered = TRUE
|
||||
@@ -95,7 +96,7 @@
|
||||
descname = "Short-Range Single-Target Stun"
|
||||
name = "Kindle"
|
||||
desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light."
|
||||
invocations = list("Divinity, show them your light!")
|
||||
invocations = list("Divinity, show them your light.")
|
||||
whispered = TRUE
|
||||
channel_time = 25 //2.5 seconds should be a okay compromise between being able to use it when needed, and not being able to just pause in combat for a second and hardstunning your enemy
|
||||
power_cost = 125
|
||||
@@ -118,7 +119,7 @@
|
||||
descname = "Handcuffs"
|
||||
name = "Hateful Manacles"
|
||||
desc = "Forms replicant manacles around a target's wrists that function like handcuffs."
|
||||
invocations = list("Shackle the heretic!", "Break them in body and spirit!")
|
||||
invocations = list("Shackle the heretic!", "Break them in body and spirit.")
|
||||
channel_time = 15
|
||||
power_cost = 25
|
||||
whispered = TRUE
|
||||
@@ -269,7 +270,7 @@
|
||||
descname = "New Clockwork Slab"
|
||||
name = "Replicant"
|
||||
desc = "Creates a new clockwork slab."
|
||||
invocations = list("Metal, become greater!")
|
||||
invocations = list("Metal, become greater.")
|
||||
channel_time = 10
|
||||
power_cost = 25
|
||||
whispered = TRUE
|
||||
@@ -290,7 +291,7 @@
|
||||
descname = "Limited Xray Vision Glasses"
|
||||
name = "Wraith Spectacles"
|
||||
desc = "Fabricates a pair of glasses which grant true sight but cause gradual vision loss."
|
||||
invocations = list("Show the truth of this world to me!")
|
||||
invocations = list("Show the truth of this world to me.")
|
||||
channel_time = 10
|
||||
power_cost = 50
|
||||
whispered = TRUE
|
||||
@@ -310,7 +311,7 @@
|
||||
name = "Spatial Gateway"
|
||||
desc = "Tears open a miniaturized gateway in spacetime to any conscious servant that can transport objects or creatures to its destination. \
|
||||
Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration."
|
||||
invocations = list("Spatial Gateway...", "...activate!")
|
||||
invocations = list("Spatial Gateway...", "...activate.")
|
||||
channel_time = 30
|
||||
power_cost = 400
|
||||
whispered = TRUE
|
||||
@@ -349,4 +350,4 @@
|
||||
if(GLOB.ratvar_awakens)
|
||||
portal_uses = max(portal_uses, 100) //Very powerful if Ratvar has been summoned
|
||||
duration = max(duration, 100)
|
||||
return slab.procure_gateway(invoker, duration, portal_uses)
|
||||
return slab.procure_gateway(invoker, duration, portal_uses)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
descname = "Structure, Turret"
|
||||
name = "Ocular Warden"
|
||||
desc = "Forms an automatic short-range turret which will automatically attack nearby unrestrained non-Servants that can see it."
|
||||
invocations = list("Guardians of Engine...", "...judge those who would harm us!")
|
||||
invocations = list("Guardians of Engine...", "...judge those who would harm us.")
|
||||
channel_time = 100
|
||||
power_cost = 250
|
||||
object_path = /obj/structure/destructible/clockwork/ocular_warden
|
||||
@@ -105,7 +105,7 @@
|
||||
descname = "Delayed Area Knockdown Glasses"
|
||||
name = "Judicial Visor"
|
||||
desc = "Creates a visor that can smite an area, applying Belligerent and briefly stunning. The smote area will explode after 3 seconds."
|
||||
invocations = list("Grant me the flames of Engine!")
|
||||
invocations = list("Grant me the flames of Engine.")
|
||||
channel_time = 10
|
||||
power_cost = 400
|
||||
whispered = TRUE
|
||||
@@ -124,7 +124,7 @@
|
||||
descname = "Shield with empowerable bashes"
|
||||
name = "Nezbere's shield"
|
||||
desc = "Creates a shield which generates charge from blocking damage, using it to empower its bashes tremendously. It is repaired with brass, and while very durable, extremely weak to lasers and, even more so, to energy weaponry."
|
||||
invocations = list("Shield me...", "... from the coming dark!")
|
||||
invocations = list("Shield me...", "... from the coming dark.")
|
||||
channel_time = 20
|
||||
power_cost = 600 //Shouldn't be too spammable but not too hard to get either
|
||||
whispered = TRUE
|
||||
@@ -143,7 +143,7 @@
|
||||
descname = "Summonable Armor and Weapons"
|
||||
name = "Clockwork Armaments"
|
||||
desc = "Allows the invoker to summon clockwork armor and a Ratvarian spear at will. The spear's attacks will generate Vitality, used for healing."
|
||||
invocations = list("Grant me armaments...", "...from the forge of Armorer!")
|
||||
invocations = list("Grant me armaments...", "...from the forge of Armorer.")
|
||||
channel_time = 20
|
||||
power_cost = 250
|
||||
whispered = TRUE
|
||||
@@ -393,45 +393,49 @@
|
||||
<b>Left-click a target to fire, quickly!</b></span>"
|
||||
timeout_time = 20
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt
|
||||
descname = "Channeled, Power Drain"
|
||||
/datum/clockwork_scripture/void_volt
|
||||
descname = "Pulse, Power Drain"
|
||||
name = "Void Volt"
|
||||
desc = "A channeled spell that quickly drains any powercells in a radius of eight tiles, but burns the invoker. \
|
||||
Can be channeled with more cultists to increase range and split the caused damage evenly over all invokers. \
|
||||
desc = "A spell that releases a pulse which drains the power of anything in a radius of eight tiles, but burns the invoker. \
|
||||
Can be used with more servants to increase range and split the caused damage evenly among all invokers. \
|
||||
Also charges clockwork power by a small percentage of the drained power amount, which can help offset this scriptures powercost."
|
||||
invocations = list("Channel their energy through my body... ", "... so it may fuel Engine!")
|
||||
chant_invocations = list("Make their lights fall dark!", "They shall be powerless!", "Rob them of their power!")
|
||||
chant_amount = 20
|
||||
chant_interval = 10 //100KW drain per pulse for guns / APCs / 1MW for other cells = 10 chants / 100ds / 10s to drain a charged weapon or a baton with a nonupgraded cell
|
||||
channel_time = 50
|
||||
power_cost = 300
|
||||
invocations = list("Take the energy...", "...of their inventions...", "...and grant it to Engine...", "...for they already live in utter darkness!")
|
||||
channel_time = 130 //You need alot of time, but it pays off. - ten times as powerful as a regular drain (done by transmission sigils) and recurses + affects weapons - incredibly useful if you can pull this off before a big fight.
|
||||
power_cost = 500 //Relatively medium powercost, but can be offset due to it adding a part of drained power to the power pool.
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
usage_tip = "It may be useful to end channelling early if the burning becomes too much to handle.."
|
||||
usage_tip = "Be sure to not be injured when using this, or the power channeled through you may overwhelm your body."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 11
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Quickly drains power in an area around the invoker, causing burns proportional to the amount of energy drained.<br><b>Maximum of 20 chants.</b>"
|
||||
quickbind_desc = "Quickly drains power in an area around the invoker, causing burns proportional to the amount of energy drained."
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/scripture_effects()
|
||||
/datum/clockwork_scripture/void_volt/chant()
|
||||
invoker.visible_message("<span class='warning'>[invoker] glows in a brilliant golden light!</span>")
|
||||
invoker.add_atom_colour("#FFD700", ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 2
|
||||
invoker.light_range = 4
|
||||
invoker.light_color = LIGHT_COLOR_FIRE
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
addtimer(CALLBACK(invoker, /mob.proc/stop_void_volt_glow), channel_time)
|
||||
..()//Do the timer & Chant
|
||||
|
||||
/mob/proc/stop_void_volt_glow() //Needed so the scripture being qdel()d doesn't prevent it.
|
||||
visible_message("<span class='warning'>[src] stops glowing...</span>")
|
||||
remove_atom_colour(ADMIN_COLOUR_PRIORITY)
|
||||
light_power = 0
|
||||
light_range = 0
|
||||
update_light()
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_effects(chant_number)
|
||||
/datum/clockwork_scripture/void_volt/scripture_effects()
|
||||
var/power_drained = 0
|
||||
var/power_mod = 0.005 //Amount of power drained (generally) is multiplied with this, and subsequently dealt in damage to the invoker, then 15 times that is added to the clockwork cult's power reserves.
|
||||
var/drain_range = 8
|
||||
var/drain_range = 12
|
||||
var/additional_chanters = 0
|
||||
var/list/chanters = list()
|
||||
chanters += invoker
|
||||
for(var/mob/living/L in range(1, invoker))
|
||||
for(var/mob/living/L in orange(1, invoker))
|
||||
if(!L.stat && is_servant_of_ratvar(L))
|
||||
additional_chanters++
|
||||
chanters += L
|
||||
@@ -440,22 +444,14 @@
|
||||
var/turf/T = t
|
||||
for(var/M in T)
|
||||
var/atom/movable/A = M
|
||||
power_drained += A.power_drain(TRUE, TRUE) //Yes, this absolutely does drain weaponry. 10 pulses to drain guns / batons, though of course they can just be recharged.
|
||||
power_drained += A.power_drain(TRUE, TRUE, TRUE, MIN_CLOCKCULT_POWER * 10) //Yes, this absolutely does drain weaponry, aswell as recurse through objects. No more hiding in lockers / mechs to avoid it.
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transgression(invoker.loc, 1 + (power_drained * power_mod))
|
||||
var/datum/effect_system/spark_spread/S = new
|
||||
S.set_up(round(1 + (power_drained * power_mod), 1), 0, get_turf(invoker))
|
||||
S.start()
|
||||
adjust_clockwork_power(power_drained * power_mod * 15)
|
||||
for(var/mob/living/L in chanters)
|
||||
L.adjustFireLoss(round(clamp(power_drained * power_mod / (1 + additional_chanters), 0, 20), 0.1)) //No you won't just immediately melt if you do this in a very power-rich area
|
||||
L.adjustFireLoss(round(clamp(power_drained * power_mod / (1 + additional_chanters), 0, 70), 0.1)) //No you won't just immediately melt if you do this in a very power-rich area, but it'll be close.
|
||||
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_end_effects()
|
||||
invoker.visible_message("<span class='warning'>[invoker] stops glowing...</span>")
|
||||
invoker.remove_atom_colour(ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 0
|
||||
invoker.light_range = 0
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/attackby(obj/item/I, mob/user, params)
|
||||
if(is_servant_of_ratvar(user) && istype(I, /obj/item/wrench) && unanchored_icon)
|
||||
if(is_servant_of_ratvar(user) && I.tool_behaviour == TOOL_WRENCH && unanchored_icon)
|
||||
if(default_unfasten_wrench(user, I, 50) == SUCCESSFUL_UNFASTEN)
|
||||
update_anchored(user)
|
||||
return 1
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user