Merge branch 'master' into loadout-json
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#define CURRENT_LIVING_PLAYERS 1
|
||||
#define CURRENT_LIVING_ANTAGS 2
|
||||
#define CURRENT_DEAD_PLAYERS 3
|
||||
#define CURRENT_OBSERVERS 4
|
||||
#define CURRENT_OBSERVERS 4
|
||||
|
||||
#define NO_ASSASSIN (1<<0)
|
||||
#define WAROPS_ALWAYS_ALLOWED (1<<1)
|
||||
@@ -9,9 +9,11 @@
|
||||
#define FORCE_IF_WON (1<<3)
|
||||
#define USE_PREV_ROUND_WEIGHTS (1<<4)
|
||||
|
||||
#define ONLY_RULESET (1<<0)
|
||||
#define HIGHLANDER_RULESET (1<<1)
|
||||
#define TRAITOR_RULESET (1<<2)
|
||||
#define MINOR_RULESET (1<<3)
|
||||
#define ONLY_RULESET (1<<0)
|
||||
#define HIGHLANDER_RULESET (1<<1)
|
||||
#define TRAITOR_RULESET (1<<2)
|
||||
#define MINOR_RULESET (1<<3)
|
||||
#define FAKE_ANTAG_RULESET (1<<4)
|
||||
#define ALWAYS_MAX_WEIGHT_RULESET (1<<5)
|
||||
|
||||
#define RULESET_STOP_PROCESSING 1
|
||||
|
||||
@@ -125,7 +125,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
|
||||
|
||||
#define isbot(A) (istype(A, /mob/living/simple_animal/bot))
|
||||
|
||||
#define isshade(A) (istype(A, /mob/living/simple_animal/shade))
|
||||
#define isshade(A) (istype(A, /mob/living/simple_animal/hostile/construct/shade))
|
||||
|
||||
#define ismouse(A) (istype(A, /mob/living/simple_animal/mouse))
|
||||
|
||||
|
||||
@@ -78,7 +78,9 @@
|
||||
#define EXP_TYPE_ADMIN "Admin"
|
||||
|
||||
//Flags in the players table in the db
|
||||
#define DB_FLAG_EXEMPT 1
|
||||
#define DB_FLAG_EXEMPT (1<<0)
|
||||
#define DB_FLAG_AGE_CONFIRMATION_INCOMPLETE (1<<1)
|
||||
#define DB_FLAG_AGE_CONFIRMATION_COMPLETE (1<<2)
|
||||
|
||||
#define DEFAULT_CYBORG_NAME "Default Cyborg Name"
|
||||
|
||||
|
||||
@@ -76,8 +76,14 @@
|
||||
#define LINGHIVE_LINK 3
|
||||
|
||||
//whether the emote is visible or audible.
|
||||
// Requires sight
|
||||
#define EMOTE_VISIBLE 1
|
||||
// Requires hearing
|
||||
#define EMOTE_AUDIBLE 2
|
||||
// Requires sight or hearing
|
||||
#define EMOTE_BOTH 3
|
||||
// Always able to be seen
|
||||
#define EMOTE_OMNI 4
|
||||
|
||||
//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam
|
||||
#define MAX_MESSAGE_LEN 2048 //Citadel edit: What's the WORST that could happen?
|
||||
@@ -89,4 +95,4 @@
|
||||
|
||||
// Audio/Visual Flags. Used to determine what sense are required to notice a message.
|
||||
#define MSG_VISUAL (1<<0)
|
||||
#define MSG_AUDIBLE (1<<1)
|
||||
#define MSG_AUDIBLE (1<<1)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#define SPECIES_ANDROID "android"
|
||||
#define SPECIES_ANGEL "angel"
|
||||
#define SPECIES_MAMMAL "mammal"
|
||||
#define SPECIES_ARACHNID "arachnid"
|
||||
#define SPECIES_INSECT "insect"
|
||||
#define SPECIES_DULLAHAN "dullahan"
|
||||
#define SPECIES_DWARF "dwarf"
|
||||
@@ -33,7 +34,9 @@
|
||||
#define SPECIES_SYNTH "synth"
|
||||
#define SPECIES_SYNTH_MIL "military_synth"
|
||||
#define SPECIES_VAMPIRE "vampire"
|
||||
#define SPECIES_VAMPIRE_WEAK "vampire_roundstart"
|
||||
#define SPECIES_XENOHYBRID "xeno"
|
||||
#define SPECIES_ZOMBIE "zombie"
|
||||
|
||||
// Species Category Defines ---------------------
|
||||
|
||||
@@ -45,6 +48,7 @@
|
||||
#define SPECIES_CATEGORY_PLANT "plant"
|
||||
#define SPECIES_CATEGORY_ROBOT "robotic"
|
||||
#define SPECIES_CATEGORY_JELLY "jelly"
|
||||
#define SPECIES_CATEGORY_LIZARD "lizard"
|
||||
#define SPECIES_CATEGORY_SHADOW "shadow"
|
||||
#define SPECIES_CATEGORY_SKELETON "skeleton"
|
||||
#define SPECIES_CATEGORY_UNDEAD "undead"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// tgstation-server DMAPI
|
||||
|
||||
#define TGS_DMAPI_VERSION "5.2.1"
|
||||
#define TGS_DMAPI_VERSION "5.2.7"
|
||||
|
||||
// All functions and datums outside this document are subject to change with any version and should not be relied on.
|
||||
|
||||
@@ -95,6 +95,8 @@
|
||||
#define TGS_EVENT_WATCHDOG_SHUTDOWN 15
|
||||
/// Before the watchdog detaches for a TGS update/restart. No parameters.
|
||||
#define TGS_EVENT_WATCHDOG_DETACH 16
|
||||
// We don't actually implement this value as the DMAPI can never receive it
|
||||
// #define TGS_EVENT_WATCHDOG_LAUNCH 17
|
||||
|
||||
// OTHER ENUMS
|
||||
|
||||
@@ -127,6 +129,7 @@
|
||||
* Call this when your initializations are complete and your game is ready to play before any player interactions happen.
|
||||
*
|
||||
* This may use [/world/var/sleep_offline] to make this happen so ensure no changes are made to it while this call is running.
|
||||
* Afterwards, consider explicitly setting it to what you want to avoid this BYOND bug: http://www.byond.com/forum/post/2575184
|
||||
* Before this point, note that any static files or directories may be in use by another server. Your code should account for this.
|
||||
* This function should not be called before ..() in [/world/proc/New].
|
||||
*/
|
||||
|
||||
@@ -208,10 +208,9 @@
|
||||
#define TRAIT_FAST_PUMP "fast_pump"
|
||||
#define TRAIT_NO_PROCESS_FOOD "no-process-food" // You don't get benefits from nutriment, nor nutrition from reagent consumables
|
||||
#define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good...
|
||||
/// Prevents stamina buffer regeneration
|
||||
#define TRAIT_NO_STAMINA_BUFFER_REGENERATION "block_stamina_buffer_regen"
|
||||
/// Prevents stamina regeneration
|
||||
#define TRAIT_NO_STAMINA_REGENERATION "block_stamina_regen"
|
||||
#define TRAIT_NO_STAMINA_BUFFER_REGENERATION "block_stamina_buffer_regen" /// Prevents stamina buffer regeneration
|
||||
#define TRAIT_NO_STAMINA_REGENERATION "block_stamina_regen" /// Prevents stamina regeneration
|
||||
#define TRAIT_ARMOR_BROKEN "armor_broken" //acts as if you are wearing no clothing when taking damage, does not affect non-clothing sources of protection
|
||||
|
||||
// mobility flag traits
|
||||
// IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it)
|
||||
@@ -324,3 +323,4 @@
|
||||
/// This trait is added by the parry system.
|
||||
#define ACTIVE_PARRY_TRAIT "active_parry"
|
||||
#define STICKY_NODROP "sticky-nodrop" //sticky nodrop sounds like a bad soundcloud rapper's name
|
||||
#define TRAIT_SACRIFICED "sacrificed" //Makes sure that people cant be cult sacrificed twice.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#define PLURALITY_VOTING 0
|
||||
#define APPROVAL_VOTING 1
|
||||
#define SCHULZE_VOTING 2
|
||||
#define SCORE_VOTING 3
|
||||
#define MAJORITY_JUDGEMENT_VOTING 4
|
||||
#define INSTANT_RUNOFF_VOTING 5
|
||||
#define PLURALITY_VOTING "PLURALITY"
|
||||
#define APPROVAL_VOTING "APPROVAL"
|
||||
#define SCHULZE_VOTING "SCHULZE"
|
||||
#define SCORE_VOTING "SCORE"
|
||||
#define MAJORITY_JUDGEMENT_VOTING "MAJORITY_JUDGEMENT"
|
||||
#define INSTANT_RUNOFF_VOTING "IRV"
|
||||
|
||||
#define SHOW_RESULTS (1<<0)
|
||||
#define SHOW_VOTES (1<<1)
|
||||
@@ -26,4 +26,4 @@ GLOBAL_LIST_INIT(display_vote_settings, list(\
|
||||
"Ongoing Votes" = SHOW_VOTES,
|
||||
"Winner" = SHOW_WINNER,
|
||||
"Abstainers" = SHOW_ABSTENTION
|
||||
))
|
||||
))
|
||||
|
||||
@@ -13,6 +13,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_NEARSIGHT" = TRAIT_NEARSIGHT,
|
||||
"TRAIT_FAT" = TRAIT_FAT,
|
||||
"TRAIT_HUSK" = TRAIT_HUSK,
|
||||
"TRAIT_SACRIFICED" = TRAIT_SACRIFICED,
|
||||
"TRAIT_NOCLONE" = TRAIT_NOCLONE,
|
||||
"TRAIT_CLUMSY" = TRAIT_CLUMSY,
|
||||
"TRAIT_CHUNKYFINGERS" = TRAIT_CHUNKYFINGERS,
|
||||
|
||||
@@ -509,21 +509,21 @@
|
||||
|
||||
//Body size configs, the feature will be disabled if both min and max have the same value.
|
||||
/datum/config_entry/number/body_size_min
|
||||
config_entry_value = RESIZE_DEFAULT_SIZE
|
||||
config_entry_value = 0.9
|
||||
min_val = 0.1 //to avoid issues with zeros and negative values.
|
||||
max_val = RESIZE_DEFAULT_SIZE
|
||||
integer = FALSE
|
||||
|
||||
/datum/config_entry/number/body_size_max
|
||||
config_entry_value = RESIZE_DEFAULT_SIZE
|
||||
config_entry_value = 1.25
|
||||
min_val = RESIZE_DEFAULT_SIZE
|
||||
integer = FALSE
|
||||
|
||||
//Pun-Pun movement slowdown given to characters with a body size smaller than this value,
|
||||
//Penalties given to characters with a body size smaller than this value,
|
||||
//to compensate for their smaller hitbox.
|
||||
//To disable, just make sure the value is lower than 'body_size_min'
|
||||
/datum/config_entry/number/threshold_body_size_slowdown
|
||||
config_entry_value = RESIZE_DEFAULT_SIZE * 0.85
|
||||
/datum/config_entry/number/threshold_body_size_penalty
|
||||
config_entry_value = RESIZE_DEFAULT_SIZE
|
||||
min_val = 0
|
||||
max_val = RESIZE_DEFAULT_SIZE
|
||||
integer = FALSE
|
||||
@@ -531,8 +531,8 @@
|
||||
//multiplicative slowdown multiplier. See 'dna.update_body_size' for the operation.
|
||||
//doesn't apply to floating or crawling mobs
|
||||
/datum/config_entry/number/body_size_slowdown_multiplier
|
||||
config_entry_value = 0.25
|
||||
min_val = 0.1 //To encourage folks to disable the slowdown through the above config instead.
|
||||
config_entry_value = 0
|
||||
min_val = 0
|
||||
integer = FALSE
|
||||
|
||||
//Allows players to set a hexadecimal color of their choice as skin tone, on top of the standard ones.
|
||||
|
||||
@@ -290,7 +290,7 @@
|
||||
/datum/config_entry/flag/tgstyle_maprotation
|
||||
|
||||
/datum/config_entry/string/map_vote_type
|
||||
config_entry_value = "SCORE"
|
||||
config_entry_value = APPROVAL_VOTING
|
||||
|
||||
/datum/config_entry/number/maprotatechancedelta
|
||||
config_entry_value = 0.75
|
||||
@@ -327,6 +327,9 @@
|
||||
/datum/config_entry/number/notify_new_player_account_age // how long do we notify admins of a new byond account
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/flag/age_verification //are we using the automated age verification which asks users if they're 18+?
|
||||
config_entry_value = TRUE
|
||||
|
||||
/datum/config_entry/flag/irc_first_connection_alert // do we notify the irc channel when somebody is connecting for the first time?
|
||||
|
||||
/datum/config_entry/flag/check_randomizer
|
||||
|
||||
@@ -50,17 +50,20 @@ PROCESSING_SUBSYSTEM_DEF(circuit)
|
||||
/obj/item/electronic_assembly/simple,
|
||||
/obj/item/electronic_assembly/hook,
|
||||
/obj/item/electronic_assembly/pda,
|
||||
/obj/item/electronic_assembly/dildo,
|
||||
/obj/item/electronic_assembly/small/default,
|
||||
/obj/item/electronic_assembly/small/cylinder,
|
||||
/obj/item/electronic_assembly/small/scanner,
|
||||
/obj/item/electronic_assembly/small/hook,
|
||||
/obj/item/electronic_assembly/small/box,
|
||||
/obj/item/electronic_assembly/small/dildo,
|
||||
/obj/item/electronic_assembly/medium/default,
|
||||
/obj/item/electronic_assembly/medium/box,
|
||||
/obj/item/electronic_assembly/medium/clam,
|
||||
/obj/item/electronic_assembly/medium/medical,
|
||||
/obj/item/electronic_assembly/medium/gun,
|
||||
/obj/item/electronic_assembly/medium/radio,
|
||||
/obj/item/electronic_assembly/medium/dildo,
|
||||
/obj/item/electronic_assembly/large/default,
|
||||
/obj/item/electronic_assembly/large/scope,
|
||||
/obj/item/electronic_assembly/large/terminal,
|
||||
|
||||
@@ -45,22 +45,29 @@ SUBSYSTEM_DEF(statpanels)
|
||||
var/list/vote_arry = list(
|
||||
list("Vote active!", "There is currently a vote running. Question: [SSvote.question]")
|
||||
) //see the MC on how this works.
|
||||
if(!(SSvote.vote_system in list(PLURALITY_VOTING, APPROVAL_VOTING)))
|
||||
if(!(SSvote.vote_system in list(PLURALITY_VOTING, APPROVAL_VOTING, SCHULZE_VOTING, INSTANT_RUNOFF_VOTING)))
|
||||
vote_arry[++vote_arry.len] += list("STATPANEL VOTING DISABLED!", "The current vote system is not supported by statpanel rendering. Please vote manually by opening the vote popup using the action button or chat link.", "disabled")
|
||||
//does not return.
|
||||
else
|
||||
vote_arry[++vote_arry.len] += list("Time Left:", " [round(SSvote.end_time - world.time)] seconds")
|
||||
vote_arry[++vote_arry.len] += list("Time Left:", " [DisplayTimeText(SSvote.end_time - world.time)] seconds")
|
||||
vote_arry[++vote_arry.len] += list("Choices:", "")
|
||||
for(var/choice in SSvote.choice_statclicks)
|
||||
var/choice_id = SSvote.choice_statclicks[choice]
|
||||
var/ivotedforthis = FALSE
|
||||
if(target.ckey)
|
||||
switch(SSvote.vote_system)
|
||||
if(APPROVAL_VOTING)
|
||||
ivotedforthis = SSvote.voted[target.ckey] && (text2num(choice_id) in SSvote.voted[usr.ckey])
|
||||
if(PLURALITY_VOTING)
|
||||
ivotedforthis = (SSvote.voted[target.ckey] == text2num(choice_id))
|
||||
vote_arry[++vote_arry.len] += list(ivotedforthis ? "\[X\]" : "\[ \]", choice, "[REF(SSvote)];vote=[choice_id];statpannel=1")
|
||||
if(PLURALITY_VOTING, APPROVAL_VOTING)
|
||||
var/ivotedforthis = FALSE
|
||||
if(SSvote.vote_system == APPROVAL_VOTING)
|
||||
ivotedforthis = SSvote.voted[target.ckey] && (text2num(choice_id) in SSvote.voted[target.ckey])
|
||||
else
|
||||
ivotedforthis = (SSvote.voted[target.ckey] == text2num(choice_id))
|
||||
vote_arry[++vote_arry.len] += list(ivotedforthis ? "\[X\]" : "\[ \]", choice, "[REF(SSvote)];vote=[choice_id];statpannel=1")
|
||||
if(SCHULZE_VOTING, INSTANT_RUNOFF_VOTING)
|
||||
var/list/vote = SSvote.voted[target.ckey]
|
||||
var/vote_position = " "
|
||||
if(vote)
|
||||
vote_position = vote.Find(text2num(choice_id))
|
||||
vote_arry[++vote_arry.len] += list("\[[vote_position]\]", choice, "[REF(SSvote)];vote=[choice_id];statpannel=1")
|
||||
var/vote_str = url_encode(json_encode(vote_arry))
|
||||
target << output("[vote_str]", "statbrowser:update_voting")
|
||||
else
|
||||
|
||||
@@ -482,18 +482,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
INVOKE_ASYNC(SSmapping, /datum/controller/subsystem/mapping/.proc/maprotate)
|
||||
else
|
||||
var/vote_type = CONFIG_GET(string/map_vote_type)
|
||||
switch(vote_type)
|
||||
if("PLURALITY")
|
||||
SSvote.initiate_vote("map","server", display = SHOW_RESULTS)
|
||||
if("APPROVAL")
|
||||
SSvote.initiate_vote("map","server", display = SHOW_RESULTS, votesystem = APPROVAL_VOTING)
|
||||
if("IRV")
|
||||
SSvote.initiate_vote("map","server", display = SHOW_RESULTS, votesystem = INSTANT_RUNOFF_VOTING)
|
||||
if("SCORE")
|
||||
SSvote.initiate_vote("map","server", display = SHOW_RESULTS, votesystem = MAJORITY_JUDGEMENT_VOTING)
|
||||
else
|
||||
SSvote.initiate_vote("map","server", display = SHOW_RESULTS)
|
||||
// fallback
|
||||
SSvote.initiate_vote("map","server", display = SHOW_RESULTS, votesystem = vote_type)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/HasRoundStarted()
|
||||
return current_state >= GAME_STATE_PLAYING
|
||||
|
||||
@@ -52,7 +52,7 @@ SUBSYSTEM_DEF(traumas)
|
||||
"doctors" = typecacheof(list(/mob/living/simple_animal/bot/medbot)),
|
||||
"the supernatural" = typecacheof(list(/mob/living/simple_animal/hostile/construct,
|
||||
/mob/living/simple_animal/hostile/clockwork, /mob/living/simple_animal/drone/cogscarab,
|
||||
/mob/living/simple_animal/revenant, /mob/living/simple_animal/shade)),
|
||||
/mob/living/simple_animal/revenant, /mob/living/simple_animal/hostile/construct/shade)),
|
||||
"aliens" = typecacheof(list(/mob/living/carbon/alien, /mob/living/simple_animal/slime)),
|
||||
"conspiracies" = typecacheof(list(/mob/living/simple_animal/bot/secbot, /mob/living/simple_animal/bot/ed209, /mob/living/simple_animal/drone,
|
||||
/mob/living/simple_animal/pet/penguin)),
|
||||
@@ -158,8 +158,8 @@ SUBSYSTEM_DEF(traumas)
|
||||
/obj/item/clothing/head/frenchberet, /obj/item/clothing/suit/suspenders, /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing,
|
||||
/obj/item/storage/backpack/mime, /obj/item/reagent_containers/food/snacks/grown/banana/mime,
|
||||
/obj/item/grown/bananapeel/mimanapeel, /obj/item/cartridge/virus/mime, /obj/item/clothing/shoes/sneakers/mime,
|
||||
/obj/item/bedsheet/mime, /obj/item/reagent_containers/food/snacks/burger/mime, /obj/item/clothing/head/beret, /obj/item/clothing/mask/gas/sexymime,
|
||||
/obj/item/clothing/under/rank/civilian/mime/sexy, /obj/item/toy/figure/mime, /obj/item/toy/crayon/mime, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced, /obj/mecha/combat/reticence)),
|
||||
/obj/item/bedsheet/mime, /obj/item/reagent_containers/food/snacks/burger/mime, /obj/item/clothing/head/beret,
|
||||
/obj/item/toy/figure/mime, /obj/item/toy/crayon/mime, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced, /obj/mecha/combat/reticence)),
|
||||
|
||||
"cats" = typecacheof(list(/obj/item/organ/ears/cat, /obj/item/organ/tail/cat, /obj/item/laser_pointer, /obj/item/toy/cattoy, /obj/item/clothing/head/kitty,
|
||||
/obj/item/clothing/head/collectable/kitty, /obj/item/melee/chainofcommand/tailwhip/kitty, /obj/item/stack/sheet/animalhide/cat)),
|
||||
|
||||
@@ -25,18 +25,15 @@
|
||||
|
||||
/datum/accent/abductor/modify_speech(list/speech_args, datum/source)
|
||||
var/message = speech_args[SPEECH_MESSAGE]
|
||||
var/mob/living/carbon/human/user = source
|
||||
var/mob/living/carbon/user = source
|
||||
var/obj/item/organ/tongue/abductor/A = user.getorgan(/obj/item/organ/tongue/abductor)
|
||||
var/rendered = "<span class='abductor'><b>[user.name]:</b> [message]</span>"
|
||||
user.log_talk(message, LOG_SAY, tag="abductor")
|
||||
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
|
||||
var/obj/item/organ/tongue/T = H.getorganslot(ORGAN_SLOT_TONGUE)
|
||||
if(!T || T.type != type)
|
||||
for(var/mob/living/carbon/C in GLOB.alive_mob_list)
|
||||
var/obj/item/organ/tongue/abductor/T = C.getorgan(/obj/item/organ/tongue/abductor)
|
||||
if(!T || T.mothership != A.mothership)
|
||||
continue
|
||||
if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor")
|
||||
var/datum/antagonist/abductor/A = user.mind.has_antag_datum(/datum/antagonist/abductor)
|
||||
if(!A || !(H.mind in A.team.members))
|
||||
continue
|
||||
to_chat(H, rendered)
|
||||
to_chat(C, rendered)
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
var/link = FOLLOW_LINK(M, user)
|
||||
to_chat(M, "[link] [rendered]")
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
M.ghostize(can_reenter_corpse = TRUE, voluntary = TRUE)
|
||||
|
||||
/datum/action/proc/OnUpdatedIcon()
|
||||
UpdateButtonIcon()
|
||||
addtimer(CALLBACK(src, .proc/UpdateButtonIcon), 1) //Hopefully runs after new icon overlays have been compiled.
|
||||
|
||||
//Presets for item actions
|
||||
/datum/action/item_action
|
||||
@@ -273,6 +273,13 @@
|
||||
if(istype(H))
|
||||
H.toggle_welding_screen(owner)
|
||||
|
||||
/datum/action/item_action/toggle_welding_screen/plasmaman
|
||||
|
||||
/datum/action/item_action/toggle_welding_screen/plasmaman/Trigger()
|
||||
var/obj/item/clothing/head/helmet/space/plasmaman/H = target
|
||||
if(istype(H))
|
||||
H.toggle_welding_screen(owner)
|
||||
|
||||
/datum/action/item_action/toggle_headphones
|
||||
name = "Toggle Headphones"
|
||||
desc = "UNTZ UNTZ UNTZ"
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ishotgun // smaller and more versatile gun requires some better materials
|
||||
/datum/crafting_recipe/ishotgun
|
||||
name = "Improvised Shotgun"
|
||||
result = /obj/item/gun/ballistic/revolver/doublebarrel/improvised
|
||||
reqs = list(/obj/item/pipe = 2, // putting a large amount of meaningless timegates by forcing people to turn base resources into upgraded resources kinda sucks
|
||||
@@ -408,7 +408,7 @@
|
||||
/datum/crafting_recipe/rifle_receiver
|
||||
name = "Improvised Rifle Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/rifle_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15) // you can carry multiple shotguns
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 25
|
||||
category = CAT_WEAPONRY
|
||||
@@ -417,10 +417,9 @@
|
||||
/datum/crafting_recipe/shotgun_receiver
|
||||
name = "Improvised Shotgun Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/shotgun_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15,
|
||||
/obj/item/stack/sheet/plasteel = 1) // requires access or hacking since shotgun is better
|
||||
reqs = list(/obj/item/stack/sheet/metal = 10) // shotgun does less damage than the rifle and can't 1shot but is more portable
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 25
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -432,6 +431,6 @@
|
||||
reqs = list(/obj/item/stack/sheet/metal = 3,
|
||||
/obj/item/assembly/igniter = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 25
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
RegisterSignal(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY), .proc/play_squeak)
|
||||
if(ismovable(parent))
|
||||
RegisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT), .proc/play_squeak)
|
||||
RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ITEM_WEARERCROSSED, COMSIG_MOVABLE_CROSS), .proc/play_squeak_crossed)
|
||||
RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ITEM_WEARERCROSSED), .proc/play_squeak_crossed)
|
||||
RegisterSignal(parent, COMSIG_CROSS_SQUEAKED, .proc/delay_squeak)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react)
|
||||
if(isitem(parent))
|
||||
@@ -46,6 +46,21 @@
|
||||
if(isnum(use_delay_override))
|
||||
use_delay = use_delay_override
|
||||
|
||||
/datum/component/squeak/UnregisterFromParent()
|
||||
if(!isatom(parent))
|
||||
return
|
||||
UnregisterSignal(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY))
|
||||
if(ismovable(parent))
|
||||
UnregisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT,
|
||||
COMSIG_MOVABLE_CROSSED, COMSIG_ITEM_WEARERCROSSED, COMSIG_MOVABLE_CROSS,
|
||||
COMSIG_CROSS_SQUEAKED, COMSIG_MOVABLE_DISPOSING))
|
||||
if(isitem(parent))
|
||||
UnregisterSignal(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_HIT_REACT, COMSIG_ITEM_ATTACK_SELF,
|
||||
COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED))
|
||||
if(istype(parent, /obj/item/clothing/shoes))
|
||||
UnregisterSignal(parent, COMSIG_SHOES_STEP_ACTION)
|
||||
return ..()
|
||||
|
||||
/datum/component/squeak/proc/play_squeak()
|
||||
do_play_squeak()
|
||||
|
||||
|
||||
@@ -236,12 +236,12 @@
|
||||
switch(stage)
|
||||
if(1)
|
||||
if(ishuman(affected_mob) && affected_mob.dna)
|
||||
if(affected_mob.dna.species.id == "slime" || affected_mob.dna.species.id == "stargazer" || affected_mob.dna.species.id == "slimelumi")
|
||||
if(affected_mob.dna.species.id == SPECIES_SLIME_LUMI || affected_mob.dna.species.id == SPECIES_STARGAZER || affected_mob.dna.species.id == SPECIES_SLIME_LUMI)
|
||||
stage = 5
|
||||
if(3)
|
||||
if(ishuman(affected_mob))
|
||||
var/mob/living/carbon/human/human = affected_mob
|
||||
if(human.dna.species.id != "slime" && affected_mob.dna.species.id != "stargazer" && affected_mob.dna.species.id != "slimelumi")
|
||||
if(human.dna.species.id != SPECIES_SLIME_LUMI && affected_mob.dna.species.id != SPECIES_STARGAZER && affected_mob.dna.species.id != SPECIES_SLIME_LUMI)
|
||||
human.set_species(/datum/species/jelly/slime)
|
||||
|
||||
/datum/disease/transformation/corgi
|
||||
|
||||
+15
-7
@@ -5,7 +5,7 @@
|
||||
var/uni_identity
|
||||
var/blood_type
|
||||
var/datum/species/species = new /datum/species/human //The type of mutant race the player is if applicable (i.e. potato-man)
|
||||
var/list/features = list("FFF") //first value is mutant color
|
||||
var/list/features = list("FFF", "body_size" = RESIZE_DEFAULT_SIZE) //first value is mutant color
|
||||
var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings,
|
||||
var/nameless = FALSE
|
||||
var/custom_species //siiiiigh I guess this is important
|
||||
@@ -696,11 +696,19 @@
|
||||
/datum/dna/proc/update_body_size(old_size)
|
||||
if(!holder || features["body_size"] == old_size)
|
||||
return
|
||||
//new size detected
|
||||
holder.resize = features["body_size"] / old_size
|
||||
holder.update_transform()
|
||||
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
|
||||
if(features["body_size"] < danger)
|
||||
var/slowdown = (1 - round(features["body_size"] / danger, 0.1)) * CONFIG_GET(number/body_size_slowdown_multiplier)
|
||||
holder.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/small_stride, TRUE, slowdown)
|
||||
else if(old_size < danger)
|
||||
holder.remove_movespeed_modifier(/datum/movespeed_modifier/small_stride)
|
||||
if(iscarbon(holder))
|
||||
var/mob/living/carbon/C = holder
|
||||
var/penalty_threshold = CONFIG_GET(number/threshold_body_size_penalty)
|
||||
if(features["body_size"] < penalty_threshold && old_size >= penalty_threshold)
|
||||
C.maxHealth -= 10 //reduce the maxhealth
|
||||
var/slowdown = (1 - round(features["body_size"] / penalty_threshold, 0.1)) * CONFIG_GET(number/body_size_slowdown_multiplier)
|
||||
holder.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/small_stride, TRUE, slowdown)
|
||||
else
|
||||
if(old_size < penalty_threshold && features["body_size"] >= penalty_threshold)
|
||||
C.maxHealth += 10 //give the maxhealth back
|
||||
holder.remove_movespeed_modifier(/datum/movespeed_modifier/small_stride) //remove the slowdown
|
||||
|
||||
|
||||
|
||||
@@ -66,8 +66,12 @@
|
||||
|
||||
if(emote_type == EMOTE_AUDIBLE)
|
||||
user.audible_message(msg)
|
||||
else
|
||||
else if(emote_type == EMOTE_VISIBLE)
|
||||
user.visible_message(msg)
|
||||
else if(emote_type == EMOTE_BOTH)
|
||||
user.visible_message(msg, blind_message = msg)
|
||||
else if(emote_type == EMOTE_OMNI)
|
||||
user.visible_message(msg, omni = TRUE)
|
||||
|
||||
/datum/emote/proc/replace_pronoun(mob/user, message)
|
||||
if(findtext(message, "their"))
|
||||
|
||||
@@ -150,7 +150,6 @@
|
||||
overlays_standing[CM.layer_used] = mut_overlay
|
||||
apply_overlay(CM.layer_used)
|
||||
|
||||
|
||||
/datum/mutation/human/proc/modify() //called when a genome is applied so we can properly update some stats without having to remove and reapply the mutation from someone
|
||||
if(modified || !power || !owner)
|
||||
return
|
||||
|
||||
@@ -72,6 +72,8 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
var/list/threat_log_verbose = list()
|
||||
/// List of roundstart rules used for selecting the rules.
|
||||
var/list/roundstart_rules = list()
|
||||
/// List of minor roundstart rules used for selecting the rules.
|
||||
var/list/minor_rules = list()
|
||||
/// List of latejoin rules used for selecting the rules.
|
||||
var/list/latejoin_rules = list()
|
||||
/// List of midround rules used for selecting the rules.
|
||||
@@ -121,10 +123,12 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
var/pop_last_updated = 0
|
||||
/// How many percent of the rounds are more peaceful.
|
||||
var/peaceful_percentage = 50
|
||||
/// If a highlander executed.
|
||||
/// If a highlander executed. No other highlander rulesets will be run.
|
||||
var/highlander_executed = FALSE
|
||||
/// If a only ruleset has been executed.
|
||||
/// If a only ruleset has been executed. No other rulesets will be run.
|
||||
var/only_ruleset_executed = FALSE
|
||||
/// If the first picked ruleset was a minor ruleset. Minor antagonists will be weighted higher.
|
||||
var/minor_ruleset_start = FALSE
|
||||
/// Antags rolled by rules so far, to keep track of and discourage scaling past a certain ratio of crew/antags especially on lowpop.
|
||||
var/antags_rolled = 0
|
||||
// Arbitrary threat addition, for fudging purposes.
|
||||
@@ -372,6 +376,8 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
if(ruleset.name == "")
|
||||
continue
|
||||
switch(ruleset.ruletype)
|
||||
if("Minor")
|
||||
minor_rules += ruleset
|
||||
if("Roundstart")
|
||||
roundstart_rules += ruleset
|
||||
if ("Latejoin")
|
||||
@@ -396,21 +402,47 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
rigged_roundstart()
|
||||
else
|
||||
roundstart()
|
||||
|
||||
var/starting_rulesets = ""
|
||||
for (var/datum/dynamic_ruleset/roundstart/DR in executed_rules)
|
||||
starting_rulesets += "[DR.name], "
|
||||
log_game("DYNAMIC: Picked the following roundstart rules: [starting_rulesets]")
|
||||
if(minor_ruleset_start)
|
||||
log_game("DYNAMIC: Starting a minor ruleset round.")
|
||||
else
|
||||
var/starting_rulesets = ""
|
||||
for (var/datum/dynamic_ruleset/roundstart/DR in executed_rules)
|
||||
starting_rulesets += "[DR.name], "
|
||||
log_game("DYNAMIC: Picked the following roundstart rules: [starting_rulesets]")
|
||||
candidates.Cut()
|
||||
return TRUE
|
||||
|
||||
/datum/game_mode/dynamic/post_setup(report)
|
||||
update_playercounts()
|
||||
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules)
|
||||
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_roundstart_rule, rule), rule.delay)
|
||||
if(minor_ruleset_start)
|
||||
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/minor_roundstart),rand(1 MINUTES,5 MINUTES))
|
||||
else
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules)
|
||||
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_roundstart_rule, rule), rule.delay)
|
||||
..()
|
||||
|
||||
/datum/game_mode/dynamic/proc/minor_roundstart()
|
||||
message_admins("Dynamic beginning minor antag roundstart rolls.")
|
||||
var/list/potential_minor_rulesets = storyteller.minor_rule_draft()
|
||||
var/iterations = 0
|
||||
var/num_rulesets_executed = 0
|
||||
while(threat < threat_level && potential_minor_rulesets.len && (!CHECK_TICK || iterations < 100))
|
||||
var/datum/dynamic_ruleset/minor/rule = pickweight(potential_minor_rulesets)
|
||||
rule.candidates = current_players[CURRENT_LIVING_PLAYERS].Copy()
|
||||
rule.trim_candidates()
|
||||
if(!check_blocking(rule.blocking_rules, executed_rules) && rule.ready())
|
||||
rule.execute()
|
||||
executed_rules |= rule
|
||||
log_threat("[rule.ruletype] - <b>[rule.name]</b> [rule.cost] threat", verbose = TRUE)
|
||||
num_rulesets_executed++
|
||||
else
|
||||
potential_minor_rulesets -= rule
|
||||
update_playercounts()
|
||||
iterations++
|
||||
message_admins("Minor antag roundstart rolls completed, with [num_rulesets_executed] antags or antag teams made.")
|
||||
log_game("DYNAMIC: Minor antag roundstart made [num_rulesets_executed] antags or antag teams.")
|
||||
|
||||
|
||||
/// A simple roundstart proc used when dynamic_forced_roundstart_ruleset has rules in it.
|
||||
/datum/game_mode/dynamic/proc/rigged_roundstart()
|
||||
message_admins("[GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.")
|
||||
@@ -429,12 +461,17 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
if (GLOB.dynamic_forced_extended)
|
||||
log_game("DYNAMIC: Starting a round of forced extended.")
|
||||
return TRUE
|
||||
if(prob(storyteller.minor_start_chance()))
|
||||
minor_ruleset_start = TRUE
|
||||
message_admins("Dynamic has initialized a minor antag start. Antags will be assigned in 1-5 minutes.")
|
||||
log_game("DYNAMIC: Minor start initialized.")
|
||||
return TRUE
|
||||
var/list/drafted_rules = storyteller.roundstart_draft()
|
||||
if(!drafted_rules.len)
|
||||
message_admins("Not enough threat level for roundstart antags!")
|
||||
log_game("DYNAMIC: Not enough threat level for roundstart antags!")
|
||||
midround_injection_cooldown = round((midround_injection_cooldown + world.time) / 2, 1)
|
||||
latejoin_injection_cooldown = round((latejoin_injection_cooldown + world.time) / 2, 1)
|
||||
message_admins("No roundstart antags drafted! Falling back to minor ruleset start.")
|
||||
log_game("DYNAMIC: No roundstart antags drafted! Falling back to minor ruleset start.")
|
||||
minor_ruleset_start = TRUE
|
||||
return FALSE
|
||||
var/indice_pop = min(10,round(roundstart_pop_ready/pop_per_requirement)+1)
|
||||
extra_rulesets_amount = 0
|
||||
if (GLOB.dynamic_classic_secret)
|
||||
@@ -468,8 +505,9 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
else
|
||||
|
||||
if(threat_level >= 50)
|
||||
message_admins("DYNAMIC: Picking first roundstart ruleset failed. You should report this.")
|
||||
message_admins("DYNAMIC: Picking first roundstart ruleset failed. You should report this. Falling back to minor antag start.")
|
||||
log_game("DYNAMIC: Picking first roundstart ruleset failed. drafted_rules.len = [drafted_rules.len] and threat = [threat]/[threat_level]")
|
||||
minor_ruleset_start = TRUE
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -513,7 +551,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
|
||||
drafted_rules -= starting_rule
|
||||
|
||||
starting_rule.trim_candidates()
|
||||
starting_rule.scale_up(extra_rulesets_amount, threat_level-added_threat)
|
||||
if (starting_rule.pre_execute())
|
||||
log_threat("[starting_rule.ruletype] - <b>[starting_rule.name]</b> [starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat", verbose = TRUE)
|
||||
if(starting_rule.flags & HIGHLANDER_RULESET)
|
||||
|
||||
@@ -50,8 +50,12 @@
|
||||
/// Used for the roundend report
|
||||
var/total_cost = 0
|
||||
/// A flag that determines how the ruleset is handled
|
||||
/// ONLY_RULESET are rulesets that prevent ALL other rulesets from rolling.
|
||||
/// HIGHLANDER_RULESET are rulesets can end the round.
|
||||
/// TRAITOR_RULESET and MINOR_RULESET can't end the round and have no difference right now.
|
||||
/// TRAITOR_RULESET are the "default" ruleset--they should always be addable to a round, if the round type allows antags and dynamic thinks there should be another.
|
||||
/// MINOR_RULESET is for rulesets whose antags can have multiple instances without causing too much issue. As roundstarts, they have their weights reduced based on the storyteller's minor-antag-round chance.
|
||||
/// FAKE_ANTAG_RULESET is for rulesets whose antags aren't actually antagonistic--essentially just flavor meant to spice the round up.
|
||||
/// ALWAYS_MAX_WEIGHT_RULESET means that the ruleset doesn't have its weight reduced based on recency.
|
||||
var/flags = 0
|
||||
/// Pop range per requirement. If zero defaults to mode's pop_per_requirement.
|
||||
var/pop_per_requirement = 0
|
||||
@@ -82,9 +86,6 @@
|
||||
var/delay = 0
|
||||
/// List of tags for use in storytellers.
|
||||
var/list/property_weights = list()
|
||||
/// Whether or not recent-round weight values are taken into account for this ruleset.
|
||||
/// Weight reduction uses the same values as secret's recent-round mode weight reduction.
|
||||
var/always_max_weight = FALSE
|
||||
/// Weight reduction by recent-rounds. Saved on new.
|
||||
var/weight_mult = 1
|
||||
|
||||
@@ -100,7 +101,7 @@
|
||||
var/high_population_requirements = CONFIG_GET(keyed_list/dynamic_high_population_requirement)
|
||||
var/list/repeated_mode_adjust = CONFIG_GET(number_list/repeated_mode_adjust)
|
||||
if(config_tag in weights)
|
||||
if(!always_max_weight && SSpersistence.saved_dynamic_rules.len == 3 && repeated_mode_adjust.len == 3)
|
||||
if(!(flags & ALWAYS_MAX_WEIGHT_RULESET) && SSpersistence.saved_dynamic_rules.len == 3 && repeated_mode_adjust.len == 3)
|
||||
var/saved_dynamic_rules = SSpersistence.saved_dynamic_rules
|
||||
for(var/i in 1 to 3)
|
||||
if(config_tag in saved_dynamic_rules[i])
|
||||
@@ -119,6 +120,9 @@
|
||||
/datum/dynamic_ruleset/roundstart // One or more of those drafted at roundstart
|
||||
ruletype = "Roundstart"
|
||||
|
||||
/datum/dynamic_ruleset/minor // drafted at roundstart in minor rounds, one antag at a time, for a "mixed" round
|
||||
ruletype = "Minor"
|
||||
|
||||
// Can be drafted when a player joins the server
|
||||
/datum/dynamic_ruleset/latejoin
|
||||
ruletype = "Latejoin"
|
||||
@@ -175,7 +179,7 @@
|
||||
/// This is called if persistent variable is true everytime SSTicker ticks.
|
||||
/datum/dynamic_ruleset/proc/rule_process()
|
||||
return TRUE
|
||||
|
||||
|
||||
/// Called on game mode pre_setup for roundstart rulesets.
|
||||
/// Do everything you need to do before job is assigned here.
|
||||
/// IMPORTANT: ASSIGN special_role HERE
|
||||
|
||||
@@ -70,9 +70,8 @@
|
||||
requirements = list(40,30,20,15,15,15,15,15,15,15)
|
||||
high_population_requirement = 15
|
||||
repeatable = TRUE
|
||||
flags = TRAITOR_RULESET
|
||||
flags = TRAITOR_RULESET | MINOR_RULESET | ALWAYS_MAX_WEIGHT_RULESET
|
||||
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
@@ -207,6 +206,7 @@
|
||||
weight = 4
|
||||
cost = 25
|
||||
requirements = list(60,60,60,55,50,50,50,50,50,50)
|
||||
flags = MINOR_RULESET
|
||||
high_population_requirement = 50
|
||||
property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2)
|
||||
repeatable = TRUE
|
||||
@@ -229,6 +229,7 @@
|
||||
cost = 10
|
||||
property_weights = list("story_potential" = 2, "extended" = 2, "trust" = -2, "valid" = 1)
|
||||
requirements = list(70,65,60,55,50,45,40,35,30,30)
|
||||
flags = MINOR_RULESET
|
||||
high_population_requirement = 30
|
||||
repeatable = TRUE
|
||||
|
||||
@@ -258,6 +259,7 @@
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
cost = 15
|
||||
flags = MINOR_RULESET
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
property_weights = list("trust" = -2, "valid" = 2)
|
||||
high_population_requirement = 101
|
||||
@@ -281,5 +283,5 @@
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
flags = TRAITOR_RULESET | MINOR_RULESET
|
||||
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 2)
|
||||
flags = TRAITOR_RULESET | MINOR_RULESET | FAKE_ANTAG_RULESET
|
||||
property_weights = list("story_potential" = 1, "trust" = -1, "extended" = 2)
|
||||
|
||||
@@ -207,9 +207,8 @@
|
||||
requirements = list(30,25,20,15,15,15,15,15,15,15)
|
||||
repeatable = TRUE
|
||||
high_population_requirement = 15
|
||||
flags = TRAITOR_RULESET
|
||||
flags = TRAITOR_RULESET | MINOR_RULESET | ALWAYS_MAX_WEIGHT_RULESET
|
||||
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0)
|
||||
var/player_count = mode.current_players[CURRENT_LIVING_PLAYERS].len
|
||||
@@ -494,6 +493,7 @@
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
cost = 10
|
||||
flags = MINOR_RULESET
|
||||
requirements = list(101,101,101,70,50,40,20,15,15,15)
|
||||
high_population_requirement = 50
|
||||
repeatable_weight_decrease = 2
|
||||
@@ -630,6 +630,7 @@
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
cost = 15
|
||||
flags = MINOR_RULESET
|
||||
requirements = list(101,101,101,90,80,70,60,50,40,30)
|
||||
high_population_requirement = 30
|
||||
property_weights = list("story_potential" = 1, "extended" = -2, "valid" = 2)
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// SYNDICATE TRAITORS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/minor/traitor
|
||||
name = "Traitors"
|
||||
config_tag = "traitor" // these having identical config tags to the roundstart modes is 100% intentional, so that config edits are simpler
|
||||
persistent = TRUE
|
||||
antag_flag = ROLE_TRAITOR
|
||||
antag_datum = /datum/antagonist/traitor/
|
||||
minimum_required_age = 0
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster", "Cyborg")
|
||||
restricted_roles = list("Cyborg", "AI")
|
||||
required_candidates = 1
|
||||
weight = 5
|
||||
flags = TRAITOR_RULESET | ALWAYS_MAX_WEIGHT_RULESET
|
||||
cost = 10 // Avoid raising traitor threat above 10, as it is the default low cost ruleset.
|
||||
requirements = list(50,50,50,50,50,50,50,50,50,50)
|
||||
high_population_requirement = 40
|
||||
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1, "valid" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/minor/traitor/execute()
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
assigned += M
|
||||
var/datum/antagonist/traitor/newTraitor = new
|
||||
M.mind.add_antag_datum(newTraitor)
|
||||
log_admin("[M] was made into a traitor by dynamic.")
|
||||
message_admins("[M] was made into a traitor by dynamic.")
|
||||
return TRUE
|
||||
|
||||
//////////////////////////////////////////
|
||||
// //
|
||||
// BLOOD BROTHERS //
|
||||
// //
|
||||
//////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/minor/traitorbro
|
||||
name = "Blood Brothers"
|
||||
config_tag = "traitorbro"
|
||||
antag_flag = ROLE_BROTHER
|
||||
antag_datum = /datum/antagonist/brother
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_candidates = 2
|
||||
weight = 4
|
||||
cost = 10
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 101
|
||||
antag_cap = list(2,2,2,2,2,2,2,2,2,2) // Can pick 3 per team, but rare enough it doesn't matter.
|
||||
property_weights = list("story_potential" = 1, "trust" = -1, "extended" = 1, "valid" = 1)
|
||||
var/list/datum/team/brother_team/pre_brother_teams = list()
|
||||
var/const/min_team_size = 2
|
||||
|
||||
/datum/dynamic_ruleset/minor/traitorbro/execute()
|
||||
if(candidates.len < min_team_size || candidates.len < required_candidates)
|
||||
return FALSE
|
||||
var/datum/team/brother_team/team = new
|
||||
var/team_size = prob(10) ? min(3, candidates.len) : 2
|
||||
for(var/k = 1 to team_size)
|
||||
var/mob/bro = pick_n_take(candidates)
|
||||
assigned += bro.mind
|
||||
team.add_member(bro.mind)
|
||||
bro.mind.special_role = "brother"
|
||||
bro.mind.restricted_roles = restricted_roles
|
||||
team.pick_meeting_area()
|
||||
team.forge_brother_objectives()
|
||||
for(var/datum/mind/M in team.members)
|
||||
M.add_antag_datum(/datum/antagonist/brother, team)
|
||||
team.update_name()
|
||||
mode.brother_teams += team
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// CHANGELINGS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/minor/changeling
|
||||
name = "Changelings"
|
||||
config_tag = "changeling"
|
||||
antag_flag = ROLE_CHANGELING
|
||||
antag_datum = /datum/antagonist/changeling
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
cost = 15
|
||||
scaling_cost = 15
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
property_weights = list("trust" = -2, "valid" = 2)
|
||||
high_population_requirement = 10
|
||||
antag_cap = list(1,1,1,1,1,2,2,2,2,3)
|
||||
var/team_mode_probability = 30
|
||||
|
||||
/datum/dynamic_ruleset/minor/changeling/execute()
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
assigned += M.mind
|
||||
M.mind.restricted_roles = restricted_roles
|
||||
M.mind.special_role = ROLE_CHANGELING
|
||||
var/datum/antagonist/changeling/new_antag = new antag_datum()
|
||||
M.mind.add_antag_datum(new_antag)
|
||||
return TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// ELDRITCH CULT //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/minor/heretics
|
||||
name = "Heretic"
|
||||
antag_flag = "heretic"
|
||||
antag_datum = /datum/antagonist/heretic
|
||||
protected_roles = list("Prisoner","Security Officer", "Warden", "Detective", "Head of Security", "Captain")
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
cost = 25
|
||||
scaling_cost = 15
|
||||
requirements = list(60,60,60,55,50,50,50,50,50,50)
|
||||
property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2)
|
||||
antag_cap = list(1,1,1,1,2,2,2,2,3,3)
|
||||
high_population_requirement = 50
|
||||
|
||||
|
||||
/datum/dynamic_ruleset/minor/heretics/pre_execute()
|
||||
var/mob/picked_candidate = pick_n_take(candidates)
|
||||
assigned += picked_candidate.mind
|
||||
picked_candidate.mind.restricted_roles = restricted_roles
|
||||
picked_candidate.mind.special_role = ROLE_HERETIC
|
||||
var/datum/antagonist/heretic/new_antag = new antag_datum()
|
||||
picked_candidate.mind.add_antag_datum(new_antag)
|
||||
return TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// DEVIL //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/minor/devil
|
||||
name = "Devil"
|
||||
config_tag = "devil"
|
||||
antag_flag = ROLE_DEVIL
|
||||
antag_datum = /datum/antagonist/devil
|
||||
restricted_roles = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI")
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
cost = 0
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 101
|
||||
antag_cap = list(1,1,1,2,2,2,3,3,3,4)
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/minor/devil/pre_execute()
|
||||
var/mob/devil = pick_n_take(candidates)
|
||||
assigned += devil.mind
|
||||
devil.mind.special_role = ROLE_DEVIL
|
||||
devil.mind.restricted_roles = restricted_roles
|
||||
|
||||
log_game("[key_name(devil)] has been selected as a devil")
|
||||
add_devil(devil, ascendable = TRUE)
|
||||
add_devil_objectives(devil.mind,2)
|
||||
return TRUE
|
||||
|
||||
/datum/dynamic_ruleset/minor/devil/proc/add_devil_objectives(datum/mind/devil_mind, quantity)
|
||||
var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target)
|
||||
var/datum/antagonist/devil/D = devil_mind.has_antag_datum(/datum/antagonist/devil)
|
||||
for(var/i = 1 to quantity)
|
||||
var/type = pick(validtypes)
|
||||
var/datum/objective/devil/objective = new type(null)
|
||||
objective.owner = devil_mind
|
||||
D.objectives += objective
|
||||
if(!istype(objective, /datum/objective/devil/buy_target))
|
||||
validtypes -= type
|
||||
else
|
||||
objective.find_target()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// BLOODSUCKERS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/minor/bloodsucker
|
||||
name = "Bloodsuckers"
|
||||
config_tag = "bloodsucker"
|
||||
antag_flag = ROLE_BLOODSUCKER
|
||||
antag_datum = ANTAG_DATUM_BLOODSUCKER
|
||||
minimum_required_age = 0
|
||||
protected_roles = list("Chaplain", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
restricted_roles = list("Cyborg", "AI")
|
||||
required_candidates = 1
|
||||
weight = 2
|
||||
cost = 15
|
||||
scaling_cost = 10
|
||||
property_weights = list("story_potential" = 1, "extended" = 1, "trust" = -2, "valid" = 1)
|
||||
requirements = list(70,65,60,55,50,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
|
||||
/datum/dynamic_ruleset/minor/bloodsucker/execute()
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
assigned += M.mind
|
||||
M.mind.special_role = ROLE_BLOODSUCKER
|
||||
M.mind.restricted_roles = restricted_roles
|
||||
mode.check_start_sunlight()
|
||||
if(mode.make_bloodsucker(M.mind))
|
||||
mode.bloodsuckers += M.mind
|
||||
return TRUE
|
||||
@@ -15,6 +15,7 @@
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster", "Cyborg")
|
||||
restricted_roles = list("Cyborg", "AI")
|
||||
required_candidates = 1
|
||||
flags = TRAITOR_RULESET | MINOR_RULESET | ALWAYS_MAX_WEIGHT_RULESET
|
||||
weight = 5
|
||||
cost = 10 // Avoid raising traitor threat above 10, as it is the default low cost ruleset.
|
||||
scaling_cost = 10
|
||||
@@ -22,7 +23,6 @@
|
||||
high_population_requirement = 40
|
||||
antag_cap = list(1,1,1,1,2,2,2,2,3,3)
|
||||
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1, "valid" = 1)
|
||||
always_max_weight = TRUE
|
||||
var/autotraitor_cooldown = 450 // 15 minutes (ticks once per 2 sec)
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/traitor/pre_execute()
|
||||
@@ -57,6 +57,7 @@
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_candidates = 2
|
||||
flags = MINOR_RULESET
|
||||
weight = 4
|
||||
cost = 10
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
@@ -106,6 +107,7 @@
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_candidates = 1
|
||||
flags = MINOR_RULESET
|
||||
weight = 3
|
||||
cost = 15
|
||||
scaling_cost = 15
|
||||
@@ -156,6 +158,7 @@
|
||||
protected_roles = list("Prisoner","Security Officer", "Warden", "Detective", "Head of Security", "Captain")
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
required_candidates = 1
|
||||
flags = MINOR_RULESET
|
||||
weight = 3
|
||||
cost = 25
|
||||
scaling_cost = 15
|
||||
@@ -694,6 +697,7 @@
|
||||
antag_datum = /datum/antagonist/devil
|
||||
restricted_roles = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI")
|
||||
required_candidates = 1
|
||||
flags = MINOR_RULESET
|
||||
weight = 3
|
||||
cost = 0
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
@@ -850,6 +854,7 @@
|
||||
protected_roles = list("Chaplain", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
restricted_roles = list("Cyborg", "AI")
|
||||
required_candidates = 1
|
||||
flags = MINOR_RULESET
|
||||
weight = 2
|
||||
cost = 15
|
||||
scaling_cost = 10
|
||||
|
||||
@@ -32,6 +32,9 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
"conversion" -- Basically a bool. Conversion antags, well, convert. It's in its own class 'cause people kinda hate conversion.
|
||||
*/
|
||||
|
||||
/datum/dynamic_storyteller/proc/minor_start_chance()
|
||||
return clamp(60 - mode.threat_level,0,100) // by default higher threat = lower chance of minor round
|
||||
|
||||
/datum/dynamic_storyteller/proc/start_injection_cooldowns()
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_latejoin_delay_max + GLOB.dynamic_first_latejoin_delay_min)
|
||||
mode.latejoin_injection_cooldown = round(clamp(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_first_latejoin_delay_min, GLOB.dynamic_first_latejoin_delay_max)) + world.time
|
||||
@@ -104,8 +107,27 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
|
||||
/datum/dynamic_storyteller/proc/roundstart_draft()
|
||||
var/list/drafted_rules = list()
|
||||
var/minor_round_weight_mult = (100-minor_start_chance()) / 100
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in mode.roundstart_rules)
|
||||
if (rule.acceptable(mode.roundstart_pop_ready, mode.threat_level)) // If we got the population and threat required
|
||||
rule.candidates = mode.candidates.Copy()
|
||||
rule.trim_candidates()
|
||||
if (rule.ready() && rule.candidates.len > 0)
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights) // just treat it as 0 if it's not in there
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult
|
||||
if(CHECK_BITFIELD(rule.flags, MINOR_RULESET))
|
||||
calced_weight *= minor_round_weight_mult
|
||||
if(calced_weight > 0) // negatives in the list might cause problems
|
||||
drafted_rules[rule] = calced_weight
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/minor_rule_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/minor/rule in mode.minor_rules)
|
||||
if (rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level))
|
||||
rule.candidates = mode.candidates.Copy()
|
||||
rule.trim_candidates()
|
||||
if (rule.ready() && rule.candidates.len > 0)
|
||||
@@ -124,7 +146,7 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
// if there are antags OR the rule is an antag rule, antag_acceptable will be true.
|
||||
if (rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level))
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET)))
|
||||
continue
|
||||
rule.trim_candidates()
|
||||
if (rule.ready())
|
||||
@@ -133,7 +155,7 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
if(property in rule.property_weights) // just treat it as 0 if it's not in there
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
|
||||
if(!(rule.flags & TRAITOR_RULESET)) // makes the traitor rulesets always possible anyway
|
||||
var/cost_difference = rule.cost-(mode.threat_level-mode.threat)
|
||||
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
|
||||
pick this particular ruleset.
|
||||
@@ -157,7 +179,7 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
for (var/datum/dynamic_ruleset/latejoin/rule in mode.latejoin_rules)
|
||||
if (rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level - mode.threat))
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET)))
|
||||
continue
|
||||
// No stacking : only one round-ender, unless threat level > stacking_limit.
|
||||
if (mode.threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
@@ -172,7 +194,7 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))
|
||||
if(!(rule.flags & TRAITOR_RULESET))
|
||||
var/cost_difference = rule.cost-(mode.threat_level-mode.threat)
|
||||
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,abs(cost_difference),0)))
|
||||
if(cost_difference > 0)
|
||||
@@ -195,6 +217,9 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
min_players = 30
|
||||
var/refund_cooldown = 0
|
||||
|
||||
/datum/dynamic_storyteller/chaotic/minor_start_chance()
|
||||
return 0
|
||||
|
||||
/datum/dynamic_storyteller/chaotic/do_process()
|
||||
if(refund_cooldown < world.time)
|
||||
mode.create_threat(20)
|
||||
@@ -215,6 +240,9 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
flags = WAROPS_ALWAYS_ALLOWED | USE_PREV_ROUND_WEIGHTS
|
||||
property_weights = list("valid" = 3, "trust" = 5)
|
||||
|
||||
/datum/dynamic_storyteller/chaotic/minor_start_chance()
|
||||
return 0
|
||||
|
||||
/datum/dynamic_storyteller/team/should_inject_antag(dry_run = FALSE)
|
||||
return (mode.current_players[CURRENT_LIVING_ANTAGS].len ? FALSE : ..())
|
||||
|
||||
@@ -228,6 +256,9 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
flags = WAROPS_ALWAYS_ALLOWED
|
||||
property_weights = list("valid" = 1, "conversion" = 20)
|
||||
|
||||
/datum/dynamic_storyteller/chaotic/minor_start_chance()
|
||||
return 0
|
||||
|
||||
/datum/dynamic_storyteller/random
|
||||
name = "Random"
|
||||
config_tag = "random"
|
||||
@@ -244,6 +275,9 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
/datum/dynamic_storyteller/random/should_inject_antag()
|
||||
return prob(50)
|
||||
|
||||
/datum/dynamic_storyteller/chaotic/minor_start_chance()
|
||||
return 20
|
||||
|
||||
/datum/dynamic_storyteller/random/roundstart_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in mode.roundstart_rules)
|
||||
@@ -254,12 +288,22 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
drafted_rules[rule] = 1
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/random/minor_rule_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/minor/rule in mode.minor_rules)
|
||||
if (rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level))
|
||||
rule.candidates = mode.candidates.Copy()
|
||||
rule.trim_candidates()
|
||||
if (rule.ready() && rule.candidates.len > 0)
|
||||
drafted_rules[rule] = 1
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/random/midround_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/midround/rule in mode.midround_rules)
|
||||
if (rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level))
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET)))
|
||||
continue
|
||||
rule.trim_candidates()
|
||||
if (rule.ready())
|
||||
@@ -271,7 +315,7 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
for (var/datum/dynamic_ruleset/latejoin/rule in mode.latejoin_rules)
|
||||
if (rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level))
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET)))
|
||||
continue
|
||||
// No stacking : only one round-ender, unless threat level > stacking_limit.
|
||||
if (mode.threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
@@ -286,7 +330,7 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
/datum/dynamic_storyteller/story
|
||||
name = "Story"
|
||||
config_tag = "story"
|
||||
desc = "Antags with options for loadouts and gimmicks. Traitor, wizard, nukies. Has a buildup-climax-falling action threat curve."
|
||||
desc = "Antags with options for loadouts and gimmicks. Traitor, wizard, nukies."
|
||||
weight = 2
|
||||
curve_width = 2
|
||||
flags = USE_PREV_ROUND_WEIGHTS
|
||||
@@ -308,6 +352,19 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
flags = USE_PREV_ROUND_WEIGHTS
|
||||
property_weights = list("trust" = -2)
|
||||
|
||||
/datum/dynamic_storyteller/intrigue/minor_start_chance()
|
||||
return 100 - mode.threat_level
|
||||
|
||||
/datum/dynamic_storyteller/grabbag
|
||||
name = "Grab Bag"
|
||||
config_tag = "grabbag"
|
||||
desc = "Crew antags (e.g. traitor, changeling, bloodsucker, heretic) only, all mixed together."
|
||||
weight = 2
|
||||
flags = USE_PREF_WEIGHTS | USE_PREV_ROUND_WEIGHTS
|
||||
|
||||
/datum/dynamic_storyteller/grabbag/minor_start_chance()
|
||||
return 100
|
||||
|
||||
/datum/dynamic_storyteller/liteextended
|
||||
name = "Calm"
|
||||
config_tag = "calm"
|
||||
@@ -319,6 +376,9 @@ Property weights are added to the config weight of the ruleset. They are:
|
||||
dead_player_weight = 5
|
||||
property_weights = list("extended" = 2, "chaos" = -1, "valid" = -1, "conversion" = -10)
|
||||
|
||||
/datum/dynamic_storyteller/liteextended/minor_start_chance()
|
||||
return 100
|
||||
|
||||
/datum/dynamic_storyteller/no_antag
|
||||
name = "Extended"
|
||||
config_tag = "semiextended"
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
|
||||
if(gangtool)//Here is where all of the text occurs when a gang boss first spawns in.
|
||||
var/obj/item/device/gangtool/G = new()
|
||||
var/where = H.equip_in_one_of_slots(G, slots)
|
||||
var/where = H.equip_in_one_of_slots(G, slots, critical = TRUE)
|
||||
if (!where)
|
||||
to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a Gangtool.")
|
||||
else
|
||||
@@ -207,7 +207,7 @@
|
||||
|
||||
if(pen)
|
||||
var/obj/item/pen/gang/T = new()
|
||||
var/where2 = H.equip_in_one_of_slots(T, slots)
|
||||
var/where2 = H.equip_in_one_of_slots(T, slots, critical = TRUE)
|
||||
if (!where2)
|
||||
to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a recruitment pen to start.")
|
||||
else
|
||||
@@ -215,7 +215,7 @@
|
||||
|
||||
if(spraycan)
|
||||
var/obj/item/toy/crayon/spraycan/gang/SC = new(null,gang)
|
||||
var/where3 = H.equip_in_one_of_slots(SC, slots)
|
||||
var/where3 = H.equip_in_one_of_slots(SC, slots, critical = TRUE)
|
||||
if (!where3)
|
||||
to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a territory spraycan to start.")
|
||||
else
|
||||
@@ -223,7 +223,7 @@
|
||||
|
||||
if(hud)
|
||||
var/obj/item/clothing/glasses/hud/security/chameleon/C = new(null,gang)
|
||||
var/where4 = H.equip_in_one_of_slots(C, slots)
|
||||
var/where4 = H.equip_in_one_of_slots(C, slots, critical = TRUE)
|
||||
if (!where4)
|
||||
to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a chameleon security HUD.")
|
||||
else
|
||||
|
||||
@@ -166,7 +166,7 @@ If not set, defaults to check_completion instead. Set it. It's used by cryo.
|
||||
var/list/slots = list("backpack" = SLOT_IN_BACKPACK)
|
||||
for(var/eq_path in special_equipment)
|
||||
var/obj/O = new eq_path
|
||||
H.equip_in_one_of_slots(O, slots)
|
||||
H.equip_in_one_of_slots(O, slots, critical = TRUE)
|
||||
|
||||
/datum/objective/assassinate
|
||||
name = "assasinate"
|
||||
@@ -1152,7 +1152,7 @@ GLOBAL_LIST_EMPTY(cult_contraband)
|
||||
I.forceMove(get_turf(owner))
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.equip_in_one_of_slots(I, list("backpack" = SLOT_IN_BACKPACK))
|
||||
H.equip_in_one_of_slots(I, list("backpack" = SLOT_IN_BACKPACK), critical = TRUE)
|
||||
hoarded_item = I
|
||||
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ GLOBAL_LIST_EMPTY(announcement_systems)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!usr.canUseTopic(src, !issilicon(usr)))
|
||||
if(!usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
|
||||
return
|
||||
if(stat & BROKEN)
|
||||
visible_message("<span class='warning'>[src] buzzes.</span>", "<span class='hear'>You hear a faint buzz.</span>")
|
||||
@@ -147,7 +147,7 @@ GLOBAL_LIST_EMPTY(announcement_systems)
|
||||
. = attack_ai(user)
|
||||
|
||||
/obj/machinery/announcement_system/attack_ai(mob/user)
|
||||
if(!user.canUseTopic(src, !issilicon(user)))
|
||||
if(!user.canUseTopic(src, !hasSiliconAccessInArea(user)))
|
||||
return
|
||||
if(stat & BROKEN)
|
||||
to_chat(user, "<span class='warning'>[src]'s firmware appears to be malfunctioning!</span>")
|
||||
@@ -167,7 +167,9 @@ GLOBAL_LIST_EMPTY(announcement_systems)
|
||||
act_up()
|
||||
|
||||
/obj/machinery/announcement_system/emag_act()
|
||||
. = ..()
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
act_up()
|
||||
return TRUE
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
return
|
||||
if(R.scrambledcodes)
|
||||
return
|
||||
if(hasSiliconAccessInArea(user) && !issilicon(user))
|
||||
if(!Adjacent(user))
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/robotics/ui_interact(mob/user, datum/tgui/ui)
|
||||
@@ -40,6 +43,10 @@
|
||||
else if(IsAdminGhost(user))
|
||||
data["can_hack"] = TRUE
|
||||
|
||||
data["can_convert"] = FALSE
|
||||
if(isAI(user) && is_servant_of_ratvar(user))
|
||||
data["can_convert"] = TRUE
|
||||
|
||||
data["cyborgs"] = list()
|
||||
for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs)
|
||||
if(!can_control(user, R))
|
||||
@@ -54,6 +61,7 @@
|
||||
module = R.module ? "[R.module.name] Module" : "No Module Detected",
|
||||
synchronization = R.connected_ai,
|
||||
emagged = R.emagged,
|
||||
servant = is_servant_of_ratvar(R),
|
||||
ref = REF(R)
|
||||
)
|
||||
data["cyborgs"] += list(cyborg_data)
|
||||
@@ -110,6 +118,13 @@
|
||||
log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!")
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] emagged cyborg [key_name_admin(R)] using robotic console!")
|
||||
R.SetEmagged(TRUE)
|
||||
if("convert")
|
||||
if(isAI(usr) && is_servant_of_ratvar(usr))
|
||||
var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs
|
||||
if(istype(R) && !is_servant_of_ratvar(R) && R.connected_ai == usr)
|
||||
log_game("[key_name(usr)] converted [key_name(R)] using robotic console!")
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] converted cyborg [key_name_admin(R)] using robotic console!")
|
||||
add_servant_of_ratvar(R)
|
||||
if("killdrone")
|
||||
if(allowed(usr))
|
||||
var/mob/living/simple_animal/drone/D = locate(params["ref"]) in GLOB.mob_list
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
. = ..()
|
||||
if(in_range(user, src) || isobserver(user))
|
||||
. += "<span class='notice'>The status display reads: Radiation pulse accuracy increased by factor <b>[precision_coeff**2]</b>.<br>Radiation pulse damage decreased by factor <b>[damage_coeff**2]</b>.</span>"
|
||||
if(scan_level >= 3)
|
||||
. += "<span class='notice'>Scanner has been upgraded to support autoprocessing.</span>"
|
||||
|
||||
/obj/machinery/dna_scannernew/update_icon_state()
|
||||
//no power or maintenance
|
||||
@@ -94,6 +96,13 @@
|
||||
|
||||
..(user)
|
||||
|
||||
// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
|
||||
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
|
||||
if(istype(mob_occupant))
|
||||
if(locate_computer(/obj/machinery/computer/cloning))
|
||||
if(!mob_occupant.suiciding && !(HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && !mob_occupant.hellbound)
|
||||
mob_occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src)
|
||||
|
||||
// DNA manipulators cannot operate on severed heads or brains
|
||||
if(iscarbon(occupant))
|
||||
if(linked_console)
|
||||
|
||||
@@ -1457,6 +1457,16 @@
|
||||
ui.open()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/door/airlock/ui_status(mob/user)
|
||||
. = ..()
|
||||
if (!issilicon(user) && hasSiliconAccessInArea(user))
|
||||
. = UI_INTERACTIVE
|
||||
|
||||
/obj/machinery/door/airlock/can_interact(mob/user)
|
||||
. = ..()
|
||||
if (!issilicon(user) && hasSiliconAccessInArea(user))
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/door/airlock/ui_data()
|
||||
var/list/data = list()
|
||||
|
||||
|
||||
@@ -508,7 +508,7 @@
|
||||
/obj/machinery/door/airlock/cult/allowed(mob/living/L)
|
||||
if(!density)
|
||||
return 1
|
||||
if(friendly || iscultist(L) || istype(L, /mob/living/simple_animal/shade) || isconstruct(L))
|
||||
if(friendly || iscultist(L) || isshade(L) || isconstruct(L))
|
||||
if(!stealthy)
|
||||
new openingoverlaytype(loc)
|
||||
return 1
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
if(!do_after(user, 30 SECONDS, TRUE, src))
|
||||
to_chat(user, "<span class='warning'>Your fingers slip as you fail to pry the [stored] from the [src], clicking it right back into the slot!</span>")
|
||||
return
|
||||
if(user.put_in_hands(stored))
|
||||
stored.forceMove(user.drop_location())
|
||||
user.put_in_hands(stored)
|
||||
to_chat(user, "<span class='warning'>You successfully pry the [stored] from the [src]\
|
||||
[user.is_holding(stored) ? "" : ", and send its overwhelming weight tumbling onto the ground"]! The tapes on the [src] stop spinning...</span>")
|
||||
stored = null
|
||||
to_chat(user, "<span class='warning'>You successfully pry the [stored] from the [src], and send its overwhelming weight tumbling onto the ground! The tapes on the [src] stop spinning...</span>")
|
||||
update_icon()
|
||||
return
|
||||
else
|
||||
@@ -41,7 +41,7 @@
|
||||
/obj/machinery/blackbox_recorder/attackby(obj/item/I, mob/living/user, params)
|
||||
. = ..()
|
||||
if(istype(I, /obj/item/blackbox))
|
||||
if(HAS_TRAIT(I, TRAIT_NODROP) || !user.transferItemToLoc(I, src))
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
to_chat(user, "<span class='warning'>[I] is stuck to your hand!</span>")
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user] clicks the [I] into the [src]!</span>", \
|
||||
|
||||
@@ -160,13 +160,13 @@
|
||||
/obj/effect/spawner/bundle/costume/sexyclown
|
||||
name = "sexy clown costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/mask/gas/sexyclown,
|
||||
/obj/item/clothing/mask/gas/clown_hat/sexy,
|
||||
/obj/item/clothing/under/rank/civilian/clown/sexy)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/sexymime
|
||||
name = "sexy mime costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/mask/gas/sexymime,
|
||||
/obj/item/clothing/mask/gas/mime/sexy,
|
||||
/obj/item/clothing/under/rank/civilian/mime/sexy)
|
||||
|
||||
/obj/effect/spawner/bundle/crate/Initialize(mapload)
|
||||
|
||||
@@ -464,7 +464,7 @@
|
||||
/obj/effect/spawner/lootdrop/cigars_cases/no_turf = 2,
|
||||
/obj/effect/spawner/lootdrop/space_cash/no_turf = 5,
|
||||
/obj/item/reagent_containers/food/snacks/grown/cannabis = 5,
|
||||
/obj/item/storage/box/dice = 5,
|
||||
/obj/item/storage/dice = 5,
|
||||
/obj/item/toy/cards/deck = 5,
|
||||
/obj/effect/spawner/lootdrop/druggie_pill/no_turf = 5
|
||||
)
|
||||
@@ -483,7 +483,7 @@
|
||||
/obj/effect/spawner/lootdrop/cig_packs/no_turf = 10,
|
||||
/obj/effect/spawner/lootdrop/cigars_cases/no_turf = 5,
|
||||
/obj/item/reagent_containers/food/snacks/grown/cannabis = 5,
|
||||
/obj/item/storage/box/dice = 5,
|
||||
/obj/item/storage/dice = 5,
|
||||
/obj/item/toy/cards/deck = 5,
|
||||
/obj/effect/spawner/lootdrop/druggie_pill/no_turf = 5,
|
||||
/obj/item/kitchen/knife = 5,
|
||||
|
||||
@@ -93,7 +93,7 @@ RSF
|
||||
use_matter(50, user)
|
||||
if(4)
|
||||
to_chat(user, "Dispensing Dice Pack...")
|
||||
new /obj/item/storage/box/dice(T)
|
||||
new /obj/item/storage/dice(T)
|
||||
use_matter(200, user)
|
||||
if(5)
|
||||
to_chat(user, "Dispensing Cigarette...")
|
||||
|
||||
@@ -616,7 +616,7 @@
|
||||
if(defib.healdisk)
|
||||
H.heal_overall_damage(25, 25)
|
||||
var/list/policies = CONFIG_GET(keyed_list/policyconfig)
|
||||
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit)
|
||||
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds
|
||||
var/late = timelimit && (tplus > timelimit)
|
||||
var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT]
|
||||
if(policy)
|
||||
|
||||
@@ -1,39 +1,38 @@
|
||||
/obj/item/storage/box/dice
|
||||
/*****************************Dice Bags********************************/
|
||||
|
||||
/obj/item/storage/dice
|
||||
name = "bag of dice"
|
||||
desc = "Contains all the luck you'll ever need."
|
||||
icon = 'icons/obj/dice.dmi'
|
||||
icon_state = "dicebag"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
var/list/special_die = list(
|
||||
/obj/item/dice/d1,
|
||||
/obj/item/dice/d2,
|
||||
/obj/item/dice/fudge,
|
||||
/obj/item/dice/d6/space,
|
||||
/obj/item/dice/d00,
|
||||
/obj/item/dice/eightbd20,
|
||||
/obj/item/dice/fourdd6,
|
||||
/obj/item/dice/d100
|
||||
)
|
||||
|
||||
/obj/item/storage/box/dice/Initialize()
|
||||
. = ..()
|
||||
var/special_die = pick("1","2","fudge","space","00","8bd20","4dd6","100")
|
||||
if(special_die == "1")
|
||||
new /obj/item/dice/d1(src)
|
||||
if(special_die == "2")
|
||||
new /obj/item/dice/d2(src)
|
||||
/obj/item/storage/dice/PopulateContents()
|
||||
new /obj/item/dice/d4(src)
|
||||
new /obj/item/dice/d6(src)
|
||||
if(special_die == "fudge")
|
||||
new /obj/item/dice/fudge(src)
|
||||
if(special_die == "space")
|
||||
new /obj/item/dice/d6/space(src)
|
||||
new /obj/item/dice/d8(src)
|
||||
new /obj/item/dice/d10(src)
|
||||
if(special_die == "00")
|
||||
new /obj/item/dice/d00(src)
|
||||
new /obj/item/dice/d12(src)
|
||||
new /obj/item/dice/d20(src)
|
||||
if(special_die == "8bd20")
|
||||
new /obj/item/dice/eightbd20(src)
|
||||
if(special_die == "4dd6")
|
||||
new /obj/item/dice/fourdd6(src)
|
||||
if(special_die == "100")
|
||||
new /obj/item/dice/d100(src)
|
||||
var/picked = pick(special_die)
|
||||
new picked(src)
|
||||
|
||||
/obj/item/storage/box/dice/suicide_act(mob/user)
|
||||
/obj/item/storage/dice/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is gambling with death! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (OXYLOSS)
|
||||
|
||||
/*****************************Dice********************************/
|
||||
|
||||
/obj/item/dice //depreciated d6, use /obj/item/dice/d6 if you actually want a d6
|
||||
name = "die"
|
||||
desc = "A die with six sides. Basic and serviceable."
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
* Gifts
|
||||
*/
|
||||
|
||||
/var/static/blacklisted_items = typecacheof(list(
|
||||
/obj/effect,
|
||||
/obj/belly,
|
||||
/obj/mafia_game_board,
|
||||
/obj/docking_port,
|
||||
/obj/shapeshift_holder,
|
||||
/obj/screen))
|
||||
|
||||
GLOBAL_LIST_EMPTY(possible_gifts)
|
||||
|
||||
/obj/item/a_gift
|
||||
@@ -95,7 +103,7 @@ GLOBAL_LIST_EMPTY(possible_gifts)
|
||||
var/list/gift_types_list = subtypesof(/obj/item)
|
||||
for(var/V in gift_types_list)
|
||||
var/obj/item/I = V
|
||||
if((!initial(I.icon_state)) || (!initial(I.item_state)) || (initial(I.item_flags) & ABSTRACT))
|
||||
if((!initial(I.icon_state)) || (!initial(I.item_state)) || (initial(I.item_flags) & ABSTRACT) || (is_type_in_typecache(I, blacklisted_items)))
|
||||
gift_types_list -= V
|
||||
GLOB.possible_gifts = gift_types_list
|
||||
var/gift_type = pick(GLOB.possible_gifts)
|
||||
|
||||
@@ -492,7 +492,7 @@
|
||||
var/possessed = FALSE
|
||||
|
||||
/obj/item/nullrod/scythe/talking/process()
|
||||
for(var/mob/living/simple_animal/shade/S in contents)
|
||||
for(var/mob/living/simple_animal/hostile/construct/shade/S in contents)
|
||||
if(S.mind)
|
||||
return
|
||||
else
|
||||
@@ -516,7 +516,7 @@
|
||||
|
||||
if(LAZYLEN(candidates))
|
||||
var/mob/C = pick(candidates)
|
||||
var/mob/living/simple_animal/shade/S = new(src)
|
||||
var/mob/living/simple_animal/hostile/construct/shade/S = new(src)
|
||||
S.real_name = name
|
||||
S.name = name
|
||||
S.ckey = C.ckey
|
||||
@@ -537,7 +537,7 @@
|
||||
possessed = FALSE
|
||||
|
||||
/obj/item/nullrod/scythe/talking/Destroy()
|
||||
for(var/mob/living/simple_animal/shade/S in contents)
|
||||
for(var/mob/living/simple_animal/hostile/construct/shade/S in contents)
|
||||
to_chat(S, "You were destroyed!")
|
||||
qdel(S)
|
||||
return ..()
|
||||
|
||||
@@ -92,10 +92,17 @@
|
||||
/obj/item/implant/hijack/proc/hijack_remotely(obj/machinery/power/apc/apc)
|
||||
if (apc.hijacker || hijacking)
|
||||
return FALSE //can't remotely hijack an already hijacked APC
|
||||
|
||||
if(apc.being_hijacked)
|
||||
to_chat(imp_in, "<span class='warning'>This APC is already being hijacked!</span>")
|
||||
return FALSE
|
||||
|
||||
apc.being_hijacked = TRUE
|
||||
hijacking = TRUE
|
||||
to_chat(imp_in, "<span class='notice'>Establishing remote connection with APC.</span>")
|
||||
if (!do_after(imp_in, 4 SECONDS,target=apc))
|
||||
to_chat(imp_in, "<span class='warning'>Aborting.</span>")
|
||||
apc.being_hijacked = FALSE
|
||||
hijacking = FALSE
|
||||
return TRUE
|
||||
if (LAZYLEN(imp_in.siliconaccessareas) >= HIJACK_APC_MAX_AMOUNT)
|
||||
@@ -118,6 +125,7 @@
|
||||
toggle_eyes()
|
||||
else
|
||||
to_chat(imp_in, "<span class='warning'>Aborting.</span>")
|
||||
apc.being_hijacked = FALSE
|
||||
hijacking = FALSE
|
||||
imp_in.light_power = 0
|
||||
imp_in.light_range = 0
|
||||
|
||||
@@ -150,8 +150,8 @@
|
||||
item_state = "knife"
|
||||
desc = "A military combat utility survival knife."
|
||||
embedding = list("pain_mult" = 4, "embed_chance" = 65, "fall_chance" = 10, "ignore_throwspeed_threshold" = TRUE)
|
||||
force = 20
|
||||
throwforce = 20
|
||||
force = 16
|
||||
throwforce = 16
|
||||
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "cut")
|
||||
bayonet = TRUE
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
|
||||
if(istype(A, /obj/item/cult_bastard))
|
||||
for(var/obj/item/soulstone/SS in A.contents)
|
||||
SS.usability = TRUE
|
||||
for(var/mob/living/simple_animal/shade/EX in SS)
|
||||
for(var/mob/living/simple_animal/hostile/construct/shade/EX in SS)
|
||||
SSticker.mode.remove_cultist(EX.mind, 1, 0)
|
||||
EX.icon_state = "ghost1"
|
||||
EX.name = "Purified [EX.name]"
|
||||
@@ -217,7 +217,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
|
||||
if(do_after(user, 40, target = SS))
|
||||
playsound(src,'sound/effects/pray_chaplain.ogg',60,1)
|
||||
SS.usability = TRUE
|
||||
for(var/mob/living/simple_animal/shade/EX in SS)
|
||||
for(var/mob/living/simple_animal/hostile/construct/shade/EX in SS)
|
||||
SSticker.mode.remove_cultist(EX.mind, 1, 0)
|
||||
EX.icon_state = "ghost1"
|
||||
EX.name = "Purified [EX.name]"
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
var/self_fueling = FALSE //Do we refill ourselves or not
|
||||
var/nextrefueltick = 0 // How long it takes before we get a new fuel unit
|
||||
|
||||
custom_materials = list(/datum/material/iron=70, /datum/material/glass=30)
|
||||
var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2)
|
||||
var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower)
|
||||
@@ -82,12 +85,18 @@
|
||||
//This is to start fires. process() is only called if the welder is on.
|
||||
open_flame()
|
||||
|
||||
//This handles refueling. Its looking at how much fuel the tool has and comparing that to how much it holds
|
||||
//This then looks if the refuel tick has come based on world time.
|
||||
//Then looks if we refuel ourselves or not.
|
||||
|
||||
if(get_fuel() < max_fuel && nextrefueltick < world.time && self_fueling)
|
||||
nextrefueltick = world.time + 10
|
||||
reagents.add_reagent(/datum/reagent/fuel, 1)
|
||||
|
||||
/obj/item/weldingtool/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (FIRELOSS)
|
||||
|
||||
|
||||
/obj/item/weldingtool/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
flamethrower_screwdriver(I, user)
|
||||
@@ -318,7 +327,6 @@
|
||||
/obj/item/weldingtool/largetank/flamethrower_screwdriver()
|
||||
return
|
||||
|
||||
|
||||
/obj/item/weldingtool/mini
|
||||
name = "emergency welding tool"
|
||||
desc = "A miniature welder used during emergencies."
|
||||
@@ -331,20 +339,6 @@
|
||||
/obj/item/weldingtool/mini/flamethrower_screwdriver()
|
||||
return
|
||||
|
||||
/obj/item/weldingtool/abductor
|
||||
name = "alien welding tool"
|
||||
desc = "An alien welding tool. Whatever fuel it uses, it never runs out."
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "welder"
|
||||
toolspeed = 0.1
|
||||
light_intensity = 0
|
||||
change_icons = 0
|
||||
|
||||
/obj/item/weldingtool/abductor/process()
|
||||
if(get_fuel() <= max_fuel)
|
||||
reagents.add_reagent(/datum/reagent/fuel, 1)
|
||||
..()
|
||||
|
||||
/obj/item/weldingtool/hugetank
|
||||
name = "upgraded industrial welding tool"
|
||||
desc = "An upgraded welder based of the industrial welder."
|
||||
@@ -353,27 +347,6 @@
|
||||
max_fuel = 80
|
||||
custom_materials = list(/datum/material/iron=70, /datum/material/glass=120)
|
||||
|
||||
/obj/item/weldingtool/experimental
|
||||
name = "experimental welding tool"
|
||||
desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes."
|
||||
icon_state = "exwelder"
|
||||
item_state = "exwelder"
|
||||
max_fuel = 40
|
||||
custom_materials = list(/datum/material/iron=70, /datum/material/glass=120)
|
||||
var/last_gen = 0
|
||||
change_icons = 0
|
||||
can_off_process = 1
|
||||
light_intensity = 1
|
||||
toolspeed = 0.5
|
||||
var/nextrefueltick = 0
|
||||
|
||||
/obj/item/weldingtool/experimental/brass
|
||||
name = "brass welding tool"
|
||||
desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch."
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
icon_state = "clockwelder"
|
||||
item_state = "brasswelder"
|
||||
|
||||
/obj/item/weldingtool/bronze
|
||||
name = "bronze plated welding tool"
|
||||
desc = "A bronze plated welder."
|
||||
@@ -382,24 +355,46 @@
|
||||
icon_state = "brasswelder"
|
||||
item_state = "brasswelder"
|
||||
|
||||
/obj/item/weldingtool/experimental/process()
|
||||
..()
|
||||
if(get_fuel() < max_fuel && nextrefueltick < world.time)
|
||||
nextrefueltick = world.time + 10
|
||||
reagents.add_reagent(/datum/reagent/fuel, 1)
|
||||
//Self filling welders below
|
||||
|
||||
/obj/item/weldingtool/experimental
|
||||
name = "experimental welding tool"
|
||||
desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes."
|
||||
icon_state = "exwelder"
|
||||
item_state = "exwelder"
|
||||
max_fuel = 40
|
||||
custom_materials = list(/datum/material/iron=70, /datum/material/glass=120)
|
||||
change_icons = 0
|
||||
self_fueling = TRUE
|
||||
can_off_process = 1
|
||||
light_intensity = 1
|
||||
toolspeed = 0.5
|
||||
|
||||
/obj/item/weldingtool/experimental/brass
|
||||
name = "brass welding tool"
|
||||
desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch."
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
icon_state = "clockwelder"
|
||||
item_state = "brasswelder"
|
||||
|
||||
/obj/item/weldingtool/abductor
|
||||
name = "alien welding tool"
|
||||
desc = "An alien welding tool. Whatever fuel it uses, it never runs out."
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "welder"
|
||||
self_fueling = TRUE
|
||||
toolspeed = 0.1
|
||||
light_intensity = 0
|
||||
change_icons = 0
|
||||
|
||||
/obj/item/weldingtool/advanced
|
||||
name = "advanced welding tool"
|
||||
desc = "A modern welding tool combined with an alien welding tool, it never runs out of fuel and works almost as fast."
|
||||
icon = 'icons/obj/advancedtools.dmi'
|
||||
icon_state = "welder"
|
||||
self_fueling = TRUE
|
||||
toolspeed = 0.2
|
||||
light_intensity = 0
|
||||
change_icons = 0
|
||||
|
||||
/obj/item/weldingtool/advanced/process()
|
||||
if(get_fuel() <= max_fuel)
|
||||
reagents.add_reagent(/datum/reagent/fuel, 1)
|
||||
..()
|
||||
|
||||
#undef WELDER_FUEL_BURN_INTERVAL
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -508,7 +508,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
|
||||
|
||||
@@ -684,10 +684,10 @@
|
||||
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 = 9 // first, do harm. all of it. all of the harm. just fuck em up.
|
||||
wound_enhancement = 9
|
||||
var/fast_enhancement = 9
|
||||
var/fast_wound_enhancement = 9
|
||||
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 = 20
|
||||
var/slow_wound_enhancement = 20
|
||||
silent = TRUE
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
var/T = new item_path(mob)
|
||||
var/item_name = initial(item_path.name)
|
||||
var/where = mob.equip_in_one_of_slots(T, slots)
|
||||
var/where = mob.equip_in_one_of_slots(T, slots, critical = TRUE)
|
||||
if(!where)
|
||||
to_chat(mob, "<span class='userdanger'>Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).</span>")
|
||||
return 0
|
||||
@@ -295,6 +295,8 @@
|
||||
++cultplayers
|
||||
else
|
||||
++alive
|
||||
if(!alive)
|
||||
return
|
||||
var/ratio = cultplayers/alive
|
||||
if(ratio > CULT_RISEN && !cult_risen)
|
||||
for(var/datum/mind/B in members)
|
||||
|
||||
@@ -82,7 +82,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
|
||||
fail_invoke()
|
||||
|
||||
/obj/effect/rune/attack_animal(mob/living/simple_animal/M)
|
||||
if(istype(M, /mob/living/simple_animal/shade) || istype(M, /mob/living/simple_animal/hostile/construct))
|
||||
if(isshade(M) || istype(M, /mob/living/simple_animal/hostile/construct))
|
||||
if(construct_invoke || !iscultist(M)) //if you're not a cult construct we want the normal fail message
|
||||
attack_hand(M)
|
||||
else
|
||||
@@ -191,7 +191,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
/obj/effect/rune/convert/do_invoke_glow()
|
||||
return
|
||||
|
||||
/obj/effect/rune/convert/invoke(var/list/invokers)
|
||||
/obj/effect/rune/convert/invoke(list/invokers)
|
||||
if(rune_in_use)
|
||||
return
|
||||
var/list/myriad_targets = list()
|
||||
@@ -203,11 +203,16 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
fail_invoke()
|
||||
log_game("Offer rune failed - no eligible targets")
|
||||
return
|
||||
var/mob/living/L = pick(myriad_targets)
|
||||
if(HAS_TRAIT(L, TRAIT_SACRIFICED))
|
||||
fail_invoke()
|
||||
log_game("Offer rune failed - target has already been sacrificed")
|
||||
to_chat(invokers, "<span class='warning'>[L] has already been sacrificed!</span>")
|
||||
return
|
||||
rune_in_use = TRUE
|
||||
visible_message("<span class='warning'>[src] pulses blood red!</span>")
|
||||
var/oldcolor = color
|
||||
color = RUNE_COLOR_DARKRED
|
||||
var/mob/living/L = pick(myriad_targets)
|
||||
var/is_clock = is_servant_of_ratvar(L)
|
||||
|
||||
var/mob/living/F = invokers[1]
|
||||
@@ -264,7 +269,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
H.uncuff()
|
||||
H.stuttering = 0
|
||||
H.cultslurring = 0
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
|
||||
var/mob/living/first_invoker = invokers[1]
|
||||
@@ -308,12 +313,16 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
stone.invisibility = 0
|
||||
|
||||
if(sacrificial)
|
||||
ADD_TRAIT(sacrificial, TRAIT_SACRIFICED, "sacrificed")
|
||||
if(iscyborg(sacrificial))
|
||||
playsound(sacrificial, 'sound/magic/disable_tech.ogg', 100, 1)
|
||||
sacrificial.dust() //To prevent the MMI from remaining
|
||||
else
|
||||
playsound(sacrificial, 'sound/magic/disintegrate.ogg', 100, 1)
|
||||
sacrificial.gib()
|
||||
var/mob/living/silicon/robot/bot = sacrificial
|
||||
playsound(sacrificial, 'sound/magic/disable_tech.ogg', 100, TRUE)
|
||||
bot.deconstruct()
|
||||
|
||||
else if(ishuman(sacrificial))
|
||||
playsound(sacrificial, 'sound/magic/disintegrate.ogg', 100, TRUE)
|
||||
var/mob/living/carbon/human/H = sacrificial
|
||||
H.spew_organ(2, 6)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/rune/empower
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
var/T = new item_path(H)
|
||||
var/item_name = initial(item_path.name)
|
||||
var/where = H.equip_in_one_of_slots(T, slots)
|
||||
var/where = H.equip_in_one_of_slots(T, slots, critical = TRUE)
|
||||
if(!where)
|
||||
to_chat(H, "<span class='userdanger'>Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).</span>")
|
||||
return FALSE
|
||||
|
||||
@@ -131,14 +131,14 @@
|
||||
"left pocket" = SLOT_L_STORE,
|
||||
"right pocket" = SLOT_R_STORE
|
||||
)
|
||||
var/where = H.equip_in_one_of_slots(O, slots)
|
||||
var/where = H.equip_in_one_of_slots(O, slots, critical = TRUE)
|
||||
if (!where)
|
||||
to_chat(H, "The Syndicate were unfortunately unable to get you the AI module.")
|
||||
else
|
||||
to_chat(H, "Use the AI board in your [where] to take control of the AI, as requested by the Syndicate.")
|
||||
// Give the implant converter
|
||||
var/obj/item/overthrow_converter/I = new(H)
|
||||
where = H.equip_in_one_of_slots(I, slots)
|
||||
where = H.equip_in_one_of_slots(I, slots, critical = TRUE)
|
||||
if (!where)
|
||||
to_chat(H, "The Syndicate were unfortunately unable to get you a converter implant.")
|
||||
else
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
"left pocket" = SLOT_L_STORE,
|
||||
"right pocket" = SLOT_R_STORE
|
||||
)
|
||||
var/where = H.equip_in_one_of_slots(T, slots)
|
||||
var/where = H.equip_in_one_of_slots(T, slots, critical = TRUE)
|
||||
if (!where)
|
||||
to_chat(H, "The Syndicate were unfortunately unable to get you a flash.")
|
||||
else
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
)
|
||||
|
||||
var/where = "At your feet"
|
||||
var/equipped_slot = mob.equip_in_one_of_slots(folder, slots)
|
||||
var/equipped_slot = mob.equip_in_one_of_slots(folder, slots, critical = TRUE)
|
||||
if (equipped_slot)
|
||||
where = "In your [equipped_slot]"
|
||||
to_chat(mob, "<BR><BR><span class='info'>[where] is a folder containing <b>secret documents</b> that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.</span><BR>")
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
/obj/item/soulstone/examine(mob/user)
|
||||
. = ..()
|
||||
if(usability || iscultist(user, TRUE) || iswizard(user) || isobserver(user))
|
||||
if(usability || iscultist(user) || iswizard(user) || isobserver(user))
|
||||
if (old_shard)
|
||||
. += "<span class='cult'>A soulstone, used to capture a soul, either from dead humans or from freed shades.</span>"
|
||||
else
|
||||
@@ -46,7 +46,7 @@
|
||||
. += "<span class='cult'>This shard is spent; it is now just a creepy rock.</span>"
|
||||
|
||||
/obj/item/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle.
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
for(var/mob/living/simple_animal/hostile/construct/shade/A in src)
|
||||
A.death()
|
||||
return ..()
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
|
||||
return
|
||||
if(spent)
|
||||
to_chat(user, "<span class='warning'>There is no power left in the shard.</span>")
|
||||
to_chat(user, "<span class='warning'>There is no power left in [src].</span>")
|
||||
return
|
||||
if(!ishuman(M))//If target is not a human.
|
||||
return ..()
|
||||
@@ -81,7 +81,7 @@
|
||||
release_shades(user)
|
||||
|
||||
/obj/item/soulstone/proc/release_shades(mob/user)
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
for(var/mob/living/simple_animal/hostile/construct/shade/A in src)
|
||||
A.status_flags &= ~GODMODE
|
||||
A.forceMove(get_turf(user))
|
||||
A.mobility_flags = MOBILITY_FLAGS_DEFAULT
|
||||
@@ -103,12 +103,12 @@
|
||||
|
||||
/obj/structure/constructshell/examine(mob/user)
|
||||
. = ..()
|
||||
if(iscultist(user, TRUE) || iswizard(user) || user.stat == DEAD)
|
||||
. += "<span class='cult'>A construct shell, used to house bound souls from a soulstone.</span>"
|
||||
. += "<span class='cult'>Placing a soulstone with a soul into this shell allows you to produce your choice of the following:</span>"
|
||||
. += "<span class='cult'>An <b>Artificer</b>, which can produce <b>more shells and soulstones</b>, as well as fortifications.</span>"
|
||||
. += "<span class='cult'>A <b>Wraith</b>, which does high damage and can jaunt through walls, though it is quite fragile.</span>"
|
||||
. += "<span class='cult'>A <b>Juggernaut</b>, which is very hard to kill and can produce temporary walls, but is slow.</span>"
|
||||
if(iscultist(user) || iswizard(user) || user.stat == DEAD)
|
||||
. += {"<span class='cult'>A construct shell, used to house bound souls from a soulstone.\n
|
||||
Placing a soulstone with a soul into this shell allows you to produce your choice of the following:\n
|
||||
An <b>Artificer</b>, which can produce <b>more shells and soulstones</b>, as well as fortifications.\n
|
||||
A <b>Wraith</b>, which does high damage and can jaunt through walls, though it is quite fragile.\n
|
||||
A <b>Juggernaut</b>, which is very hard to kill and can produce temporary walls, but is slow.</span>"}
|
||||
|
||||
/obj/structure/constructshell/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/soulstone))
|
||||
@@ -145,14 +145,14 @@
|
||||
if("VICTIM")
|
||||
var/mob/living/carbon/human/T = target
|
||||
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if(C && C.cult_team?.is_sacrifice_target(T.mind))
|
||||
if(C?.cult_team.is_sacrifice_target(T.mind))
|
||||
if(iscultist(user))
|
||||
to_chat(user, "<span class='cult'><b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\"</span>")
|
||||
else
|
||||
to_chat(user, "<span class='danger'>The soulstone seems to reject this soul.</span>")
|
||||
to_chat(user, "<span class='danger'>[src] seems to reject this soul.</span>")
|
||||
return FALSE
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: [src] is full! Free an existing soul to make room.")
|
||||
else
|
||||
if((!old_shard && T.stat != CONSCIOUS) || (old_shard && T.stat == DEAD))
|
||||
if(T.client == null)
|
||||
@@ -167,7 +167,7 @@
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: Kill or maim the victim first!")
|
||||
|
||||
if("SHADE")
|
||||
var/mob/living/simple_animal/shade/T = target
|
||||
var/mob/living/simple_animal/hostile/construct/shade/T = target
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
|
||||
else
|
||||
@@ -177,13 +177,13 @@
|
||||
T.health = T.maxHealth
|
||||
icon_state = "soulstone2"
|
||||
name = "soulstone: Shade of [T.real_name]"
|
||||
to_chat(T, "<span class='notice'>Your soul has been captured by the soulstone. Its arcane energies are reknitting your ethereal form.</span>")
|
||||
to_chat(T, "<span class='notice'>Your soul has been captured by [src]. Its arcane energies are reknitting your ethereal form.</span>")
|
||||
if(user != T)
|
||||
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been captured and stored within the soulstone.")
|
||||
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been captured and stored within [src].")
|
||||
|
||||
if("CONSTRUCT")
|
||||
var/obj/structure/constructshell/T = target
|
||||
var/mob/living/simple_animal/shade/A = locate() in src
|
||||
var/mob/living/simple_animal/hostile/construct/shade/A = locate() in src
|
||||
if(A)
|
||||
var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
|
||||
if(!T || !T.loc)
|
||||
@@ -199,8 +199,8 @@
|
||||
if(iscultist(user) || iswizard(user))
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, A, user, 0, T.loc)
|
||||
|
||||
else
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder/noncult, A, user, 0, T.loc)
|
||||
else
|
||||
return
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B == A.mind)
|
||||
SSticker.mode.cult -= A.mind
|
||||
@@ -208,19 +208,24 @@
|
||||
qdel(T)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='userdanger'>Creation failed!</span>: The soul stone is empty! Go kill someone!")
|
||||
to_chat(user, "<span class='userdanger'>Creation failed!</span>: [src] is empty! Go kill someone!")
|
||||
|
||||
|
||||
/proc/makeNewConstruct(mob/living/simple_animal/hostile/construct/ctype, mob/target, mob/stoner = null, cultoverride = 0, loc_override = null)
|
||||
if(QDELETED(target))
|
||||
return
|
||||
var/mob/living/simple_animal/hostile/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target)))
|
||||
if(stoner)
|
||||
newstruct.faction |= "[REF(stoner)]"
|
||||
newstruct.master = stoner
|
||||
var/datum/action/innate/seek_master/SM = new()
|
||||
SM.Grant(newstruct)
|
||||
target.transfer_ckey(newstruct)
|
||||
newstruct.key = target.key
|
||||
if(target.type == /mob/living/simple_animal/hostile/construct/shade) //Make sure we remember which body belonged to the shade
|
||||
var/mob/living/simple_animal/hostile/construct/shade/shade = target
|
||||
newstruct.original_mind = shade.original_mind
|
||||
var/obj/screen/alert/bloodsense/BS
|
||||
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker && SSticker.mode)
|
||||
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker?.mode)
|
||||
SSticker.mode.add_cultist(newstruct.mind, 0)
|
||||
if(iscultist(stoner) || cultoverride)
|
||||
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow [stoner ? stoner.p_their() : "their"] orders and help [stoner ? stoner.p_them() : "them"] complete [stoner ? stoner.p_their() : "their"] goals at all costs.</b>")
|
||||
@@ -234,19 +239,18 @@
|
||||
|
||||
|
||||
/obj/item/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/user, vic = 0)
|
||||
new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton
|
||||
if(HAS_TRAIT_FROM(T, TRAIT_SACRIFICED, "sacrificed"))
|
||||
if(user)
|
||||
to_chat(user, "This body has already been harvested!")
|
||||
return
|
||||
ADD_TRAIT(T, TRAIT_SACRIFICED, "sacrificed")
|
||||
T.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
T.invisibility = INVISIBILITY_ABSTRACT
|
||||
T.dust_animation()
|
||||
QDEL_IN(T, 5)
|
||||
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade(src)
|
||||
S.status_flags |= GODMODE //So they won't die inside the stone somehow
|
||||
S.mobility_flags = NONE //Can't move out of the soul stone
|
||||
var/mob/living/simple_animal/hostile/construct/shade/S = new /mob/living/simple_animal/hostile/construct/shade(src)
|
||||
S.name = "Shade of [T.real_name]"
|
||||
S.real_name = "Shade of [T.real_name]"
|
||||
T.transfer_ckey(S)
|
||||
S.original_mind = T.mind.current
|
||||
S.copy_languages(T, LANGUAGE_MIND)//Copies the old mobs languages into the new mob holder.
|
||||
S.copy_languages(user, LANGUAGE_MASTER)
|
||||
S.update_atom_languages()
|
||||
grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
|
||||
if(user)
|
||||
@@ -264,7 +268,7 @@
|
||||
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been ripped from [T.p_their()] body and stored within the soul stone.")
|
||||
|
||||
|
||||
/obj/item/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/U)
|
||||
/obj/item/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/user)
|
||||
var/mob/dead/observer/chosen_ghost
|
||||
|
||||
for(var/mob/dead/observer/ghost in GLOB.player_list) //We put them back in their body
|
||||
@@ -279,13 +283,12 @@
|
||||
if(!T)
|
||||
return FALSE
|
||||
if(!chosen_ghost)
|
||||
to_chat(U, "<span class='danger'>There were no spirits willing to become a shade.</span>")
|
||||
to_chat(user, "<span class='danger'>There were no spirits willing to become a shade.</span>")
|
||||
return FALSE
|
||||
if(contents.len) //If they used the soulstone on someone else in the meantime
|
||||
return FALSE
|
||||
T.ckey = chosen_ghost.ckey
|
||||
for(var/obj/item/W in T)
|
||||
T.dropItemToGround(W)
|
||||
init_shade(T, U)
|
||||
qdel(T)
|
||||
init_shade(T, user)
|
||||
return TRUE
|
||||
|
||||
@@ -237,12 +237,21 @@
|
||||
. += "<span class='notice'>Alt-click to [locked ? "unlock" : "lock"] the interface.</span>"
|
||||
|
||||
/obj/machinery/airalarm/ui_status(mob/user)
|
||||
if(hasSiliconAccessInArea(user) && aidisabled)
|
||||
to_chat(user, "AI control has been disabled.")
|
||||
else if(!shorted)
|
||||
if(hasSiliconAccessInArea(user))
|
||||
if(aidisabled)
|
||||
to_chat(user, "AI control has been disabled")
|
||||
return UI_CLOSE
|
||||
else if(!issilicon(user)) //True sillycones use ..()
|
||||
return UI_INTERACTIVE
|
||||
if(!shorted)
|
||||
return ..()
|
||||
return UI_CLOSE
|
||||
|
||||
/obj/machinery/airalarm/can_interact(mob/user)
|
||||
. = ..()
|
||||
if (!issilicon(user) && hasSiliconAccessInArea(user))
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/airalarm/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
|
||||
@@ -196,8 +196,8 @@
|
||||
icon_state = "inje_map-1"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/layer3
|
||||
piping_layer = 2
|
||||
icon_state = "inje_map-2"
|
||||
piping_layer = 3
|
||||
icon_state = "inje_map-3"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/on
|
||||
on = TRUE
|
||||
@@ -207,8 +207,8 @@
|
||||
icon_state = "inje_map-1"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/on/layer3
|
||||
piping_layer = 2
|
||||
icon_state = "inje_map-2"
|
||||
piping_layer = 3
|
||||
icon_state = "inje_map-3"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/atmos
|
||||
frequency = FREQ_ATMOS_STORAGE
|
||||
|
||||
@@ -208,7 +208,11 @@
|
||||
stack_trace("[src]([REF(src)]) has one or more null gas mixtures, which may cause bugs. Null mixtures will not be considered in reconcile_air().")
|
||||
return listclearnulls(.)
|
||||
|
||||
/datum/pipeline/proc/reconcile_air()
|
||||
/datum/pipeline/proc/empty()
|
||||
for(var/datum/gas_mixture/GM in get_all_connected_airs())
|
||||
GM.clear()
|
||||
|
||||
/datum/pipeline/proc/get_all_connected_airs()
|
||||
var/list/datum/gas_mixture/GL = list()
|
||||
var/list/datum/pipeline/PL = list()
|
||||
PL += src
|
||||
@@ -233,6 +237,10 @@
|
||||
var/obj/machinery/atmospherics/components/unary/portables_connector/C = atmosmch
|
||||
if(C.connected_device)
|
||||
GL += C.portableConnectorReturnAir()
|
||||
return GL
|
||||
|
||||
/datum/pipeline/proc/reconcile_air()
|
||||
var/list/datum/gas_mixture/GL = get_all_connected_airs()
|
||||
|
||||
var/total_thermal_energy = 0
|
||||
var/total_heat_capacity = 0
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// welcome to the jungle, we got fun and games
|
||||
|
||||
//areas
|
||||
|
||||
/area/awaymission/jungleresort
|
||||
name = "Jungle Resort"
|
||||
icon_state = "awaycontent30"
|
||||
|
||||
//objects
|
||||
|
||||
/obj/item/paper/crumpled/awaymissions/jungleresort/notice
|
||||
name = "Resort Notice"
|
||||
info = "Due to unforeseen circumstances and the disappearance of several resort employees and visitors, the resort shall be closed to the public until further notice. - <i>Resort Manager Joe Lawrence</i.>"
|
||||
|
||||
/obj/item/melee/chainofcommand/jungle
|
||||
name = "treasure hunter's whip"
|
||||
desc = "The tool of a fallen treasure hunter, old and outdated, it still stings like hell to be hit by."
|
||||
hitsound = 'sound/weapons/whip.ogg'
|
||||
icon_state = "whip"
|
||||
|
||||
//turfs
|
||||
|
||||
/turf/open/water/jungle
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
|
||||
|
||||
/turf/open/floor/plating/dirt/jungle
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
|
||||
|
||||
/turf/open/floor/plating/dirt/dark/jungle
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
|
||||
|
||||
/turf/closed/mineral/random/labormineral/jungle
|
||||
baseturfs = /turf/open/floor/plating/asteroid
|
||||
turf_type = /turf/open/floor/plating/asteroid
|
||||
|
||||
//mobs
|
||||
|
||||
/mob/living/carbon/monkey/punpun/curiousgorge
|
||||
name = "Curious Gorge"
|
||||
pet_monkey_names = list("Curious Gorge", "Jungle Gorge", "Jungah Joe", "Mr. Monke")
|
||||
rare_pet_monkey_names = list("Sun Mukong", "Monkey Kong")
|
||||
|
||||
/mob/living/simple_animal/hostile/jungle/leaper/boss
|
||||
health = 450
|
||||
@@ -268,7 +268,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
else
|
||||
prefs = new /datum/preferences(src)
|
||||
GLOB.preferences_datums[ckey] = prefs
|
||||
|
||||
|
||||
addtimer(CALLBACK(src, .proc/ensure_keys_set), 10) //prevents possible race conditions
|
||||
|
||||
prefs.last_ip = address //these are gonna be used for banning
|
||||
@@ -561,36 +561,49 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(!query_client_in_db.Execute())
|
||||
qdel(query_client_in_db)
|
||||
return
|
||||
if(!query_client_in_db.NextRow())
|
||||
if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey] && !(ckey in GLOB.bunker_passthrough))
|
||||
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
|
||||
message_admins("<span class='adminnotice'>Failed Login: [key] - New account attempting to connect during panic bunker</span>")
|
||||
to_chat(src, "<span class='notice'>You must first join the Discord to verify your account before joining this server.<br>To do so, read the rules and post a request in the #station-access-requests channel under the \"Main server\" category in the Discord server linked here: <a href='https://discord.gg/E6SQuhz'>https://discord.gg/E6SQuhz</a><br>If you have already done so, wait a few minutes then try again; sometimes the server needs to fully load before you can join.</span>") //CIT CHANGE - makes the panic bunker disconnect message point to the discord
|
||||
var/list/connectiontopic_a = params2list(connectiontopic)
|
||||
var/list/panic_addr = CONFIG_GET(string/panic_server_address)
|
||||
if(panic_addr && !connectiontopic_a["redirect"])
|
||||
var/panic_name = CONFIG_GET(string/panic_server_name)
|
||||
to_chat(src, "<span class='notice'>Sending you to [panic_name ? panic_name : panic_addr].</span>")
|
||||
winset(src, null, "command=.options")
|
||||
src << link("[panic_addr]?redirect=1")
|
||||
qdel(query_client_in_db)
|
||||
qdel(src)
|
||||
return
|
||||
if(!query_client_in_db.NextRow()) //new user detected
|
||||
if(!holder && !GLOB.deadmins[ckey])
|
||||
if(CONFIG_GET(flag/panic_bunker) && !(ckey in GLOB.bunker_passthrough))
|
||||
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
|
||||
message_admins("<span class='adminnotice'>Failed Login: [key] - New account attempting to connect during panic bunker</span>")
|
||||
to_chat(src, "<span class='notice'>You must first join the Discord to verify your account before joining this server.<br>To do so, read the rules and post a request in the #station-access-requests channel under the \"Main server\" category in the Discord server linked here: <a href='https://discord.gg/E6SQuhz'>https://discord.gg/E6SQuhz</a><br>If you have already done so, wait a few minutes then try again; sometimes the server needs to fully load before you can join.</span>") //CIT CHANGE - makes the panic bunker disconnect message point to the discord
|
||||
var/list/connectiontopic_a = params2list(connectiontopic)
|
||||
var/list/panic_addr = CONFIG_GET(string/panic_server_address)
|
||||
if(panic_addr && !connectiontopic_a["redirect"])
|
||||
var/panic_name = CONFIG_GET(string/panic_server_name)
|
||||
to_chat(src, "<span class='notice'>Sending you to [panic_name ? panic_name : panic_addr].</span>")
|
||||
winset(src, null, "command=.options")
|
||||
src << link("[panic_addr]?redirect=1")
|
||||
qdel(query_client_in_db)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
new_player = 1
|
||||
account_join_date = sanitizeSQL(findJoinDate())
|
||||
var/sql_key = sanitizeSQL(key)
|
||||
var/datum/DBQuery/query_add_player = SSdbcore.NewQuery("INSERT INTO [format_table_name("player")] (`ckey`, `byond_key`, `firstseen`, `firstseen_round_id`, `lastseen`, `lastseen_round_id`, `ip`, `computerid`, `lastadminrank`, `accountjoindate`) VALUES ('[sql_ckey]', '[sql_key]', Now(), '[GLOB.round_id]', Now(), '[GLOB.round_id]', INET_ATON('[sql_ip]'), '[sql_computerid]', '[sql_admin_rank]', [account_join_date ? "'[account_join_date]'" : "NULL"])")
|
||||
if(!query_add_player.Execute())
|
||||
qdel(query_client_in_db)
|
||||
new_player = 1
|
||||
account_join_date = sanitizeSQL(findJoinDate())
|
||||
var/sql_key = sanitizeSQL(key)
|
||||
var/datum/DBQuery/query_add_player = SSdbcore.NewQuery("INSERT INTO [format_table_name("player")] (`ckey`, `byond_key`, `firstseen`, `firstseen_round_id`, `lastseen`, `lastseen_round_id`, `ip`, `computerid`, `lastadminrank`, `accountjoindate`) VALUES ('[sql_ckey]', '[sql_key]', Now(), '[GLOB.round_id]', Now(), '[GLOB.round_id]', INET_ATON('[sql_ip]'), '[sql_computerid]', '[sql_admin_rank]', [account_join_date ? "'[account_join_date]'" : "NULL"])")
|
||||
if(!query_add_player.Execute())
|
||||
qdel(query_client_in_db)
|
||||
qdel(query_add_player)
|
||||
return
|
||||
qdel(query_add_player)
|
||||
return
|
||||
qdel(query_add_player)
|
||||
if(!account_join_date)
|
||||
account_join_date = "Error"
|
||||
account_age = -1
|
||||
else if(ckey in GLOB.bunker_passthrough)
|
||||
GLOB.bunker_passthrough -= ckey
|
||||
if(!account_join_date)
|
||||
account_join_date = "Error"
|
||||
account_age = -1
|
||||
else if(ckey in GLOB.bunker_passthrough)
|
||||
GLOB.bunker_passthrough -= ckey
|
||||
if(CONFIG_GET(flag/age_verification)) //setup age verification
|
||||
if(!set_db_player_flags())
|
||||
message_admins(usr, "<span class='danger'>ERROR: Unable to read player flags from database. Please check logs.</span>")
|
||||
return
|
||||
else
|
||||
var/dbflags = prefs.db_flags
|
||||
if(!(dbflags & DB_FLAG_AGE_CONFIRMATION_COMPLETE)) //they have not completed age verification
|
||||
if((ckey in GLOB.bunker_passthrough)) //they're verified in the panic bunker though
|
||||
update_flag_db(DB_FLAG_AGE_CONFIRMATION_COMPLETE, TRUE)
|
||||
else
|
||||
update_flag_db(DB_FLAG_AGE_CONFIRMATION_INCOMPLETE, TRUE)
|
||||
|
||||
qdel(query_client_in_db)
|
||||
var/datum/DBQuery/query_get_client_age = SSdbcore.NewQuery("SELECT firstseen, DATEDIFF(Now(),firstseen), accountjoindate, DATEDIFF(Now(),accountjoindate) FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_get_client_age.Execute())
|
||||
|
||||
@@ -482,7 +482,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "<span style='border: 1px solid #161616; background-color: #[features["mcolor3"]];'> </span> <a href='?_src_=prefs;preference=mutant_color3;task=input'>Change</a><BR>"
|
||||
mutant_colors = TRUE
|
||||
|
||||
if (CONFIG_GET(number/body_size_min) != CONFIG_GET(number/body_size_max))
|
||||
dat += "<b>Sprite Size:</b> <a href='?_src_=prefs;preference=body_size;task=input'>[features["body_size"]*100]%</a><br>"
|
||||
|
||||
if(!(NOEYES in pref_species.species_traits))
|
||||
@@ -2267,21 +2266,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
gender = chosengender
|
||||
|
||||
if("body_size")
|
||||
var/min = CONFIG_GET(number/body_size_min)
|
||||
var/max = CONFIG_GET(number/body_size_max)
|
||||
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
|
||||
var/new_body_size = input(user, "Choose your desired sprite size: ([min*100]%-[max*100]%)\nWarning: This may make your character look distorted[danger > min ? "! Additionally, a proportional movement speed penalty will be applied to characters smaller than [danger*100]%." : "!"]", "Character Preference", features["body_size"]*100) as num|null
|
||||
if (new_body_size)
|
||||
new_body_size = clamp(new_body_size * 0.01, min, max)
|
||||
var/dorfy
|
||||
if((new_body_size + 0.01) < danger) // Adding 0.01 as a dumb fix to prevent the warning message from appearing when exactly at threshold... Not sure why that happens in the first place.
|
||||
dorfy = alert(user, "You have chosen a size below the slowdown threshold of [danger*100]%. For balancing purposes, the further you go below this percentage, the slower your character will be. Do you wish to keep this size?", "Speed Penalty Alert", "Yes", "Move it to the threshold", "No")
|
||||
if(dorfy == "Move it to the threshold")
|
||||
new_body_size = danger
|
||||
if(!dorfy) //Aborts if this var is somehow empty
|
||||
return
|
||||
if(dorfy != "No")
|
||||
features["body_size"] = new_body_size
|
||||
var/new_body_size = input(user, "Choose your desired sprite size: (90-125%)\nWarning: This may make your character look distorted. Additionally, any size under 100% takes a 10% maximum health penalty", "Character Preference", features["body_size"]*100) as num|null
|
||||
if(new_body_size)
|
||||
features["body_size"] = clamp(new_body_size * 0.01, CONFIG_GET(number/body_size_min), CONFIG_GET(number/body_size_max))
|
||||
|
||||
if("tongue")
|
||||
var/selected_custom_tongue = input(user, "Choose your desired tongue (none means your species tongue)", "Character Preference") as null|anything in GLOB.roundstart_tongues
|
||||
if(selected_custom_tongue)
|
||||
@@ -2701,6 +2689,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
else if(firstspace == name_length)
|
||||
real_name += "[pick(GLOB.last_names)]"
|
||||
|
||||
//reset size if applicable
|
||||
if(character.dna.features["body_size"])
|
||||
var/initial_old_size = character.dna.features["body_size"]
|
||||
character.dna.features["body_size"] = RESIZE_DEFAULT_SIZE
|
||||
character.dna.update_body_size(initial_old_size)
|
||||
|
||||
character.real_name = nameless ? "[real_name] #[rand(10000, 99999)]" : real_name
|
||||
character.name = character.real_name
|
||||
character.nameless = nameless
|
||||
@@ -2743,8 +2737,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
pref_species = new /datum/species/human
|
||||
save_character()
|
||||
|
||||
var/old_size = character.dna.features["body_size"]
|
||||
|
||||
character.dna.features = features.Copy()
|
||||
character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
|
||||
character.dna.species.eye_type = eye_type
|
||||
@@ -2754,6 +2746,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
character.dna.nameless = character.nameless
|
||||
character.dna.custom_species = character.custom_species
|
||||
|
||||
var/old_size = RESIZE_DEFAULT_SIZE
|
||||
if(isdwarf(character))
|
||||
character.dna.features["body_size"] = RESIZE_DEFAULT_SIZE
|
||||
|
||||
if((parent && parent.can_have_part("meat_type")) || pref_species.mutant_bodyparts["meat_type"])
|
||||
character.type_of_meat = GLOB.meat_types[features["meat_type"]]
|
||||
|
||||
|
||||
@@ -248,14 +248,15 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
path = "data/player_saves/[ckey[1]]/[ckey]/[filename]"
|
||||
vr_path = "data/player_saves/[ckey[1]]/[ckey]/vore"
|
||||
|
||||
/datum/preferences/proc/load_preferences()
|
||||
/datum/preferences/proc/load_preferences(bypass_cooldown = FALSE)
|
||||
if(!path)
|
||||
return FALSE
|
||||
if(world.time < loadprefcooldown)
|
||||
if(istype(parent))
|
||||
to_chat(parent, "<span class='warning'>You're attempting to load your preferences a little too fast. Wait half a second, then try again.</span>")
|
||||
return FALSE
|
||||
loadprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN
|
||||
if(!bypass_cooldown)
|
||||
if(world.time < loadprefcooldown)
|
||||
if(istype(parent))
|
||||
to_chat(parent, "<span class='warning'>You're attempting to load your preferences a little too fast. Wait half a second, then try again.</span>")
|
||||
return FALSE
|
||||
loadprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN
|
||||
if(!fexists(path))
|
||||
return FALSE
|
||||
|
||||
@@ -340,8 +341,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
fcopy(S, bacpath) //byond helpfully lets you use a savefile for the first arg.
|
||||
update_preferences(needs_update, S) //needs_update = savefile_version if we need an update (positive integer)
|
||||
|
||||
|
||||
|
||||
//Sanitize
|
||||
ooccolor = sanitize_ooccolor(sanitize_hexcolor(ooccolor, 6, 1, initial(ooccolor)))
|
||||
lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
|
||||
@@ -397,11 +396,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
continue
|
||||
max_save_slots = max(max_save_slots, slotnum) //so we can still update byond member slots after they lose memeber status
|
||||
default_slot = slotnum
|
||||
if (load_character()) // this updtates char slots
|
||||
save_character()
|
||||
if (load_character(null, TRUE)) // this updtates char slots
|
||||
save_character(TRUE)
|
||||
default_slot = old_default_slot
|
||||
max_save_slots = old_max_save_slots
|
||||
save_preferences()
|
||||
save_preferences(TRUE)
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -423,14 +422,15 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
if(!GLOB.keybindings_by_name[bindname])
|
||||
modless_key_bindings -= key
|
||||
|
||||
/datum/preferences/proc/save_preferences()
|
||||
/datum/preferences/proc/save_preferences(bypass_cooldown = FALSE)
|
||||
if(!path)
|
||||
return 0
|
||||
if(world.time < saveprefcooldown)
|
||||
if(istype(parent))
|
||||
to_chat(parent, "<span class='warning'>You're attempting to save your preferences a little too fast. Wait half a second, then try again.</span>")
|
||||
return 0
|
||||
saveprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN
|
||||
if(!bypass_cooldown)
|
||||
if(world.time < saveprefcooldown)
|
||||
if(istype(parent))
|
||||
to_chat(parent, "<span class='warning'>You're attempting to save your preferences a little too fast. Wait half a second, then try again.</span>")
|
||||
return 0
|
||||
saveprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN
|
||||
var/savefile/S = new /savefile(path)
|
||||
if(!S)
|
||||
return 0
|
||||
@@ -491,14 +491,15 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/load_character(slot)
|
||||
/datum/preferences/proc/load_character(slot, bypass_cooldown = FALSE)
|
||||
if(!path)
|
||||
return FALSE
|
||||
if(world.time < loadcharcooldown) //This is before the check to see if the filepath exists to ensure that BYOND can't get hung up on read attempts when the hard drive is a little slow
|
||||
if(istype(parent))
|
||||
to_chat(parent, "<span class='warning'>You're attempting to load your character a little too fast. Wait half a second, then try again.</span>")
|
||||
return "SLOW THE FUCK DOWN" //the reason this isn't null is to make sure that people don't have their character slots overridden by random chars if they accidentally double-click a slot
|
||||
loadcharcooldown = world.time + PREF_SAVELOAD_COOLDOWN
|
||||
if(!bypass_cooldown)
|
||||
if(world.time < loadcharcooldown) //This is before the check to see if the filepath exists to ensure that BYOND can't get hung up on read attempts when the hard drive is a little slow
|
||||
if(istype(parent))
|
||||
to_chat(parent, "<span class='warning'>You're attempting to load your character a little too fast. Wait half a second, then try again.</span>")
|
||||
return "SLOW THE FUCK DOWN" //the reason this isn't null is to make sure that people don't have their character slots overridden by random chars if they accidentally double-click a slot
|
||||
loadcharcooldown = world.time + PREF_SAVELOAD_COOLDOWN
|
||||
if(!fexists(path))
|
||||
return FALSE
|
||||
var/savefile/S = new /savefile(path)
|
||||
@@ -830,14 +831,15 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/save_character()
|
||||
/datum/preferences/proc/save_character(bypass_cooldown = FALSE)
|
||||
if(!path)
|
||||
return 0
|
||||
if(world.time < savecharcooldown)
|
||||
if(istype(parent))
|
||||
to_chat(parent, "<span class='warning'>You're attempting to save your character a little too fast. Wait half a second, then try again.</span>")
|
||||
return 0
|
||||
savecharcooldown = world.time + PREF_SAVELOAD_COOLDOWN
|
||||
if(!bypass_cooldown)
|
||||
if(world.time < savecharcooldown)
|
||||
if(istype(parent))
|
||||
to_chat(parent, "<span class='warning'>You're attempting to save your character a little too fast. Wait half a second, then try again.</span>")
|
||||
return 0
|
||||
savecharcooldown = world.time + PREF_SAVELOAD_COOLDOWN
|
||||
var/savefile/S = new /savefile(path)
|
||||
if(!S)
|
||||
return 0
|
||||
|
||||
@@ -44,30 +44,38 @@
|
||||
var/mob/M = loc
|
||||
M.update_inv_wear_mask()
|
||||
|
||||
//Proc that moves gas/breath masks out of the way, disabling them and allowing pill/food consumption
|
||||
/obj/item/clothing/mask/proc/adjustmask(mob/living/user)
|
||||
/**
|
||||
* Proc that moves gas/breath masks out of the way, disabling them and allowing pill/food consumption
|
||||
* The flavor_details variable is for masks that use this function only to toggle HIDEFACE for identity.
|
||||
*/
|
||||
/obj/item/clothing/mask/proc/adjustmask(mob/living/user, just_flavor = FALSE)
|
||||
if(user && user.incapacitated())
|
||||
return
|
||||
return FALSE
|
||||
mask_adjusted = !mask_adjusted
|
||||
if(!mask_adjusted)
|
||||
src.icon_state = initial(icon_state)
|
||||
gas_transfer_coefficient = initial(gas_transfer_coefficient)
|
||||
permeability_coefficient = initial(permeability_coefficient)
|
||||
clothing_flags |= visor_flags
|
||||
if(!just_flavor)
|
||||
src.icon_state = initial(icon_state)
|
||||
gas_transfer_coefficient = initial(gas_transfer_coefficient)
|
||||
permeability_coefficient = initial(permeability_coefficient)
|
||||
slot_flags = initial(slot_flags)
|
||||
flags_cover |= visor_flags_cover
|
||||
clothing_flags |= visor_flags
|
||||
flags_inv |= visor_flags_inv
|
||||
flags_cover |= visor_flags_cover
|
||||
to_chat(user, "<span class='notice'>You push \the [src] back into place.</span>")
|
||||
slot_flags = initial(slot_flags)
|
||||
else
|
||||
icon_state += "_up"
|
||||
to_chat(user, "<span class='notice'>You push \the [src] out of the way.</span>")
|
||||
gas_transfer_coefficient = null
|
||||
permeability_coefficient = null
|
||||
clothing_flags &= ~visor_flags
|
||||
if(!just_flavor)
|
||||
icon_state += "_up"
|
||||
gas_transfer_coefficient = null
|
||||
permeability_coefficient = null
|
||||
clothing_flags &= ~visor_flags
|
||||
flags_cover &= ~visor_flags_cover
|
||||
if(adjusted_flags)
|
||||
slot_flags = adjusted_flags
|
||||
flags_inv &= ~visor_flags_inv
|
||||
flags_cover &= ~visor_flags_cover
|
||||
if(adjusted_flags)
|
||||
slot_flags = adjusted_flags
|
||||
if(user)
|
||||
user.wear_mask_update(src, toggle_off = mask_adjusted)
|
||||
user.update_action_buttons_icon() //when mask is adjusted out, we update all buttons icon so the user's potential internal tank correctly shows as off.
|
||||
if(!just_flavor)
|
||||
to_chat(user, "<span class='notice'>You push \the [src] [mask_adjusted ? "out of the way" : "back into place"].</span>")
|
||||
user.wear_mask_update(src, toggle_off = mask_adjusted)
|
||||
user.update_action_buttons_icon() //when mask is adjusted out, we update all buttons icon so the user's potential internal tank correctly shows as off.
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You adjust [src], it will now [mask_adjusted ? "not" : ""] obscure your identity while worn.</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -72,18 +72,29 @@
|
||||
flags_cover = MASKCOVERSEYES
|
||||
resistance_flags = FLAMMABLE
|
||||
actions_types = list(/datum/action/item_action/adjust)
|
||||
visor_flags_inv = HIDEFACE
|
||||
dog_fashion = /datum/dog_fashion/head/clown
|
||||
var/list/clownmask_designs = list()
|
||||
var/static/list/clownmask_designs
|
||||
|
||||
/obj/item/clothing/mask/gas/clown_hat/Initialize(mapload)
|
||||
.=..()
|
||||
clownmask_designs = list(
|
||||
"True Form" = image(icon = src.icon, icon_state = "clown"),
|
||||
"The Feminist" = image(icon = src.icon, icon_state = "sexyclown"),
|
||||
"The Jester" = image(icon = src.icon, icon_state = "chaos"),
|
||||
"The Madman" = image(icon = src.icon, icon_state = "joker"),
|
||||
"The Rainbow Color" = image(icon = src.icon, icon_state = "rainbow")
|
||||
)
|
||||
if(!clownmask_designs)
|
||||
clownmask_designs = list(
|
||||
"True Form" = image(icon = src.icon, icon_state = "clown"),
|
||||
"The Feminist" = image(icon = src.icon, icon_state = "sexyclown"),
|
||||
"The Jester" = image(icon = src.icon, icon_state = "chaos"),
|
||||
"The Madman" = image(icon = src.icon, icon_state = "joker"),
|
||||
"The Rainbow Color" = image(icon = src.icon, icon_state = "rainbow")
|
||||
)
|
||||
|
||||
/obj/item/clothing/mask/gas/clown_hat/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='info'>Alt-click to toggle identity concealment. it's currently <b>[flags_inv & HIDEFACE ? "on" : "off"]</b>.</span>"
|
||||
|
||||
/obj/item/clothing/mask/gas/clown_hat/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(adjustmask(user, TRUE))
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/mask/gas/clown_hat/ui_action_click(mob/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
@@ -103,14 +114,12 @@
|
||||
to_chat(user, "<span class='notice'>Your Clown Mask has now morphed into [choice], all praise the Honkmother!</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/mask/gas/sexyclown
|
||||
/obj/item/clothing/mask/gas/clown_hat/sexy
|
||||
name = "sexy-clown wig and mask"
|
||||
desc = "A feminine clown mask for the dabbling crossdressers or female entertainers."
|
||||
clothing_flags = ALLOWINTERNALS
|
||||
icon_state = "sexyclown"
|
||||
item_state = "sexyclown"
|
||||
flags_cover = MASKCOVERSEYES
|
||||
resistance_flags = FLAMMABLE
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/clothing/mask/gas/mime
|
||||
name = "mime mask"
|
||||
@@ -121,18 +130,27 @@
|
||||
flags_cover = MASKCOVERSEYES
|
||||
resistance_flags = FLAMMABLE
|
||||
actions_types = list(/datum/action/item_action/adjust)
|
||||
var/list/mimemask_designs = list()
|
||||
visor_flags_inv = HIDEFACE
|
||||
var/static/list/mimemask_designs
|
||||
|
||||
/obj/item/clothing/mask/gas/mime/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='info'>Alt-click to toggle identity concealment. it's currently <b>[flags_inv & HIDEFACE ? "on" : "off"]</b>.</span>"
|
||||
|
||||
/obj/item/clothing/mask/gas/mime/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(adjustmask(user, TRUE))
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/mask/gas/mime/Initialize(mapload)
|
||||
.=..()
|
||||
mimemask_designs = list(
|
||||
"Blanc" = image(icon = src.icon, icon_state = "mime"),
|
||||
"Excité" = image(icon = src.icon, icon_state = "sexymime"),
|
||||
"Triste" = image(icon = src.icon, icon_state = "sadmime"),
|
||||
"Effrayé" = image(icon = src.icon, icon_state = "scaredmime")
|
||||
)
|
||||
|
||||
if(!mimemask_designs)
|
||||
mimemask_designs = list(
|
||||
"Blanc" = image(icon = src.icon, icon_state = "mime"),
|
||||
"Excité" = image(icon = src.icon, icon_state = "sexymime"),
|
||||
"Triste" = image(icon = src.icon, icon_state = "sadmime"),
|
||||
"Effrayé" = image(icon = src.icon, icon_state = "scaredmime")
|
||||
)
|
||||
|
||||
/obj/item/clothing/mask/gas/mime/ui_action_click(mob/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
@@ -151,6 +169,13 @@
|
||||
to_chat(user, "<span class='notice'>Your Mime Mask has now morphed into [choice]!</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/mask/gas/mime/sexy
|
||||
name = "sexy mime mask"
|
||||
desc = "A traditional female mime's mask."
|
||||
icon_state = "sexymime"
|
||||
item_state = "sexymime"
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/clothing/mask/gas/monkeymask
|
||||
name = "monkey mask"
|
||||
desc = "A mask used when acting as a monkey."
|
||||
@@ -160,15 +185,6 @@
|
||||
flags_cover = MASKCOVERSEYES
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/clothing/mask/gas/sexymime
|
||||
name = "sexy mime mask"
|
||||
desc = "A traditional female mime's mask."
|
||||
clothing_flags = ALLOWINTERNALS
|
||||
icon_state = "sexymime"
|
||||
item_state = "sexymime"
|
||||
flags_cover = MASKCOVERSEYES
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/clothing/mask/gas/death_commando
|
||||
name = "Death Commando Mask"
|
||||
icon_state = "death_commando_mask"
|
||||
|
||||
@@ -40,37 +40,115 @@
|
||||
icon_state = "plasmaman-helm"
|
||||
item_state = "plasmaman-helm"
|
||||
strip_delay = 80
|
||||
flash_protect = 2
|
||||
tint = 2
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 0, "fire" = 100, "acid" = 75, "wound" = 10)
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/brightness_on = 4 //luminosity when the light is on
|
||||
var/on = FALSE
|
||||
var/helmet_on = FALSE
|
||||
var/smile = FALSE
|
||||
var/smile_color = "#FF0000"
|
||||
var/light_overlay = "envirohelm-light"
|
||||
actions_types = list(/datum/action/item_action/toggle_helmet_light)
|
||||
var/visor_icon = "envisor"
|
||||
var/smile_state = "envirohelm_smile"
|
||||
actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_welding_screen/plasmaman)
|
||||
visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
|
||||
flags_cover = HEADCOVERSMOUTH|HEADCOVERSEYES
|
||||
visor_flags_inv = HIDEEYES|HIDEFACE|HIDEFACIALHAIR
|
||||
mutantrace_variation = NONE
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/Initialize()
|
||||
. = ..()
|
||||
visor_toggling()
|
||||
update_icon()
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/ComponentInitialize()
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, .proc/wipe_that_smile_off_your_face)
|
||||
AddElement(/datum/element/update_icon_updates_onmob)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(user.canUseTopic(src, BE_CLOSE))
|
||||
toggle_welding_screen(user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/proc/toggle_welding_screen(mob/living/user)
|
||||
if(weldingvisortoggle(user))
|
||||
if(helmet_on)
|
||||
to_chat(user, "<span class='notice'>Your helmet's torch can't pass through your welding visor!</span>")
|
||||
helmet_on = FALSE
|
||||
set_light(0)
|
||||
playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) //Visors don't just come from nothing
|
||||
update_icon()
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/update_overlays()
|
||||
. = ..()
|
||||
if(!up)
|
||||
. += visor_icon
|
||||
if(helmet_on)
|
||||
. += light_overlay
|
||||
if(smile)
|
||||
var/mutable_appearance/M = mutable_appearance(icon, smile_state)
|
||||
M.color = smile_color
|
||||
. += M
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/attackby(obj/item/C, mob/living/user)
|
||||
. = ..()
|
||||
if(istype(C, /obj/item/toy/crayon))
|
||||
if(!smile)
|
||||
var/obj/item/toy/crayon/CR = C
|
||||
to_chat(user, "<span class='notice'>You start drawing a smiley face on the helmet's visor..</span>")
|
||||
if(do_after(user, 25, target = src))
|
||||
smile = TRUE
|
||||
smile_color = CR.paint_color
|
||||
to_chat(user, "You draw a smiley on the helmet visor.")
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Seems like someone already drew something on this helmet's visor!</span>")
|
||||
|
||||
///gets called when receiving the CLEAN_ACT signal from something, i.e soap or a shower. exists to remove any smiley faces drawn on the helmet.
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/proc/wipe_that_smile_off_your_face()
|
||||
if(smile)
|
||||
smile = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/attack_self(mob/user)
|
||||
if(!light_overlay)
|
||||
return
|
||||
on = !on
|
||||
if(!on)
|
||||
cut_overlay(light_overlay)
|
||||
else
|
||||
add_overlay(light_overlay)
|
||||
user.update_inv_head() //So the mob overlay updates
|
||||
if(!up)
|
||||
to_chat(user, "<span class='notice'>Your helmet's torch can't pass through your welding visor!</span>")
|
||||
return
|
||||
helmet_on = !helmet_on
|
||||
|
||||
if(on)
|
||||
if(helmet_on)
|
||||
set_light(brightness_on, 0.8, "#FFCC66")
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
for(var/X in actions)
|
||||
var/datum/action/A=X
|
||||
A.UpdateButtonIcon()
|
||||
update_icon()
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/visor_toggling() //handles all the actual toggling of flags
|
||||
up = !up
|
||||
clothing_flags ^= visor_flags
|
||||
flags_inv ^= visor_flags_inv
|
||||
if(visor_vars_to_toggle & VISOR_FLASHPROTECT)
|
||||
flash_protect ^= initial(flash_protect)
|
||||
if(visor_vars_to_toggle & VISOR_TINT)
|
||||
tint ^= initial(tint)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE)
|
||||
. = ..()
|
||||
if(!isinhands && on)
|
||||
. += mutable_appearance(icon_file, light_overlay)
|
||||
if(!isinhands)
|
||||
if(smile)
|
||||
var/mutable_appearance/M = mutable_appearance(icon_file, smile_state)
|
||||
M.color = smile_color
|
||||
. += M
|
||||
if(!up)
|
||||
. += mutable_appearance(icon_file, visor_icon)
|
||||
if(helmet_on)
|
||||
. += mutable_appearance(icon_file, light_overlay)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/security
|
||||
name = "security plasma envirosuit helmet"
|
||||
@@ -170,6 +248,7 @@
|
||||
desc = "A khaki helmet given to plasmamen miners operating on lavaland."
|
||||
icon_state = "explorer_envirohelm"
|
||||
item_state = "explorer_envirohelm"
|
||||
visor_icon = "explorer_envisor"
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/chaplain
|
||||
name = "chaplain's plasma envirosuit helmet"
|
||||
@@ -202,7 +281,9 @@
|
||||
icon_state = "prototype_envirohelm"
|
||||
item_state = "prototype_envirohelm"
|
||||
light_overlay = null
|
||||
actions_types = list()
|
||||
actions_types = list(/datum/action/item_action/toggle_welding_screen/plasmaman)
|
||||
smile_state = "prototype_smile"
|
||||
visor_icon = "prototype_envisor"
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/botany
|
||||
name = "botany plasma envirosuit helmet"
|
||||
@@ -222,6 +303,7 @@
|
||||
icon_state = "mime_envirohelm"
|
||||
item_state = "mime_envirohelm"
|
||||
light_overlay = "mime_envirohelm-light"
|
||||
visor_icon = "mime_envisor"
|
||||
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/clown
|
||||
name = "clown envirosuit helmet"
|
||||
@@ -229,3 +311,6 @@
|
||||
icon_state = "clown_envirohelm"
|
||||
item_state = "clown_envirohelm"
|
||||
light_overlay = "clown_envirohelm-light"
|
||||
item_state = "clown_envirohelm"
|
||||
visor_icon = "clown_envisor"
|
||||
smile_state = "clown_smile"
|
||||
|
||||
@@ -199,6 +199,15 @@
|
||||
can_adjust = FALSE
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
|
||||
|
||||
/obj/item/clothing/under/rank/civilian/janitor/maid/polychromic
|
||||
icon_state = "polymaid"
|
||||
item_state = "polymaid"
|
||||
var/list/poly_colors = list("#FFFFFF", "#000000")
|
||||
|
||||
/obj/item/clothing/under/rank/civilian/janitor/maid/polychromic/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/polychromic, poly_colors, 2)
|
||||
|
||||
/obj/item/clothing/under/rank/civilian/lawyer
|
||||
desc = "Slick threads."
|
||||
name = "Lawyer suit"
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
|
||||
triggering = TRUE
|
||||
if (alert_observers)
|
||||
message_admins("Random Event triggering in 10 seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)")
|
||||
sleep(100)
|
||||
message_admins("Random Event triggering in 30 seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)")
|
||||
sleep(300)
|
||||
var/gamemode = SSticker.mode.config_tag
|
||||
var/players_amt = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE)
|
||||
if(!canSpawnEvent(players_amt, gamemode))
|
||||
|
||||
@@ -44,7 +44,13 @@
|
||||
priority_announce("Localized energetic flux wave detected on long range scanners. Expected location of impact: [impact_area.name].", "Anomaly Alert")
|
||||
|
||||
/datum/round_event/anomaly/start()
|
||||
var/turf/T = pick(get_area_turfs(impact_area))
|
||||
var/list/turf/valid = list()
|
||||
for(var/i in get_area_turfs(impact_area))
|
||||
var/turf/T = i
|
||||
if(T.density)
|
||||
continue
|
||||
valid += T
|
||||
var/turf/T = pick(valid)
|
||||
var/newAnomaly
|
||||
if(T)
|
||||
newAnomaly = new anomaly_path(T)
|
||||
|
||||
@@ -219,7 +219,7 @@
|
||||
suit_type = /obj/item/clothing/suit/space
|
||||
helmet_type = /obj/item/clothing/head/helmet/space
|
||||
mask_type = /obj/item/clothing/mask/breath
|
||||
storage_type = /obj/item/tank/internals/oxygen
|
||||
storage_type = /obj/item/tank/jetpack/void
|
||||
|
||||
|
||||
/obj/machinery/loot_locator
|
||||
@@ -275,6 +275,7 @@
|
||||
|
||||
/obj/machinery/computer/piratepad_control
|
||||
name = "cargo hold control terminal"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
ui_x = 600
|
||||
ui_y = 230
|
||||
var/status_report = "Ready for delivery."
|
||||
|
||||
@@ -321,6 +321,7 @@ mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize()
|
||||
var/new_implant = new chosen_implant
|
||||
var/obj/item/autosurgeon/reward = new(get_turf(src))
|
||||
reward.insert_organ(new_implant)
|
||||
reward.uses = 1
|
||||
|
||||
/datum/outfit/otherworldly_surgeon
|
||||
name = "Otherworldly Surgeon"
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
else if(trapped == HOWLING_GHOST)
|
||||
visible_message("<span class='userdanger'><font size='5'>[pick("OooOOooooOOOoOoOOooooOOOOO", "BooOOooOooooOOOO", "BOO!", "WoOOoOoooOooo")]</font></span>")
|
||||
playsound(loc, 'sound/spookoween/ghosty_wind.ogg', 300, 1)
|
||||
new /mob/living/simple_animal/shade/howling_ghost(loc)
|
||||
new /mob/living/simple_animal/hostile/construct/shade/howling_ghost(loc)
|
||||
trapped = 0
|
||||
|
||||
else if(trapped == SCARY_BATS)
|
||||
@@ -123,7 +123,7 @@
|
||||
//Spookoween Ghost//
|
||||
////////////////////
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost
|
||||
name = "ghost"
|
||||
real_name = "ghost"
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
@@ -137,13 +137,13 @@
|
||||
layer = 4
|
||||
var/timer = 0
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/Initialize()
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/Initialize()
|
||||
. = ..()
|
||||
icon_state = pick("ghost","ghostian","ghostian2","ghostking","ghost1","ghost2")
|
||||
icon_living = icon_state
|
||||
timer = rand(1,15)
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/Life()
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/Life()
|
||||
..()
|
||||
timer--
|
||||
if(prob(20))
|
||||
@@ -152,16 +152,16 @@
|
||||
spooky_ghosty()
|
||||
timer = rand(1,15)
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/proc/EtherealMove(direction)
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/proc/EtherealMove(direction)
|
||||
forceMove(get_step(src, direction))
|
||||
setDir(direction)
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/proc/roam()
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/proc/roam()
|
||||
if(prob(80))
|
||||
var/direction = pick(NORTH,SOUTH,EAST,WEST,NORTHEAST,NORTHWEST,SOUTHEAST,SOUTHWEST)
|
||||
EtherealMove(direction)
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/proc/spooky_ghosty()
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/proc/spooky_ghosty()
|
||||
if(prob(20)) //haunt
|
||||
playsound(loc, pick('sound/spookoween/ghosty_wind.ogg','sound/spookoween/ghost_whisper.ogg','sound/spookoween/chain_rattling.ogg'), 300, 1)
|
||||
if(prob(10)) //flickers
|
||||
@@ -175,7 +175,7 @@
|
||||
step(I,direction)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/CanPass(atom/movable/mover, turf/target)
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/CanPass(atom/movable/mover, turf/target)
|
||||
return 1
|
||||
|
||||
///////////////////////////
|
||||
|
||||
@@ -50,6 +50,13 @@
|
||||
var/cached_z
|
||||
/// I'm busy, don't move.
|
||||
var/busy = FALSE
|
||||
var/static/blacklisted_items = typecacheof(list(
|
||||
/obj/effect,
|
||||
/obj/belly,
|
||||
/obj/mafia_game_board,
|
||||
/obj/docking_port,
|
||||
/obj/shapeshift_holder,
|
||||
/obj/screen))
|
||||
|
||||
/mob/living/simple_animal/jacq/Initialize()
|
||||
..()
|
||||
@@ -112,7 +119,7 @@
|
||||
|
||||
/mob/living/simple_animal/jacq/proc/jacqrunes(message, mob/living/carbon/C) //Displays speechtext over Jacq for the user only.
|
||||
var/atom/hearer = C
|
||||
var/list/spans = list("spooky")
|
||||
var/list/spans = list("spooky")
|
||||
new /datum/chatmessage(message, src, hearer, spans)
|
||||
|
||||
|
||||
@@ -228,10 +235,13 @@
|
||||
return
|
||||
|
||||
var/new_obj = pick(subtypesof(/obj))
|
||||
//for(var/item in blacklist)
|
||||
// if(new_obj == item)
|
||||
// panic()
|
||||
for(var/item in blacklisted_items)
|
||||
if(is_type_in_typecache(new_obj, blacklisted_items))
|
||||
new_obj = /obj/item/reagent_containers/food/snacks/special_candy
|
||||
var/reward = new new_obj(C.loc)
|
||||
if(new_obj == /obj/item/reagent_containers/food/snacks/special_candy)
|
||||
new new_obj(C.loc)
|
||||
new new_obj(C.loc) //Giving them back their candies in case it's something from the blacklist or if the game literally rolled candies. What rotten luck.
|
||||
C.put_in_hands(reward)
|
||||
visible_message("<b>[src]</b> waves her hands, magicking up a [reward] from thin air, <span class='spooky'>\"There ye are [gender], enjoy! \"</span>")
|
||||
jacqrunes("There ye are [gender], enjoy!", C)
|
||||
|
||||
@@ -651,6 +651,11 @@
|
||||
icon_state = "setup_small_pda"
|
||||
desc = "It's a case, for building small electronics with. This one resembles a PDA."
|
||||
|
||||
/obj/item/electronic_assembly/dildo
|
||||
name = "type-g electronic assembly"
|
||||
icon_state = "setup_dildo_medium"
|
||||
desc = "It's a case, for building small electronics with. This one has a phallic design."
|
||||
|
||||
/obj/item/electronic_assembly/small
|
||||
name = "electronic device"
|
||||
icon_state = "setup_device"
|
||||
@@ -682,6 +687,11 @@
|
||||
icon_state = "setup_device_box"
|
||||
desc = "It's a case, for building tiny-sized electronics with. This one has a boxy design."
|
||||
|
||||
/obj/item/electronic_assembly/small/dildo
|
||||
name = "type-f electronic device"
|
||||
icon_state = "setup_dildo_small"
|
||||
desc = "It's a case, for building tiny-sized electronics with. This one has a phallic design."
|
||||
|
||||
/obj/item/electronic_assembly/medium
|
||||
name = "electronic mechanism"
|
||||
icon_state = "setup_medium"
|
||||
@@ -722,6 +732,12 @@
|
||||
icon_state = "setup_medium_radio"
|
||||
desc = "It's a case, for building medium-sized electronics with. This one resembles an old radio."
|
||||
|
||||
/obj/item/electronic_assembly/medium/dildo
|
||||
name = "type-g electronic mechanism"
|
||||
icon_state = "setup_dildo_large"
|
||||
desc = "It's a case, for building medium-sized electronics with. This one has a phallic design."
|
||||
|
||||
|
||||
/obj/item/electronic_assembly/large
|
||||
name = "electronic machine"
|
||||
icon_state = "setup_large"
|
||||
|
||||
@@ -115,10 +115,10 @@
|
||||
source_air = air_contents
|
||||
|
||||
// Move gas from one place to another
|
||||
move_gas(source_air, target_air)
|
||||
move_gas(source_air, target_air, (istype(target, /obj/item/tank) ? target : null))
|
||||
air_update_turf()
|
||||
|
||||
/obj/item/integrated_circuit/atmospherics/pump/proc/move_gas(datum/gas_mixture/source_air, datum/gas_mixture/target_air)
|
||||
/obj/item/integrated_circuit/atmospherics/pump/proc/move_gas(datum/gas_mixture/source_air, datum/gas_mixture/target_air, obj/item/tank/snowflake)
|
||||
|
||||
// No moles = nothing to pump
|
||||
if(source_air.total_moles() <= 0 || target_air.return_pressure() >= PUMP_MAX_PRESSURE)
|
||||
@@ -132,7 +132,10 @@
|
||||
if(pressure_delta > 0.1)
|
||||
var/transfer_moles = (pressure_delta*target_air.return_volume()/(source_air.return_temperature() * R_IDEAL_GAS_EQUATION))*PUMP_EFFICIENCY
|
||||
var/datum/gas_mixture/removed = source_air.remove(transfer_moles)
|
||||
target_air.merge(removed)
|
||||
if(istype(snowflake)) //Snowflake check for tanks specifically, because tank ruptures are handled in a very snowflakey way that expects all tank interactions to be handled via the tank's procs
|
||||
snowflake.assume_air(removed)
|
||||
else
|
||||
target_air.merge(removed)
|
||||
|
||||
|
||||
// - volume pump - // **Works**
|
||||
@@ -165,7 +168,7 @@
|
||||
direction = SOURCE_TO_TARGET
|
||||
target_pressure = min(PUMP_MAX_VOLUME,abs(new_amount))
|
||||
|
||||
/obj/item/integrated_circuit/atmospherics/pump/volume/move_gas(datum/gas_mixture/source_air, datum/gas_mixture/target_air)
|
||||
/obj/item/integrated_circuit/atmospherics/pump/volume/move_gas(datum/gas_mixture/source_air, datum/gas_mixture/target_air, obj/item/tank/snowflake)
|
||||
// No moles = nothing to pump
|
||||
if(source_air.total_moles() <= 0)
|
||||
return
|
||||
@@ -182,7 +185,10 @@
|
||||
|
||||
var/datum/gas_mixture/removed = source_air.remove_ratio(transfer_ratio * PUMP_EFFICIENCY)
|
||||
|
||||
target_air.merge(removed)
|
||||
if(istype(snowflake))
|
||||
snowflake.assume_air(removed)
|
||||
else
|
||||
target_air.merge(removed)
|
||||
|
||||
|
||||
// - gas vent - // **works**
|
||||
@@ -379,9 +385,20 @@ obj/item/integrated_circuit/atmospherics/connector/portableConnectorReturnAir()
|
||||
removed.set_moles(filtered_gas, 0)
|
||||
|
||||
//Check if the pressure is high enough to put stuff in filtered, or else just put it back in the source
|
||||
var/datum/gas_mixture/target = (filtered_air.return_pressure() < target_pressure ? filtered_air : source_air)
|
||||
target.merge(filtered_out)
|
||||
contaminated_air.merge(removed)
|
||||
if(filtered_air.return_pressure() < target_pressure)
|
||||
if(istype(filtered, /obj/item/tank))
|
||||
filtered.assume_air(filtered_out)
|
||||
else
|
||||
filtered_air.merge(filtered_out)
|
||||
else
|
||||
if(istype(source, /obj/item/tank))
|
||||
source.assume_air(filtered_out)
|
||||
else
|
||||
source_air.merge(filtered_out)
|
||||
if(istype(contaminants, /obj/item/tank))
|
||||
contaminants.assume_air(removed)
|
||||
else
|
||||
contaminated_air.merge(removed)
|
||||
|
||||
|
||||
/obj/item/integrated_circuit/atmospherics/pump/filter/Initialize()
|
||||
@@ -449,10 +466,18 @@ obj/item/integrated_circuit/atmospherics/connector/portableConnectorReturnAir()
|
||||
if(transfer_moles <= 0)
|
||||
return
|
||||
|
||||
var/snowflakecheck = istype(gas_output, /obj/item/tank)
|
||||
|
||||
var/datum/gas_mixture/mix = source_1_gases.remove(transfer_moles * gas_percentage)
|
||||
output_gases.merge(mix)
|
||||
if(snowflakecheck)
|
||||
gas_output.assume_air(mix)
|
||||
else
|
||||
output_gases.merge(mix)
|
||||
mix = source_2_gases.remove(transfer_moles * (1-gas_percentage))
|
||||
output_gases.merge(mix)
|
||||
if(snowflakecheck)
|
||||
gas_output.assume_air(mix)
|
||||
else
|
||||
output_gases.merge(mix)
|
||||
|
||||
|
||||
// - integrated tank - // **works**
|
||||
|
||||
@@ -5,17 +5,6 @@
|
||||
/datum/keybinding/human/can_use(client/user)
|
||||
return ishuman(user.mob)
|
||||
|
||||
/datum/keybinding/human/quick_equip
|
||||
hotkey_keys = list("E")
|
||||
name = "quick_equip"
|
||||
full_name = "Quick Equip"
|
||||
description = "Quickly puts an item in the best slot available"
|
||||
|
||||
/datum/keybinding/human/quick_equip/down(client/user)
|
||||
var/mob/living/carbon/human/H = user.mob
|
||||
H.quick_equip()
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/human/quick_equipbelt
|
||||
hotkey_keys = list("ShiftE")
|
||||
name = "quick_equipbelt"
|
||||
|
||||
@@ -5,6 +5,17 @@
|
||||
/datum/keybinding/living/can_use(client/user)
|
||||
return isliving(user.mob)
|
||||
|
||||
/datum/keybinding/living/quick_equip
|
||||
hotkey_keys = list("E")
|
||||
name = "quick_equip"
|
||||
full_name = "Quick Equip"
|
||||
description = "Quickly puts an item in the best slot available"
|
||||
|
||||
/datum/keybinding/living/quick_equip/down(client/user)
|
||||
var/mob/living/carbon/human/H = user.mob
|
||||
H.quick_equip()
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/living/resist
|
||||
hotkey_keys = list("B")
|
||||
name = "resist"
|
||||
|
||||
@@ -107,7 +107,18 @@
|
||||
|
||||
/datum/keybinding/living/subtle/down(client/user)
|
||||
var/mob/living/L = user.mob
|
||||
L.subtle_keybind()
|
||||
L.subtle()
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/living/subtler
|
||||
hotkey_keys = list("6")
|
||||
classic_keys = list()
|
||||
name = "subtler_emote"
|
||||
full_name = "Subtler Anti-Ghost Emote"
|
||||
|
||||
/datum/keybinding/living/subtler/down(client/user)
|
||||
var/mob/living/L = user.mob
|
||||
L.subtler()
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/mob/whisper
|
||||
|
||||
@@ -59,17 +59,3 @@
|
||||
var/mob/living/silicon/robot/R = user.mob
|
||||
R.uneq_active()
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/robot/drone/can_use(client/user)
|
||||
return isdrone(user.mob)
|
||||
|
||||
/datum/keybinding/robot/drone/quick_equip_drone // QOL: Drone quickequip
|
||||
hotkey_keys = list("E")
|
||||
name = "quick_equip_drone"
|
||||
full_name = "Quick Equip (Drone)"
|
||||
description = "Quickly puts an item in the best slot available"
|
||||
|
||||
/datum/keybinding/robot/drone/quick_equip_drone/down(client/user)
|
||||
var/mob/living/simple_animal/drone/D = user.mob
|
||||
D.quick_equip()
|
||||
return TRUE
|
||||
@@ -202,7 +202,7 @@
|
||||
var/obj/item/reagent_containers/food/snacks/donkpocket/warm/W = new(src)
|
||||
load(W)
|
||||
if(prob(50))
|
||||
var/obj/item/storage/box/dice/D = new(src)
|
||||
var/obj/item/storage/dice/D = new(src)
|
||||
load(D)
|
||||
else
|
||||
var/obj/item/instrument/guitar/G = new(src)
|
||||
|
||||
@@ -109,9 +109,12 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
|
||||
if(!(obj_flags & EMAGGED))
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
. = ..()
|
||||
if((obj_flags & EMAGGED))
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
return TRUE
|
||||
|
||||
/**********************Prisoner Collection Unit**************************/
|
||||
|
||||
|
||||
@@ -760,6 +760,7 @@
|
||||
/obj/item/melee/transforming/cleaving_saw
|
||||
name = "cleaving saw"
|
||||
desc = "This saw, effective at drawing the blood of beasts, transforms into a long cleaver that makes use of centrifugal force."
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
force = 12
|
||||
force_on = 20 //force when active
|
||||
throwforce = 20
|
||||
@@ -1177,6 +1178,7 @@
|
||||
/obj/item/gun/ballistic/revolver/doublebarrel/super
|
||||
name = "super combat shotgun"
|
||||
desc = "From the belly of the beast - or rather, demon. Twice as lethal as a less-than-super shotgun, but a tad bulkier."
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
icon_state = "heckgun"
|
||||
slot_flags = null
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/dual/heck
|
||||
@@ -1207,6 +1209,7 @@
|
||||
/obj/item/hierophant_club
|
||||
name = "hierophant club"
|
||||
desc = "The strange technology of this large club allows various nigh-magical feats. It used to beat you, but now you can set the beat."
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
icon_state = "hierophant_club_ready_beacon"
|
||||
item_state = "hierophant_club_ready_beacon"
|
||||
icon = 'icons/obj/lavaland/artefacts.dmi'
|
||||
|
||||
@@ -78,6 +78,28 @@
|
||||
popup.set_content(output)
|
||||
popup.open(FALSE)
|
||||
|
||||
/mob/dead/new_player/proc/age_verify()
|
||||
if(CONFIG_GET(flag/age_verification) && !check_rights_for(client, R_ADMIN) && !(client.ckey in GLOB.bunker_passthrough)) //make sure they are verified
|
||||
if(!client.set_db_player_flags())
|
||||
message_admins("Blocked [src] from new player panel because age gate could not access player database flags.")
|
||||
return FALSE
|
||||
else
|
||||
var/dbflags = client.prefs.db_flags
|
||||
if(dbflags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE) //they have not completed age gate
|
||||
var/age_verification = askuser(src, "Are you 18+", "Age Gate", "I am 18+", "I am not 18+", null, TRUE, null)
|
||||
if(age_verification != 1)
|
||||
client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process")
|
||||
qdel(client) //kick the user
|
||||
return FALSE
|
||||
else
|
||||
//they claim to be of age, so allow them to continue and update their flags
|
||||
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_COMPLETE, TRUE)
|
||||
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_INCOMPLETE, FALSE)
|
||||
//log this
|
||||
message_admins("[ckey] has joined through the automated age gate process.")
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
/mob/dead/new_player/Topic(href, href_list[])
|
||||
if(src != usr)
|
||||
return 0
|
||||
@@ -85,6 +107,9 @@
|
||||
if(!client)
|
||||
return 0
|
||||
|
||||
if(!age_verify())
|
||||
return
|
||||
|
||||
//Determines Relevent Population Cap
|
||||
var/relevant_cap
|
||||
var/hpc = CONFIG_GET(number/hard_popcap)
|
||||
|
||||
@@ -651,11 +651,11 @@
|
||||
name = "Fennec"
|
||||
icon_state = "fennec"
|
||||
|
||||
/datum/sprite_accessory/tails/mam_tails/human/fish
|
||||
/datum/sprite_accessory/tails/mam_tails/fish
|
||||
name = "Fish"
|
||||
icon_state = "fish"
|
||||
|
||||
/datum/sprite_accessory/tails_animated/mam_tails_animated/human/fish
|
||||
/datum/sprite_accessory/tails_animated/mam_tails_animated/fish
|
||||
name = "Fish"
|
||||
icon_state = "fish"
|
||||
|
||||
|
||||
@@ -100,6 +100,14 @@
|
||||
return held_items.Find(I)
|
||||
|
||||
|
||||
///Find number of held items, multihand compatible
|
||||
/mob/proc/get_num_held_items()
|
||||
. = 0
|
||||
for(var/i in 1 to held_items.len)
|
||||
if(held_items[i])
|
||||
.++
|
||||
|
||||
|
||||
//Sad that this will cause some overhead, but the alias seems necessary
|
||||
//*I* may be happy with a million and one references to "indexes" but others won't be
|
||||
/mob/proc/is_holding(obj/item/I)
|
||||
|
||||
@@ -611,7 +611,7 @@
|
||||
update_mobility()
|
||||
UpdateStaminaBuffer()
|
||||
update_health_hud()
|
||||
|
||||
|
||||
/mob/living/carbon/update_sight()
|
||||
if(!client)
|
||||
return
|
||||
|
||||
@@ -453,14 +453,14 @@
|
||||
/mob/living/carbon/getBruteLoss_nonProsthetic()
|
||||
var/amount = 0
|
||||
for(var/obj/item/bodypart/BP in bodyparts)
|
||||
if (BP.status < 2)
|
||||
if (BP.is_organic_limb())
|
||||
amount += BP.brute_dam
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/getFireLoss_nonProsthetic()
|
||||
var/amount = 0
|
||||
for(var/obj/item/bodypart/BP in bodyparts)
|
||||
if (BP.status < 2)
|
||||
if (BP.is_organic_limb())
|
||||
amount += BP.burn_dam
|
||||
return amount
|
||||
|
||||
|
||||
@@ -212,6 +212,7 @@
|
||||
// called when something steps onto a human
|
||||
// this could be made more general, but for now just handle mulebot
|
||||
/mob/living/carbon/human/Crossed(atom/movable/AM)
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_CROSSED, AM)
|
||||
var/mob/living/simple_animal/bot/mulebot/MB = AM
|
||||
if(istype(MB))
|
||||
MB.RunOver(src)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/mob/living/carbon/human/getarmor(def_zone, type)
|
||||
if(HAS_TRAIT(src, TRAIT_ARMOR_BROKEN)) //trait that makes it act as if you have no armor at all, you take natural damage from all sources
|
||||
return 0
|
||||
var/armorval = 0
|
||||
var/organnum = 0
|
||||
|
||||
@@ -18,7 +20,6 @@
|
||||
organnum++
|
||||
return (armorval/max(organnum, 1))
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/def_zone, d_type)
|
||||
if(!d_type || !def_zone)
|
||||
return 0
|
||||
|
||||
@@ -668,7 +668,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
H.remove_overlay(BODY_FRONT_LAYER)
|
||||
H.remove_overlay(HORNS_LAYER)
|
||||
|
||||
if(!mutant_bodyparts)
|
||||
if(!length(mutant_bodyparts))
|
||||
return
|
||||
|
||||
var/tauric = mutant_bodyparts["taur"] && H.dna.features["taur"] && H.dna.features["taur"] != "None"
|
||||
@@ -1451,9 +1451,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target.apply_damage(damage*1.5, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
target.apply_damage(damage*0.5, STAMINA, affecting, armor_block)
|
||||
log_combat(user, target, "kicked")
|
||||
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.3x raw damage + 1x stam damage, and have some armor pierce
|
||||
target.apply_damage(damage*1.3, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
target.apply_damage(damage, STAMINA, affecting, armor_block)
|
||||
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.1x raw damage + 1.3x stam damage, and have some armor pierce
|
||||
target.apply_damage(damage*1.1, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
target.apply_damage(damage*1.3, STAMINA, affecting, armor_block)
|
||||
log_combat(user, target, "punched (mauler)")
|
||||
else //other attacks deal full raw damage + 2x in stamina damage
|
||||
target.apply_damage(damage, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
damage_overlay_type = "synth"
|
||||
mutanttongue = /obj/item/organ/tongue/robot
|
||||
species_language_holder = /datum/language_holder/synthetic
|
||||
limbs_id = "synth"
|
||||
limbs_id = SPECIES_SYNTH
|
||||
species_category = SPECIES_CATEGORY_ROBOT
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
|
||||
no_equip = list(SLOT_BACK)
|
||||
blacklisted = 1
|
||||
limbs_id = "human"
|
||||
limbs_id = SPECIES_HUMAN
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/human
|
||||
species_category = SPECIES_CATEGORY_BASIC //they're a kind of human
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
/datum/species/angel/proc/ToggleFlight(mob/living/carbon/human/H,flight)
|
||||
if(flight && CanFly(H))
|
||||
stunmod = 2
|
||||
speedmod = -0.35
|
||||
speedmod = -0.1
|
||||
H.setMovetype(H.movement_type | FLYING)
|
||||
override_float = TRUE
|
||||
H.pass_flags |= PASSTABLE
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/datum/species/arachnid
|
||||
name = "Arachnid"
|
||||
id = "arachnid"
|
||||
id = SPECIES_ARACHNID
|
||||
override_bp_icon = 'icons/mob/arachnid_parts.dmi'
|
||||
say_mod = "chitters"
|
||||
default_color = "00FF00"
|
||||
@@ -59,10 +59,10 @@
|
||||
SW?.Remove(H)
|
||||
|
||||
/datum/action/innate/spin_web
|
||||
name = "Spin Web"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
icon_icon = 'icons/mob/actions/actions_animal.dmi'
|
||||
button_icon_state = "lay_web"
|
||||
name = "Spin Web"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
icon_icon = 'icons/mob/actions/actions_animal.dmi'
|
||||
button_icon_state = "lay_web"
|
||||
|
||||
/datum/action/innate/spin_cocoon
|
||||
name = "Spin Cocoon"
|
||||
@@ -152,4 +152,4 @@
|
||||
else
|
||||
A.forceMove(C)
|
||||
H.visible_message("<span class='danger'>[H] wraps [A] into a cocoon!</span>")
|
||||
return
|
||||
return
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user