Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit277
This commit is contained in:
@@ -41,6 +41,12 @@
|
||||
//Create a list global that is initialized as an empty list
|
||||
#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list())
|
||||
|
||||
// Create a typed list global with an initializer expression
|
||||
#define GLOBAL_LIST_INIT_TYPED(X, Typepath, InitValue) GLOBAL_RAW(/list##Typepath/X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
// Create a typed list global that is initialized as an empty list
|
||||
#define GLOBAL_LIST_EMPTY_TYPED(X, Typepath) GLOBAL_LIST_INIT_TYPED(X, Typepath, list())
|
||||
|
||||
//Create a typed global with an initializer expression
|
||||
#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
|
||||
@@ -147,6 +147,20 @@
|
||||
#define CANATMOSPASS(A, O) ( A.CanAtmosPass == ATMOS_PASS_PROC ? A.CanAtmosPass(O) : ( A.CanAtmosPass == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPass ) )
|
||||
#define CANVERTICALATMOSPASS(A, O) ( A.CanAtmosPassVertical == ATMOS_PASS_PROC ? A.CanAtmosPass(O, TRUE) : ( A.CanAtmosPassVertical == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPassVertical ) )
|
||||
|
||||
//OPEN TURF ATMOS
|
||||
#define OPENTURF_DEFAULT_ATMOS "o2=22;n2=82;TEMP=293.15" //the default air mix that open turfs spawn
|
||||
#define TCOMMS_ATMOS "n2=100;TEMP=80" //-193,15°C telecommunications. also used for xenobiology slime killrooms
|
||||
#define AIRLESS_ATMOS "TEMP=2.7" //space
|
||||
#define FROZEN_ATMOS "o2=22;n2=82;TEMP=180" //-93.15°C snow and ice turfs
|
||||
#define BURNMIX_ATMOS "o2=2500;plasma=5000;TEMP=370" //used in the holodeck burn test program
|
||||
|
||||
//ATMOSPHERICS DEPARTMENT GAS TANK TURFS
|
||||
#define ATMOS_TANK_N2O "n2o=6000;TEMP=293.15"
|
||||
#define ATMOS_TANK_CO2 "co2=50000;TEMP=293.15"
|
||||
#define ATMOS_TANK_PLASMA "plasma=70000;TEMP=293.15"
|
||||
#define ATMOS_TANK_O2 "o2=100000;TEMP=293.15"
|
||||
#define ATMOS_TANK_N2 "n2=100000;TEMP=293.15"
|
||||
#define ATMOS_TANK_AIRMIX "o2=2644;n2=10580;TEMP=293.15"
|
||||
//LAVALAND
|
||||
#define LAVALAND_EQUIPMENT_EFFECT_PRESSURE 50 //what pressure you have to be under to increase the effect of equipment meant for lavaland
|
||||
#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=23;TEMP=300"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#define DONATOR_GROUP_TIER_1_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_1_donators
|
||||
#define DONATOR_GROUP_TIER_2_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_2_donators
|
||||
#define DONATOR_GROUP_TIER_3_CONFIG_PATH /datum/config_entry/keyed_list/donator_group/tier_3_donators
|
||||
#define DONATOR_GROUP_TIER_1_CONFIG_PATH /datum/config_entry/multi_keyed_flag/donator_group/tier_1_donators
|
||||
#define DONATOR_GROUP_TIER_2_CONFIG_PATH /datum/config_entry/multi_keyed_flag/donator_group/tier_2_donators
|
||||
#define DONATOR_GROUP_TIER_3_CONFIG_PATH /datum/config_entry/multi_keyed_flag/donator_group/tier_3_donators
|
||||
|
||||
#define DONATOR_GROUP_TIER_1_CONFIG_SUBPATH keyed_list/donator_group/tier_1_donators
|
||||
#define DONATOR_GROUP_TIER_2_CONFIG_SUBPATH keyed_list/donator_group/tier_2_donators
|
||||
#define DONATOR_GROUP_TIER_3_CONFIG_SUBPATH keyed_list/donator_group/tier_3_donators
|
||||
#define DONATOR_GROUP_TIER_1_CONFIG_SUBPATH multi_keyed_flag/donator_group/tier_1_donators
|
||||
#define DONATOR_GROUP_TIER_2_CONFIG_SUBPATH multi_keyed_flag/donator_group/tier_2_donators
|
||||
#define DONATOR_GROUP_TIER_3_CONFIG_SUBPATH multi_keyed_flag/donator_group/tier_3_donators
|
||||
|
||||
#define TIER_1_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_1_CONFIG_SUBPATH)
|
||||
#define TIER_2_DONATORS CONFIG_GET(DONATOR_GROUP_TIER_2_CONFIG_SUBPATH)
|
||||
|
||||
@@ -210,6 +210,8 @@ GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list(
|
||||
|
||||
#define isitem(A) (istype(A, /obj/item))
|
||||
|
||||
#define isidcard(I) (istype(I, /obj/item/card/id))
|
||||
|
||||
#define isstructure(A) (istype(A, /obj/structure))
|
||||
|
||||
#define ismachinery(A) (istype(A, /obj/machinery))
|
||||
|
||||
@@ -75,3 +75,10 @@
|
||||
#define JP_LOW 1
|
||||
#define JP_MEDIUM 2
|
||||
#define JP_HIGH 3
|
||||
|
||||
//Chaos levels for dynamic voting
|
||||
#define CHAOS_NONE "None (Extended)"
|
||||
#define CHAOS_LOW "Low"
|
||||
#define CHAOS_MED "Medium"
|
||||
#define CHAOS_HIGH "High"
|
||||
#define CHAOS_MAX "Maximum"
|
||||
|
||||
@@ -213,3 +213,4 @@
|
||||
#define NINJA_SUIT_TRAIT "ninja-suit"
|
||||
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
|
||||
#define ABDUCTOR_ANTAGONIST "abductor-antagonist"
|
||||
#define MADE_UNCLONEABLE "made-uncloneable"
|
||||
|
||||
@@ -84,3 +84,9 @@ GLOBAL_VAR_INIT(cmp_field, "name")
|
||||
|
||||
/proc/cmp_job_display_asc(datum/job/A, datum/job/B)
|
||||
return A.display_order - B.display_order
|
||||
|
||||
/proc/cmp_numbered_displays_name_asc(datum/numbered_display/A, datum/numbered_display/B)
|
||||
return sorttext(A.sample_object.name, B.sample_object.name)
|
||||
|
||||
/proc/cmp_numbered_displays_name_dsc(datum/numbered_display/A, datum/numbered_display/B)
|
||||
return sorttext(B.sample_object.name, A.sample_object.name)
|
||||
@@ -313,8 +313,14 @@
|
||||
parts += "[FOURSPACES]Threat level: [mode.threat_level]"
|
||||
parts += "[FOURSPACES]Threat left: [mode.threat]"
|
||||
parts += "[FOURSPACES]Executed rules:"
|
||||
for(var/str in mode.threat_log)
|
||||
parts += "[FOURSPACES][FOURSPACES][str]"
|
||||
for(var/entry in mode.threat_tallies)
|
||||
parts += "[FOURSPACES][FOURSPACES][entry] added [mode.threat_tallies[entry]]"
|
||||
/*
|
||||
for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
|
||||
parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost] threat"
|
||||
parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat"
|
||||
*/
|
||||
return parts.Join("<br>")
|
||||
|
||||
/client/proc/roundend_report_file()
|
||||
|
||||
@@ -7,15 +7,15 @@ GLOBAL_LIST_EMPTY(facial_hair_styles_list) //stores /datum/sprite_accessory/faci
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_male_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_female_list) //stores only hair names
|
||||
//Underwear
|
||||
GLOBAL_LIST_EMPTY(underwear_list) //stores /datum/sprite_accessory/underwear/bottom indexed by name
|
||||
GLOBAL_LIST_EMPTY_TYPED(underwear_list, /datum/sprite_accessory/underwear/bottom) //stores bottoms indexed by name
|
||||
GLOBAL_LIST_EMPTY(underwear_m) //stores only underwear name
|
||||
GLOBAL_LIST_EMPTY(underwear_f) //stores only underwear name
|
||||
//Undershirts
|
||||
GLOBAL_LIST_EMPTY(undershirt_list) //stores /datum/sprite_accessory/underwear/top indexed by name
|
||||
GLOBAL_LIST_EMPTY_TYPED(undershirt_list, /datum/sprite_accessory/underwear/top) //stores tops indexed by name
|
||||
GLOBAL_LIST_EMPTY(undershirt_m) //stores only undershirt name
|
||||
GLOBAL_LIST_EMPTY(undershirt_f) //stores only undershirt name
|
||||
//Socks
|
||||
GLOBAL_LIST_EMPTY(socks_list) //stores /datum/sprite_accessory/underwear/socks indexed by name
|
||||
GLOBAL_LIST_EMPTY_TYPED(socks_list, /datum/sprite_accessory/underwear/socks) //stores socks indexed by name
|
||||
//Lizard Bits (all datum lists indexed by name)
|
||||
GLOBAL_LIST_EMPTY(body_markings_list)
|
||||
GLOBAL_LIST_EMPTY(tails_list_lizard)
|
||||
|
||||
@@ -45,6 +45,6 @@ GLOBAL_LIST_EMPTY(vr_spawnpoints)
|
||||
//used by jump-to-area etc. Updated by area/updateName()
|
||||
GLOBAL_LIST_EMPTY(sortedAreas)
|
||||
/// An association from typepath to area instance. Only includes areas with `unique` set.
|
||||
GLOBAL_LIST_EMPTY(areas_by_type)
|
||||
GLOBAL_LIST_EMPTY_TYPED(areas_by_type, /area)
|
||||
|
||||
GLOBAL_LIST_EMPTY(all_abstract_markers)
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#define POLL_IGNORE_GOLEM "golem"
|
||||
#define POLL_IGNORE_SWARMER "swarmer"
|
||||
#define POLL_IGNORE_DRONE "drone"
|
||||
#define POLL_IGNORE_DEMON "demon"
|
||||
#define POLL_IGNORE_WIZARD "wizard"
|
||||
#define POLL_IGNORE_CLONE "clone"
|
||||
|
||||
GLOBAL_LIST_INIT(poll_ignore_desc, list(
|
||||
@@ -29,6 +31,8 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list(
|
||||
POLL_IGNORE_GOLEM = "Golems",
|
||||
POLL_IGNORE_SWARMER = "Swarmer shells",
|
||||
POLL_IGNORE_DRONE = "Drone shells",
|
||||
POLL_IGNORE_DEMON = "Demons",
|
||||
POLL_IGNORE_WIZARD = "Wizards",
|
||||
POLL_IGNORE_CLONE = "Defective/SDGF clones"
|
||||
))
|
||||
GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore())
|
||||
|
||||
@@ -211,3 +211,27 @@
|
||||
|
||||
/datum/config_entry/keyed_list/vv_edit_var(var_name, var_value)
|
||||
return var_name != "splitter" && ..()
|
||||
|
||||
//snowflake for donator things being on one line smh
|
||||
/datum/config_entry/multi_keyed_flag
|
||||
vv_VAS = FALSE
|
||||
abstract_type = /datum/config_entry/multi_keyed_flag
|
||||
config_entry_value = list()
|
||||
var/delimiter = "|"
|
||||
|
||||
/datum/config_entry/multi_keyed_flag/vv_edit_var(var_name, var_value)
|
||||
if(var_name == NAMEOF(src, delimiter))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/config_entry/multi_keyed_flag/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
str_val = trim(str_val)
|
||||
var/list/keys = splittext(str_val, delimiter)
|
||||
for(var/i in keys)
|
||||
config_entry_value[process_key(i)] = TRUE
|
||||
return length(keys)? TRUE : FALSE
|
||||
|
||||
/datum/config_entry/multi_keyed_flag/proc/process_key(key)
|
||||
return trim(key)
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
/datum/config_entry/keyed_list/donator_group
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_FLAG
|
||||
abstract_type = /datum/config_entry/keyed_list/donator_group
|
||||
/datum/config_entry/multi_keyed_flag/donator_group
|
||||
abstract_type = /datum/config_entry/multi_keyed_flag/donator_group
|
||||
|
||||
//If we're in the middle of a config load, only do the regeneration afterwards to prevent this from wasting a massive amount of CPU for list regenerations.
|
||||
/datum/config_entry/keyed_list/donator_group/ValidateAndSet(str_val, during_load)
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/ValidateAndSet(str_val, during_load)
|
||||
. = ..()
|
||||
if(. && during_load)
|
||||
if(. && !during_load)
|
||||
regenerate_donator_grouping_list()
|
||||
|
||||
/datum/config_entry/keyed_list/donator_group/OnPostload()
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/process_key(key)
|
||||
return ckey(key)
|
||||
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/OnPostload()
|
||||
. = ..()
|
||||
regenerate_donator_grouping_list()
|
||||
|
||||
//This is kinda weird in that the config entries are defined here but all the handling/calculations are in __HELPERS/donator_groupings.dm
|
||||
|
||||
/datum/config_entry/keyed_list/donator_group/tier_1_donators
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/tier_1_donators
|
||||
|
||||
/datum/config_entry/keyed_list/donator_group/tier_2_donators
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/tier_2_donators
|
||||
|
||||
/datum/config_entry/keyed_list/donator_group/tier_3_donators
|
||||
/datum/config_entry/multi_keyed_flag/donator_group/tier_3_donators
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/datum/config_entry/flag/dynamic_voting
|
||||
|
||||
/datum/config_entry/number/dynamic_high_pop_limit
|
||||
config_entry_value = 55
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_pop_per_requirement
|
||||
config_entry_value = 6
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_min
|
||||
config_entry_value = 15
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_max
|
||||
config_entry_value = 35
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_min
|
||||
config_entry_value = 5
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_max
|
||||
config_entry_value = 25
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_midround_delay_min
|
||||
config_entry_value = 20
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_midround_delay_max
|
||||
config_entry_value = 40
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_latejoin_delay_min
|
||||
config_entry_value = 10
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_first_latejoin_delay_max
|
||||
config_entry_value = 30
|
||||
min_val = 1
|
||||
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_cost
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_weight
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_requirements
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM_LIST
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_high_population_requirement
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/number_list/dynamic_second_rule_requirements
|
||||
|
||||
/datum/config_entry/number_list/dynamic_third_rule_requirements
|
||||
|
||||
/datum/config_entry/number/dynamic_second_rule_high_pop_requirement
|
||||
config_entry_value = 50
|
||||
|
||||
/datum/config_entry/number/dynamic_third_rule_high_pop_requirement
|
||||
config_entry_value = 70
|
||||
|
||||
/datum/config_entry/number_list/dynamic_hijack_requirements
|
||||
|
||||
/datum/config_entry/number/dynamic_hijack_high_population_requirement
|
||||
config_entry_value = 25
|
||||
|
||||
/datum/config_entry/number/dynamic_hijack_cost
|
||||
config_entry_value = 5
|
||||
|
||||
/datum/config_entry/number/dynamic_glorious_death_cost
|
||||
config_entry_value = 5
|
||||
|
||||
/datum/config_entry/number/dynamic_assassinate_cost
|
||||
config_entry_value = 2
|
||||
|
||||
/datum/config_entry/number/dynamic_warops_requirement
|
||||
config_entry_value = 60
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/dynamic_warops_cost
|
||||
config_entry_value = 10
|
||||
min_val = 0
|
||||
@@ -379,43 +379,3 @@
|
||||
/datum/config_entry/number/auto_transfer_delay
|
||||
config_entry_value = 72000
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/dynamic_high_pop_limit
|
||||
config_entry_value = 55
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_pop_per_requirement
|
||||
config_entry_value = 6
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_min
|
||||
config_entry_value = 15
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_midround_delay_max
|
||||
config_entry_value = 35
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_min
|
||||
config_entry_value = 5
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/number/dynamic_latejoin_delay_max
|
||||
config_entry_value = 25
|
||||
min_val = 1
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_cost
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_weight
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_requirements
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM_LIST
|
||||
|
||||
/datum/config_entry/keyed_list/dynamic_high_population_requirement
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_NUM
|
||||
|
||||
@@ -29,6 +29,7 @@ SUBSYSTEM_DEF(chat)
|
||||
target = GLOB.clients
|
||||
|
||||
//Some macros remain in the string even after parsing and fuck up the eventual output
|
||||
var/original_message = message
|
||||
message = replacetext(message, "\improper", "")
|
||||
message = replacetext(message, "\proper", "")
|
||||
if(handle_whitespace)
|
||||
@@ -45,6 +46,12 @@ SUBSYSTEM_DEF(chat)
|
||||
for(var/I in target)
|
||||
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
|
||||
|
||||
if(!C)
|
||||
return
|
||||
|
||||
//Send it to the old style output window.
|
||||
SEND_TEXT(C, original_message)
|
||||
|
||||
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
|
||||
continue
|
||||
|
||||
@@ -57,6 +64,12 @@ SUBSYSTEM_DEF(chat)
|
||||
else
|
||||
var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
|
||||
|
||||
if(!C)
|
||||
return
|
||||
|
||||
//Send it to the old style output window.
|
||||
SEND_TEXT(C, original_message)
|
||||
|
||||
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
|
||||
return
|
||||
|
||||
|
||||
@@ -444,7 +444,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
GLOB.the_gateway.wait = world.time
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override, border_type_override)
|
||||
UNTIL(reservation_ready["[z]"] && !clearing_reserved_turfs)
|
||||
UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs)
|
||||
var/datum/turf_reservation/reserve = new type
|
||||
if(turf_type_override)
|
||||
reserve.turf_type = turf_type_override
|
||||
|
||||
@@ -479,7 +479,8 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(SSticker.timeLeft < 900)
|
||||
SSticker.timeLeft = 900
|
||||
SSticker.modevoted = TRUE
|
||||
SSvote.initiate_vote("roundtype","server",TRUE)
|
||||
var/dynamic = CONFIG_GET(flag/dynamic_voting)
|
||||
SSvote.initiate_vote(dynamic ? "dynamic" : "roundtype","server",TRUE)
|
||||
|
||||
/datum/controller/subsystem/ticker/Recover()
|
||||
current_state = SSticker.current_state
|
||||
|
||||
@@ -29,8 +29,8 @@ SUBSYSTEM_DEF(vis_overlays)
|
||||
return
|
||||
|
||||
//the "thing" var can be anything with vis_contents which includes images
|
||||
/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha=255)
|
||||
. = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]"
|
||||
/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE)
|
||||
. = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
|
||||
var/obj/effect/overlay/vis/overlay = vis_overlay_cache[.]
|
||||
if(!overlay)
|
||||
overlay = new
|
||||
@@ -40,6 +40,7 @@ SUBSYSTEM_DEF(vis_overlays)
|
||||
overlay.plane = plane
|
||||
overlay.dir = dir
|
||||
overlay.alpha = alpha
|
||||
overlay.appearance_flags |= add_appearance_flags
|
||||
vis_overlay_cache[.] = overlay
|
||||
else
|
||||
overlay.unused = 0
|
||||
@@ -64,10 +65,12 @@ SUBSYSTEM_DEF(vis_overlays)
|
||||
UnregisterSignal(thing, COMSIG_ATOM_DIR_CHANGE)
|
||||
|
||||
/datum/controller/subsystem/vis_overlays/proc/rotate_vis_overlay(atom/thing, old_dir, new_dir)
|
||||
if(old_dir == new_dir)
|
||||
return
|
||||
var/rotation = dir2angle(old_dir) - dir2angle(new_dir)
|
||||
var/list/overlays_to_remove = list()
|
||||
for(var/i in thing.managed_vis_overlays)
|
||||
var/obj/effect/overlay/vis/overlay = i
|
||||
add_vis_overlay(thing, overlay.icon, overlay.icon_state, overlay.layer, overlay.plane, turn(overlay.dir, rotation))
|
||||
add_vis_overlay(thing, overlay.icon, overlay.icon_state, overlay.layer, overlay.plane, turn(overlay.dir, rotation), overlay.alpha, overlay.appearance_flags)
|
||||
overlays_to_remove += overlay
|
||||
remove_vis_overlay(thing, overlays_to_remove)
|
||||
|
||||
@@ -87,7 +87,7 @@ SUBSYSTEM_DEF(vote)
|
||||
/datum/controller/subsystem/vote/proc/announce_result()
|
||||
var/list/winners = get_result()
|
||||
var/text
|
||||
var/was_roundtype_vote = mode == "roundtype"
|
||||
var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic"
|
||||
if(winners.len > 0)
|
||||
if(question)
|
||||
text += "<b>[question]</b>"
|
||||
@@ -124,6 +124,9 @@ SUBSYSTEM_DEF(vote)
|
||||
message_admins(admintext)
|
||||
return .
|
||||
|
||||
#define PEACE "calm"
|
||||
#define CHAOS "chaotic"
|
||||
|
||||
/datum/controller/subsystem/vote/proc/result()
|
||||
. = announce_result()
|
||||
var/restart = 0
|
||||
@@ -146,6 +149,32 @@ SUBSYSTEM_DEF(vote)
|
||||
restart = 1
|
||||
else
|
||||
GLOB.master_mode = .
|
||||
if("dynamic")
|
||||
if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started.
|
||||
return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
|
||||
GLOB.master_mode = "dynamic"
|
||||
var/mean = 0
|
||||
var/voters = 0
|
||||
for(var/client/c in GLOB.clients)
|
||||
var/vote = c.prefs.preferred_chaos
|
||||
if(vote)
|
||||
voters += 1
|
||||
switch(vote)
|
||||
if(CHAOS_NONE)
|
||||
mean -= 0.1
|
||||
if(CHAOS_LOW)
|
||||
mean -= 0.05
|
||||
if(CHAOS_HIGH)
|
||||
mean += 0.05
|
||||
if(CHAOS_MAX)
|
||||
mean += 0.1
|
||||
mean/=voters
|
||||
if(voted.len != 0)
|
||||
mean += (choices[PEACE]*-1+choices[CHAOS])/voted.len
|
||||
GLOB.dynamic_curve_centre = mean*20
|
||||
GLOB.dynamic_curve_width = CLAMP(2-abs(mean*5),0.5,4)
|
||||
to_chat(world,"<span class='boldannounce'>Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width].</span>")
|
||||
log_admin("Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width]")
|
||||
if("map")
|
||||
var/datum/map_config/VM = config.maplist[.]
|
||||
message_admins("The map has been voted for and will change to: [VM.map_name]")
|
||||
@@ -223,6 +252,8 @@ SUBSYSTEM_DEF(vote)
|
||||
choices |= M
|
||||
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
|
||||
choices.Add("secret", "extended")
|
||||
if("dynamic")
|
||||
choices.Add(PEACE,CHAOS)
|
||||
if("custom")
|
||||
question = stripped_input(usr,"What is the vote for?")
|
||||
if(!question)
|
||||
@@ -379,4 +410,7 @@ SUBSYSTEM_DEF(vote)
|
||||
else if(owner.ckey)
|
||||
var/datum/player_details/P = GLOB.player_details[owner.ckey]
|
||||
if(P)
|
||||
P.player_actions -= src
|
||||
P.player_actions -= src
|
||||
|
||||
#undef PEACE
|
||||
#undef CHAOS
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
/datum/component/lockon_aiming
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
var/lock_icon = 'icons/mob/blob.dmi'
|
||||
var/lock_icon = 'icons/mob/cameramob.dmi'
|
||||
var/lock_icon_state = "marker"
|
||||
var/mutable_appearance/lock_appearance
|
||||
var/list/image/lock_images
|
||||
|
||||
@@ -309,6 +309,7 @@
|
||||
else
|
||||
var/datum/numbered_display/ND = .[I.type]
|
||||
ND.number++
|
||||
. = sortTim(., /proc/cmp_numbered_displays_name_asc, associative = TRUE)
|
||||
|
||||
//This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing.
|
||||
/datum/component/storage/proc/orient2hud(mob/user, maxcolumns)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
var/restraining = 0 //used in cqc's disarm_act to check if the disarmed is being restrained and so whether they should be put in a chokehold or not
|
||||
var/help_verb
|
||||
var/no_guns = FALSE
|
||||
var/pacifism_check = TRUE //are the martial arts combos/attacks unable to be used by pacifist.
|
||||
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
|
||||
|
||||
/datum/martial_art/proc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/martial_art/boxing
|
||||
name = "Boxing"
|
||||
id = MARTIALART_BOXING
|
||||
pacifism_check = FALSE //Let's pretend pacifists can boxe the heck out of other people, it only deals stamina damage right now.
|
||||
|
||||
/datum/martial_art/boxing/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
to_chat(A, "<span class='warning'>Can't disarm while boxing!</span>")
|
||||
@@ -16,14 +17,15 @@
|
||||
|
||||
var/atk_verb = pick("left hook","right hook","straight punch")
|
||||
|
||||
var/damage = rand(5, 8) + A.dna.species.punchdamagelow
|
||||
if(!damage)
|
||||
var/damage = rand(10, 13)
|
||||
var/extra_damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
|
||||
if(extra_damage == A.dna.species.punchdamagelow)
|
||||
playsound(D.loc, A.dna.species.miss_sound, 25, 1, -1)
|
||||
D.visible_message("<span class='warning'>[A] has attempted to [atk_verb] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] has attempted to [atk_verb] [D]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
log_combat(A, D, "attempted to hit", atk_verb)
|
||||
return 0
|
||||
|
||||
return TRUE
|
||||
damage += extra_damage
|
||||
|
||||
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
|
||||
var/armor_block = D.run_armor_check(affecting, "melee")
|
||||
|
||||
@@ -124,6 +124,8 @@
|
||||
add_to_streak("G",D)
|
||||
if(check_streak(A,D))
|
||||
return TRUE
|
||||
if(A == D) // no self grab.
|
||||
return FALSE
|
||||
if(A.grab_state >= GRAB_AGGRESSIVE)
|
||||
D.grabbedby(A, 1)
|
||||
else
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
owner.visible_message("<span class='danger'>[owner] assumes a neutral stance.</span>", "<b><i>Your next attack is cleared.</i></b>")
|
||||
H.mind.martial_art.streak = ""
|
||||
else
|
||||
if(HAS_TRAIT(H, TRAIT_PACIFISM))
|
||||
to_chat(H, "<span class='warning'>You don't want to harm other people!</span>")
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] assumes the Neck Chop stance!</span>", "<b><i>Your next attack will be a Neck Chop.</i></b>")
|
||||
H.mind.martial_art.streak = "neck_chop"
|
||||
|
||||
@@ -36,6 +39,9 @@
|
||||
owner.visible_message("<span class='danger'>[owner] assumes a neutral stance.</span>", "<b><i>Your next attack is cleared.</i></b>")
|
||||
H.mind.martial_art.streak = ""
|
||||
else
|
||||
if(HAS_TRAIT(H, TRAIT_PACIFISM))
|
||||
to_chat(H, "<span class='warning'>You don't want to harm other people!</span>")
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] assumes the Leg Sweep stance!</span>", "<b><i>Your next attack will be a Leg Sweep.</i></b>")
|
||||
H.mind.martial_art.streak = "leg_sweep"
|
||||
|
||||
@@ -53,6 +59,9 @@
|
||||
owner.visible_message("<span class='danger'>[owner] assumes a neutral stance.</span>", "<b><i>Your next attack is cleared.</i></b>")
|
||||
H.mind.martial_art.streak = ""
|
||||
else
|
||||
if(HAS_TRAIT(H, TRAIT_PACIFISM))
|
||||
to_chat(H, "<span class='warning'>You don't want to harm other people!</span>")
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] assumes the Lung Punch stance!</span>", "<b><i>Your next attack will be a Lung Punch.</i></b>")
|
||||
H.mind.martial_art.streak = "quick_choke"//internal name for lung punch
|
||||
|
||||
@@ -145,8 +154,6 @@
|
||||
return 1
|
||||
|
||||
/datum/martial_art/krav_maga/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
var/obj/item/I = null
|
||||
if(prob(60))
|
||||
I = D.get_active_held_item()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/martial_art/psychotic_brawling
|
||||
name = "Psychotic Brawling"
|
||||
id = MARTIALART_PSYCHOBRAWL
|
||||
pacifism_check = FALSE //Quite uncontrollable and unpredictable, people will still end up harming others with it.
|
||||
|
||||
/datum/martial_art/psychotic_brawling/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
return psycho_attack(A,D)
|
||||
|
||||
@@ -105,6 +105,8 @@
|
||||
add_to_streak("G",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
if(A == D) //no self grab stun
|
||||
return FALSE
|
||||
if(A.grab_state >= GRAB_AGGRESSIVE)
|
||||
D.grabbedby(A, 1)
|
||||
else
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
|
||||
return
|
||||
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
|
||||
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to BODY SLAM!</span>", "<b><i>Your next attack will be a BODY SLAM.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.mind.martial_art.streak = "slam"
|
||||
@@ -61,6 +64,9 @@
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
|
||||
return
|
||||
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
|
||||
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to THROW!</span>", "<b><i>Your next attack will be a THROW.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.mind.martial_art.streak = "throw"
|
||||
@@ -73,6 +79,9 @@
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
|
||||
return
|
||||
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
|
||||
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to KICK!</span>", "<b><i>Your next attack will be a KICK.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.mind.martial_art.streak = "kick"
|
||||
@@ -85,6 +94,9 @@
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
|
||||
return
|
||||
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
|
||||
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to STRIKE!</span>", "<b><i>Your next attack will be a STRIKE.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.mind.martial_art.streak = "strike"
|
||||
@@ -97,6 +109,9 @@
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, "<span class='warning'>You can't WRESTLE while you're OUT FOR THE COUNT.</span>")
|
||||
return
|
||||
if(HAS_TRAIT(owner, TRAIT_PACIFISM))
|
||||
to_chat(owner, "<span class='warning'>You are too HIPPIE to WRESTLE other living beings!</span>")
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to LEG DROP!</span>", "<b><i>Your next attack will be a LEG DROP.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.mind.martial_art.streak = "drop"
|
||||
@@ -433,8 +448,8 @@
|
||||
/datum/martial_art/wrestling/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
if(A.pulling == D)
|
||||
return 1
|
||||
if(A.pulling == D || A == D) // don't stun grab yoursel
|
||||
return FALSE
|
||||
A.start_pulling(D)
|
||||
D.visible_message("<span class='danger'>[A] gets [D] in a cinch!</span>", \
|
||||
"<span class='userdanger'>[A] gets [D] in a cinch!</span>")
|
||||
|
||||
@@ -28,16 +28,16 @@
|
||||
var/can_be_admin_equipped = TRUE // Set to FALSE if your outfit requires runtime parameters
|
||||
var/list/chameleon_extras //extra types for chameleon outfit changes, mostly guns
|
||||
|
||||
/datum/outfit/proc/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
/datum/outfit/proc/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
//to be overridden for customization depending on client prefs,species etc
|
||||
return
|
||||
|
||||
/datum/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
/datum/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
//to be overridden for toggling internals, id binding, access etc
|
||||
return
|
||||
|
||||
/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
pre_equip(H, visualsOnly)
|
||||
/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
pre_equip(H, visualsOnly, preference_source)
|
||||
|
||||
//Start with uniform,suit,backpack for additional slots
|
||||
if(uniform)
|
||||
@@ -103,7 +103,7 @@
|
||||
var/obj/item/clothing/suit/space/hardsuit/HS = H.wear_suit
|
||||
HS.ToggleHelmet()
|
||||
|
||||
post_equip(H, visualsOnly)
|
||||
post_equip(H, visualsOnly, preference_source)
|
||||
|
||||
if(!visualsOnly)
|
||||
apply_fingerprints(H)
|
||||
|
||||
@@ -339,10 +339,6 @@ Credit where due:
|
||||
CLOCKCULTCHANGELOG\
|
||||
</ul>\
|
||||
<hr>\
|
||||
<li><b>Zelus oil:</b> A new reagent. It can be used to heal the faithful to Ratvar, or kill heretics and moreso stun blood cultists,\
|
||||
or splashed onto metal sheets to make brass. This chemical can be found in minimal quantities by grinding brass sheets.\
|
||||
<li><b>Brass Flasks:</b>Intended to store Zelus Oil in, but can also be used as fragile single use throwing weapons in a pinch! \
|
||||
These are crafted with a single sheet of brass and fit in the Clockwork Cuirass' suit storage.\
|
||||
<b>Good luck!</b>"
|
||||
|
||||
/obj/item/paper/servant_primer/Initialize()
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
/datum/outfit/syndicate/clownop/no_crystals
|
||||
tc = 0
|
||||
|
||||
/datum/outfit/syndicate/clownop/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
/datum/outfit/syndicate/clownop/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
..()
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
@@ -11,15 +11,26 @@
|
||||
#define RULESET_STOP_PROCESSING 1
|
||||
|
||||
// -- Injection delays
|
||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (5 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (25 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (10 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (30 MINUTES))
|
||||
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_min, (15 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_max, (35 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_min, (10 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_midround_delay_max, (30 MINUTES))
|
||||
|
||||
GLOBAL_VAR_INIT(dynamic_event_delay_min, (10 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_event_delay_max, (30 MINUTES)) // this is on top of regular events, so can't be quite as often
|
||||
|
||||
|
||||
// -- Roundstart injection delays
|
||||
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_min, (2 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_max, (30 MINUTES))
|
||||
|
||||
GLOBAL_VAR_INIT(dynamic_first_midround_delay_min, (20 MINUTES))
|
||||
GLOBAL_VAR_INIT(dynamic_first_midround_delay_max, (30 MINUTES))
|
||||
|
||||
// Are HIGHLANDER_RULESETs allowed to stack?
|
||||
GLOBAL_VAR_INIT(dynamic_no_stacking, TRUE)
|
||||
// A number between -5 and +5.
|
||||
// A number between -5 and +5.
|
||||
// A negative value will give a more peaceful round and
|
||||
// a positive value will give a round with higher threat.
|
||||
GLOBAL_VAR_INIT(dynamic_curve_centre, 0)
|
||||
@@ -27,7 +38,7 @@ GLOBAL_VAR_INIT(dynamic_curve_centre, 0)
|
||||
// Higher value will favour extreme rounds and
|
||||
// lower value rounds closer to the average.
|
||||
GLOBAL_VAR_INIT(dynamic_curve_width, 1.8)
|
||||
// If enabled only picks a single starting rule and executes only autotraitor midround ruleset.
|
||||
// If enabled only picks a single starting rule and executes only autotraitor midround ruleset.
|
||||
GLOBAL_VAR_INIT(dynamic_classic_secret, FALSE)
|
||||
// How many roundstart players required for high population override to take effect.
|
||||
GLOBAL_VAR_INIT(dynamic_high_pop_limit, 55)
|
||||
@@ -38,7 +49,7 @@ GLOBAL_VAR_INIT(dynamic_forced_extended, FALSE)
|
||||
GLOBAL_VAR_INIT(dynamic_stacking_limit, 90)
|
||||
// List of forced roundstart rulesets.
|
||||
GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset)
|
||||
// Forced threat level, setting this to zero or higher forces the roundstart threat to the value.
|
||||
// Forced threat level, setting this to zero or higher forces the roundstart threat to the value.
|
||||
GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
|
||||
/datum/game_mode/dynamic
|
||||
@@ -49,20 +60,28 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
announce_text = "Dynamic mode!" // This needs to be changed maybe
|
||||
|
||||
reroll_friendly = FALSE;
|
||||
|
||||
|
||||
// Threat logging vars
|
||||
/// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations
|
||||
var/threat_level = 0
|
||||
var/threat_level = 0
|
||||
/// Set at the beginning of the round. Spent by the mode to "purchase" rules.
|
||||
var/threat = 0
|
||||
/// Starting threat level, for things that increase it but can bring it back down.
|
||||
var/initial_threat_level = 0
|
||||
/// Things that cause a rolling threat adjustment to be displayed at roundend.
|
||||
var/list/threat_tallies = list()
|
||||
/// Running information about the threat. Can store text or datum entries.
|
||||
var/list/threat_log = list()
|
||||
/// As above, but with info such as refunds.
|
||||
var/list/threat_log_verbose = list()
|
||||
/// List of roundstart rules used for selecting the rules.
|
||||
var/list/roundstart_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.
|
||||
var/list/midround_rules = list()
|
||||
/// List of events used for reducing threat without causing antag injection (necessarily).
|
||||
var/list/events = list()
|
||||
/** # Pop range per requirement.
|
||||
* If the value is five the range is:
|
||||
* 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+
|
||||
@@ -71,15 +90,21 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
* If it is seven the range is:
|
||||
* 0-6, 7-13, 14-20, 21-27, 28-34, 35-41, 42-48, 49-55, 56-62, 63+
|
||||
*/
|
||||
var/pop_per_requirement = 6
|
||||
/// The requirement used for checking if a second rule should be selected.
|
||||
var/pop_per_requirement = 9
|
||||
/// The requirement used for checking if a second rule should be selected. Index based on pop_per_requirement.
|
||||
var/list/second_rule_req = list(100, 100, 80, 70, 60, 50, 30, 20, 10, 0)
|
||||
/// The requirement used for checking if a third rule should be selected.
|
||||
/// The probability for a second ruleset with index being every ten threat.
|
||||
var/list/second_rule_prob = list(0,0,60,80,80,80,100,100,100,100)
|
||||
/// The requirement used for checking if a third rule should be selected. Index based on pop_per_requirement.
|
||||
var/list/third_rule_req = list(100, 100, 100, 90, 80, 70, 60, 50, 40, 30)
|
||||
/// Threat requirement for a second ruleset when high pop override is in effect.
|
||||
/// The probability for a third ruleset with index being every ten threat.
|
||||
var/list/third_rule_prob = list(0,0,0,0,60,60,80,90,100,100)
|
||||
/// Threat requirement for a second ruleset when high pop override is in effect.
|
||||
var/high_pop_second_rule_req = 40
|
||||
/// Threat requirement for a third ruleset when high pop override is in effect.
|
||||
/// Threat requirement for a third ruleset when high pop override is in effect.
|
||||
var/high_pop_third_rule_req = 60
|
||||
/// The amount of additional rulesets waiting to be picked.
|
||||
var/extra_rulesets_amount = 0
|
||||
/// Number of players who were ready on roundstart.
|
||||
var/roundstart_pop_ready = 0
|
||||
/// List of candidates used on roundstart rulesets.
|
||||
@@ -94,6 +119,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
var/latejoin_injection_cooldown = 0
|
||||
/// When world.time is over this number the mode tries to inject a midround ruleset.
|
||||
var/midround_injection_cooldown = 0
|
||||
/// When wor.dtime is over this number the mode tries to do an event.
|
||||
var/event_injection_cooldown = 0
|
||||
/// When TRUE GetInjectionChance returns 100.
|
||||
var/forced_injection = FALSE
|
||||
/// Forced ruleset to be executed for the next latejoin.
|
||||
@@ -106,19 +133,33 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
var/highlander_executed = FALSE
|
||||
/// If a only ruleset has been executed.
|
||||
var/only_ruleset_executed = 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
|
||||
|
||||
/datum/game_mode/dynamic/New() // i have NO IDEA if this is the proper way to do this.
|
||||
..()
|
||||
pop_per_requirement = CONFIG_GET(number/dynamic_pop_per_requirement)
|
||||
second_rule_req = CONFIG_GET(number_list/dynamic_second_rule_requirements)
|
||||
third_rule_req = CONFIG_GET(number_list/dynamic_third_rule_requirements)
|
||||
if(second_rule_req.len<10)
|
||||
second_rule_req = list(101, 101, 101, 101, 100, 90, 80, 70, 60, 50)
|
||||
if(third_rule_req.len<10)
|
||||
third_rule_req = list(101, 101, 101, 101, 101, 100, 90, 80, 70, 60)
|
||||
high_pop_second_rule_req = CONFIG_GET(number/dynamic_second_rule_high_pop_requirement)
|
||||
high_pop_third_rule_req = CONFIG_GET(number/dynamic_third_rule_high_pop_requirement)
|
||||
GLOB.dynamic_high_pop_limit = CONFIG_GET(number/dynamic_high_pop_limit)
|
||||
GLOB.dynamic_latejoin_delay_min = CONFIG_GET(number/dynamic_latejoin_delay_min)*600
|
||||
GLOB.dynamic_latejoin_delay_max = CONFIG_GET(number/dynamic_latejoin_delay_max)*600
|
||||
GLOB.dynamic_midround_delay_min = CONFIG_GET(number/dynamic_midround_delay_min)*600
|
||||
GLOB.dynamic_midround_delay_max = CONFIG_GET(number/dynamic_midround_delay_max)*600
|
||||
GLOB.dynamic_first_latejoin_delay_min = CONFIG_GET(number/dynamic_first_latejoin_delay_min)*600
|
||||
GLOB.dynamic_first_latejoin_delay_max = CONFIG_GET(number/dynamic_first_latejoin_delay_max)*600
|
||||
GLOB.dynamic_first_midround_delay_min = CONFIG_GET(number/dynamic_first_midround_delay_min)*600
|
||||
GLOB.dynamic_first_midround_delay_max = CONFIG_GET(number/dynamic_first_midround_delay_max)*600
|
||||
|
||||
/datum/game_mode/dynamic/admin_panel()
|
||||
var/list/dat = list("<html><head><title>Game Mode Panel</title></head><body><h1><B>Game Mode Panel</B></h1>")
|
||||
dat += "Dynamic Mode <a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</A><BR>"
|
||||
dat += "Dynamic Mode <a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</A><a href='?src=\ref[src];[HrefToken()]'>\[Refresh\]</A><BR>"
|
||||
dat += "Threat Level: <b>[threat_level]</b><br/>"
|
||||
|
||||
dat += "Threat to Spend: <b>[threat]</b> <a href='?src=\ref[src];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='?src=\ref[src];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>"
|
||||
@@ -140,6 +181,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
dat += "<br>Injection Timers: (<b>[get_injection_chance(TRUE)]%</b> chance)<BR>"
|
||||
dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
|
||||
dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
|
||||
dat += "Event: [(event_injection_cooldown-world.time)>60*10 ? "[round((event_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(event_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];forceevent=1'>\[Now!\]</a><BR>"
|
||||
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
|
||||
|
||||
/datum/game_mode/dynamic/Topic(href, href_list)
|
||||
@@ -171,11 +213,15 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
midround_injection_cooldown = 0
|
||||
forced_injection = TRUE
|
||||
message_admins("[key_name(usr)] forced a midround injection.", 1)
|
||||
else if (href_list["forceevent"])
|
||||
event_injection_cooldown = 0
|
||||
// events always happen anyway
|
||||
message_admins("[key_name(usr)] forced an event.", 1)
|
||||
else if (href_list["threatlog"])
|
||||
show_threatlog(usr)
|
||||
else if (href_list["stacking_limit"])
|
||||
GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num
|
||||
|
||||
|
||||
admin_panel() // Refreshes the window
|
||||
|
||||
// Checks if there are HIGHLANDER_RULESETs and calls the rule's round_result() proc
|
||||
@@ -193,30 +239,33 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
/datum/game_mode/dynamic/send_intercept()
|
||||
. = "<b><i>Central Command Status Summary</i></b><hr>"
|
||||
switch(round(threat_level))
|
||||
if(0 to 19)
|
||||
update_playercounts()
|
||||
if(!current_players[CURRENT_LIVING_ANTAGS].len)
|
||||
. += "<b>Peaceful Waypoint</b></center><BR>"
|
||||
. += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive."
|
||||
else
|
||||
if(0 to 20)
|
||||
. += "<b>Peaceful Waypoint</b></center><BR>"
|
||||
. += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive. However, even deep in our territory there may be subversive elements, especially for such a high-value target as your station. Keep an eye out, but don't expect much trouble."
|
||||
set_security_level(SEC_LEVEL_GREEN)
|
||||
if(21 to 79)
|
||||
var/perc_green = 100-round(100*((threat_level-21)/(79-21)))
|
||||
if(prob(perc_green))
|
||||
. += "<b>Core Territory</b></center><BR>"
|
||||
. += "Your station orbits within reliably mundane, secure space. Although Nanotrasen has a firm grip on security in your region, the valuable resources and strategic position aboard your station make it a potential target for infiltrations. Monitor crew for non-loyal behavior, but expect a relatively tame shift free of large-scale destruction. We expect great things from your station."
|
||||
if(20 to 39)
|
||||
. += "<b>Anomalous Exogeology</b></center><BR>"
|
||||
. += "Although your station lies within what is generally considered Nanotrasen-controlled space, the course of its orbit has caused it to cross unusually close to exogeological features with anomalous readings. Although these features offer opportunities for our research department, it is known that these little understood readings are often correlated with increased activity from competing interstellar organizations and individuals, among them the Wizard Federation and Cult of the Geometer of Blood - all known competitors for Anomaly Type B sites. Exercise elevated caution."
|
||||
if(40 to 65)
|
||||
. += "<b>Contested System</b></center><BR>"
|
||||
. += "Your station's orbit passes along the edge of Nanotrasen's sphere of influence. While subversive elements remain the most likely threat against your station, hostile organizations are bolder here, where our grip is weaker. Exercise increased caution against elite Syndicate strike forces, or Executives forbid, some kind of ill-conceived unionizing attempt."
|
||||
if(66 to 79)
|
||||
. += "<b>Uncharted Space</b></center><BR>"
|
||||
. += "Congratulations and thank you for participating in the NT 'Frontier' space program! Your station is actively orbiting a high value system far from the nearest support stations. Little is known about your region of space, and the opportunity to encounter the unknown invites greater glory. You are encouraged to elevate security as necessary to protect Nanotrasen assets."
|
||||
set_security_level(SEC_LEVEL_GREEN)
|
||||
else if(prob(perc_green))
|
||||
. += "<b>Contested System</b></center><BR>"
|
||||
. += "Your station's orbit passes along the edge of Nanotrasen's sphere of influence. While subversive elements remain the most likely threat against your station, hostile organizations are bolder here, where our grip is weaker. Exercise increased caution against elite Syndicate strike forces, or Executives forbid, some kind of ill-conceived unionizing attempt."
|
||||
set_security_level(SEC_LEVEL_BLUE)
|
||||
else
|
||||
. += "<b>Uncharted Space</b></center><BR>"
|
||||
. += "Congratulations and thank you for participating in the NT 'Frontier' space program! Your station is actively orbiting a high value system far from the nearest support stations. Little is known about your region of space, and the opportunity to encounter the unknown invites greater glory. You are encouraged to elevate security as necessary to protect Nanotrasen assets."
|
||||
set_security_level(SEC_LEVEL_BLUE)
|
||||
if(80 to 99)
|
||||
. += "<b>Black Orbit</b></center><BR>"
|
||||
. += "As part of a mandatory security protocol, we are required to inform you that as a result of your orbital pattern directly behind an astrological body (oriented from our nearest observatory), your station will be under decreased monitoring and support. It is anticipated that your extreme location and decreased surveillance could pose security risks. Avoid unnecessary risks and attempt to keep your station in one piece."
|
||||
set_security_level(SEC_LEVEL_AMBER)
|
||||
if(100)
|
||||
. += "<b>Impending Doom</b></center><BR>"
|
||||
. += "Your station is somehow in the middle of hostile territory, in clear view of any enemy of the corporation. Your likelihood to survive is low, and station destruction is expected and almost inevitable. Secure any sensitive material and neutralize any enemy you will come across. It is important that you at least try to maintain the station.<BR>"
|
||||
. += "Good luck."
|
||||
set_security_level(SEC_LEVEL_RED)
|
||||
|
||||
if(station_goals.len)
|
||||
. += "<hr><b>Special Orders for [station_name()]:</b>"
|
||||
@@ -225,9 +274,10 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
. += G.get_report()
|
||||
|
||||
print_command_report(., "Central Command Status Summary", announce=FALSE)
|
||||
priority_announce("A summary has been copied and printed to all communications consoles.", "Security level elevated.", "intercept")
|
||||
if(GLOB.security_level < SEC_LEVEL_BLUE)
|
||||
set_security_level(SEC_LEVEL_BLUE)
|
||||
if(GLOB.security_level >= SEC_LEVEL_BLUE)
|
||||
priority_announce("A summary has been copied and printed to all communications consoles.", "Security level elevated.", "intercept")
|
||||
else
|
||||
priority_announce("Thanks to the tireless efforts of our security and intelligence divisions, there are currently no likely threats to [station_name()]. Have a secure shift!", "Security Report", "commandreport")
|
||||
|
||||
// Yes, this is copy pasted from game_mode
|
||||
/datum/game_mode/dynamic/check_finished(force_ending)
|
||||
@@ -245,6 +295,11 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if(rule.flags & HIGHLANDER_RULESET)
|
||||
return rule.check_finished()
|
||||
|
||||
/datum/game_mode/dynamic/proc/log_threat(var/log_str,var/verbose = FALSE)
|
||||
threat_log_verbose += ("[worldtime2text()]: "+log_str)
|
||||
if(!verbose)
|
||||
threat_log += log_str
|
||||
|
||||
/datum/game_mode/dynamic/proc/show_threatlog(mob/admin)
|
||||
if(!SSticker.HasRoundStarted())
|
||||
alert("The round hasn't started yet!")
|
||||
@@ -253,9 +308,9 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
var/list/out = list("<TITLE>Threat Log</TITLE><B><font size='3'>Threat Log</font></B><br><B>Starting Threat:</B> [threat_level]<BR>")
|
||||
var/list/out = list("<TITLE>Threat Log</TITLE><B><font size='3'>Threat Log</font></B><br><B>Starting Threat:</B> [initial_threat_level]<BR>")
|
||||
|
||||
for(var/entry in threat_log)
|
||||
for(var/entry in threat_log_verbose)
|
||||
if(istext(entry))
|
||||
out += "[entry]<BR>"
|
||||
|
||||
@@ -273,15 +328,6 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
threat = threat_level
|
||||
|
||||
/datum/game_mode/dynamic/can_start()
|
||||
/* Disabled for now, had some changes that need to be tested and this might interfere with that.
|
||||
if(GLOB.dynamic_curve_centre == 0)
|
||||
// 10 is when the centre starts to decrease
|
||||
// 6 is just 1 + 5 (from the maximum value and the one decreased)
|
||||
// 1 just makes the curve look better, I don't know.
|
||||
// Limited between 1 and 5 then inverted and rounded
|
||||
// With this you get a centre curve that stays at -5 until 10 then first rapidly decreases but slows down at the end
|
||||
GLOB.dynamic_curve_centre = round(-CLAMP((10*6/GLOB.player_list.len)-1, 0, 5), 0.5)
|
||||
*/
|
||||
message_admins("Dynamic mode parameters for the round:")
|
||||
message_admins("Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].")
|
||||
message_admins("Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].")
|
||||
@@ -294,12 +340,17 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
else
|
||||
generate_threat()
|
||||
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
|
||||
latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_latejoin_delay_max + GLOB.dynamic_first_latejoin_delay_min)
|
||||
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
|
||||
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
|
||||
midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
|
||||
midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
|
||||
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
|
||||
|
||||
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
|
||||
initial_threat_level = threat_level
|
||||
return TRUE
|
||||
|
||||
/datum/game_mode/dynamic/pre_setup()
|
||||
@@ -316,24 +367,30 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if ("Midround")
|
||||
if (ruleset.weight)
|
||||
midround_rules += ruleset
|
||||
if("Event")
|
||||
if(ruleset.weight)
|
||||
events += ruleset
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
|
||||
roundstart_pop_ready++
|
||||
candidates.Add(player)
|
||||
log_game("DYNAMIC: Listing [roundstart_rules.len] round start rulesets, and [candidates.len] players ready.")
|
||||
if (candidates.len <= 0)
|
||||
log_game("DYNAMIC: [candidates.len] candidates.")
|
||||
return TRUE
|
||||
if (roundstart_rules.len <= 0)
|
||||
log_game("DYNAMIC: [roundstart_rules.len] rules.")
|
||||
return TRUE
|
||||
|
||||
|
||||
if(GLOB.dynamic_forced_roundstart_ruleset.len > 0)
|
||||
rigged_roundstart()
|
||||
else
|
||||
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]")
|
||||
candidates.Cut()
|
||||
return TRUE
|
||||
|
||||
@@ -341,9 +398,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
update_playercounts()
|
||||
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules)
|
||||
rule.candidates.Cut() // The rule should not use candidates at this point as they all are null.
|
||||
if(!rule.execute())
|
||||
stack_trace("The starting rule \"[rule.name]\" failed to execute.")
|
||||
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_roundstart_rule, rule), rule.delay)
|
||||
..()
|
||||
|
||||
/// A simple roundstart proc used when dynamic_forced_roundstart_ruleset has rules in it.
|
||||
@@ -354,6 +409,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
message_admins("Drafting players for forced ruleset [rule.name].")
|
||||
log_game("DYNAMIC: Drafting players for forced ruleset [rule.name].")
|
||||
rule.mode = src
|
||||
rule.acceptable(GLOB.player_list.len, threat_level) // Assigns some vars in the modes, running it here for consistency
|
||||
rule.candidates = candidates.Copy()
|
||||
rule.trim_candidates()
|
||||
if (rule.ready(TRUE))
|
||||
@@ -365,18 +421,20 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
return TRUE
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules)
|
||||
if (rule.acceptable(roundstart_pop_ready, threat_level) && threat >= rule.cost) // If we got the population and threat required
|
||||
if (rule.acceptable(GLOB.player_list.len, threat_level) && threat >= rule.cost) // If we got the population and threat required
|
||||
rule.candidates = candidates.Copy()
|
||||
rule.trim_candidates()
|
||||
if (rule.ready() && rule.candidates.len > 0)
|
||||
drafted_rules[rule] = rule.weight
|
||||
|
||||
var/indice_pop = min(10,round(roundstart_pop_ready/pop_per_requirement)+1)
|
||||
var/extra_rulesets_amount = 0
|
||||
if(!drafted_rules.len)
|
||||
message_admins("Not enough threat level for roundstart antags!")
|
||||
log_game("DYNAMIC: Not enough threat level for roundstart antags!")
|
||||
var/indice_pop = min(10,round(GLOB.player_list.len/pop_per_requirement)+1)
|
||||
extra_rulesets_amount = 0
|
||||
if (GLOB.dynamic_classic_secret)
|
||||
extra_rulesets_amount = 0
|
||||
else
|
||||
if (roundstart_pop_ready > GLOB.dynamic_high_pop_limit)
|
||||
if (GLOB.player_list.len > GLOB.dynamic_high_pop_limit)
|
||||
message_admins("High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.")
|
||||
log_game("DYNAMIC: High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.")
|
||||
if (threat_level > high_pop_second_rule_req)
|
||||
@@ -384,23 +442,28 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if (threat_level > high_pop_third_rule_req)
|
||||
extra_rulesets_amount++
|
||||
else
|
||||
if (threat_level >= second_rule_req[indice_pop])
|
||||
var/threat_indice = min(10, max(round(threat_level ? threat_level/10 : 1), 1)) // 0-9 threat = 1, 10-19 threat = 2 ...
|
||||
if (threat_level >= second_rule_req[indice_pop] && prob(second_rule_prob[threat_indice]))
|
||||
extra_rulesets_amount++
|
||||
if (threat_level >= third_rule_req[indice_pop])
|
||||
if (threat_level >= third_rule_req[indice_pop] && prob(third_rule_prob[threat_indice]))
|
||||
extra_rulesets_amount++
|
||||
log_game("DYNAMIC: Trying to roll [extra_rulesets_amount + 1] roundstart rulesets. Picking from [drafted_rules.len] eligible rulesets.")
|
||||
|
||||
if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules))
|
||||
if (extra_rulesets_amount > 0) // We've got enough population and threat for a second rulestart rule
|
||||
log_game("DYNAMIC: First ruleset picked successfully. [extra_rulesets_amount] remaining.")
|
||||
while(extra_rulesets_amount > 0 && drafted_rules.len > 0) // We had enough threat for one or two more rulesets
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules)
|
||||
if (rule.cost > threat)
|
||||
drafted_rules -= rule
|
||||
if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules))
|
||||
if (extra_rulesets_amount > 1) // We've got enough population and threat for a third rulestart rule
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules)
|
||||
if (rule.cost > threat)
|
||||
drafted_rules -= rule
|
||||
picking_roundstart_rule(drafted_rules)
|
||||
if(drafted_rules.len)
|
||||
picking_roundstart_rule(drafted_rules)
|
||||
extra_rulesets_amount--
|
||||
log_game("DYNAMIC: Additional ruleset picked successfully, now [executed_rules.len] picked. [extra_rulesets_amount] remaining.")
|
||||
else
|
||||
|
||||
if(threat >= 50)
|
||||
message_admins("DYNAMIC: Picking first roundstart ruleset failed. You should report this.")
|
||||
log_game("DYNAMIC: Picking first roundstart ruleset failed. drafted_rules.len = [drafted_rules.len] and threat = [threat]/[threat_level]")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -408,68 +471,74 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
/datum/game_mode/dynamic/proc/picking_roundstart_rule(list/drafted_rules = list(), forced = FALSE)
|
||||
var/datum/dynamic_ruleset/roundstart/starting_rule = pickweight(drafted_rules)
|
||||
if(!starting_rule)
|
||||
log_game("DYNAMIC: Couldn't pick a starting ruleset. No rulesets available")
|
||||
return FALSE
|
||||
|
||||
if(!forced)
|
||||
if(only_ruleset_executed)
|
||||
return FALSE
|
||||
// Check if a blocking ruleset has been executed.
|
||||
else if(check_blocking(starting_rule.blocking_rules, executed_rules))
|
||||
else if(check_blocking(starting_rule.blocking_rules, executed_rules)) // Should already be filtered out, but making sure. Check filtering at end of proc if reported.
|
||||
drafted_rules -= starting_rule
|
||||
if(drafted_rules.len <= 0)
|
||||
log_game("DYNAMIC: Picking [starting_rule.name] failed due to blocking_rules and no more rulesets available. Report this.")
|
||||
return FALSE
|
||||
starting_rule = pickweight(drafted_rules)
|
||||
// Check if the ruleset is highlander and if a highlander ruleset has been executed
|
||||
else if(starting_rule.flags & HIGHLANDER_RULESET)
|
||||
if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
else if(starting_rule.flags & HIGHLANDER_RULESET) // Should already be filtered out, but making sure. Check filtering at end of proc if reported.
|
||||
if(threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(highlander_executed)
|
||||
drafted_rules -= starting_rule
|
||||
if(drafted_rules.len <= 0)
|
||||
log_game("DYNAMIC: Picking [starting_rule.name] failed due to no highlander stacking and no more rulesets available. Report this.")
|
||||
return FALSE
|
||||
starting_rule = pickweight(drafted_rules)
|
||||
// With low pop and high threat there might be rulesets that get executed with no valid candidates.
|
||||
else if(!starting_rule.ready()) // Should already be filtered out, but making sure. Check filtering at end of proc if reported.
|
||||
drafted_rules -= starting_rule
|
||||
if(drafted_rules.len <= 0)
|
||||
log_game("DYNAMIC: Picking [starting_rule.name] failed because there were not enough candidates and no more rulesets available. Report this.")
|
||||
return FALSE
|
||||
starting_rule = pickweight(drafted_rules)
|
||||
|
||||
log_game("DYNAMIC: Picking a [istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/) ? " delayed " : ""] ruleset [starting_rule.name]")
|
||||
log_game("DYNAMIC: Picked a ruleset: [starting_rule.name]")
|
||||
|
||||
roundstart_rules -= starting_rule
|
||||
drafted_rules -= starting_rule
|
||||
|
||||
if (istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/))
|
||||
var/datum/dynamic_ruleset/roundstart/delayed/rule = starting_rule
|
||||
addtimer(CALLBACK(src, .proc/execute_delayed, rule), rule.delay)
|
||||
|
||||
starting_rule.trim_candidates()
|
||||
var/added_threat = starting_rule.scale_up(extra_rulesets_amount, threat)
|
||||
if (starting_rule.pre_execute())
|
||||
spend_threat(starting_rule.cost)
|
||||
threat_log += "[worldtime2text()]: Roundstart [starting_rule.name] spent [starting_rule.cost]"
|
||||
spend_threat(starting_rule.cost + added_threat)
|
||||
log_threat("[starting_rule.ruletype] - <b>[starting_rule.name]</b> -[starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat")
|
||||
if(starting_rule.flags & HIGHLANDER_RULESET)
|
||||
highlander_executed = TRUE
|
||||
else if(starting_rule.flags & ONLY_RULESET)
|
||||
only_ruleset_executed = TRUE
|
||||
executed_rules += starting_rule
|
||||
if (starting_rule.persistent)
|
||||
current_rules += starting_rule
|
||||
for(var/mob/M in starting_rule.assigned)
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules)
|
||||
if (!rule.ready())
|
||||
drafted_rules -= rule // And removing rules that are no longer elligible
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in drafted_rules)
|
||||
if(check_blocking(rule.blocking_rules, executed_rules))
|
||||
drafted_rules -= rule
|
||||
if(highlander_executed && rule.flags & HIGHLANDER_RULESET)
|
||||
drafted_rules -= rule
|
||||
if(!rule.ready())
|
||||
drafted_rules -= rule // And removing rules that are no longer eligible
|
||||
return TRUE
|
||||
else
|
||||
stack_trace("The starting rule \"[starting_rule.name]\" failed to pre_execute.")
|
||||
return FALSE
|
||||
|
||||
/// Executes delayed roundstart rules and has a hack in it.
|
||||
/datum/game_mode/dynamic/proc/execute_delayed(datum/dynamic_ruleset/roundstart/delayed/rule)
|
||||
update_playercounts()
|
||||
rule.candidates = current_players[CURRENT_LIVING_PLAYERS].Copy()
|
||||
rule.trim_candidates()
|
||||
/// Mainly here to facilitate delayed rulesets. All roundstart rulesets are executed with a timered callback to this proc.
|
||||
/datum/game_mode/dynamic/proc/execute_roundstart_rule(sent_rule)
|
||||
var/datum/dynamic_ruleset/rule = sent_rule
|
||||
if(rule.execute())
|
||||
executed_rules += rule
|
||||
if (rule.persistent)
|
||||
if(rule.persistent)
|
||||
current_rules += rule
|
||||
return TRUE
|
||||
else
|
||||
stack_trace("The delayed roundstart rule \"[rule.name]\" failed to execute.")
|
||||
return FALSE
|
||||
rule.clean_up() // Refund threat, delete teams and so on.
|
||||
executed_rules -= rule
|
||||
stack_trace("The starting rule \"[rule.name]\" failed to execute.")
|
||||
return FALSE
|
||||
|
||||
/// Picks a random midround OR latejoin rule from the list given as an argument and executes it.
|
||||
/// Also this could be named better.
|
||||
@@ -477,7 +546,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
var/datum/dynamic_ruleset/rule = pickweight(drafted_rules)
|
||||
if(!rule)
|
||||
return FALSE
|
||||
|
||||
|
||||
if(!forced)
|
||||
if(only_ruleset_executed)
|
||||
return FALSE
|
||||
@@ -489,23 +558,75 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
rule = pickweight(drafted_rules)
|
||||
// Check if the ruleset is highlander and if a highlander ruleset has been executed
|
||||
else if(rule.flags & HIGHLANDER_RULESET)
|
||||
if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(highlander_executed)
|
||||
drafted_rules -= rule
|
||||
if(drafted_rules.len <= 0)
|
||||
return FALSE
|
||||
rule = pickweight(drafted_rules)
|
||||
|
||||
|
||||
if(!rule.repeatable)
|
||||
if(rule.ruletype == "Latejoin")
|
||||
latejoin_rules = remove_from_list(latejoin_rules, rule.type)
|
||||
else if(rule.type == "Midround")
|
||||
else if(rule.ruletype == "Midround")
|
||||
midround_rules = remove_from_list(midround_rules, rule.type)
|
||||
|
||||
else if(rule.ruletype == "Event")
|
||||
events = remove_from_list(events,rule.type)
|
||||
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_midround_latejoin_rule, rule), rule.delay)
|
||||
return TRUE
|
||||
|
||||
/// An experimental proc to allow admins to call rules on the fly or have rules call other rules.
|
||||
/datum/game_mode/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE)
|
||||
var/datum/dynamic_ruleset/midround/new_rule
|
||||
if(ispath(ruletype))
|
||||
new_rule = new ruletype() // You should only use it to call midround rules though.
|
||||
else if(istype(ruletype, /datum/dynamic_ruleset))
|
||||
new_rule = ruletype
|
||||
else
|
||||
return FALSE
|
||||
|
||||
if(!new_rule)
|
||||
return FALSE
|
||||
|
||||
if(!forced)
|
||||
if(only_ruleset_executed)
|
||||
return FALSE
|
||||
// Check if a blocking ruleset has been executed.
|
||||
else if(check_blocking(new_rule.blocking_rules, executed_rules))
|
||||
return FALSE
|
||||
// Check if the ruleset is highlander and if a highlander ruleset has been executed
|
||||
else if(new_rule.flags & HIGHLANDER_RULESET)
|
||||
if(threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(highlander_executed)
|
||||
return FALSE
|
||||
|
||||
update_playercounts()
|
||||
if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat)))
|
||||
new_rule.trim_candidates()
|
||||
if (new_rule.ready(forced))
|
||||
spend_threat(new_rule.cost)
|
||||
log_threat("[new_rule.ruletype] - <b>[new_rule.name]</b> -[new_rule.cost] threat")
|
||||
if (new_rule.execute()) // This should never fail since ready() returned 1
|
||||
if(new_rule.flags & HIGHLANDER_RULESET)
|
||||
highlander_executed = TRUE
|
||||
else if(new_rule.flags & ONLY_RULESET)
|
||||
only_ruleset_executed = TRUE
|
||||
log_game("DYNAMIC: Making a call to a specific ruleset...[new_rule.name]!")
|
||||
executed_rules += new_rule
|
||||
if (new_rule.persistent)
|
||||
current_rules += new_rule
|
||||
return TRUE
|
||||
else if (forced)
|
||||
log_game("DYNAMIC: The ruleset [new_rule.name] couldn't be executed due to lack of eligible players.")
|
||||
return FALSE
|
||||
|
||||
/// Mainly here to facilitate delayed rulesets. All midround/latejoin rulesets are executed with a timered callback to this proc.
|
||||
/datum/game_mode/dynamic/proc/execute_midround_latejoin_rule(sent_rule)
|
||||
var/datum/dynamic_ruleset/rule = sent_rule
|
||||
if (rule.execute())
|
||||
log_game("DYNAMIC: Injected a [rule.ruletype == "latejoin" ? "latejoin" : "midround"] ruleset [rule.name].")
|
||||
spend_threat(rule.cost)
|
||||
threat_log += "[worldtime2text()]: [rule.ruletype] [rule.name] spent [rule.cost]"
|
||||
log_threat("[rule.ruletype] [rule.name] spent [rule.cost]")
|
||||
if(rule.flags & HIGHLANDER_RULESET)
|
||||
highlander_executed = TRUE
|
||||
else if(rule.flags & ONLY_RULESET)
|
||||
@@ -519,54 +640,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if (rule.persistent)
|
||||
current_rules += rule
|
||||
return TRUE
|
||||
else
|
||||
stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.")
|
||||
return FALSE
|
||||
|
||||
/// An experimental proc to allow admins to call rules on the fly or have rules call other rules.
|
||||
/datum/game_mode/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE)
|
||||
var/datum/dynamic_ruleset/midround/new_rule
|
||||
if(ispath(ruletype))
|
||||
new_rule = new ruletype() // You should only use it to call midround rules though.
|
||||
else if(istype(ruletype, /datum/dynamic_ruleset))
|
||||
new_rule = ruletype
|
||||
else
|
||||
return FALSE
|
||||
|
||||
if(!new_rule)
|
||||
return FALSE
|
||||
|
||||
if(!forced)
|
||||
if(only_ruleset_executed)
|
||||
return FALSE
|
||||
// Check if a blocking ruleset has been executed.
|
||||
else if(check_blocking(new_rule.blocking_rules, executed_rules))
|
||||
return FALSE
|
||||
// Check if the ruleset is highlander and if a highlander ruleset has been executed
|
||||
else if(new_rule.flags & HIGHLANDER_RULESET)
|
||||
if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(highlander_executed)
|
||||
return FALSE
|
||||
|
||||
update_playercounts()
|
||||
if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat)))
|
||||
new_rule.candidates = current_players.Copy()
|
||||
new_rule.trim_candidates()
|
||||
if (new_rule.ready(forced))
|
||||
spend_threat(new_rule.cost)
|
||||
threat_log += "[worldtime2text()]: Forced rule [new_rule.name] spent [new_rule.cost]"
|
||||
if (new_rule.execute()) // This should never fail since ready() returned 1
|
||||
if(new_rule.flags & HIGHLANDER_RULESET)
|
||||
highlander_executed = TRUE
|
||||
else if(new_rule.flags & ONLY_RULESET)
|
||||
only_ruleset_executed = TRUE
|
||||
log_game("DYNAMIC: Making a call to a specific ruleset...[new_rule.name]!")
|
||||
executed_rules += new_rule
|
||||
if (new_rule.persistent)
|
||||
current_rules += new_rule
|
||||
return TRUE
|
||||
else if (forced)
|
||||
log_game("DYNAMIC: The ruleset [new_rule.name] couldn't be executed due to lack of elligible players.")
|
||||
rule.clean_up()
|
||||
stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.")
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/dynamic/process()
|
||||
@@ -581,35 +656,54 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if (midround_injection_cooldown < world.time)
|
||||
if (GLOB.dynamic_forced_extended)
|
||||
return
|
||||
|
||||
// Somehow it manages to trigger midround multiple times so this was moved here.
|
||||
|
||||
// Somehow it managed to trigger midround multiple times so this was moved here.
|
||||
// There is no way this should be able to trigger an injection twice now.
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
|
||||
midround_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time)
|
||||
|
||||
|
||||
// Time to inject some threat into the round
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone
|
||||
return
|
||||
message_admins("DYNAMIC: Checking for midround injection.")
|
||||
log_game("DYNAMIC: Checking for midround injection.")
|
||||
|
||||
log_game("DYNAMIC: Checking state of the round.")
|
||||
|
||||
update_playercounts()
|
||||
|
||||
if (prob(get_injection_chance()))
|
||||
if (get_injection_chance())
|
||||
var/cur_threat_frac = threat/threat_level
|
||||
var/list/drafted_rules = list()
|
||||
var/antag_num = current_players[CURRENT_LIVING_ANTAGS].len
|
||||
for (var/datum/dynamic_ruleset/midround/rule in midround_rules)
|
||||
// if there are antags OR the rule is an antag rule, antag_acceptable will be true.
|
||||
if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
continue
|
||||
rule.candidates = list()
|
||||
rule.candidates = current_players.Copy()
|
||||
rule.trim_candidates()
|
||||
if (rule.ready() && rule.candidates.len > 0)
|
||||
drafted_rules[rule] = rule.get_weight()
|
||||
if (rule.ready())
|
||||
if(!antag_num)
|
||||
drafted_rules[rule] = round(rule.get_weight() + (rule.cost * cur_threat_frac))
|
||||
else
|
||||
drafted_rules[rule] = rule.get_weight()
|
||||
if (drafted_rules.len > 0)
|
||||
picking_midround_latejoin_rule(drafted_rules)
|
||||
|
||||
else
|
||||
midround_injection_cooldown = (midround_injection_cooldown + world.time)/2
|
||||
|
||||
if(event_injection_cooldown < world.time)
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
|
||||
message_admins("DYNAMIC: Doing event injection.")
|
||||
log_game("DYNAMIC: Doing event injection.")
|
||||
update_playercounts()
|
||||
var/list/drafted_rules = list()
|
||||
for(var/datum/dynamic_ruleset/event/rule in events)
|
||||
if(rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
|
||||
if(rule.ready())
|
||||
drafted_rules[rule] = rule.get_weight()
|
||||
if(drafted_rules.len > 0)
|
||||
picking_midround_latejoin_rule(drafted_rules)
|
||||
|
||||
/// Updates current_players.
|
||||
/datum/game_mode/dynamic/proc/update_playercounts()
|
||||
current_players[CURRENT_LIVING_PLAYERS] = list()
|
||||
@@ -641,7 +735,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
var/high_pop_factor = (current_players[CURRENT_LIVING_PLAYERS].len >= GLOB.dynamic_high_pop_limit)
|
||||
var/max_pop_per_antag = max(5,15 - round(threat_level/10) - round(current_players[CURRENT_LIVING_PLAYERS].len/(high_pop_factor ? 10 : 5)))
|
||||
if (!current_players[CURRENT_LIVING_ANTAGS].len)
|
||||
chance += 50 // No antags at all? let's boost those odds!
|
||||
chance += 80 // No antags at all? let's boost those odds!
|
||||
else
|
||||
var/current_pop_per_antag = current_players[CURRENT_LIVING_PLAYERS].len / current_players[CURRENT_LIVING_ANTAGS].len
|
||||
if (current_pop_per_antag > max_pop_per_antag)
|
||||
@@ -704,11 +798,11 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
continue
|
||||
// No stacking : only one round-enter, unless > stacking_limit threat.
|
||||
if (threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
// No stacking : only one round-ender, unless threat level > stacking_limit.
|
||||
if (threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(rule.flags & HIGHLANDER_RULESET && highlander_executed)
|
||||
continue
|
||||
|
||||
|
||||
rule.candidates = list(newPlayer)
|
||||
rule.trim_candidates()
|
||||
if (rule.ready())
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
#define EXTRA_RULESET_PENALTY 20 // Changes how likely a gamemode is to scale based on how many other roundstart rulesets are waiting to be rolled.
|
||||
#define POP_SCALING_PENALTY 50 // Discourages scaling up rulesets if ratio of antags to crew is high.
|
||||
|
||||
#define REVOLUTION_VICTORY 1
|
||||
#define STATION_VICTORY 2
|
||||
|
||||
/datum/dynamic_ruleset
|
||||
/// For admin logging and round end screen.
|
||||
var/name = ""
|
||||
/// For admin logging and round end screen, do not change this unless making a new rule type.
|
||||
var/ruletype = ""
|
||||
var/ruletype = ""
|
||||
/// For config purposes, similar to config_tag for secret game modes.
|
||||
var/config_tag = null
|
||||
/// If set to TRUE, the rule won't be discarded after being executed, and dynamic will call rule_process() every time it ticks.
|
||||
var/persistent = FALSE
|
||||
var/persistent = FALSE
|
||||
/// If set to TRUE, dynamic mode will be able to draft this ruleset again later on. (doesn't apply for roundstart rules)
|
||||
var/repeatable = FALSE
|
||||
var/repeatable = FALSE
|
||||
/// If set higher than 0 decreases weight by itself causing the ruleset to appear less often the more it is repeated.
|
||||
var/repeatable_weight_decrease = 2
|
||||
var/repeatable_weight_decrease = 2
|
||||
/// List of players that are being drafted for this rule
|
||||
var/list/mob/candidates = list()
|
||||
var/list/mob/candidates = list()
|
||||
/// List of players that were selected for this rule
|
||||
var/list/datum/mind/assigned = list()
|
||||
var/list/datum/mind/assigned = list()
|
||||
/// Preferences flag such as ROLE_WIZARD that need to be turned on for players to be antag
|
||||
var/antag_flag = null
|
||||
var/antag_flag = null
|
||||
/// The antagonist datum that is assigned to the mobs mind on ruleset execution.
|
||||
var/datum/antagonist/antag_datum = null
|
||||
/// The required minimum account age for this ruleset.
|
||||
@@ -24,19 +30,25 @@
|
||||
/// If set, and config flag protect_roles_from_antagonist is false, then the rule will not pick players from these roles.
|
||||
var/list/protected_roles = list()
|
||||
/// If set, rule will deny candidates from those roles always.
|
||||
var/list/restricted_roles = list()
|
||||
var/list/restricted_roles = list()
|
||||
/// If set, rule will only accept candidates from those roles, IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS.
|
||||
var/list/exclusive_roles = list()
|
||||
var/list/exclusive_roles = list()
|
||||
/// If set, there needs to be a certain amount of players doing those roles (among the players who won't be drafted) for the rule to be drafted IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS.
|
||||
var/list/enemy_roles = list()
|
||||
var/list/enemy_roles = list()
|
||||
/// If enemy_roles was set, this is the amount of enemy job workers needed per threat_level range (0-10,10-20,etc) IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS.
|
||||
var/required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
||||
var/required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
||||
/// The rule needs this many candidates (post-trimming) to be executed (example: Cult needs 4 players at round start)
|
||||
var/required_candidates = 0
|
||||
var/required_candidates = 0
|
||||
/// 1 -> 9, probability for this rule to be picked against other rules
|
||||
var/weight = 5
|
||||
var/weight = 5
|
||||
/// Threat cost for this rule, this is decreased from the mode's threat when the rule is executed.
|
||||
var/cost = 0
|
||||
var/cost = 0
|
||||
/// Cost per level the rule scales up.
|
||||
var/scaling_cost = 0
|
||||
/// How many times a rule has scaled up upon getting picked.
|
||||
var/scaled_times = 0
|
||||
/// Used for the roundend report
|
||||
var/total_cost = 0
|
||||
/// A flag that determines how the ruleset is handled
|
||||
/// HIGHLANDER_RULESET are rulesets can end the round.
|
||||
/// TRAITOR_RULESET and MINOR_RULESET can't end the round and have no difference right now.
|
||||
@@ -46,20 +58,28 @@
|
||||
/// Requirements are the threat level requirements per pop range.
|
||||
/// With the default values, The rule will never get drafted below 10 threat level (aka: "peaceful extended"), and it requires a higher threat level at lower pops.
|
||||
var/list/requirements = list(40,30,20,10,10,10,10,10,10,10)
|
||||
/// An alternative, static requirement used instead when pop is over mode's high_pop_limit.
|
||||
/// An alternative, static requirement used instead when pop is over mode's high_pop_limit.
|
||||
var/high_population_requirement = 10
|
||||
/// Reference to the mode, use this instead of SSticker.mode.
|
||||
var/datum/game_mode/dynamic/mode = null
|
||||
/// If a role is to be considered another for the purpose of banning.
|
||||
var/antag_flag_override = null
|
||||
var/antag_flag_override = null
|
||||
/// If a ruleset type which is in this list has been executed, then the ruleset will not be executed.
|
||||
var/list/blocking_rules = list()
|
||||
/// The minimum amount of players required for the rule to be considered.
|
||||
/// The minimum amount of players required for the rule to be considered.
|
||||
var/minimum_players = 0
|
||||
/// The maximum amount of players required for the rule to be considered.
|
||||
/// Anything below zero or exactly zero is ignored.
|
||||
/// Anything below zero or exactly zero is ignored.
|
||||
var/maximum_players = 0
|
||||
|
||||
/// Calculated during acceptable(), used in scaling and team sizes.
|
||||
var/indice_pop = 0
|
||||
/// Population scaling. Used by team antags and scaling for solo antags.
|
||||
var/list/antag_cap = list()
|
||||
/// Base probability used in scaling. The higher it is, the more likely to scale. Kept as a var to allow for config editing._SendSignal(sigtype, list/arguments)
|
||||
var/base_prob = 60
|
||||
/// Delay for when execute will get called from the time of post_setup (roundstart) or process (midround/latejoin).
|
||||
/// Make sure your ruleset works with execute being called during the game when using this, and that the clean_up proc reverts it properly in case of faliure.
|
||||
var/delay = 0
|
||||
|
||||
/datum/dynamic_ruleset/New()
|
||||
..()
|
||||
@@ -87,10 +107,6 @@
|
||||
/datum/dynamic_ruleset/roundstart // One or more of those drafted at roundstart
|
||||
ruletype = "Roundstart"
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/delayed/ // Executed with a 30 seconds delay
|
||||
var/delay = 30 SECONDS
|
||||
var/required_type = /mob/living/carbon/human // No ghosts, new players or silicons allowed.
|
||||
|
||||
// Can be drafted when a player joins the server
|
||||
/datum/dynamic_ruleset/latejoin
|
||||
ruletype = "Latejoin"
|
||||
@@ -103,17 +119,48 @@
|
||||
if(maximum_players > 0 && population > maximum_players)
|
||||
return FALSE
|
||||
if (population >= GLOB.dynamic_high_pop_limit)
|
||||
return (threat_level >= high_population_requirement)
|
||||
indice_pop = 10
|
||||
if(threat_level < high_population_requirement)
|
||||
log_game("DYNAMIC: [name] did not reach threat level threshold: [threat_level]/[high_population_requirement]")
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
else
|
||||
pop_per_requirement = pop_per_requirement > 0 ? pop_per_requirement : mode.pop_per_requirement
|
||||
var/indice_pop = min(10,round(population/pop_per_requirement)+1)
|
||||
return (threat_level >= requirements[indice_pop])
|
||||
if(antag_cap.len && requirements.len != antag_cap.len)
|
||||
message_admins("DYNAMIC: requirements and antag_cap lists have different lengths in ruleset [name]. Likely config issue, report this.")
|
||||
log_game("DYNAMIC: requirements and antag_cap lists have different lengths in ruleset [name]. Likely config issue, report this.")
|
||||
indice_pop = min(requirements.len,round(population/pop_per_requirement)+1)
|
||||
if(threat_level < requirements[indice_pop])
|
||||
log_game("DYNAMIC: [name] did not reach threat level threshold: [threat_level]/[requirements[indice_pop]]")
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
/// Called when a suitable rule is picked during roundstart(). Will some times attempt to scale a rule up when there is threat remaining. Returns the amount of scaled steps.
|
||||
/datum/dynamic_ruleset/proc/scale_up(extra_rulesets = 0, remaining_threat_level = 0)
|
||||
remaining_threat_level -= cost
|
||||
if(scaling_cost && scaling_cost <= remaining_threat_level) // Only attempts to scale the modes with a scaling cost explicitly set.
|
||||
var/new_prob
|
||||
var/pop_to_antags = (mode.antags_rolled + (antag_cap[indice_pop] * (scaled_times + 1))) / mode.roundstart_pop_ready
|
||||
log_game("DYNAMIC: [name] roundstart ruleset attempting to scale up with [extra_rulesets] rulesets waiting and [remaining_threat_level] threat remaining.")
|
||||
for(var/i in 1 to 3) //Can scale a max of 3 times
|
||||
if(remaining_threat_level >= scaling_cost && pop_to_antags < 0.25)
|
||||
new_prob = base_prob + (remaining_threat_level) - (scaled_times * scaling_cost) - (extra_rulesets * EXTRA_RULESET_PENALTY) - (pop_to_antags * POP_SCALING_PENALTY)
|
||||
if (!prob(new_prob))
|
||||
break
|
||||
remaining_threat_level -= scaling_cost
|
||||
scaled_times++
|
||||
pop_to_antags = (mode.antags_rolled + (antag_cap[indice_pop] * (scaled_times + 1))) / mode.roundstart_pop_ready
|
||||
log_game("DYNAMIC: [name] roundstart ruleset failed scaling up at [new_prob ? new_prob : 0]% chance after [scaled_times]/3 successful scaleups. [remaining_threat_level] threat remaining, antag to crew ratio: [pop_to_antags*100]%.")
|
||||
mode.antags_rolled += (1 + scaled_times) * antag_cap[indice_pop]
|
||||
return scaled_times * scaling_cost
|
||||
|
||||
/// This is called if persistent variable is true everytime SSTicker ticks.
|
||||
/datum/dynamic_ruleset/proc/rule_process()
|
||||
return
|
||||
|
||||
/// Called on game mode pre_setup, used for non-delayed roundstart rulesets only.
|
||||
/// 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
|
||||
/datum/dynamic_ruleset/proc/pre_execute()
|
||||
@@ -126,20 +173,20 @@
|
||||
M.add_antag_datum(antag_datum)
|
||||
return TRUE
|
||||
|
||||
/// Called after delay set in ruleset.
|
||||
/// Give your candidates or assignees equipment and antag datum here.
|
||||
/datum/dynamic_ruleset/roundstart/delayed/execute()
|
||||
if (SSticker && SSticker.current_state < GAME_STATE_PLAYING)
|
||||
CRASH("The delayed ruleset [name] executed before the round started.")
|
||||
|
||||
/// Here you can perform any additional checks you want. (such as checking the map etc)
|
||||
/// Remember that on roundstart no one knows what their job is at this point.
|
||||
/// IMPORTANT: If ready() returns TRUE, that means pre_execute() or execute() should never fail!
|
||||
/datum/dynamic_ruleset/proc/ready(forced = 0)
|
||||
if (required_candidates > candidates.len)
|
||||
/datum/dynamic_ruleset/proc/ready(forced = 0)
|
||||
if (required_candidates > candidates.len)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// Runs from gamemode process() if ruleset fails to start, like delayed rulesets not getting valid candidates.
|
||||
/// This one only handles refunding the threat, override in ruleset to clean up the rest.
|
||||
/datum/dynamic_ruleset/proc/clean_up()
|
||||
mode.refund_threat(cost + (scaled_times * scaling_cost))
|
||||
mode.log_threat("[ruletype] [name] refunded [cost + (scaled_times * scaling_cost)]",verbose=TRUE)
|
||||
|
||||
/// Gets weight of the ruleset
|
||||
/// Note that this decreases weight if repeatable is TRUE and repeatable_weight_decrease is higher than 0
|
||||
/// Note: If you don't want repeatable rulesets to decrease their weight use the weight variable directly
|
||||
@@ -156,14 +203,6 @@
|
||||
/datum/dynamic_ruleset/proc/trim_candidates()
|
||||
return
|
||||
|
||||
/// Counts how many players are ready at roundstart.
|
||||
/// Used only by non-delayed roundstart rulesets.
|
||||
/datum/dynamic_ruleset/proc/num_players()
|
||||
. = 0
|
||||
for(var/mob/dead/new_player/P in GLOB.player_list)
|
||||
if(P.client && P.ready == PLAYER_READY_TO_PLAY)
|
||||
. ++
|
||||
|
||||
/// Set mode result and news report here.
|
||||
/// Only called if ruleset is flagged as HIGHLANDER_RULESET
|
||||
/datum/dynamic_ruleset/proc/round_result()
|
||||
@@ -191,32 +230,14 @@
|
||||
if(P.mind.special_role) // We really don't want to give antag to an antag.
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
|
||||
/// Checks if candidates are required mob type, connected, banned and if the job is exclusive to the role.
|
||||
/datum/dynamic_ruleset/roundstart/delayed/trim_candidates()
|
||||
. = ..()
|
||||
for (var/mob/P in candidates)
|
||||
if (!istype(P, required_type))
|
||||
candidates.Remove(P) // Can be a new_player, etc.
|
||||
continue
|
||||
if(!mode.check_age(P.client, minimum_required_age))
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if(P.mind.special_role || P.mind.antag_datums?.len > 0) // Are they an antag already?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if(antag_flag_override)
|
||||
if(!(antag_flag_override in P.client.prefs.be_special) || jobban_isbanned(P.ckey, antag_flag_override))
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
else
|
||||
if(!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, antag_flag))
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
|
||||
/// Do your checks if the ruleset is ready to be executed here.
|
||||
/// Should ignore certain checks if forced is TRUE
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
/datum/dynamic_ruleset/event
|
||||
ruletype = "Event"
|
||||
var/typepath // typepath of the event
|
||||
var/triggering
|
||||
|
||||
/datum/dynamic_ruleset/event/execute()
|
||||
var/datum/round_event/E = new typepath()
|
||||
E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
|
||||
// E.control = src // can't be done! we just don't use events that require these, those can be from_ghost almost always
|
||||
|
||||
testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
|
||||
deadchat_broadcast("<span class='deadsay'><b>[name]</b> has just been triggered by dynamic!</span>")
|
||||
log_game("Random Event triggering: [name] ([typepath])")
|
||||
|
||||
return E
|
||||
|
||||
/datum/dynamic_ruleset/event/ready(forced = FALSE) // same as midround cause we're still using enemy system
|
||||
if (!forced)
|
||||
var/job_check = 0
|
||||
if (enemy_roles.len > 0)
|
||||
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
|
||||
if (M.stat == DEAD)
|
||||
continue // Dead players cannot count as opponents
|
||||
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles))
|
||||
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
|
||||
|
||||
var/threat = round(mode.threat_level/10)
|
||||
if (job_check < required_enemies[threat])
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// PIRATES //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/pirates
|
||||
name = "Space Pirates"
|
||||
config_tag = "pirates"
|
||||
typepath = /datum/round_event/pirates
|
||||
antag_flag = ROLE_TRAITOR
|
||||
enemy_roles = list("AI","Security Officer","Head of Security","Captain")
|
||||
required_enemies = list(2,2,1,1,0,0,0,0,0,0)
|
||||
weight = 5
|
||||
cost = 10
|
||||
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
|
||||
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
||||
high_population_requirement = 15
|
||||
|
||||
/datum/dynamic_ruleset/event/pirates/ready(forced = FALSE)
|
||||
if (!SSmapping.empty_space)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// SPIDERS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/spiders
|
||||
name = "Spider Infestation"
|
||||
config_tag = "spiders"
|
||||
typepath = /datum/round_event/spider_infestation
|
||||
enemy_roles = list("AI","Security Officer","Head of Security","Captain")
|
||||
required_enemies = list(2,2,1,1,0,0,0,0,0,0)
|
||||
weight = 5
|
||||
cost = 10
|
||||
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
||||
high_population_requirement = 15
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// CLOGGED VENTS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/ventclog
|
||||
name = "Clogged Vents"
|
||||
config_tag = "ventclog"
|
||||
typepath = /datum/round_event/vent_clog
|
||||
enemy_roles = list("Chemist","Medical Doctor","Chief Medical Officer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
cost = 2
|
||||
weight = 4
|
||||
repeatable_weight_decrease = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5) // yes, can happen on fake-extended
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/ventclog/ready()
|
||||
if(mode.threat_level > 30 && mode.threat >= 5 && prob(20))
|
||||
name = "Clogged Vents: Threatening"
|
||||
cost = 5
|
||||
required_enemies = list(3,3,3,2,2,2,1,1,1,1)
|
||||
typepath = /datum/round_event/vent_clog/threatening
|
||||
else if(mode.threat_level > 15 && mode.threat > 15 && prob(30))
|
||||
name = "Clogged Vents: Catastrophic"
|
||||
cost = 15
|
||||
required_enemies = list(2,2,1,1,1,1,0,0,0,0)
|
||||
typepath = /datum/round_event/vent_clog/catastrophic
|
||||
else
|
||||
cost = 2
|
||||
name = "Clogged Vents: Normal"
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
typepath = /datum/round_event/vent_clog
|
||||
return ..()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// ION STORM //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/ion_storm
|
||||
name = "Ion Storm"
|
||||
config_tag = "ion_storm"
|
||||
typepath = /datum/round_event/ion_storm
|
||||
enemy_roles = list("Research Director","Captain","Chief Engineer")
|
||||
required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
||||
weight = 4
|
||||
// no repeatable weight decrease. too variable to be unfun multiple times in one round
|
||||
cost = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// METEORS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/meteor_wave
|
||||
name = "Meteor Wave"
|
||||
config_tag = "meteor_wave"
|
||||
typepath = /datum/round_event/meteor_wave
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Captain","Cyborg")
|
||||
required_enemies = list(3,3,3,3,3,3,3,3,3,3)
|
||||
cost = 15
|
||||
weight = 3
|
||||
repeatable_weight_decrease = 2
|
||||
requirements = list(60,50,40,30,30,30,30,30,30,30)
|
||||
high_population_requirement = 30
|
||||
|
||||
/datum/dynamic_ruleset/event/meteor_wave/ready()
|
||||
if(mode.threat_level > 40 && mode.threat >= 25 && prob(20))
|
||||
cost = 25
|
||||
typepath = /datum/round_event/meteor_wave/threatening
|
||||
else if(mode.threat_level > 50 && mode.threat >= 40 && prob(30))
|
||||
cost = 40
|
||||
typepath = /datum/round_event/meteor_wave/catastrophic
|
||||
else
|
||||
cost = 15
|
||||
typepath = /datum/round_event/meteor_wave
|
||||
return ..()
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// ANOMALIES //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_bluespace
|
||||
name = "Anomaly: Bluespace"
|
||||
config_tag = "anomaly_bluespace"
|
||||
typepath = /datum/round_event/anomaly/anomaly_bluespace
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_flux
|
||||
name = "Anomaly: Hyper-Energetic Flux"
|
||||
config_tag = "anomaly_flux"
|
||||
typepath = /datum/round_event/anomaly/anomaly_flux
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 5
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_gravitational
|
||||
name = "Anomaly: Gravitational"
|
||||
config_tag = "anomaly_gravitational"
|
||||
typepath = /datum/round_event/anomaly/anomaly_grav
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 3
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_pyroclastic
|
||||
name = "Anomaly: Pyroclastic"
|
||||
config_tag = "anomaly_pyroclastic"
|
||||
typepath = /datum/round_event/anomaly/anomaly_pyro
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 5
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_vortex
|
||||
name = "Anomaly: Vortex"
|
||||
config_tag = "anomaly_vortex"
|
||||
typepath = /datum/round_event/anomaly/anomaly_vortex
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 5
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// WOW THAT'S A LOT OF EVENTS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/event/brand_intelligence
|
||||
name = "Brand Intelligence"
|
||||
config_tag = "brand_intelligence"
|
||||
typepath = /datum/round_event/brand_intelligence
|
||||
weight = 1
|
||||
repeatable_weight_decrease = 1
|
||||
cost = 2
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
|
||||
required_enemies = list(1,1,1,1,0,0,0,0,0,0)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/carp_migration
|
||||
name = "Carp Migration"
|
||||
config_tag = "carp_migration"
|
||||
typepath = /datum/round_event/carp_migration
|
||||
weight = 7
|
||||
repeatable_weight_decrease = 3
|
||||
cost = 4
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/communications_blackout
|
||||
name = "Communications Blackout"
|
||||
config_tag = "communications_blackout"
|
||||
typepath = /datum/round_event/communications_blackout
|
||||
cost = 4
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 3
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/processor_overload
|
||||
name = "Processor Overload"
|
||||
config_tag = "processor_overload"
|
||||
typepath = /datum/round_event/processor_overload
|
||||
cost = 4
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 3
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/space_dust
|
||||
name = "Minor Space Dust"
|
||||
config_tag = "space_dust"
|
||||
typepath = /datum/round_event/space_dust
|
||||
cost = 2
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/major_dust
|
||||
name = "Major Space Dust"
|
||||
config_tag = "major_dust"
|
||||
typepath = /datum/round_event/meteor_wave/major_dust
|
||||
cost = 4
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/electrical_storm
|
||||
name = "Electrical Storm"
|
||||
config_tag = "electrical_storm"
|
||||
typepath = /datum/round_event/electrical_storm
|
||||
cost = 1
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Chief Engineer","Station Engineer")
|
||||
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/heart_attack
|
||||
name = "Random Heart Attack"
|
||||
config_tag = "heart_attack"
|
||||
typepath = /datum/round_event/heart_attack
|
||||
cost = 3
|
||||
weight = 2
|
||||
repeatable_weight_decrease = 1
|
||||
enemy_roles = list("Medical Doctor","Chief Medical Officer")
|
||||
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
|
||||
requirements = list(101,101,101,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/radiation_storm
|
||||
name = "Radiation Storm"
|
||||
config_tag = "radiation_storm"
|
||||
typepath = /datum/round_event/radiation_storm
|
||||
cost = 3
|
||||
weight = 1
|
||||
enemy_roles = list("Chemist","Chief Medical Officer","Geneticist","Medical Doctor","AI","Captain")
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
@@ -12,9 +12,14 @@
|
||||
if(!mode.check_age(P.client, minimum_required_age))
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override))))//are they willing and not antag-banned?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if(antag_flag_override)
|
||||
if(!(antag_flag_override in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag_override)))
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
else
|
||||
if(!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)))
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
if (P.mind.assigned_role in restricted_roles) // Does their job allow for it?
|
||||
candidates.Remove(P)
|
||||
continue
|
||||
@@ -60,8 +65,8 @@
|
||||
required_candidates = 1
|
||||
weight = 7
|
||||
cost = 5
|
||||
requirements = list(40,30,20,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
requirements = list(40,30,20,15,15,15,15,15,15,15)
|
||||
high_population_requirement = 15
|
||||
repeatable = TRUE
|
||||
flags = TRAITOR_RULESET
|
||||
|
||||
@@ -73,40 +78,138 @@
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/provocateur
|
||||
name = "Provocateur"
|
||||
persistent = TRUE
|
||||
config_tag = "latejoin_revolution"
|
||||
antag_datum = /datum/antagonist/rev/head
|
||||
antag_flag = ROLE_REV_HEAD
|
||||
antag_flag_override = ROLE_REV
|
||||
restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
enemy_roles = list("AI", "Cyborg", "Security Officer","Detective","Head of Security", "Captain", "Warden")
|
||||
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
|
||||
required_enemies = list(4,4,3,3,3,3,3,2,2,1)
|
||||
required_candidates = 1
|
||||
weight = 2
|
||||
delay = 1 MINUTES // Prevents rule start while head is offstation.
|
||||
cost = 20
|
||||
requirements = list(101,101,70,40,30,20,20,20,20,20)
|
||||
high_population_requirement = 50
|
||||
requirements = list(101,101,70,40,40,40,40,40,40,40)
|
||||
high_population_requirement = 40
|
||||
flags = HIGHLANDER_RULESET
|
||||
var/required_heads = 3
|
||||
var/required_heads_of_staff = 3
|
||||
var/finished = FALSE
|
||||
var/datum/team/revolution/revolution
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/provocateur/ready(forced=FALSE)
|
||||
if (forced)
|
||||
required_heads = 1
|
||||
required_heads_of_staff = 1
|
||||
if(!..())
|
||||
return FALSE
|
||||
var/head_check = 0
|
||||
for(var/mob/player in mode.current_players[CURRENT_LIVING_PLAYERS])
|
||||
if (player.mind.assigned_role in GLOB.command_positions)
|
||||
head_check++
|
||||
return (head_check >= required_heads)
|
||||
return (head_check >= required_heads_of_staff)
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/provocateur/execute()
|
||||
var/mob/M = pick(candidates)
|
||||
assigned += M.mind
|
||||
M.mind.special_role = antag_flag
|
||||
var/datum/antagonist/rev/head/new_head = new()
|
||||
new_head.give_flash = TRUE
|
||||
new_head.give_hud = TRUE
|
||||
new_head.remove_clumsy = TRUE
|
||||
new_head = M.mind.add_antag_datum(new_head)
|
||||
new_head.rev_team.max_headrevs = 1 // Only one revhead if it is latejoin.
|
||||
var/mob/M = pick(candidates) // This should contain a single player, but in case.
|
||||
if(check_eligible(M.mind)) // Didnt die/run off z-level/get implanted since leaving shuttle.
|
||||
assigned += M.mind
|
||||
M.mind.special_role = antag_flag
|
||||
revolution = new()
|
||||
var/datum/antagonist/rev/head/new_head = new()
|
||||
new_head.give_flash = TRUE
|
||||
new_head.give_hud = TRUE
|
||||
new_head.remove_clumsy = TRUE
|
||||
new_head = M.mind.add_antag_datum(new_head, revolution)
|
||||
revolution.update_objectives()
|
||||
revolution.update_heads()
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
return TRUE
|
||||
else
|
||||
log_game("DYNAMIC: [ruletype] [name] discarded [M.name] from head revolutionary due to ineligibility.")
|
||||
log_game("DYNAMIC: [ruletype] [name] failed to get any eligible headrevs. Refunding [cost] threat.")
|
||||
return FALSE
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/provocateur/rule_process()
|
||||
if(check_rev_victory())
|
||||
finished = REVOLUTION_VICTORY
|
||||
return RULESET_STOP_PROCESSING
|
||||
else if (check_heads_victory())
|
||||
finished = STATION_VICTORY
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
priority_announce("It appears the mutiny has been quelled. Please return yourself and your colleagues to work. \
|
||||
We have remotely blacklisted the head revolutionaries from your cloning software to prevent accidental cloning.", null, "attention", null, "Central Command Loyalty Monitoring Division")
|
||||
for(var/datum/mind/M in revolution.members) // Remove antag datums and prevent headrev cloning then restarting rebellions.
|
||||
if(M.has_antag_datum(/datum/antagonist/rev/head))
|
||||
var/datum/antagonist/rev/head/R = M.has_antag_datum(/datum/antagonist/rev/head)
|
||||
R.remove_revolutionary(FALSE, "gamemode")
|
||||
var/mob/living/carbon/C = M.current
|
||||
if(C.stat == DEAD)
|
||||
C.makeUncloneable()
|
||||
if(M.has_antag_datum(/datum/antagonist/rev))
|
||||
var/datum/antagonist/rev/R = M.has_antag_datum(/datum/antagonist/rev)
|
||||
R.remove_revolutionary(FALSE, "gamemode")
|
||||
return RULESET_STOP_PROCESSING
|
||||
|
||||
/// Checks for revhead loss conditions and other antag datums.
|
||||
/datum/dynamic_ruleset/latejoin/provocateur/proc/check_eligible(var/datum/mind/M)
|
||||
var/turf/T = get_turf(M.current)
|
||||
if(!considered_afk(M) && considered_alive(M) && is_station_level(T.z) && !M.antag_datums?.len && !HAS_TRAIT(M, TRAIT_MINDSHIELD))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/provocateur/check_finished()
|
||||
if(finished == REVOLUTION_VICTORY)
|
||||
return TRUE
|
||||
else
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/provocateur/proc/check_rev_victory()
|
||||
for(var/datum/objective/mutiny/objective in revolution.objectives)
|
||||
if(!(objective.check_completion()))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/provocateur/proc/check_heads_victory()
|
||||
for(var/datum/mind/rev_mind in revolution.head_revolutionaries())
|
||||
var/turf/T = get_turf(rev_mind.current)
|
||||
if(!considered_afk(rev_mind) && considered_alive(rev_mind) && is_station_level(T.z))
|
||||
if(ishuman(rev_mind.current) || ismonkey(rev_mind.current))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/provocateur/round_result()
|
||||
if(finished == REVOLUTION_VICTORY)
|
||||
SSticker.mode_result = "win - heads killed"
|
||||
SSticker.news_report = REVS_WIN
|
||||
else if(finished == STATION_VICTORY)
|
||||
SSticker.mode_result = "loss - rev heads killed"
|
||||
SSticker.news_report = REVS_LOSE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// VAMPIRE //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
/datum/dynamic_ruleset/latejoin/vampire
|
||||
name = "vampire"
|
||||
config_tag = "vampire_latejoin"
|
||||
antag_flag = ROLE_VAMPIRE
|
||||
antag_datum = ANTAG_DATUM_VAMPIRE
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
required_candidates = 1
|
||||
weight = 5
|
||||
cost = 15
|
||||
requirements = list(80,70,60,50,40,20,20,15,15,15)
|
||||
repeatable = TRUE
|
||||
high_population_requirement = 15
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/vampire/pre_execute()
|
||||
var/mob/M = pick(candidates)
|
||||
candidates -= M
|
||||
assigned += M.mind
|
||||
M.mind.restricted_roles = restricted_roles
|
||||
M.mind.special_role = ROLE_VAMPIRE
|
||||
return TRUE
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#define REVENANT_SPAWN_THRESHOLD 20
|
||||
#define ABDUCTOR_MAX_TEAMS 4 // blame TG for not using the defines files
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// MIDROUND RULESETS //
|
||||
@@ -8,7 +11,7 @@
|
||||
ruletype = "Midround"
|
||||
/// If the ruleset should be restricted from ghost roles.
|
||||
var/restrict_ghost_roles = TRUE
|
||||
/// What type the ruleset is restricted to.
|
||||
/// What mob type the ruleset is restricted to.
|
||||
var/required_type = /mob/living/carbon/human
|
||||
var/list/living_players = list()
|
||||
var/list/living_antags = list()
|
||||
@@ -17,12 +20,11 @@
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts
|
||||
weight = 0
|
||||
required_type = /mob/dead/observer
|
||||
/// Whether the ruleset should call generate_ruleset_body or not.
|
||||
var/makeBody = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/midround/trim_candidates()
|
||||
// Unlike the previous two types, these rulesets are not meant for /mob/dead/new_player
|
||||
// And since I want those rulesets to be as flexible as possible, I'm not gonna put much here,
|
||||
//
|
||||
// All you need to know is that here, the candidates list contains 4 lists itself, indexed with the following defines:
|
||||
// Candidates = list(CURRENT_LIVING_PLAYERS, CURRENT_LIVING_ANTAGS, CURRENT_DEAD_PLAYERS, CURRENT_OBSERVERS)
|
||||
@@ -31,12 +33,10 @@
|
||||
// We're still gonna trim the obvious (mobs without clients, jobbanned players, etc)
|
||||
living_players = trim_list(mode.current_players[CURRENT_LIVING_PLAYERS])
|
||||
living_antags = trim_list(mode.current_players[CURRENT_LIVING_ANTAGS])
|
||||
dead_players = trim_list(mode.current_players[CURRENT_DEAD_PLAYERS])
|
||||
list_observers = trim_list(mode.current_players[CURRENT_OBSERVERS])
|
||||
|
||||
/datum/dynamic_ruleset/midround/proc/trim_list(list/L = list())
|
||||
var/list/trimmed_list = L.Copy()
|
||||
var/antag_name = initial(antag_flag)
|
||||
for(var/mob/M in trimmed_list)
|
||||
if (!istype(M, required_type))
|
||||
trimmed_list.Remove(M)
|
||||
@@ -47,14 +47,19 @@
|
||||
if(!mode.check_age(M.client, minimum_required_age))
|
||||
trimmed_list.Remove(M)
|
||||
continue
|
||||
if (!(antag_name in M.client.prefs.be_special) || jobban_isbanned(M.ckey, list(antag_name, ROLE_SYNDICATE)))//are they willing and not antag-banned?
|
||||
trimmed_list.Remove(M)
|
||||
continue
|
||||
if(antag_flag_override)
|
||||
if(!(antag_flag_override in M.client.prefs.be_special) || jobban_isbanned(M.ckey, antag_flag_override))
|
||||
trimmed_list.Remove(M)
|
||||
continue
|
||||
else
|
||||
if(!(antag_flag in M.client.prefs.be_special) || jobban_isbanned(M.ckey, antag_flag))
|
||||
trimmed_list.Remove(M)
|
||||
continue
|
||||
if (M.mind)
|
||||
if (restrict_ghost_roles && M.mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL]) // Are they playing a ghost role?
|
||||
trimmed_list.Remove(M)
|
||||
continue
|
||||
if (M.mind.assigned_role in restricted_roles || HAS_TRAIT(M, TRAIT_MINDSHIELD)) // Does their job allow it or are they mindshielded?
|
||||
if (M.mind.assigned_role in restricted_roles) // Does their job allow it?
|
||||
trimmed_list.Remove(M)
|
||||
continue
|
||||
if ((exclusive_roles.len > 0) && !(M.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job?
|
||||
@@ -71,7 +76,7 @@
|
||||
if (!forced)
|
||||
var/job_check = 0
|
||||
if (enemy_roles.len > 0)
|
||||
for (var/mob/M in living_players)
|
||||
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
|
||||
if (M.stat == DEAD)
|
||||
continue // Dead players cannot count as opponents
|
||||
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles)))
|
||||
@@ -100,13 +105,13 @@
|
||||
message_admins("Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
|
||||
log_game("DYNAMIC: Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
|
||||
|
||||
candidates = pollGhostCandidates("The mode is looking for volunteers to become [antag_flag] for [name]", antag_flag, SSticker.mode, antag_flag, poll_time = 300)
|
||||
candidates = pollGhostCandidates("The mode is looking for volunteers to become a [name]", antag_flag, SSticker.mode, antag_flag, poll_time = 300)
|
||||
|
||||
if(!candidates || candidates.len <= 0)
|
||||
message_admins("The ruleset [name] received no applications.")
|
||||
log_game("DYNAMIC: The ruleset [name] received no applications.")
|
||||
if(!candidates || candidates.len <= required_candidates)
|
||||
message_admins("The ruleset [name] did not receive enough applications.")
|
||||
log_game("DYNAMIC: The ruleset [name] did not receive enough applications.")
|
||||
mode.refund_threat(cost)
|
||||
mode.threat_log += "[worldtime2text()]: Rule [name] refunded [cost] (no applications)"
|
||||
mode.log_threat("Rule [name] refunded [cost] (not receive enough applications)",verbose=TRUE)
|
||||
mode.executed_rules -= src
|
||||
return
|
||||
|
||||
@@ -122,7 +127,7 @@
|
||||
if(i == 1)
|
||||
// We have found no candidates so far and we are out of applicants.
|
||||
mode.refund_threat(cost)
|
||||
mode.threat_log += "[worldtime2text()]: Rule [name] refunded [cost] (all applications invalid)"
|
||||
mode.log_threat("Rule [name] refunded [cost] (all applications invalid)",verbose=TRUE)
|
||||
mode.executed_rules -= src
|
||||
break
|
||||
var/mob/applicant = pick(candidates)
|
||||
@@ -145,7 +150,7 @@
|
||||
|
||||
finish_setup(new_character, i)
|
||||
assigned += applicant
|
||||
notify_ghosts("[new_character] has been picked for the ruleset [name]!", source = new_character, action = NOTIFY_ORBIT, header="Something Interesting!")
|
||||
notify_ghosts("[new_character] has been picked for the ruleset [name]!", source = new_character, action = NOTIFY_ORBIT)
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/proc/generate_ruleset_body(mob/applicant)
|
||||
var/mob/living/carbon/human/new_character = makeBody(applicant)
|
||||
@@ -177,9 +182,9 @@
|
||||
required_candidates = 1
|
||||
weight = 7
|
||||
cost = 10
|
||||
requirements = list(50,40,30,20,10,10,10,10,10,10)
|
||||
requirements = list(30,25,20,15,15,15,15,15,15,15)
|
||||
repeatable = TRUE
|
||||
high_population_requirement = 10
|
||||
high_population_requirement = 15
|
||||
flags = TRAITOR_RULESET
|
||||
|
||||
/datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0)
|
||||
@@ -225,24 +230,24 @@
|
||||
|
||||
/datum/dynamic_ruleset/midround/malf
|
||||
name = "Malfunctioning AI"
|
||||
config_tag = "malf_ai"
|
||||
config_tag = "midround_malf_ai"
|
||||
antag_datum = /datum/antagonist/traitor
|
||||
antag_flag = ROLE_MALF
|
||||
enemy_roles = list("Security Officer", "Warden","Detective","Head of Security", "Captain", "Scientist", "Chemist", "Research Director", "Chief Engineer")
|
||||
exclusive_roles = list("AI")
|
||||
required_enemies = list(4,4,4,4,4,4,2,2,2,0)
|
||||
required_enemies = list(6,6,6,4,4,4,2,2,2,1)
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
weight = 2
|
||||
cost = 35
|
||||
requirements = list(101,101,80,70,60,60,50,50,40,40)
|
||||
high_population_requirement = 35
|
||||
requirements = list(101,101,70,50,50,50,40,30,30,30)
|
||||
high_population_requirement = 30
|
||||
required_type = /mob/living/silicon/ai
|
||||
var/ion_announce = 33
|
||||
var/removeDontImproveChance = 10
|
||||
|
||||
/datum/dynamic_ruleset/midround/malf/trim_candidates()
|
||||
..()
|
||||
candidates = candidates[CURRENT_LIVING_PLAYERS]
|
||||
living_players = candidates[CURRENT_LIVING_PLAYERS]
|
||||
for(var/mob/living/player in candidates)
|
||||
if(!isAI(player))
|
||||
candidates -= player
|
||||
@@ -256,8 +261,7 @@
|
||||
/datum/dynamic_ruleset/midround/malf/execute()
|
||||
if(!candidates || !candidates.len)
|
||||
return FALSE
|
||||
var/mob/living/silicon/ai/M = pick(candidates)
|
||||
candidates -= M
|
||||
var/mob/living/silicon/ai/M = pick_n_take(candidates)
|
||||
assigned += M.mind
|
||||
var/datum/antagonist/traitor/AI = new
|
||||
M.mind.special_role = antag_flag
|
||||
@@ -279,16 +283,18 @@
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/wizard
|
||||
name = "Wizard"
|
||||
config_tag = "midround_wizard"
|
||||
persistent = TRUE
|
||||
antag_datum = /datum/antagonist/wizard
|
||||
antag_flag = ROLE_WIZARD
|
||||
enemy_roles = list("Security Officer","Detective","Head of Security", "Captain")
|
||||
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
|
||||
required_enemies = list(4,4,3,2,2,1,1,0,0,0)
|
||||
required_candidates = 1
|
||||
weight = 1
|
||||
cost = 20
|
||||
requirements = list(90,90,70,40,30,20,10,10,10,10)
|
||||
high_population_requirement = 50
|
||||
requirements = list(90,90,70,50,50,50,50,40,30,30)
|
||||
high_population_requirement = 30
|
||||
repeatable = TRUE
|
||||
var/datum/mind/wizard
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE)
|
||||
if (required_candidates > (dead_players.len + list_observers.len))
|
||||
@@ -303,6 +309,20 @@
|
||||
..()
|
||||
new_character.forceMove(pick(GLOB.wizardstart))
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/wizard/rule_process() // i can literally copy this from are_special_antags_dead it's great
|
||||
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
|
||||
return FALSE
|
||||
|
||||
for(var/obj/item/phylactery/P in GLOB.poi_list) //TODO : IsProperlyDead()
|
||||
if(P.mind && P.mind.has_antag_datum(/datum/antagonist/wizard))
|
||||
return FALSE
|
||||
|
||||
if(SSevents.wizardmode) //If summon events was active, turn it off
|
||||
SSevents.toggleWizardmode()
|
||||
SSevents.resetFrequency()
|
||||
|
||||
return RULESET_STOP_PROCESSING
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// NUCLEAR OPERATIVES (MIDROUND) //
|
||||
@@ -315,12 +335,12 @@
|
||||
antag_flag = ROLE_OPERATIVE
|
||||
antag_datum = /datum/antagonist/nukeop
|
||||
enemy_roles = list("AI", "Cyborg", "Security Officer", "Warden","Detective","Head of Security", "Captain")
|
||||
required_enemies = list(3,3,3,3,3,2,1,1,0,0)
|
||||
required_enemies = list(5,5,4,3,3,2,2,2,1,1)
|
||||
required_candidates = 5
|
||||
weight = 5
|
||||
cost = 35
|
||||
requirements = list(90,90,90,80,60,40,30,20,10,10)
|
||||
high_population_requirement = 10
|
||||
requirements = list(90,90,90,80,70,60,50,40,40,40)
|
||||
high_population_requirement = 40
|
||||
var/operative_cap = list(2,2,3,3,4,5,5,5,5,5)
|
||||
var/datum/team/nuclear/nuke_team
|
||||
flags = HIGHLANDER_RULESET
|
||||
@@ -328,7 +348,13 @@
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/nuclear/acceptable(population=0, threat=0)
|
||||
if (locate(/datum/dynamic_ruleset/roundstart/nuclear) in mode.executed_rules)
|
||||
return FALSE // Unavailable if nuke ops were already sent at roundstart
|
||||
var/indice_pop = min(10,round(living_players.len/5)+1)
|
||||
indice_pop = min(10, round(living_players.len/5)+1)
|
||||
/* NOTE: The above line's magic value of "10" is a hack due to the fact that byond was
|
||||
not recognizing operative_cap as a defined variable. It should be operative_cap.len--
|
||||
and yes, this means that if the len is changed, this variable must be changed along with it.
|
||||
One day, once the mystery of why this issue was occuring is figured out,
|
||||
we may change it back, but until this day comes, we must make it simply 10.
|
||||
*/
|
||||
required_candidates = operative_cap[indice_pop]
|
||||
return ..()
|
||||
|
||||
@@ -359,14 +385,20 @@
|
||||
antag_datum = /datum/antagonist/blob
|
||||
antag_flag = ROLE_BLOB
|
||||
enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain")
|
||||
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
|
||||
required_enemies = list(3,3,2,2,2,1,1,1,1,0)
|
||||
required_candidates = 1
|
||||
blocking_rules = list(/datum/dynamic_ruleset/roundstart/clockcult)
|
||||
weight = 4
|
||||
cost = 10
|
||||
requirements = list(101,101,101,80,60,50,30,20,10,10)
|
||||
requirements = list(101,101,101,80,60,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/blob/ready(forced = FALSE)
|
||||
if (required_candidates > (dead_players.len + list_observers.len))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/blob/generate_ruleset_body(mob/applicant)
|
||||
var/body = applicant.become_overmind()
|
||||
return body
|
||||
@@ -383,15 +415,21 @@
|
||||
antag_datum = /datum/antagonist/xeno
|
||||
antag_flag = ROLE_ALIEN
|
||||
enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain")
|
||||
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
|
||||
required_enemies = list(3,3,2,2,1,1,1,1,1,0)
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
cost = 10
|
||||
requirements = list(101,101,101,70,50,40,20,15,10,10)
|
||||
requirements = list(101,101,101,70,50,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
repeatable_weight_decrease = 2
|
||||
repeatable = TRUE
|
||||
var/list/vents = list()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/ready(forced = FALSE)
|
||||
if (required_candidates > (dead_players.len + list_observers.len))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/execute()
|
||||
// 50% chance of being incremented by one
|
||||
required_candidates += prob(50)
|
||||
@@ -435,8 +473,9 @@
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
cost = 10
|
||||
requirements = list(101,101,101,70,50,40,20,15,10,10)
|
||||
requirements = list(101,101,101,70,50,40,20,15,15,15)
|
||||
high_population_requirement = 50
|
||||
repeatable_weight_decrease = 2
|
||||
repeatable = TRUE
|
||||
var/list/spawn_locs = list()
|
||||
|
||||
@@ -465,3 +504,240 @@
|
||||
message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a Nightmare by the midround ruleset.")
|
||||
log_game("DYNAMIC: [key_name(S)] was spawned as a Nightmare by the midround ruleset.")
|
||||
return S
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// SENTIENT DISEASE //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease
|
||||
name = "Sentient Disease"
|
||||
config_tag = "sentient_disease"
|
||||
antag_flag = ROLE_ALIEN
|
||||
enemy_roles = list("Virologist","Chief Medical Officer","Captain","Chemist")
|
||||
required_enemies = list(2,1,1,1,0,0,0,0,0,0)
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
cost = 5
|
||||
requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"!
|
||||
high_population_requirement = 5
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/ready(forced = FALSE)
|
||||
if (required_candidates > (dead_players.len + list_observers.len))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/generate_ruleset_body(mob/applicant)
|
||||
var/mob/camera/disease/virus = new /mob/camera/disease(SSmapping.get_station_center())
|
||||
applicant.transfer_ckey(virus, FALSE)
|
||||
INVOKE_ASYNC(virus, /mob/camera/disease/proc/pick_name)
|
||||
message_admins("[ADMIN_LOOKUPFLW(virus)] has been made into a sentient disease by the midround ruleset.")
|
||||
log_game("[key_name(virus)] was spawned as a sentient disease by the midround ruleset.")
|
||||
return virus
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// REVENANT //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/revenant
|
||||
name = "Revenant"
|
||||
config_tag = "revenant"
|
||||
antag_flag = ROLE_REVENANT
|
||||
enemy_roles = list("Chief Engineer","Station Engineer","Captain","Chaplain","AI")
|
||||
required_enemies = list(2,1,1,1,0,0,0,0,0,0)
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
cost = 5
|
||||
requirements = list(30,30,30,30,20,15,15,15,15,15)
|
||||
high_population_requirement = 15
|
||||
var/list/spawn_locs = list()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/revenant/ready(forced = FALSE)
|
||||
var/deadMobs = 0
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
deadMobs++
|
||||
if(deadMobs < REVENANT_SPAWN_THRESHOLD)
|
||||
return FALSE
|
||||
if(required_candidates > (dead_players.len + list_observers.len))
|
||||
return FALSE
|
||||
for(var/mob/living/L in GLOB.dead_mob_list) //look for any dead bodies
|
||||
var/turf/T = get_turf(L)
|
||||
if(T && is_station_level(T.z))
|
||||
spawn_locs += T
|
||||
if(!spawn_locs.len || spawn_locs.len < 15) //look for any morgue trays, crematoriums, ect if there weren't alot of dead bodies on the station to pick from
|
||||
for(var/obj/structure/bodycontainer/bc in GLOB.bodycontainers)
|
||||
var/turf/T = get_turf(bc)
|
||||
if(T && is_station_level(T.z))
|
||||
spawn_locs += T
|
||||
if(!spawn_locs.len) //If we can't find any valid spawnpoints, try the carp spawns
|
||||
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
|
||||
if(isturf(L.loc))
|
||||
spawn_locs += L.loc
|
||||
if(!spawn_locs.len) //If we can't find THAT, then just give up and cry
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/revenant/generate_ruleset_body(mob/applicant)
|
||||
var/mob/living/simple_animal/revenant/revvie = new(pick(spawn_locs))
|
||||
applicant.transfer_ckey(revvie, FALSE)
|
||||
message_admins("[ADMIN_LOOKUPFLW(revvie)] has been made into a revenant by the midround ruleset.")
|
||||
log_game("[key_name(revvie)] was spawned as a revenant by the midround ruleset.")
|
||||
return revvie
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// SLAUGHTER DEMON //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/slaughter_demon
|
||||
name = "Slaughter Demon"
|
||||
config_tag = "slaughter_demon"
|
||||
antag_flag = ROLE_ALIEN
|
||||
enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg")
|
||||
required_enemies = list(3,2,2,2,2,1,1,1,1,0)
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
cost = 15
|
||||
requirements = list(101,101,101,90,80,70,60,50,40,30)
|
||||
high_population_requirement = 30
|
||||
var/list/spawn_locs = list()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/slaughter_demon/ready(forced = FALSE)
|
||||
if(required_candidates > (dead_players.len + list_observers.len))
|
||||
return FALSE
|
||||
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
|
||||
if(isturf(L.loc))
|
||||
spawn_locs += L.loc
|
||||
|
||||
if(!spawn_locs.len)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/slaughter_demon/generate_ruleset_body(mob/applicant)
|
||||
var/datum/mind/player_mind = new /datum/mind(applicant.key)
|
||||
player_mind.active = 1
|
||||
var/obj/effect/dummy/phased_mob/slaughter/holder = new /obj/effect/dummy/phased_mob/slaughter((pick(spawn_locs)))
|
||||
var/mob/living/simple_animal/slaughter/S = new (holder)
|
||||
S.holder = holder
|
||||
player_mind.transfer_to(S)
|
||||
player_mind.assigned_role = "Slaughter Demon"
|
||||
player_mind.special_role = "Slaughter Demon"
|
||||
player_mind.add_antag_datum(/datum/antagonist/slaughter)
|
||||
to_chat(S, S.playstyle_string)
|
||||
to_chat(S, "<B>You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.</B>")
|
||||
SEND_SOUND(S, 'sound/magic/demon_dies.ogg')
|
||||
message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a slaughter demon by dynamic.")
|
||||
log_game("[key_name(S)] was spawned as a slaughter demon by dynamic.")
|
||||
return S
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// ABDUCTORS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/abductors
|
||||
name = "Abductors"
|
||||
config_tag = "abductors"
|
||||
antag_flag = ROLE_ABDUCTOR
|
||||
// Has two antagonist flags, in fact
|
||||
enemy_roles = list("AI", "Cyborg", "Security Officer", "Warden","Detective","Head of Security", "Captain")
|
||||
required_enemies = list(3,3,2,2,1,1,0,0,0,0)
|
||||
required_candidates = 2
|
||||
weight = 8
|
||||
cost = 10
|
||||
requirements = list(101,101,70,50,40,30,30,20,15,15)
|
||||
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
|
||||
high_population_requirement = 15
|
||||
var/datum/team/abductor_team/team
|
||||
repeatable_weight_decrease = 4
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/abductors/ready(forced = FALSE)
|
||||
if(required_candidates > (dead_players.len + list_observers.len))
|
||||
return FALSE
|
||||
team = new /datum/team/abductor_team
|
||||
if(team.team_number > ABDUCTOR_MAX_TEAMS)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/abductors/finish_setup(mob/new_character, index)
|
||||
switch(index)
|
||||
if(1) // yeah this seems like a baffling anti-pattern but it's actually the best way to do this, shit you not
|
||||
var/mob/living/carbon/human/agent = new_character
|
||||
agent.mind.add_antag_datum(/datum/antagonist/abductor/agent, team)
|
||||
log_game("[key_name(agent)] has been selected as [team.name] abductor agent.")
|
||||
if(2)
|
||||
var/mob/living/carbon/human/scientist = new_character
|
||||
scientist.mind.add_antag_datum(/datum/antagonist/abductor/scientist, team)
|
||||
log_game("[key_name(scientist)] has been selected as [team.name] abductor scientist.")
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// SPACE NINJA //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/ninja
|
||||
name = "Space Ninja"
|
||||
config_tag = "ninja"
|
||||
antag_flag = ROLE_NINJA
|
||||
enemy_roles = list("Security Officer","Head of Security","Captain","AI","Cyborg")
|
||||
required_enemies = list(3,2,2,2,2,1,1,1,1,0)
|
||||
required_candidates = 1
|
||||
weight = 4
|
||||
cost = 15
|
||||
requirements = list(101,101,101,90,80,70,60,50,40,30)
|
||||
high_population_requirement = 30
|
||||
var/list/spawn_locs = list()
|
||||
var/spawn_loc
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/ninja/ready(forced = FALSE)
|
||||
if(required_candidates > (dead_players.len + list_observers.len))
|
||||
return FALSE
|
||||
if(!spawn_loc)
|
||||
var/list/spawn_locs = list()
|
||||
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
|
||||
if(isturf(L.loc))
|
||||
spawn_locs += L.loc
|
||||
if(!spawn_locs.len)
|
||||
return FALSE
|
||||
spawn_loc = pick(spawn_locs)
|
||||
if(!spawn_loc)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/ninja/generate_ruleset_body(mob/applicant)
|
||||
var/key = applicant.key
|
||||
|
||||
//Prepare ninja player mind
|
||||
var/datum/mind/Mind = new /datum/mind(key)
|
||||
Mind.assigned_role = ROLE_NINJA
|
||||
Mind.special_role = ROLE_NINJA
|
||||
Mind.active = 1
|
||||
|
||||
//spawn the ninja and assign the candidate
|
||||
var/mob/living/carbon/human/Ninja = create_space_ninja(spawn_loc)
|
||||
Mind.transfer_to(Ninja)
|
||||
var/datum/antagonist/ninja/ninjadatum = new
|
||||
ninjadatum.helping_station = pick(TRUE,FALSE)
|
||||
if(ninjadatum.helping_station)
|
||||
mode.refund_threat(5)
|
||||
Mind.add_antag_datum(ninjadatum)
|
||||
|
||||
if(Ninja.mind != Mind) //something has gone wrong!
|
||||
throw EXCEPTION("Ninja created with incorrect mind")
|
||||
|
||||
message_admins("[ADMIN_LOOKUPFLW(Ninja)] has been made into a ninja by dynamic.")
|
||||
log_game("[key_name(Ninja)] was spawned as a ninja by dynamic.")
|
||||
return Ninja
|
||||
|
||||
#undef ABDUCTOR_MAX_TEAMS
|
||||
#undef REVENANT_SPAWN_THRESHOLD
|
||||
|
||||
@@ -13,20 +13,20 @@
|
||||
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")
|
||||
restricted_roles = list("Cyborg", "AI")
|
||||
required_candidates = 1
|
||||
weight = 5
|
||||
cost = 10
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
cost = 10 // Avoid raising traitor threat above 10, as it is the default low cost ruleset.
|
||||
scaling_cost = 10
|
||||
requirements = list(50,50,50,50,50,50,50,50,50,50)
|
||||
high_population_requirement = 40
|
||||
antag_cap = list(1,1,1,1,2,2,2,2,3,3)
|
||||
var/autotraitor_cooldown = 450 // 15 minutes (ticks once per 2 sec)
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/traitor/pre_execute()
|
||||
var/traitor_scaling_coeff = 10 - max(0,round(mode.threat_level/10)-5) // Above 50 threat level, coeff goes down by 1 for every 10 levels
|
||||
var/num_traitors = min(round(mode.candidates.len / traitor_scaling_coeff) + 1, candidates.len)
|
||||
var/num_traitors = antag_cap[indice_pop] * (scaled_times + 1)
|
||||
for (var/i = 1 to num_traitors)
|
||||
var/mob/M = pick(candidates)
|
||||
candidates -= M
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
assigned += M.mind
|
||||
M.mind.special_role = ROLE_TRAITOR
|
||||
M.mind.restricted_roles = restricted_roles
|
||||
@@ -51,32 +51,27 @@
|
||||
name = "Blood Brothers"
|
||||
config_tag = "traitorbro"
|
||||
antag_flag = ROLE_BROTHER
|
||||
antag_datum = /datum/antagonist/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(40,30,30,20,20,15,15,15,10,10)
|
||||
high_population_requirement = 15
|
||||
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.
|
||||
var/list/datum/team/brother_team/pre_brother_teams = list()
|
||||
var/const/team_amount = 2 // Hard limit on brother teams if scaling is turned off
|
||||
var/const/min_team_size = 2
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/traitorbro/pre_execute()
|
||||
var/num_teams = team_amount
|
||||
var/bsc = CONFIG_GET(number/brother_scaling_coeff)
|
||||
if(bsc)
|
||||
num_teams = max(1, round(num_players() / bsc))
|
||||
|
||||
var/num_teams = (antag_cap[indice_pop]/min_team_size) * (scaled_times + 1) // 1 team per scaling
|
||||
for(var/j = 1 to num_teams)
|
||||
if(candidates.len < min_team_size || candidates.len < required_candidates)
|
||||
break
|
||||
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(candidates)
|
||||
candidates -= bro
|
||||
var/mob/bro = pick_n_take(candidates)
|
||||
assigned += bro.mind
|
||||
team.add_member(bro.mind)
|
||||
bro.mind.special_role = "brother"
|
||||
@@ -109,16 +104,17 @@
|
||||
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 = 30
|
||||
requirements = list(80,70,60,50,40,20,20,10,10,10)
|
||||
cost = 15
|
||||
scaling_cost = 15
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
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/roundstart/changeling/pre_execute()
|
||||
var/num_changelings = min(round(mode.candidates.len / 10) + 1, candidates.len)
|
||||
var/num_changelings = antag_cap[indice_pop] * (scaled_times + 1)
|
||||
for (var/i = 1 to num_changelings)
|
||||
var/mob/M = pick(candidates)
|
||||
candidates -= M
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
assigned += M.mind
|
||||
M.mind.restricted_roles = restricted_roles
|
||||
M.mind.special_role = ROLE_CHANGELING
|
||||
@@ -153,6 +149,7 @@
|
||||
/datum/dynamic_ruleset/roundstart/wizard
|
||||
name = "Wizard"
|
||||
config_tag = "wizard"
|
||||
persistent = TRUE
|
||||
antag_flag = ROLE_WIZARD
|
||||
antag_datum = /datum/antagonist/wizard
|
||||
minimum_required_age = 14
|
||||
@@ -160,8 +157,8 @@
|
||||
required_candidates = 1
|
||||
weight = 1
|
||||
cost = 30
|
||||
requirements = list(90,90,70,40,30,20,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
requirements = list(101,101,101,60,50,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
var/list/roundstart_wizards = list()
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0)
|
||||
@@ -174,10 +171,9 @@
|
||||
/datum/dynamic_ruleset/roundstart/wizard/pre_execute()
|
||||
if(GLOB.wizardstart.len == 0)
|
||||
return FALSE
|
||||
|
||||
var/mob/M = pick(candidates)
|
||||
mode.antags_rolled += 1
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
if (M)
|
||||
candidates -= M
|
||||
assigned += M.mind
|
||||
M.mind.assigned_role = ROLE_WIZARD
|
||||
M.mind.special_role = ROLE_WIZARD
|
||||
@@ -188,8 +184,25 @@
|
||||
for(var/datum/mind/M in assigned)
|
||||
M.current.forceMove(pick(GLOB.wizardstart))
|
||||
M.add_antag_datum(new antag_datum())
|
||||
roundstart_wizards += M
|
||||
return TRUE
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/wizard/rule_process() // i can literally copy this from are_special_antags_dead it's great
|
||||
for(var/datum/mind/wizard in roundstart_wizards)
|
||||
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
|
||||
return FALSE
|
||||
|
||||
for(var/obj/item/phylactery/P in GLOB.poi_list) //TODO : IsProperlyDead()
|
||||
if(P.mind && P.mind.has_antag_datum(/datum/antagonist/wizard))
|
||||
return FALSE
|
||||
|
||||
if(SSevents.wizardmode) //If summon events was active, turn it off
|
||||
SSevents.toggleWizardmode()
|
||||
SSevents.resetFrequency()
|
||||
|
||||
return RULESET_STOP_PROCESSING
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// BLOOD CULT //
|
||||
@@ -207,26 +220,23 @@
|
||||
required_candidates = 2
|
||||
weight = 3
|
||||
cost = 30
|
||||
requirements = list(100,90,80,60,40,30,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
pop_per_requirement = 5
|
||||
requirements = list(101,101,101,80,70,60,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
flags = HIGHLANDER_RULESET
|
||||
var/cultist_cap = list(2,2,2,3,3,4,4,4,4,4)
|
||||
antag_cap = list(2,2,2,3,3,4,4,4,4,4)
|
||||
var/datum/team/cult/main_cult
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/bloodcult/ready(forced = FALSE)
|
||||
var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1)
|
||||
required_candidates = cultist_cap[indice_pop]
|
||||
required_candidates = antag_cap[indice_pop]
|
||||
. = ..()
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/bloodcult/pre_execute()
|
||||
var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1)
|
||||
var/cultists = cultist_cap[indice_pop]
|
||||
var/cultists = antag_cap[indice_pop]
|
||||
mode.antags_rolled += cultists
|
||||
for(var/cultists_number = 1 to cultists)
|
||||
if(candidates.len <= 0)
|
||||
break
|
||||
var/mob/M = pick(candidates)
|
||||
candidates -= M
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
assigned += M.mind
|
||||
M.mind.special_role = ROLE_CULTIST
|
||||
M.mind.restricted_roles = restricted_roles
|
||||
@@ -268,28 +278,24 @@
|
||||
required_candidates = 5
|
||||
weight = 3
|
||||
cost = 40
|
||||
requirements = list(90,90,90,80,60,40,30,20,10,10)
|
||||
high_population_requirement = 10
|
||||
pop_per_requirement = 5
|
||||
requirements = list(100,90,80,70,60,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
flags = HIGHLANDER_RULESET
|
||||
var/operative_cap = list(2,2,2,3,3,3,4,4,5,5)
|
||||
antag_cap = list(1,1,2,3,4,5,5,5,5,5)
|
||||
var/datum/team/nuclear/nuke_team
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE)
|
||||
var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1)
|
||||
required_candidates = operative_cap[indice_pop]
|
||||
required_candidates = antag_cap[indice_pop]
|
||||
. = ..()
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/nuclear/pre_execute()
|
||||
// If ready() did its job, candidates should have 5 or more members in it
|
||||
|
||||
var/indice_pop = min(10,round(mode.roundstart_pop_ready/5)+1)
|
||||
var/operatives = operative_cap[indice_pop]
|
||||
var/operatives = antag_cap[indice_pop]
|
||||
mode.antags_rolled += operatives
|
||||
for(var/operatives_number = 1 to operatives)
|
||||
if(candidates.len <= 0)
|
||||
break
|
||||
var/mob/M = pick(candidates)
|
||||
candidates -= M
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
assigned += M.mind
|
||||
M.mind.assigned_role = "Nuclear Operative"
|
||||
M.mind.special_role = "Nuclear Operative"
|
||||
@@ -347,7 +353,7 @@
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/delayed/revs
|
||||
/datum/dynamic_ruleset/roundstart/revs
|
||||
name = "Revolution"
|
||||
config_tag = "revolution"
|
||||
persistent = TRUE
|
||||
@@ -358,63 +364,98 @@
|
||||
restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_candidates = 3
|
||||
weight = 2
|
||||
delay = 7 MINUTES
|
||||
cost = 35
|
||||
requirements = list(101,101,70,40,30,20,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
delay = 5 MINUTES
|
||||
requirements = list(101,101,101,60,50,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
antag_cap = list(3,3,3,3,3,3,3,3,3,3)
|
||||
flags = HIGHLANDER_RULESET
|
||||
// I give up, just there should be enough heads with 35 players...
|
||||
minimum_players = 35
|
||||
var/datum/team/revolution/revolution
|
||||
var/finished = 0
|
||||
var/finished = FALSE
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/delayed/revs/execute()
|
||||
var/max_canditates = 4
|
||||
revolution = new()
|
||||
for(var/i = 1 to max_canditates)
|
||||
/datum/dynamic_ruleset/roundstart/revs/pre_execute()
|
||||
var/max_candidates = antag_cap[indice_pop]
|
||||
mode.antags_rolled += max_candidates
|
||||
for(var/i = 1 to max_candidates)
|
||||
if(candidates.len <= 0)
|
||||
break
|
||||
var/mob/M = pick(candidates)
|
||||
candidates -= M
|
||||
var/mob/M = pick_n_take(candidates)
|
||||
assigned += M.mind
|
||||
M.mind.restricted_roles = restricted_roles
|
||||
M.mind.special_role = antag_flag
|
||||
var/datum/antagonist/rev/head/new_head = new antag_datum()
|
||||
new_head.give_flash = TRUE
|
||||
new_head.give_hud = TRUE
|
||||
new_head.remove_clumsy = TRUE
|
||||
M.mind.add_antag_datum(new_head,revolution)
|
||||
|
||||
revolution.update_objectives()
|
||||
revolution.update_heads()
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/delayed/revs/rule_process()
|
||||
if(check_rev_victory())
|
||||
finished = 1
|
||||
else if(check_heads_victory())
|
||||
finished = 2
|
||||
return
|
||||
/datum/dynamic_ruleset/roundstart/revs/execute()
|
||||
var/success = TRUE
|
||||
revolution = new()
|
||||
for(var/datum/mind/M in assigned)
|
||||
if(check_eligible(M))
|
||||
var/datum/antagonist/rev/head/new_head = new antag_datum()
|
||||
new_head.give_flash = TRUE
|
||||
new_head.give_hud = TRUE
|
||||
new_head.remove_clumsy = TRUE
|
||||
M.add_antag_datum(new_head,revolution)
|
||||
else
|
||||
assigned -= M
|
||||
log_game("DYNAMIC: [ruletype] [name] discarded [M.name] from head revolutionary due to ineligibility.")
|
||||
if(!revolution.members.len)
|
||||
success = FALSE
|
||||
log_game("DYNAMIC: [ruletype] [name] failed to get any eligible headrevs. Refunding [cost] threat.")
|
||||
if(success)
|
||||
revolution.update_objectives()
|
||||
revolution.update_heads()
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/delayed/revs/check_finished()
|
||||
if(CONFIG_GET(keyed_list/continuous)["revolution"])
|
||||
if(finished)
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
return ..()
|
||||
if(finished != 0)
|
||||
/datum/dynamic_ruleset/roundstart/revs/clean_up()
|
||||
qdel(revolution)
|
||||
..()
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/revs/rule_process()
|
||||
if(check_rev_victory())
|
||||
finished = REVOLUTION_VICTORY
|
||||
return RULESET_STOP_PROCESSING
|
||||
else if (check_heads_victory())
|
||||
finished = STATION_VICTORY
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
priority_announce("It appears the mutiny has been quelled. Please return yourself and your incapacitated colleagues to work. \
|
||||
We have remotely blacklisted the head revolutionaries from your cloning software to prevent accidental cloning.", null, "attention", null, "Central Command Loyalty Monitoring Division")
|
||||
|
||||
for(var/datum/mind/M in revolution.members) // Remove antag datums and prevents podcloned or exiled headrevs restarting rebellions.
|
||||
if(M.has_antag_datum(/datum/antagonist/rev/head))
|
||||
var/datum/antagonist/rev/head/R = M.has_antag_datum(/datum/antagonist/rev/head)
|
||||
R.remove_revolutionary(FALSE, "gamemode")
|
||||
var/mob/living/carbon/C = M.current
|
||||
if(C.stat == DEAD)
|
||||
C.makeUncloneable()
|
||||
if(M.has_antag_datum(/datum/antagonist/rev))
|
||||
var/datum/antagonist/rev/R = M.has_antag_datum(/datum/antagonist/rev)
|
||||
R.remove_revolutionary(FALSE, "gamemode")
|
||||
return RULESET_STOP_PROCESSING
|
||||
|
||||
/// Checks for revhead loss conditions and other antag datums.
|
||||
/datum/dynamic_ruleset/roundstart/revs/proc/check_eligible(var/datum/mind/M)
|
||||
var/turf/T = get_turf(M.current)
|
||||
if(!considered_afk(M) && considered_alive(M) && is_station_level(T.z) && !M.antag_datums?.len && !HAS_TRAIT(M, TRAIT_MINDSHIELD))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/revs/check_finished()
|
||||
if(finished == REVOLUTION_VICTORY)
|
||||
return TRUE
|
||||
else
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_rev_victory()
|
||||
/datum/dynamic_ruleset/roundstart/revs/proc/check_rev_victory()
|
||||
for(var/datum/objective/mutiny/objective in revolution.objectives)
|
||||
if(!(objective.check_completion()))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_heads_victory()
|
||||
/datum/dynamic_ruleset/roundstart/revs/proc/check_heads_victory()
|
||||
for(var/datum/mind/rev_mind in revolution.head_revolutionaries())
|
||||
var/turf/T = get_turf(rev_mind.current)
|
||||
if(!considered_afk(rev_mind) && considered_alive(rev_mind) && is_station_level(T.z))
|
||||
@@ -422,11 +463,11 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/delayed/revs/round_result()
|
||||
if(finished == 1)
|
||||
/datum/dynamic_ruleset/roundstart/revs/round_result()
|
||||
if(finished == REVOLUTION_VICTORY)
|
||||
SSticker.mode_result = "win - heads killed"
|
||||
SSticker.news_report = REVS_WIN
|
||||
else if(finished == 2)
|
||||
else if(finished == STATION_VICTORY)
|
||||
SSticker.mode_result = "loss - rev heads killed"
|
||||
SSticker.news_report = REVS_LOSE
|
||||
|
||||
@@ -470,10 +511,11 @@
|
||||
restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_candidates = 4
|
||||
weight = 3
|
||||
cost = 0
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 101
|
||||
cost = 35
|
||||
requirements = list(101,101,101,80,70,60,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
flags = HIGHLANDER_RULESET
|
||||
antag_cap = list(2,3,3,4,4,4,4,4,4,4)
|
||||
var/ark_time
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/clockcult/pre_execute()
|
||||
@@ -486,16 +528,15 @@
|
||||
for(var/datum/parsed_map/PM in reebes)
|
||||
PM.initTemplateBounds()
|
||||
|
||||
var/starter_servants = 4
|
||||
var/number_players = num_players()
|
||||
var/starter_servants = antag_cap[indice_pop]
|
||||
var/number_players = mode.roundstart_pop_ready
|
||||
if(number_players > 30)
|
||||
number_players -= 30
|
||||
starter_servants += round(number_players / 10)
|
||||
starter_servants = min(starter_servants, 8)
|
||||
GLOB.clockwork_vitality += 50 * starter_servants //some starter Vitality to help recover from initial fuck ups
|
||||
starter_servants += min(round(number_players / 10), 5)
|
||||
mode.antags_rolled += starter_servants
|
||||
GLOB.clockwork_vitality += 50 * starter_servants
|
||||
for (var/i in 1 to starter_servants)
|
||||
var/mob/servant = pick(candidates)
|
||||
candidates -= servant
|
||||
var/mob/servant = pick_n_take(candidates)
|
||||
assigned += servant.mind
|
||||
servant.mind.assigned_role = ROLE_SERVANT_OF_RATVAR
|
||||
servant.mind.special_role = ROLE_SERVANT_OF_RATVAR
|
||||
@@ -604,23 +645,16 @@
|
||||
cost = 0
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 101
|
||||
var/devil_limit = 4 // Hard limit on devils if scaling is turned off
|
||||
antag_cap = list(1,1,1,2,2,2,3,3,3,4)
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/devil/pre_execute()
|
||||
var/tsc = CONFIG_GET(number/traitor_scaling_coeff)
|
||||
var/num_devils = 1
|
||||
|
||||
if(tsc)
|
||||
num_devils = max(required_candidates, min(round(num_players() / (tsc * 3)) + 2, round(num_players() / (tsc * 1.5))))
|
||||
else
|
||||
num_devils = max(required_candidates, min(num_players(), devil_limit))
|
||||
|
||||
var/num_devils = antag_cap[indice_pop]
|
||||
mode.antags_rolled += num_devils
|
||||
for(var/j = 0, j < num_devils, j++)
|
||||
if (!candidates.len)
|
||||
break
|
||||
var/mob/devil = pick(candidates)
|
||||
assigned += devil
|
||||
candidates -= devil
|
||||
var/mob/devil = pick_n_take(candidates)
|
||||
assigned += devil.mind
|
||||
devil.mind.special_role = ROLE_DEVIL
|
||||
devil.mind.restricted_roles = restricted_roles
|
||||
|
||||
@@ -669,13 +703,13 @@
|
||||
var/datum/team/monkey/monkey_team
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/monkey/pre_execute()
|
||||
var/carriers_to_make = max(round(num_players()/players_per_carrier, 1), 1)
|
||||
var/carriers_to_make = max(round(mode.roundstart_pop_ready / players_per_carrier, 1), 1)
|
||||
mode.antags_rolled += carriers_to_make
|
||||
|
||||
for(var/j = 0, j < carriers_to_make, j++)
|
||||
if (!candidates.len)
|
||||
break
|
||||
var/mob/carrier = pick(candidates)
|
||||
candidates -= carrier
|
||||
var/mob/carrier = pick_n_take(candidates)
|
||||
assigned += carrier.mind
|
||||
carrier.mind.special_role = "Monkey Leader"
|
||||
carrier.mind.restricted_roles = restricted_roles
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
/datum/outfit/syndicate/no_crystals
|
||||
tc = 0
|
||||
|
||||
/datum/outfit/syndicate/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/syndicate/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
var/obj/item/radio/R = H.ears
|
||||
R.set_frequency(FREQ_SYNDICATE)
|
||||
R.freqlock = TRUE
|
||||
|
||||
@@ -92,9 +92,7 @@
|
||||
if(!usr || !usr.canUseTopic(src) || stat || QDELETED(src))
|
||||
return
|
||||
if(href_list["authenticate"])
|
||||
var/obj/item/card/id/ID = usr.get_active_held_item()
|
||||
if(!istype(ID))
|
||||
ID = usr.get_idcard()
|
||||
var/obj/item/card/id/ID = usr.get_idcard(TRUE)
|
||||
if(ID && istype(ID))
|
||||
if(check_access(ID))
|
||||
authenticated = TRUE
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='notice'>You start deconstructing the frame...</span>")
|
||||
if(P.use_tool(src, user, 20, volume=50))
|
||||
if(P.use_tool(src, user, 20, volume=50) && state == 0)
|
||||
to_chat(user, "<span class='notice'>You deconstruct the frame.</span>")
|
||||
var/obj/item/stack/sheet/metal/M = new (drop_location(), 5)
|
||||
M.add_fingerprint(user)
|
||||
@@ -28,7 +28,7 @@
|
||||
if(1)
|
||||
if(istype(P, /obj/item/wrench))
|
||||
to_chat(user, "<span class='notice'>You start to unfasten the frame...</span>")
|
||||
if(P.use_tool(src, user, 20, volume=50))
|
||||
if(P.use_tool(src, user, 20, volume=50) && state == 1)
|
||||
to_chat(user, "<span class='notice'>You unfasten the frame.</span>")
|
||||
setAnchored(FALSE)
|
||||
state = 0
|
||||
@@ -72,9 +72,7 @@
|
||||
if(!P.tool_start_check(user, amount=5))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You start adding cables to the frame...</span>")
|
||||
if(P.use_tool(src, user, 20, volume=50, amount=5))
|
||||
if(state != 2)
|
||||
return
|
||||
if(P.use_tool(src, user, 20, 5, 50, CALLBACK(src, .proc/check_state, 2)))
|
||||
to_chat(user, "<span class='notice'>You add cables to the frame.</span>")
|
||||
state = 3
|
||||
icon_state = "3"
|
||||
@@ -94,9 +92,7 @@
|
||||
return
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>You start to put in the glass panel...</span>")
|
||||
if(P.use_tool(src, user, 20, amount=2))
|
||||
if(state != 3)
|
||||
return
|
||||
if(P.use_tool(src, user, 20, 2, 0, CALLBACK(src, .proc/check_state, 3)))
|
||||
to_chat(user, "<span class='notice'>You put in the glass panel.</span>")
|
||||
state = 4
|
||||
src.icon_state = "4"
|
||||
@@ -121,6 +117,11 @@
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return ..()
|
||||
|
||||
//callback proc used on stacks use_tool to stop unnecessary amounts being wasted from spam clicking.
|
||||
/obj/structure/frame/computer/proc/check_state(target_state)
|
||||
if(state == target_state)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/structure/frame/computer/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
|
||||
@@ -287,9 +287,9 @@
|
||||
|
||||
/obj/machinery/computer/camera_advanced/ratvar/CreateEye()
|
||||
..()
|
||||
eyeobj.visible_icon = 1
|
||||
eyeobj.icon = 'icons/obj/abductor.dmi' //in case you still had any doubts
|
||||
eyeobj.icon_state = "camera_target"
|
||||
eyeobj.visible_icon = TRUE
|
||||
eyeobj.icon = 'icons/mob/cameramob.dmi' //in case you still had any doubts
|
||||
eyeobj.icon_state = "generic_camera"
|
||||
|
||||
/obj/machinery/computer/camera_advanced/ratvar/GrantActions(mob/living/carbon/user)
|
||||
..()
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
//increase the slots of many jobs.
|
||||
GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
|
||||
#define JOB_ALLOWED 1
|
||||
#define JOB_COOLDOWN -2
|
||||
#define JOB_MAX_POSITIONS -1 // Trying to reduce the number of slots below that of current holders of that job, or trying to open more slots than allowed
|
||||
#define JOB_DENIED 0
|
||||
|
||||
/obj/machinery/computer/card
|
||||
name = "identification console"
|
||||
desc = "You can use this to manage jobs and ID access."
|
||||
@@ -29,7 +34,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
"Head of Security",
|
||||
"Chief Engineer",
|
||||
"Research Director",
|
||||
"Chief Medical Officer")
|
||||
"Chief Medical Officer",
|
||||
"Quartermaster")
|
||||
|
||||
//The scaling factor of max total positions in relation to the total amount of people on board the station in %
|
||||
var/max_relative_positions = 30 //30%: Seems reasonable, limit of 6 @ 20 players
|
||||
@@ -44,10 +50,11 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
|
||||
light_color = LIGHT_COLOR_BLUE
|
||||
|
||||
/obj/machinery/computer/card/examine(mob/user)
|
||||
..()
|
||||
if(inserted_scan_id || inserted_modify_id)
|
||||
to_chat(user, "<span class='notice'>Alt-click to eject the ID card.</span>")
|
||||
/obj/machinery/computer/card/proc/get_jobs()
|
||||
return get_all_jobs()
|
||||
|
||||
/obj/machinery/computer/card/centcom/get_jobs()
|
||||
return get_all_centcom_jobs()
|
||||
|
||||
/obj/machinery/computer/card/Initialize()
|
||||
. = ..()
|
||||
@@ -59,17 +66,14 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
to_chat(user, "<span class='notice'>Alt-click to eject the ID card.</span>")
|
||||
|
||||
/obj/machinery/computer/card/attackby(obj/I, mob/user, params)
|
||||
if(istype(I, /obj/item/card/id))
|
||||
if(!inserted_scan_id)
|
||||
if(isidcard(I))
|
||||
if(check_access(I) && !inserted_scan_id)
|
||||
if(id_insert(user, I, inserted_scan_id))
|
||||
inserted_scan_id = I
|
||||
return
|
||||
if(!inserted_modify_id)
|
||||
if(id_insert(user, I, inserted_modify_id))
|
||||
inserted_modify_id = I
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='warning'>There's already an ID card in the console!</span>")
|
||||
updateUsrDialog()
|
||||
else if(id_insert(user, I, inserted_modify_id))
|
||||
inserted_modify_id = I
|
||||
updateUsrDialog()
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -103,7 +107,6 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
/obj/machinery/computer/card/proc/job_blacklisted(jobtitle)
|
||||
return (jobtitle in blacklisted)
|
||||
|
||||
|
||||
//Logic check for Topic() if you can open the job
|
||||
/obj/machinery/computer/card/proc/can_open_job(datum/job/job)
|
||||
if(job)
|
||||
@@ -111,10 +114,10 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
if((job.total_positions <= GLOB.player_list.len * (max_relative_positions / 100)))
|
||||
var/delta = (world.time / 10) - GLOB.time_last_changed_position
|
||||
if((change_position_cooldown < delta) || (opened_positions[job.title] < 0))
|
||||
return 1
|
||||
return -2
|
||||
return -1
|
||||
return 0
|
||||
return JOB_ALLOWED
|
||||
return JOB_COOLDOWN
|
||||
return JOB_MAX_POSITIONS
|
||||
return JOB_DENIED
|
||||
|
||||
//Logic check for Topic() if you can close the job
|
||||
/obj/machinery/computer/card/proc/can_close_job(datum/job/job)
|
||||
@@ -123,34 +126,45 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
if(job.total_positions > job.current_positions)
|
||||
var/delta = (world.time / 10) - GLOB.time_last_changed_position
|
||||
if((change_position_cooldown < delta) || (opened_positions[job.title] > 0))
|
||||
return 1
|
||||
return -2
|
||||
return -1
|
||||
return 0
|
||||
return JOB_ALLOWED
|
||||
return JOB_COOLDOWN
|
||||
return JOB_MAX_POSITIONS
|
||||
return JOB_DENIED
|
||||
|
||||
/obj/machinery/computer/card/proc/id_insert(mob/user, obj/item/card/id/I, target)
|
||||
if(istype(I))
|
||||
if(target)
|
||||
to_chat(user, "<span class='warning'>There's already an ID card in the console!</span>")
|
||||
return FALSE
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return FALSE
|
||||
user.visible_message("<span class='notice'>[user] inserts an ID card into the console.</span>", \
|
||||
"<span class='notice'>You insert the ID card into the console.</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/card/proc/id_insert(mob/user, obj/item/inserting_item, obj/item/target)
|
||||
var/obj/item/card/id/card_to_insert = inserting_item
|
||||
var/holder_item = FALSE
|
||||
|
||||
if(!isidcard(card_to_insert))
|
||||
card_to_insert = inserting_item.RemoveID()
|
||||
holder_item = TRUE
|
||||
|
||||
if(!card_to_insert || !user.transferItemToLoc(card_to_insert, src))
|
||||
return FALSE
|
||||
|
||||
if(target)
|
||||
if(holder_item && inserting_item.InsertID(target))
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
else
|
||||
id_eject(user, target)
|
||||
|
||||
user.visible_message("<span class='notice'>[user] inserts \the [card_to_insert] into \the [src].</span>",
|
||||
"<span class='notice'>You insert \the [card_to_insert] into \the [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/card/proc/id_eject(mob/user, obj/target)
|
||||
if(!target)
|
||||
to_chat(user, "<span class='warning'>There's no ID card in the console!</span>")
|
||||
to_chat(user, "<span class='warning'>That slot is empty!</span>")
|
||||
return FALSE
|
||||
else
|
||||
target.forceMove(drop_location())
|
||||
if(!issilicon(user) && Adjacent(user))
|
||||
user.put_in_hands(target)
|
||||
user.visible_message("<span class='notice'>[user] gets an ID card from the console.</span>", \
|
||||
"<span class='notice'>You get the ID card from the console.</span>")
|
||||
user.visible_message("<span class='notice'>[user] gets \the [target] from \the [src].</span>", \
|
||||
"<span class='notice'>You get \the [target] from \the [src].</span>")
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
@@ -162,86 +176,68 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
if(inserted_modify_id)
|
||||
if(id_eject(user, inserted_modify_id))
|
||||
inserted_modify_id = null
|
||||
authenticated = FALSE
|
||||
updateUsrDialog()
|
||||
return
|
||||
if(inserted_scan_id)
|
||||
if(id_eject(user, inserted_scan_id))
|
||||
inserted_scan_id = null
|
||||
authenticated = FALSE
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/card/ui_interact(mob/user)
|
||||
. = ..()
|
||||
var/dat
|
||||
if(!SSticker)
|
||||
return
|
||||
var/list/dat = list()
|
||||
if (mode == 1) // accessing crew manifest
|
||||
var/crew = ""
|
||||
dat += "<tt><b>Crew Manifest:</b><br>Please use security record computer to modify entries.<br><br>"
|
||||
for(var/datum/data/record/t in sortRecord(GLOB.data_core.general))
|
||||
crew += t.fields["name"] + " - " + t.fields["rank"] + "<br>"
|
||||
dat = "<tt><b>Crew Manifest:</b><br>Please use security record computer to modify entries.<br><br>[crew]<a href='?src=[REF(src)];choice=print'>Print</a><br><br><a href='?src=[REF(src)];choice=mode;mode_target=0'>Access ID modification console.</a><br></tt>"
|
||||
dat += {"[t.fields["name"]] - [t.fields["rank"]]<br>"}
|
||||
dat += "<a href='?src=[REF(src)];choice=print'>Print</a><br><br><a href='?src=[REF(src)];choice=mode;mode_target=0'>Access ID modification console.</a><br></tt>"
|
||||
|
||||
else if(mode == 2)
|
||||
// JOB MANAGEMENT
|
||||
dat = "<a href='?src=[REF(src)];choice=return'>Return</a>"
|
||||
dat += " || Confirm Identity: "
|
||||
var/S
|
||||
if(inserted_scan_id)
|
||||
S = html_encode(inserted_scan_id.name)
|
||||
else
|
||||
S = "--------"
|
||||
dat += "<a href='?src=[REF(src)];choice=inserted_scan_id'>[S]</a>"
|
||||
dat += "<table>"
|
||||
dat += "<tr><td style='width:25%'><b>Job</b></td><td style='width:25%'><b>Slots</b></td><td style='width:25%'><b>Open job</b></td><td style='width:25%'><b>Close job</b><td style='width:25%'><b>Prioritize</b></td></td></tr>"
|
||||
var/ID
|
||||
if(inserted_scan_id && (ACCESS_CHANGE_IDS in inserted_scan_id.access) && !target_dept)
|
||||
ID = 1
|
||||
else
|
||||
ID = 0
|
||||
dat += {"<a href='?src=[REF(src)];choice=return'>Return</a>
|
||||
<table><tr><td style='width:25%'><b>Job</b></td><td style='width:25%'><b>Slots</b></td>
|
||||
<td style='width:25%'><b>Open job</b></td><td style='width:25%'><b>Close job</b><td style='width:25%'><b>Prioritize</b></td></td></tr>"}
|
||||
for(var/datum/job/job in SSjob.occupations)
|
||||
dat += "<tr>"
|
||||
if(job.title in blacklisted)
|
||||
continue
|
||||
dat += "<td>[job.title]</td>"
|
||||
dat += "<td>[job.current_positions]/[job.total_positions]</td>"
|
||||
dat += "<td>"
|
||||
dat += {"<td>[job.title]</td>
|
||||
<td>[job.current_positions]/[job.total_positions]</td>
|
||||
<td>"}
|
||||
switch(can_open_job(job))
|
||||
if(1)
|
||||
if(ID)
|
||||
if(JOB_ALLOWED)
|
||||
if(authenticated == 2)
|
||||
dat += "<a href='?src=[REF(src)];choice=make_job_available;job=[job.title]'>Open Position</a><br>"
|
||||
else
|
||||
dat += "Open Position"
|
||||
if(-1)
|
||||
dat += "Denied"
|
||||
if(-2)
|
||||
if(JOB_COOLDOWN)
|
||||
var/time_to_wait = round(change_position_cooldown - ((world.time / 10) - GLOB.time_last_changed_position), 1)
|
||||
var/mins = round(time_to_wait / 60)
|
||||
var/seconds = time_to_wait - (60*mins)
|
||||
dat += "Cooldown ongoing: [mins]:[(seconds < 10) ? "0[seconds]" : "[seconds]"]"
|
||||
if(0)
|
||||
else
|
||||
dat += "Denied"
|
||||
dat += "</td><td>"
|
||||
switch(can_close_job(job))
|
||||
if(1)
|
||||
if(ID)
|
||||
if(JOB_ALLOWED)
|
||||
if(authenticated == 2)
|
||||
dat += "<a href='?src=[REF(src)];choice=make_job_unavailable;job=[job.title]'>Close Position</a>"
|
||||
else
|
||||
dat += "Close Position"
|
||||
if(-1)
|
||||
dat += "Denied"
|
||||
if(-2)
|
||||
if(JOB_COOLDOWN)
|
||||
var/time_to_wait = round(change_position_cooldown - ((world.time / 10) - GLOB.time_last_changed_position), 1)
|
||||
var/mins = round(time_to_wait / 60)
|
||||
var/seconds = time_to_wait - (60*mins)
|
||||
dat += "Cooldown ongoing: [mins]:[(seconds < 10) ? "0[seconds]" : "[seconds]"]"
|
||||
if(0)
|
||||
else
|
||||
dat += "Denied"
|
||||
dat += "</td><td>"
|
||||
switch(job.total_positions)
|
||||
if(0)
|
||||
dat += "Denied"
|
||||
else
|
||||
if(ID)
|
||||
if(authenticated == 2)
|
||||
if(job in SSjob.prioritized_jobs)
|
||||
dat += "<a href='?src=[REF(src)];choice=prioritize_job;job=[job.title]'>Deprioritize</a>"
|
||||
else
|
||||
@@ -255,57 +251,36 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
dat += "</td></tr>"
|
||||
dat += "</table>"
|
||||
else
|
||||
var/header = ""
|
||||
var/list/header = list()
|
||||
|
||||
var/target_name
|
||||
var/target_owner
|
||||
var/target_rank
|
||||
if(inserted_modify_id)
|
||||
target_name = html_encode(inserted_modify_id.name)
|
||||
else
|
||||
target_name = "--------"
|
||||
if(inserted_modify_id && inserted_modify_id.registered_name)
|
||||
target_owner = html_encode(inserted_modify_id.registered_name)
|
||||
else
|
||||
target_owner = "--------"
|
||||
if(inserted_modify_id && inserted_modify_id.assignment)
|
||||
target_rank = html_encode(inserted_modify_id.assignment)
|
||||
else
|
||||
target_rank = "Unassigned"
|
||||
|
||||
var/scan_name
|
||||
if(inserted_scan_id)
|
||||
scan_name = html_encode(inserted_scan_id.name)
|
||||
else
|
||||
scan_name = "--------"
|
||||
var/scan_name = inserted_scan_id ? html_encode(inserted_scan_id.name) : "--------"
|
||||
var/target_name = inserted_modify_id ? html_encode(inserted_modify_id.name) : "--------"
|
||||
var/target_owner = (inserted_modify_id && inserted_modify_id.registered_name) ? html_encode(inserted_modify_id.registered_name) : "--------"
|
||||
var/target_rank = (inserted_modify_id && inserted_modify_id.assignment) ? html_encode(inserted_modify_id.assignment) : "Unassigned"
|
||||
|
||||
if(!authenticated)
|
||||
header += "<br><i>Please insert the cards into the slots</i><br>"
|
||||
header += "Target: <a href='?src=[REF(src)];choice=inserted_modify_id'>[target_name]</a><br>"
|
||||
header += "Confirm Identity: <a href='?src=[REF(src)];choice=inserted_scan_id'>[scan_name]</a><br>"
|
||||
header += {"<br><i>Please insert the cards into the slots</i><br>
|
||||
Target: <a href='?src=[REF(src)];choice=inserted_modify_id'>[target_name]</a><br>
|
||||
Confirm Identity: <a href='?src=[REF(src)];choice=inserted_scan_id'>[scan_name]</a><br>"}
|
||||
else
|
||||
header += "<div align='center'><br>"
|
||||
header += "<a href='?src=[REF(src)];choice=inserted_modify_id'>Remove [target_name]</a> || "
|
||||
header += "<a href='?src=[REF(src)];choice=inserted_scan_id'>Remove [scan_name]</a> <br> "
|
||||
header += "<a href='?src=[REF(src)];choice=mode;mode_target=1'>Access Crew Manifest</a> <br> "
|
||||
header += "<a href='?src=[REF(src)];choice=logout'>Log Out</a></div>"
|
||||
header += {"<div align='center'><br>
|
||||
Target: <a href='?src=[REF(src)];choice=inserted_modify_id'>Remove [target_name]</a> ||
|
||||
Confirm Identity: <a href='?src=[REF(src)];choice=inserted_scan_id'>Remove [scan_name]</a><br>
|
||||
<a href='?src=[REF(src)];choice=mode;mode_target=1'>Access Crew Manifest</a><br>
|
||||
[!target_dept ? "<a href='?src=[REF(src)];choice=mode;mode_target=2'>Job Management</a><br>" : ""]
|
||||
<a href='?src=[REF(src)];choice=logout'>Log Out</a></div>"}
|
||||
|
||||
header += "<hr>"
|
||||
|
||||
var/jobs_all = ""
|
||||
var/list/alljobs = list("Unassigned")
|
||||
alljobs += (istype(src, /obj/machinery/computer/card/centcom)? get_all_centcom_jobs() : get_all_jobs()) + "Custom"
|
||||
for(var/job in alljobs)
|
||||
jobs_all += "<a href='?src=[REF(src)];choice=assign;assign_target=[job]'>[replacetext(job, " ", " ")]</a> " //make sure there isn't a line break in the middle of a job
|
||||
|
||||
|
||||
var/body
|
||||
|
||||
if (authenticated && inserted_modify_id)
|
||||
|
||||
var/carddesc = text("")
|
||||
var/jobs = text("")
|
||||
if( authenticated == 2)
|
||||
var/list/carddesc = list()
|
||||
var/list/jobs = list()
|
||||
if (authenticated == 2)
|
||||
var/list/jobs_all = list()
|
||||
for(var/job in (list("Unassigned") + get_jobs() + "Custom"))
|
||||
jobs_all += "<a href='?src=[REF(src)];choice=assign;assign_target=[job]'>[replacetext(job, " ", " ")]</a> " //make sure there isn't a line break in the middle of a job
|
||||
carddesc += {"<script type="text/javascript">
|
||||
function markRed(){
|
||||
var nameField = document.getElementById('namefield');
|
||||
@@ -317,20 +292,20 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
}
|
||||
function showAll(){
|
||||
var allJobsSlot = document.getElementById('alljobsslot');
|
||||
allJobsSlot.innerHTML = "<a href='#' onclick='hideAll()'>hide</a><br>"+ "[jobs_all]";
|
||||
allJobsSlot.innerHTML = "<a href='#' onclick='hideAll()'>hide</a><br>"+ "[jobs_all.Join()]";
|
||||
}
|
||||
function hideAll(){
|
||||
var allJobsSlot = document.getElementById('alljobsslot');
|
||||
allJobsSlot.innerHTML = "<a href='#' onclick='showAll()'>show</a>";
|
||||
}
|
||||
</script>"}
|
||||
carddesc += "<form name='cardcomp' action='?src=[REF(src)]' method='get'>"
|
||||
carddesc += "<input type='hidden' name='src' value='[REF(src)]'>"
|
||||
carddesc += "<input type='hidden' name='choice' value='reg'>"
|
||||
carddesc += "<b>registered name:</b> <input type='text' id='namefield' name='reg' value='[target_owner]' style='width:250px; background-color:white;' onchange='markRed()'>"
|
||||
carddesc += "<input type='submit' value='Rename' onclick='markGreen()'>"
|
||||
carddesc += "</form>"
|
||||
carddesc += "<b>Assignment:</b> "
|
||||
carddesc += {"<form name='cardcomp' action='?src=[REF(src)]' method='get'>
|
||||
<input type='hidden' name='src' value='[REF(src)]'>
|
||||
<input type='hidden' name='choice' value='reg'>
|
||||
<b>registered name:</b> <input type='text' id='namefield' name='reg' value='[target_owner]' style='width:250px; background-color:white;' onchange='markRed()'>
|
||||
<input type='submit' value='Rename' onclick='markGreen()'>
|
||||
</form>
|
||||
<b>Assignment:</b> "}
|
||||
|
||||
jobs += "<span id='alljobsslot'><a href='#' onclick='showAll()'>[target_rank]</a></span>" //CHECK THIS
|
||||
|
||||
@@ -338,18 +313,18 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
carddesc += "<b>registered_name:</b> [target_owner]</span>"
|
||||
jobs += "<b>Assignment:</b> [target_rank] (<a href='?src=[REF(src)];choice=demote'>Demote</a>)</span>"
|
||||
|
||||
var/accesses = ""
|
||||
if(istype(src, /obj/machinery/computer/card/centcom))
|
||||
var/list/accesses = list()
|
||||
if(istype(src, /obj/machinery/computer/card/centcom)) // REE
|
||||
accesses += "<h5>Central Command:</h5>"
|
||||
for(var/A in get_all_centcom_access())
|
||||
if(A in inserted_modify_id.access)
|
||||
accesses += "<a href='?src=[REF(src)];choice=access;access_target=[A];allowed=0'><font color=\"red\">[replacetext(get_centcom_access_desc(A), " ", " ")]</font></a> "
|
||||
accesses += "<a href='?src=[REF(src)];choice=access;access_target=[A];allowed=0'><font color=\"6bc473\">[replacetext(get_centcom_access_desc(A), " ", " ")]</font></a> "
|
||||
else
|
||||
accesses += "<a href='?src=[REF(src)];choice=access;access_target=[A];allowed=1'>[replacetext(get_centcom_access_desc(A), " ", " ")]</a> "
|
||||
else
|
||||
accesses += "<div align='center'><b>Access</b></div>"
|
||||
accesses += "<table style='width:100%'>"
|
||||
accesses += "<tr>"
|
||||
accesses += {"<div align='center'><b>Access</b></div>
|
||||
<table style='width:100%'>
|
||||
<tr>"}
|
||||
for(var/i = 1; i <= 7; i++)
|
||||
if(authenticated == 1 && !(i in region_access))
|
||||
continue
|
||||
@@ -361,23 +336,23 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
accesses += "<td style='width:14%' valign='top'>"
|
||||
for(var/A in get_region_accesses(i))
|
||||
if(A in inserted_modify_id.access)
|
||||
accesses += "<a href='?src=[REF(src)];choice=access;access_target=[A];allowed=0'><font color=\"red\">[replacetext(get_access_desc(A), " ", " ")]</font></a> "
|
||||
accesses += "<a href='?src=[REF(src)];choice=access;access_target=[A];allowed=0'><font color=\"6bc473\">[replacetext(get_access_desc(A), " ", " ")]</font></a> "
|
||||
else
|
||||
accesses += "<a href='?src=[REF(src)];choice=access;access_target=[A];allowed=1'>[replacetext(get_access_desc(A), " ", " ")]</a> "
|
||||
accesses += "<br>"
|
||||
accesses += "</td>"
|
||||
accesses += "</tr></table>"
|
||||
body = "[carddesc]<br>[jobs]<br><br>[accesses]" //CHECK THIS
|
||||
body = "[carddesc.Join()]<br>[jobs.Join()]<br><br>[accesses.Join()]<hr>" //CHECK THIS
|
||||
|
||||
else
|
||||
body = "<a href='?src=[REF(src)];choice=auth'>{Log in}</a> <br><hr>"
|
||||
body += "<a href='?src=[REF(src)];choice=mode;mode_target=1'>Access Crew Manifest</a>"
|
||||
else if (!authenticated)
|
||||
body = {"<a href='?src=[REF(src)];choice=auth'>Log In</a><br><hr>
|
||||
<a href='?src=[REF(src)];choice=mode;mode_target=1'>Access Crew Manifest</a><br><hr>"}
|
||||
if(!target_dept)
|
||||
body += "<br><hr><a href = '?src=[REF(src)];choice=mode;mode_target=2'>Job Management</a>"
|
||||
body += "<a href='?src=[REF(src)];choice=mode;mode_target=2'>Job Management</a><hr>"
|
||||
|
||||
dat = "<tt>[header][body]<hr><br></tt>"
|
||||
dat = list("<tt>", header.Join(), body, "<br></tt>")
|
||||
var/datum/browser/popup = new(user, "id_com", src.name, 900, 620)
|
||||
popup.set_content(dat)
|
||||
popup.set_content(dat.Join())
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
|
||||
@@ -393,25 +368,31 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
usr.set_machine(src)
|
||||
switch(href_list["choice"])
|
||||
if ("inserted_modify_id")
|
||||
if (inserted_modify_id)
|
||||
if(inserted_modify_id && !usr.get_active_held_item())
|
||||
if(id_eject(usr, inserted_modify_id))
|
||||
inserted_modify_id = null
|
||||
else
|
||||
var/mob/M = usr
|
||||
var/obj/item/card/id/I = M.get_idcard(TRUE)
|
||||
if(id_insert(usr, I, inserted_modify_id))
|
||||
inserted_modify_id = I
|
||||
updateUsrDialog()
|
||||
return
|
||||
if(usr.get_id_in_hand())
|
||||
var/obj/item/held_item = usr.get_active_held_item()
|
||||
var/obj/item/card/id/id_to_insert = held_item.GetID()
|
||||
if(id_insert(usr, held_item, inserted_modify_id))
|
||||
inserted_modify_id = id_to_insert
|
||||
updateUsrDialog()
|
||||
if ("inserted_scan_id")
|
||||
if (inserted_scan_id)
|
||||
if(inserted_scan_id && !usr.get_active_held_item())
|
||||
if(id_eject(usr, inserted_scan_id))
|
||||
inserted_scan_id = null
|
||||
else
|
||||
var/mob/M = usr
|
||||
var/obj/item/card/id/I = M.get_idcard(TRUE)
|
||||
if(id_insert(usr, I, inserted_scan_id))
|
||||
inserted_scan_id = I
|
||||
updateUsrDialog()
|
||||
return
|
||||
if(usr.get_id_in_hand())
|
||||
var/obj/item/held_item = usr.get_active_held_item()
|
||||
var/obj/item/card/id/id_to_insert = held_item.GetID()
|
||||
if(id_insert(usr, held_item, inserted_scan_id))
|
||||
inserted_scan_id = id_to_insert
|
||||
updateUsrDialog()
|
||||
if ("auth")
|
||||
if ((!( authenticated ) && (inserted_scan_id || issilicon(usr)) && (inserted_modify_id || mode)))
|
||||
if ((!( authenticated ) && (inserted_scan_id || issilicon(usr)) || mode))
|
||||
if (check_access(inserted_scan_id))
|
||||
region_access = list()
|
||||
head_subordinates = list()
|
||||
@@ -483,7 +464,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
updateUsrDialog()
|
||||
break
|
||||
if(!jobdatum)
|
||||
to_chat(usr, "<span class='error'>No log exists for this job.</span>")
|
||||
to_chat(usr, "<span class='alert'>No log exists for this job.</span>")
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
@@ -496,7 +477,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
inserted_modify_id.assignment = "Unassigned"
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
else
|
||||
to_chat(usr, "<span class='error'>You are not authorized to demote this position.</span>")
|
||||
to_chat(usr, "<span class='alert'>You are not authorized to demote this position.</span>")
|
||||
if ("reg")
|
||||
if (authenticated)
|
||||
var/t2 = inserted_modify_id
|
||||
@@ -506,7 +487,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
inserted_modify_id.registered_name = newName
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
else
|
||||
to_chat(usr, "<span class='error'>Invalid name entered.</span>")
|
||||
to_chat(usr, "<span class='alert'>Invalid name entered.</span>")
|
||||
updateUsrDialog()
|
||||
return
|
||||
if ("mode")
|
||||
@@ -519,7 +500,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
|
||||
if("make_job_available")
|
||||
// MAKE ANOTHER JOB POSITION AVAILABLE FOR LATE JOINERS
|
||||
if(inserted_scan_id && (ACCESS_CHANGE_IDS in inserted_scan_id.access) && !target_dept)
|
||||
if(authenticated && !target_dept)
|
||||
var/edit_job_target = href_list["job"]
|
||||
var/datum/job/j = SSjob.GetJob(edit_job_target)
|
||||
if(!j)
|
||||
@@ -536,7 +517,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
|
||||
if("make_job_unavailable")
|
||||
// MAKE JOB POSITION UNAVAILABLE FOR LATE JOINERS
|
||||
if(inserted_scan_id && (ACCESS_CHANGE_IDS in inserted_scan_id.access) && !target_dept)
|
||||
if(authenticated && !target_dept)
|
||||
var/edit_job_target = href_list["job"]
|
||||
var/datum/job/j = SSjob.GetJob(edit_job_target)
|
||||
if(!j)
|
||||
@@ -554,7 +535,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
|
||||
if ("prioritize_job")
|
||||
// TOGGLE WHETHER JOB APPEARS AS PRIORITIZED IN THE LOBBY
|
||||
if(inserted_scan_id && (ACCESS_CHANGE_IDS in inserted_scan_id.access) && !target_dept)
|
||||
if(authenticated && !target_dept)
|
||||
var/priority_target = href_list["job"]
|
||||
var/datum/job/j = SSjob.GetJob(priority_target)
|
||||
if(!j)
|
||||
@@ -570,7 +551,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
return
|
||||
else
|
||||
SSjob.prioritized_jobs += j
|
||||
to_chat(usr, "<span class='notice'>[j.title] has been successfully [priority ? "prioritized" : "unprioritized"]. Potential employees will notice your request.</span>")
|
||||
to_chat(usr, "<span class='notice'>[j.title] has been successfully [priority ? "prioritized" : "unprioritized"]. Potential employees will notice your request.</span>")
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
|
||||
if ("print")
|
||||
@@ -641,4 +622,9 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
target_dept = 6
|
||||
icon_screen = "idqm"
|
||||
|
||||
light_color = LIGHT_COLOR_ORANGE
|
||||
light_color = LIGHT_COLOR_ORANGE
|
||||
|
||||
#undef JOB_ALLOWED
|
||||
#undef JOB_COOLDOWN
|
||||
#undef JOB_MAX_POSITIONS
|
||||
#undef JOB_DENIED
|
||||
|
||||
@@ -70,9 +70,7 @@
|
||||
if("login")
|
||||
var/mob/M = usr
|
||||
|
||||
var/obj/item/card/id/I = M.get_active_held_item()
|
||||
if(!istype(I))
|
||||
I = M.get_idcard()
|
||||
var/obj/item/card/id/I = M.get_idcard(TRUE)
|
||||
|
||||
if(I && istype(I))
|
||||
if(check_access(I))
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
/turf/open/floor/mech_bay_recharge_floor/airless
|
||||
icon_state = "recharge_floor_asteroid"
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/obj/machinery/mech_bay_recharge_port
|
||||
name = "mech bay power port"
|
||||
|
||||
@@ -17,8 +17,15 @@
|
||||
hud.add_hud_to(H)
|
||||
|
||||
/obj/mecha/medical/odysseus/go_out()
|
||||
if(ishuman(occupant))
|
||||
var/mob/living/carbon/human/H = occupant
|
||||
if(isliving(occupant))
|
||||
var/mob/living/carbon/human/L = occupant
|
||||
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
hud.remove_hud_from(H)
|
||||
hud.remove_hud_from(L)
|
||||
..()
|
||||
|
||||
/obj/mecha/medical/odysseus/mmi_moved_inside(obj/item/mmi/mmi_as_oc, mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
var/mob/living/brain/B = mmi_as_oc.brainmob
|
||||
hud.add_hud_to(B)
|
||||
|
||||
@@ -163,8 +163,6 @@ RLD
|
||||
var/use_one_access = 0 //If the airlock should require ALL or only ONE of the listed accesses.
|
||||
var/delay_mod = 1
|
||||
var/canRturf = FALSE //Variable for R walls to deconstruct them
|
||||
var/adjacency_check = TRUE //Wheter it checks if the tool has to be in our hands or not. Wsed for the aux base construction drone's internal RCD
|
||||
|
||||
|
||||
/obj/item/construction/rcd/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] sets the RCD to 'Wall' and points it down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide..</span>")
|
||||
@@ -227,11 +225,10 @@ RLD
|
||||
|
||||
t1 += "<p><a href='?src=[REF(src)];close=1'>Close</a></p>\n"
|
||||
|
||||
var/datum/browser/popup = new(user, "rcd_access", "Access Control", 900, 500)
|
||||
var/datum/browser/popup = new(user, "rcd_access", "Access Control", 900, 500, src)
|
||||
popup.set_content(t1)
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.open()
|
||||
onclose(user, "rcd_access")
|
||||
|
||||
/obj/item/construction/rcd/Topic(href, href_list)
|
||||
..()
|
||||
@@ -275,7 +272,7 @@ RLD
|
||||
/obj/item/construction/rcd/proc/check_menu(mob/living/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated() || (adjacency_check && !user.Adjacent(src)))
|
||||
if(user.incapacitated() || !user.Adjacent(src))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -288,7 +285,7 @@ RLD
|
||||
"SOUTH" = image(icon = 'icons/mob/radial.dmi', icon_state = "csouth"),
|
||||
"WEST" = image(icon = 'icons/mob/radial.dmi', icon_state = "cwest")
|
||||
)
|
||||
var/computerdirs = show_radial_menu(user, src, computer_dirs, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = adjacency_check, tooltips = TRUE)
|
||||
var/computerdirs = show_radial_menu(user, src, computer_dirs, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE)
|
||||
if(!check_menu(user))
|
||||
return
|
||||
switch(computerdirs)
|
||||
@@ -347,13 +344,13 @@ RLD
|
||||
"External Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/external/glass)
|
||||
)
|
||||
|
||||
var/airlockcat = show_radial_menu(user, src, solid_or_glass_choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = adjacency_check)
|
||||
var/airlockcat = show_radial_menu(user, src, solid_or_glass_choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE)
|
||||
if(!check_menu(user))
|
||||
return
|
||||
switch(airlockcat)
|
||||
if("Solid")
|
||||
if(advanced_airlock_setting == 1)
|
||||
var/airlockpaint = show_radial_menu(user, src, solid_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = adjacency_check)
|
||||
var/airlockpaint = show_radial_menu(user, src, solid_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE)
|
||||
if(!check_menu(user))
|
||||
return
|
||||
switch(airlockpaint)
|
||||
@@ -398,7 +395,7 @@ RLD
|
||||
|
||||
if("Glass")
|
||||
if(advanced_airlock_setting == 1)
|
||||
var/airlockpaint = show_radial_menu(user, src , glass_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = adjacency_check)
|
||||
var/airlockpaint = show_radial_menu(user, src , glass_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE)
|
||||
if(!check_menu(user))
|
||||
return
|
||||
switch(airlockpaint)
|
||||
@@ -557,6 +554,7 @@ RLD
|
||||
desc = "A device used to rapidly build walls and floors."
|
||||
canRturf = TRUE
|
||||
upgrade = TRUE
|
||||
var/energyfactor = 72
|
||||
|
||||
|
||||
/obj/item/construction/rcd/borg/useResource(amount, mob/user)
|
||||
@@ -567,7 +565,7 @@ RLD
|
||||
if(user)
|
||||
to_chat(user, no_ammo_message)
|
||||
return 0
|
||||
. = borgy.cell.use(amount * 72) //borgs get 1.3x the use of their RCDs
|
||||
. = borgy.cell.use(amount * energyfactor) //borgs get 1.3x the use of their RCDs
|
||||
if(!. && user)
|
||||
to_chat(user, no_ammo_message)
|
||||
return .
|
||||
@@ -580,11 +578,16 @@ RLD
|
||||
if(user)
|
||||
to_chat(user, no_ammo_message)
|
||||
return 0
|
||||
. = borgy.cell.charge >= (amount * 72)
|
||||
. = borgy.cell.charge >= (amount * energyfactor)
|
||||
if(!. && user)
|
||||
to_chat(user, no_ammo_message)
|
||||
return .
|
||||
|
||||
/obj/item/construction/rcd/borg/syndicate
|
||||
icon_state = "ircd"
|
||||
item_state = "ircd"
|
||||
energyfactor = 66
|
||||
|
||||
/obj/item/construction/rcd/loaded
|
||||
matter = 160
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
// Possible restyles for the cutout;
|
||||
// add an entry in change_appearance() if you add to here
|
||||
var/list/possible_appearances = list("Assistant", "Clown", "Mime",
|
||||
"Traitor", "Nuke Op", "Cultist", "Clockwork Cultist",
|
||||
"Traitor", "Nuke Op", "Cultist", "Brass Cultist", "Clockwork Cultist",
|
||||
"Revolutionary", "Wizard", "Shadowling", "Xenomorph", "Xenomorph Maid", "Swarmer",
|
||||
"Ash Walker", "Deathsquad Officer", "Ian", "Slaughter Demon",
|
||||
"Laughter Demon", "Private Security Officer")
|
||||
"Laughter Demon", "Private Security Officer", "Securitron", "Gondola", "Monkey")
|
||||
var/pushed_over = FALSE //If the cutout is pushed over and has to be righted
|
||||
var/deceptive = FALSE //If the cutout actually appears as what it portray and not a discolored version
|
||||
|
||||
@@ -123,10 +123,14 @@
|
||||
name = "Unknown"
|
||||
desc = "A cardboard cutout of a cultist."
|
||||
icon_state = "cutout_cultist"
|
||||
if("Brass Cultist")
|
||||
name = "[pick(GLOB.first_names_male)] [pick(GLOB.last_names)]"
|
||||
desc = "A cardboard cutout of a \"servant\" of Ratvar."
|
||||
icon_state = "cutout_servant"
|
||||
if("Clockwork Cultist")
|
||||
name = "[pick(GLOB.first_names_male)] [pick(GLOB.last_names)]"
|
||||
desc = "A cardboard cutout of a servant of Ratvar."
|
||||
icon_state = "cutout_servant"
|
||||
icon_state = "cutout_new_servant"
|
||||
if("Revolutionary")
|
||||
name = "Unknown"
|
||||
desc = "A cardboard cutout of a revolutionary."
|
||||
@@ -179,6 +183,18 @@
|
||||
name = "Private Security Officer"
|
||||
desc = "A cardboard cutout of a private security officer."
|
||||
icon_state = "cutout_ntsec"
|
||||
if("Securitron")
|
||||
name = "[pick("Officer", "Oftiser", "Sergeant", "General")][pick(" Genesky", " Pingsky", " Beepsky", " Pipsqueak", "-at-Armsky")]"
|
||||
desc = "A cardboard cutout of a securitron."
|
||||
icon_state = "cutout_law"
|
||||
if("Gondola")
|
||||
name = "gondola"
|
||||
desc = "A cardboard cutout of a gondola."
|
||||
icon_state = "cutout_gondola"
|
||||
if("Monkey")
|
||||
name = "monkey ([rand(1, 999)])"
|
||||
desc = "A cardboard cutout of a monkey."
|
||||
icon_state = "cutout_monky"
|
||||
return 1
|
||||
|
||||
/obj/item/cardboard_cutout/setDir(newdir)
|
||||
|
||||
@@ -203,6 +203,9 @@
|
||||
/obj/item/card/id/GetID()
|
||||
return src
|
||||
|
||||
/obj/item/card/id/RemoveID()
|
||||
return src
|
||||
|
||||
/*
|
||||
Usage:
|
||||
update_label()
|
||||
|
||||
@@ -111,13 +111,15 @@
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
attack_verb = list("HONKED")
|
||||
var/moodlet = "honk" //used to define which kind of moodlet is added to the honked target
|
||||
var/honksound = 'sound/items/bikehorn.ogg'
|
||||
|
||||
/obj/item/bikehorn/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 50)
|
||||
AddComponent(/datum/component/squeak, list(honksound=1), 50)
|
||||
|
||||
/obj/item/bikehorn/attack(mob/living/carbon/M, mob/living/carbon/user)
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "honk", /datum/mood_event/honk)
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, moodlet, /datum/mood_event/honk)
|
||||
return ..()
|
||||
|
||||
/obj/item/bikehorn/suicide_act(mob/user)
|
||||
@@ -130,10 +132,7 @@
|
||||
name = "air horn"
|
||||
desc = "Damn son, where'd you find this?"
|
||||
icon_state = "air_horn"
|
||||
|
||||
/obj/item/bikehorn/airhorn/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/squeak, list('sound/items/airhorn2.ogg'=1), 50)
|
||||
honksound = 'sound/items/airhorn2.ogg'
|
||||
|
||||
//golden bikehorn
|
||||
/obj/item/bikehorn/golden
|
||||
@@ -163,6 +162,19 @@
|
||||
M.emote("flip")
|
||||
flip_cooldown = world.time + 7
|
||||
|
||||
/obj/item/bikehorn/silver
|
||||
name = "silver bike horn"
|
||||
desc = "A shiny bike horn handcrafted in the artisan workshops of Mars, with superior kevlar-reinforced rubber bulb attached to a polished plasteel reed horn."
|
||||
attack_verb = list("elegantly HONKED")
|
||||
icon_state = "silverhorn"
|
||||
|
||||
/obj/item/bikehorn/bluespacehonker
|
||||
name = "bluespace bike horn"
|
||||
desc = "A normal bike horn colored blue and has bluespace dust held in to reed horn allowing for silly honks through space and time, into your in childhood."
|
||||
attack_verb = list("HONKED in bluespace", "HONKED", "quantumly HONKED")
|
||||
icon_state = "bluespacehonker"
|
||||
moodlet = "bshonk"
|
||||
|
||||
//canned laughter
|
||||
/obj/item/reagent_containers/food/drinks/soda_cans/canned_laughter
|
||||
name = "Canned Laughter"
|
||||
|
||||
@@ -162,31 +162,33 @@ GLOBAL_LIST_EMPTY(PDAs)
|
||||
|
||||
/obj/item/pda/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(equipped)
|
||||
if(equipped || !user.client)
|
||||
return
|
||||
if(user.client)
|
||||
background_color = user.client.prefs.pda_color
|
||||
switch(user.client.prefs.pda_style)
|
||||
if(MONO)
|
||||
font_index = MODE_MONO
|
||||
font_mode = FONT_MONO
|
||||
if(SHARE)
|
||||
font_index = MODE_SHARE
|
||||
font_mode = FONT_SHARE
|
||||
if(ORBITRON)
|
||||
font_index = MODE_ORBITRON
|
||||
font_mode = FONT_ORBITRON
|
||||
if(VT)
|
||||
font_index = MODE_VT
|
||||
font_mode = FONT_VT
|
||||
else
|
||||
font_index = MODE_MONO
|
||||
font_mode = FONT_MONO
|
||||
var/pref_skin = GLOB.pda_reskins[user.client.prefs.pda_skin]
|
||||
if(icon != pref_skin)
|
||||
icon = pref_skin
|
||||
update_icon(FALSE, TRUE)
|
||||
equipped = TRUE
|
||||
update_style(user.client)
|
||||
|
||||
/obj/item/pda/proc/update_style(client/C)
|
||||
background_color = C.prefs.pda_color
|
||||
switch(C.prefs.pda_style)
|
||||
if(MONO)
|
||||
font_index = MODE_MONO
|
||||
font_mode = FONT_MONO
|
||||
if(SHARE)
|
||||
font_index = MODE_SHARE
|
||||
font_mode = FONT_SHARE
|
||||
if(ORBITRON)
|
||||
font_index = MODE_ORBITRON
|
||||
font_mode = FONT_ORBITRON
|
||||
if(VT)
|
||||
font_index = MODE_VT
|
||||
font_mode = FONT_VT
|
||||
else
|
||||
font_index = MODE_MONO
|
||||
font_mode = FONT_MONO
|
||||
var/pref_skin = GLOB.pda_reskins[C.prefs.pda_skin]
|
||||
if(icon != pref_skin)
|
||||
icon = pref_skin
|
||||
update_icon(FALSE, TRUE)
|
||||
equipped = TRUE
|
||||
|
||||
/obj/item/pda/proc/update_label()
|
||||
name = "PDA-[owner] ([ownjob])" //Name generalisation
|
||||
@@ -200,6 +202,18 @@ GLOBAL_LIST_EMPTY(PDAs)
|
||||
/obj/item/pda/GetID()
|
||||
return id
|
||||
|
||||
/obj/item/pda/RemoveID()
|
||||
return do_remove_id()
|
||||
|
||||
/obj/item/pda/InsertID(obj/item/inserting_item)
|
||||
var/obj/item/card/inserting_id = inserting_item.RemoveID()
|
||||
if(!inserting_id)
|
||||
return
|
||||
insert_id(inserting_id)
|
||||
if(id == inserting_id)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/pda/update_icon(alert = FALSE, new_overlays = FALSE)
|
||||
if(new_overlays)
|
||||
set_new_overlays()
|
||||
@@ -688,15 +702,27 @@ GLOBAL_LIST_EMPTY(PDAs)
|
||||
return
|
||||
|
||||
/obj/item/pda/proc/remove_id()
|
||||
|
||||
if(issilicon(usr) || !usr.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
return
|
||||
do_remove_id(usr)
|
||||
|
||||
if (id)
|
||||
usr.put_in_hands(id)
|
||||
to_chat(usr, "<span class='notice'>You remove the ID from the [name].</span>")
|
||||
id = null
|
||||
update_icon()
|
||||
/obj/item/pda/proc/do_remove_id(mob/user)
|
||||
if(!id)
|
||||
return
|
||||
if(user)
|
||||
user.put_in_hands(id)
|
||||
to_chat(user, "<span class='notice'>You remove the ID from the [name].</span>")
|
||||
else
|
||||
id.forceMove(get_turf(src))
|
||||
|
||||
. = id
|
||||
id = null
|
||||
update_icon()
|
||||
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
if(H.wear_id == src)
|
||||
H.sec_hud_set_ID()
|
||||
|
||||
/obj/item/pda/proc/msg_input(mob/living/U = usr)
|
||||
var/t = stripped_input(U, "Please enter message", name)
|
||||
@@ -878,17 +904,27 @@ GLOBAL_LIST_EMPTY(PDAs)
|
||||
if(istype(C))
|
||||
I = C
|
||||
|
||||
if(I && I.registered_name)
|
||||
if(I?.registered_name)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return FALSE
|
||||
var/obj/old_id = id
|
||||
id = I
|
||||
if(old_id)
|
||||
user.put_in_hands(old_id)
|
||||
insert_id(I, user)
|
||||
update_icon()
|
||||
playsound(src, 'sound/machines/button.ogg', 50, 1)
|
||||
return TRUE
|
||||
|
||||
/obj/item/pda/proc/insert_id(obj/item/card/id/inserting_id, mob/user)
|
||||
var/obj/old_id = id
|
||||
id = inserting_id
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/human_wearer = loc
|
||||
if(human_wearer.wear_id == src)
|
||||
human_wearer.sec_hud_set_ID()
|
||||
if(old_id)
|
||||
if(user)
|
||||
user.put_in_hands(old_id)
|
||||
else
|
||||
old_id.forceMove(get_turf(src))
|
||||
|
||||
// access to status display signals
|
||||
/obj/item/pda/attackby(obj/item/C, mob/user, params)
|
||||
if(istype(C, /obj/item/cartridge) && !cartridge)
|
||||
|
||||
@@ -134,7 +134,6 @@
|
||||
var/voracious = hound ? TRUE : FALSE
|
||||
var/list/targets = target && hound ? list(target) : contents
|
||||
if(hound)
|
||||
hound.setClickCooldown(50)
|
||||
if(!hound.client || !(hound.client.prefs.cit_toggles & MEDIHOUND_SLEEPER))
|
||||
voracious = FALSE
|
||||
else
|
||||
@@ -447,7 +446,7 @@
|
||||
if (!target.devourable)
|
||||
to_chat(user, "The target registers an error code. Unable to insert into [src].")
|
||||
return
|
||||
if(target)
|
||||
if(patient)
|
||||
to_chat(user,"<span class='warning'>Your [src] is already occupied.</span>")
|
||||
return
|
||||
if(target.buckled)
|
||||
@@ -524,3 +523,7 @@
|
||||
update_gut()
|
||||
user.visible_message("<span class='warning'>[hound.name]'s garbage processor groans lightly as [trashman] slips inside.</span>", "<span class='notice'>Your garbage compactor groans lightly as [trashman] slips inside.</span>")
|
||||
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1)
|
||||
|
||||
/obj/item/dogborg/sleeper/K9/flavour
|
||||
name = "Mobile Sleeper"
|
||||
desc = "A mounted, underslung sleeper, intended for holding willing occupants for leisurely purposes."
|
||||
@@ -247,6 +247,8 @@
|
||||
/obj/item/multitool/cyborg
|
||||
name = "multitool"
|
||||
desc = "Optimised and stripped-down version of a regular multitool."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "multitool_cyborg"
|
||||
toolspeed = 0.5
|
||||
|
||||
/obj/item/multitool/abductor
|
||||
|
||||
@@ -755,3 +755,47 @@
|
||||
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
attack_verb = list("bashes", "smacks", "whacks")
|
||||
|
||||
/obj/item/nullrod/rosary
|
||||
icon_state = "rosary"
|
||||
item_state = null
|
||||
name = "prayer beads"
|
||||
desc = "A set of prayer beads used by many of the more traditional religions in space"
|
||||
force = 4
|
||||
throwforce = 0
|
||||
attack_verb = list("whipped", "repented", "lashed", "flagellated")
|
||||
var/praying = FALSE
|
||||
var/deity_name = "Coderbus" //This is the default, hopefully won't actually appear if the religion subsystem is running properly
|
||||
|
||||
/obj/item/nullrod/rosary/Initialize()
|
||||
.=..()
|
||||
if(GLOB.deity)
|
||||
deity_name = GLOB.deity
|
||||
|
||||
/obj/item/nullrod/rosary/attack(mob/living/M, mob/living/user)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return ..()
|
||||
|
||||
if(!user.mind || user.mind.assigned_role != "Chaplain")
|
||||
to_chat(user, "<span class='notice'>You are not close enough with [deity_name] to use [src].</span>")
|
||||
return
|
||||
|
||||
if(praying)
|
||||
to_chat(user, "<span class='notice'>You are already using [src].</span>")
|
||||
return
|
||||
|
||||
user.visible_message("<span class='info'>[user] kneels[M == user ? null : " next to [M]"] and begins to utter a prayer to [deity_name].</span>", \
|
||||
"<span class='info'>You kneel[M == user ? null : " next to [M]"] and begin a prayer to [deity_name].</span>")
|
||||
|
||||
praying = TRUE
|
||||
if(do_after(user, 20, target = M))
|
||||
M.reagents?.add_reagent("holywater", 5)
|
||||
to_chat(M, "<span class='notice'>[user]'s prayer to [deity_name] has eased your pain!</span>")
|
||||
M.adjustToxLoss(-5, TRUE, TRUE)
|
||||
M.adjustOxyLoss(-5)
|
||||
M.adjustBruteLoss(-5)
|
||||
M.adjustFireLoss(-5)
|
||||
praying = FALSE
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Your prayer to [deity_name] was interrupted.</span>")
|
||||
praying = FALSE
|
||||
|
||||
@@ -1014,3 +1014,9 @@
|
||||
icon_state = "maya"
|
||||
item_state = "maya"
|
||||
attack_verb = list("nuked", "arrested", "harmbatonned")
|
||||
|
||||
/obj/item/toy/plush/catgirl/marisa
|
||||
desc = "An adorable stuffed toy that resembles a crew member, or maybe a witch. Having it makes you feel you can win."
|
||||
icon_state = "marisa"
|
||||
item_state = "marisa"
|
||||
attack_verb = list("blasted", "sparked", "dazzled")
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
desc = "A trash bag of holding replacement for the janiborg's standard trash bag."
|
||||
icon_state = "cyborg_upgrade3"
|
||||
require_module = 1
|
||||
module_type = list(/obj/item/robot_module/janitor, /obj/item/robot_module/scrubpup)
|
||||
module_type = list(/obj/item/robot_module/butler)
|
||||
|
||||
/obj/item/borg/upgrade/tboh/action(mob/living/silicon/robot/R)
|
||||
. = ..()
|
||||
@@ -230,7 +230,7 @@
|
||||
desc = "An advanced mop replacement for the janiborg's standard mop."
|
||||
icon_state = "cyborg_upgrade3"
|
||||
require_module = 1
|
||||
module_type = list(/obj/item/robot_module/janitor, /obj/item/robot_module/scrubpup)
|
||||
module_type = list(/obj/item/robot_module/butler)
|
||||
|
||||
/obj/item/borg/upgrade/amop/action(mob/living/silicon/robot/R)
|
||||
. = ..()
|
||||
@@ -522,8 +522,7 @@
|
||||
module_type = list(
|
||||
/obj/item/robot_module/medical,
|
||||
/obj/item/robot_module/syndicate_medical,
|
||||
/obj/item/robot_module/medihound,
|
||||
/obj/item/robot_module/borgi)
|
||||
/obj/item/robot_module/medihound)
|
||||
|
||||
/obj/item/borg/upgrade/advhealth/action(mob/living/silicon/robot/R, user = usr)
|
||||
. = ..()
|
||||
@@ -607,7 +606,7 @@
|
||||
icon = 'icons/obj/storage.dmi'
|
||||
icon_state = "borg_BS_RPED"
|
||||
require_module = TRUE
|
||||
module_type = list(/obj/item/robot_module/engineering)
|
||||
module_type = list(/obj/item/robot_module/engineering, /obj/item/robot_module/saboteur)
|
||||
|
||||
/obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr)
|
||||
. = ..()
|
||||
|
||||
@@ -191,6 +191,12 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
|
||||
new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20), \
|
||||
new/datum/stack_recipe("wood table frame", /obj/structure/table_frame/wood, 2, time = 10), \
|
||||
null, \
|
||||
new/datum/stack_recipe_list("pews", list(
|
||||
new /datum/stack_recipe("pew (middle)", /obj/structure/chair/pew, 3, one_per_turf = TRUE, on_floor = TRUE),\
|
||||
new /datum/stack_recipe("pew (left)", /obj/structure/chair/pew/left, 3, one_per_turf = TRUE, on_floor = TRUE),\
|
||||
new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, one_per_turf = TRUE, on_floor = TRUE),\
|
||||
)),
|
||||
null, \
|
||||
new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 40), \
|
||||
new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 30), \
|
||||
new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \
|
||||
|
||||
@@ -239,8 +239,8 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
|
||||
/obj/item/storage/toolbox/gold_real
|
||||
name = "golden toolbox"
|
||||
desc = "A larger then normal toolbox made of gold plated plastitanium."
|
||||
item_state = "gold"
|
||||
icon_state = "gold"
|
||||
item_state = "toolbox_gold"
|
||||
has_latches = FALSE
|
||||
force = 16 // Less then a spear
|
||||
throwforce = 14
|
||||
@@ -266,7 +266,7 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
|
||||
name = "golden toolbox"
|
||||
desc = "A gold plated toolbox, fancy and harmless due to the gold plating being on cardboard!"
|
||||
icon_state = "gold"
|
||||
item_state = "gold"
|
||||
item_state = "toolbox_gold"
|
||||
has_latches = FALSE
|
||||
force = 0
|
||||
throwforce = 0
|
||||
|
||||
@@ -381,3 +381,13 @@
|
||||
new /obj/item/gun/ballistic/automatic/pistol/m1911/kitchengun(src)
|
||||
new /obj/item/ammo_box/magazine/m45/kitchengun(src)
|
||||
new /obj/item/ammo_box/magazine/m45/kitchengun(src)
|
||||
|
||||
|
||||
/obj/item/storage/box/strange_seeds_10pack
|
||||
|
||||
/obj/item/storage/box/strange_seeds_10pack/PopulateContents()
|
||||
for(var/i in 1 to 10)
|
||||
new /obj/item/seeds/random(src)
|
||||
|
||||
if(prob(50))
|
||||
new /obj/item/seeds/random(src) //oops, an additional packet might have slipped its way into the box
|
||||
@@ -68,6 +68,21 @@
|
||||
/obj/item/storage/wallet/GetID()
|
||||
return front_id
|
||||
|
||||
/obj/item/storage/wallet/RemoveID()
|
||||
if(!front_id)
|
||||
return
|
||||
. = front_id
|
||||
front_id.forceMove(get_turf(src))
|
||||
|
||||
/obj/item/storage/wallet/InsertID(obj/item/inserting_item)
|
||||
var/obj/item/card/inserting_id = inserting_item.RemoveID()
|
||||
if(!inserting_id)
|
||||
return FALSE
|
||||
attackby(inserting_id)
|
||||
if(inserting_id in contents)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/storage/wallet/GetAccess()
|
||||
if(LAZYLEN(combined_access))
|
||||
return combined_access
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
/obj/item/crowbar/cyborg
|
||||
name = "hydraulic crowbar"
|
||||
desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "crowbar_cyborg"
|
||||
usesound = 'sound/items/jaws_pry.ogg'
|
||||
force = 10
|
||||
toolspeed = 0.5
|
||||
|
||||
@@ -138,10 +138,14 @@
|
||||
user.put_in_active_hand(b_drill)
|
||||
|
||||
/obj/item/screwdriver/cyborg
|
||||
name = "powered screwdriver"
|
||||
name = "automated screwdriver"
|
||||
desc = "An electrical screwdriver, designed to be both precise and quick."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "screwdriver_cyborg"
|
||||
hitsound = 'sound/items/drill_hit.ogg'
|
||||
usesound = 'sound/items/drill_use.ogg'
|
||||
toolspeed = 0.5
|
||||
random_color = FALSE
|
||||
|
||||
/obj/item/screwdriver/advanced
|
||||
name = "advanced screwdriver"
|
||||
|
||||
@@ -302,6 +302,8 @@
|
||||
/obj/item/weldingtool/largetank/cyborg
|
||||
name = "integrated welding tool"
|
||||
desc = "An advanced welder designed to be used in robotic systems."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "indwelder_cyborg"
|
||||
toolspeed = 0.5
|
||||
|
||||
/obj/item/weldingtool/largetank/flamethrower_screwdriver()
|
||||
|
||||
@@ -87,7 +87,10 @@
|
||||
/obj/item/wirecutters/cyborg
|
||||
name = "wirecutters"
|
||||
desc = "This cuts wires."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "wirecutters_cyborg"
|
||||
toolspeed = 0.5
|
||||
random_color = FALSE
|
||||
|
||||
/obj/item/wirecutters/power
|
||||
name = "jaws of life"
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
/obj/item/wrench/cyborg
|
||||
name = "automatic wrench"
|
||||
desc = "An advanced robotic wrench. Can be found in construction cyborgs."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "wrench_cyborg"
|
||||
toolspeed = 0.5
|
||||
|
||||
/obj/item/wrench/brass
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/obj/structure/chair/pew
|
||||
name = "wooden pew"
|
||||
desc = "Kneel here and pray."
|
||||
icon = 'icons/obj/sofa.dmi'
|
||||
icon_state = "pewmiddle"
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 70
|
||||
buildstacktype = /obj/item/stack/sheet/mineral/wood
|
||||
buildstackamount = 3
|
||||
item_chair = null
|
||||
|
||||
/obj/structure/chair/pew/left
|
||||
name = "left wooden pew end"
|
||||
icon_state = "pewend_left"
|
||||
var/mutable_appearance/leftpewarmrest
|
||||
|
||||
/obj/structure/chair/pew/left/Initialize()
|
||||
leftpewarmrest = GetLeftPewArmrest()
|
||||
leftpewarmrest.layer = ABOVE_MOB_LAYER
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/pew/left/proc/GetLeftPewArmrest()
|
||||
return mutable_appearance('icons/obj/sofa.dmi', "pewend_left_armrest")
|
||||
|
||||
/obj/structure/chair/pew/left/Destroy()
|
||||
QDEL_NULL(leftpewarmrest)
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/pew/left/post_buckle_mob(mob/living/M)
|
||||
. = ..()
|
||||
update_leftpewarmrest()
|
||||
|
||||
/obj/structure/chair/pew/left/proc/update_leftpewarmrest()
|
||||
if(has_buckled_mobs())
|
||||
add_overlay(leftpewarmrest)
|
||||
else
|
||||
cut_overlay(leftpewarmrest)
|
||||
|
||||
/obj/structure/chair/pew/left/post_unbuckle_mob()
|
||||
. = ..()
|
||||
update_leftpewarmrest()
|
||||
|
||||
/obj/structure/chair/pew/right
|
||||
name = "left wooden pew end"
|
||||
icon_state = "pewend_right"
|
||||
var/mutable_appearance/rightpewarmrest
|
||||
|
||||
/obj/structure/chair/pew/right/Initialize()
|
||||
rightpewarmrest = GetRightPewArmrest()
|
||||
rightpewarmrest.layer = ABOVE_MOB_LAYER
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/pew/right/proc/GetRightPewArmrest()
|
||||
return mutable_appearance('icons/obj/sofa.dmi', "pewend_right_armrest")
|
||||
|
||||
/obj/structure/chair/pew/right/Destroy()
|
||||
QDEL_NULL(rightpewarmrest)
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/pew/right/post_buckle_mob(mob/living/M)
|
||||
. = ..()
|
||||
update_rightpewarmrest()
|
||||
|
||||
/obj/structure/chair/pew/right/proc/update_rightpewarmrest()
|
||||
if(has_buckled_mobs())
|
||||
add_overlay(rightpewarmrest)
|
||||
else
|
||||
cut_overlay(rightpewarmrest)
|
||||
|
||||
/obj/structure/chair/pew/right/post_unbuckle_mob()
|
||||
. = ..()
|
||||
update_rightpewarmrest()
|
||||
@@ -23,3 +23,4 @@
|
||||
new /obj/item/circuitboard/machine/techfab/department/cargo(src)
|
||||
new /obj/item/storage/photo_album/QM(src)
|
||||
new /obj/item/circuitboard/machine/ore_silo(src)
|
||||
new /obj/item/clothing/suit/hooded/wintercoat/qm(src)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
new /obj/item/storage/photo_album/CE(src)
|
||||
new /obj/item/storage/lockbox/medal/engineering(src)
|
||||
new /obj/item/construction/rcd/loaded/upgraded(src)
|
||||
new /obj/item/clothing/suit/hooded/wintercoat/ce(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/engineering_electrical
|
||||
name = "electrical supplies locker"
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
new /obj/item/circuitboard/machine/techfab/department/medical(src)
|
||||
new /obj/item/storage/photo_album/CMO(src)
|
||||
new /obj/item/storage/lockbox/medal/medical(src)
|
||||
new /obj/item/clothing/suit/hooded/wintercoat/cmo(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/animal
|
||||
name = "animal control"
|
||||
|
||||
@@ -30,3 +30,4 @@
|
||||
new /obj/item/door_remote/research_director(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/science(src)
|
||||
new /obj/item/storage/photo_album/RD(src)
|
||||
new /obj/item/clothing/suit/hooded/wintercoat/rd(src)
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
new /obj/item/door_remote/civillian(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/service(src)
|
||||
new /obj/item/storage/photo_album/HoP(src)
|
||||
new /obj/item/clothing/suit/hooded/wintercoat/hop(src)
|
||||
/obj/structure/closet/secure_closet/hos
|
||||
name = "\proper head of security's locker"
|
||||
req_access = list(ACCESS_HOS)
|
||||
@@ -94,6 +95,7 @@
|
||||
new /obj/item/pinpointer/nuke(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/security(src)
|
||||
new /obj/item/storage/photo_album/HoS(src)
|
||||
new /obj/item/clothing/suit/hooded/wintercoat/hos(src)
|
||||
/obj/structure/closet/secure_closet/warden
|
||||
name = "\proper warden's locker"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
|
||||
@@ -422,7 +422,7 @@
|
||||
implants = list(/obj/item/implant/weapons_auth)
|
||||
id = /obj/item/card/id/syndicate
|
||||
|
||||
/datum/outfit/syndicate_empty/post_equip(mob/living/carbon/human/H)
|
||||
/datum/outfit/syndicate_empty/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
H.faction |= ROLE_SYNDICATE
|
||||
|
||||
/obj/effect/mob_spawn/human/syndicate/battlecruiser
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
armor = list("melee" = 0, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 20)
|
||||
var/obj/item/holosign_creator/projector
|
||||
|
||||
/obj/structure/holosign/New(loc, source_projector)
|
||||
/obj/structure/holosign/Initialize(mapload, source_projector)
|
||||
. = ..()
|
||||
if(source_projector)
|
||||
projector = source_projector
|
||||
projector.signs += src
|
||||
..()
|
||||
alpha = 0
|
||||
SSvis_overlays.add_vis_overlay(src, icon, icon_state, ABOVE_MOB_LAYER, plane, dir, add_appearance_flags = RESET_ALPHA) //you see mobs under it, but you hit them like they are above it
|
||||
|
||||
/obj/structure/holosign/Destroy()
|
||||
if(projector)
|
||||
@@ -71,10 +73,8 @@
|
||||
desc = "A holographic barrier resembling a firelock. Though it does not prevent solid objects from passing through, gas is kept out."
|
||||
icon_state = "holo_firelock"
|
||||
density = FALSE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
anchored = TRUE
|
||||
CanAtmosPass = ATMOS_PASS_NO
|
||||
layer = ABOVE_MOB_LAYER
|
||||
alpha = 150
|
||||
|
||||
/obj/structure/holosign/barrier/atmos/Initialize()
|
||||
@@ -100,7 +100,6 @@
|
||||
desc = "A holobarrier that uses biometrics to detect human viruses. Denies passing to personnel with easily-detected, malicious viruses. Good for quarantines."
|
||||
icon_state = "holo_medical"
|
||||
alpha = 125 //lazy :)
|
||||
layer = ABOVE_MOB_LAYER
|
||||
var/force_allaccess = FALSE
|
||||
var/buzzcd = 0
|
||||
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
armor = list("melee" = 100, "bullet" = 80, "laser" = 80, "energy" = 100, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 50, "acid" = 50)
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
CanAtmosPass = ATMOS_PASS_NO
|
||||
|
||||
/obj/structure/plasticflaps/opaque
|
||||
opacity = TRUE
|
||||
|
||||
/obj/structure/plasticflaps/Initialize()
|
||||
. = ..()
|
||||
alpha = 0
|
||||
SSvis_overlays.add_vis_overlay(src, icon, icon_state, ABOVE_MOB_LAYER, plane, dir, add_appearance_flags = RESET_ALPHA) //you see mobs under it, but you hit them like they are above it
|
||||
|
||||
/obj/structure/plasticflaps/examine(mob/user)
|
||||
. = ..()
|
||||
if(anchored)
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
icon_state = "necro[rand(2,3)]"
|
||||
|
||||
/turf/open/indestructible/necropolis/air
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
|
||||
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
|
||||
|
||||
/turf/open/indestructible/boss //you put stone tiles on this and use it as a base
|
||||
name = "necropolis floor"
|
||||
@@ -121,7 +121,7 @@
|
||||
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
|
||||
|
||||
/turf/open/indestructible/boss/air
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
|
||||
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
|
||||
|
||||
/turf/open/indestructible/hierophant
|
||||
icon = 'icons/turf/floors/hierophant_floor.dmi'
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
temperature = 255.37
|
||||
|
||||
/turf/open/floor/wood/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/grass
|
||||
name = "grass patch"
|
||||
@@ -105,7 +105,7 @@
|
||||
ore_type = /obj/item/stack/sheet/mineral/snow
|
||||
planetary_atmos = TRUE
|
||||
floor_tile = null
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
slowdown = 2
|
||||
bullet_sizzle = TRUE
|
||||
footstep = FOOTSTEP_SAND
|
||||
|
||||
@@ -84,31 +84,31 @@
|
||||
broken_states = list("titanium_dam1","titanium_dam2","titanium_dam3","titanium_dam4","titanium_dam5")
|
||||
|
||||
/turf/open/floor/mineral/titanium/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/mineral/titanium/yellow
|
||||
icon_state = "titanium_yellow"
|
||||
|
||||
/turf/open/floor/mineral/titanium/yellow/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/mineral/titanium/blue
|
||||
icon_state = "titanium_blue"
|
||||
|
||||
/turf/open/floor/mineral/titanium/blue/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/mineral/titanium/white
|
||||
icon_state = "titanium_white"
|
||||
|
||||
/turf/open/floor/mineral/titanium/white/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/mineral/titanium/purple
|
||||
icon_state = "titanium_purple"
|
||||
|
||||
/turf/open/floor/mineral/titanium/purple/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
//PLASTITANIUM (syndieshuttle)
|
||||
/turf/open/floor/mineral/plastitanium
|
||||
@@ -118,13 +118,13 @@
|
||||
broken_states = list("plastitanium_dam1","plastitanium_dam2","plastitanium_dam3","plastitanium_dam4","plastitanium_dam5")
|
||||
|
||||
/turf/open/floor/mineral/plastitanium/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/mineral/plastitanium/red
|
||||
icon_state = "plastitanium_red"
|
||||
|
||||
/turf/open/floor/mineral/plastitanium/red/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/mineral/plastitanium/red/brig
|
||||
name = "brig floor"
|
||||
@@ -170,7 +170,7 @@
|
||||
spam_flag = world.time + 10
|
||||
|
||||
/turf/open/floor/mineral/bananium/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
//DIAMOND
|
||||
|
||||
|
||||
@@ -45,10 +45,10 @@
|
||||
on = FALSE
|
||||
|
||||
/turf/open/floor/circuit/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/circuit/telecomms
|
||||
initial_gas_mix = "n2=100;TEMP=80"
|
||||
initial_gas_mix = TCOMMS_ATMOS
|
||||
|
||||
/turf/open/floor/circuit/telecomms/mainframe
|
||||
name = "mainframe base"
|
||||
@@ -72,10 +72,10 @@
|
||||
floor_tile = /obj/item/stack/tile/circuit/green/anim
|
||||
|
||||
/turf/open/floor/circuit/green/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/circuit/green/telecomms
|
||||
initial_gas_mix = "n2=100;TEMP=80"
|
||||
initial_gas_mix = TCOMMS_ATMOS
|
||||
|
||||
/turf/open/floor/circuit/green/telecomms/mainframe
|
||||
name = "mainframe base"
|
||||
@@ -96,10 +96,10 @@
|
||||
floor_tile = /obj/item/stack/tile/circuit/red/anim
|
||||
|
||||
/turf/open/floor/circuit/red/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/circuit/red/telecomms
|
||||
initial_gas_mix = "n2=100;TEMP=80"
|
||||
initial_gas_mix = TCOMMS_ATMOS
|
||||
|
||||
/turf/open/floor/pod
|
||||
name = "pod floor"
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
|
||||
|
||||
/turf/open/floor/plasteel/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
/turf/open/floor/plasteel/telecomms
|
||||
initial_gas_mix = "n2=100;TEMP=80"
|
||||
initial_gas_mix = TCOMMS_ATMOS
|
||||
|
||||
|
||||
/turf/open/floor/plasteel/dark
|
||||
icon_state = "darkfull"
|
||||
/turf/open/floor/plasteel/dark/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
/turf/open/floor/plasteel/dark/telecomms
|
||||
initial_gas_mix = "n2=100;TEMP=80"
|
||||
initial_gas_mix = TCOMMS_ATMOS
|
||||
/turf/open/floor/plasteel/airless/dark
|
||||
icon_state = "darkfull"
|
||||
/turf/open/floor/plasteel/dark/side
|
||||
@@ -50,7 +50,7 @@
|
||||
/turf/open/floor/plasteel/airless/white/corner
|
||||
icon_state = "whitecorner"
|
||||
/turf/open/floor/plasteel/white/telecomms
|
||||
initial_gas_mix = "n2=100;TEMP=80"
|
||||
initial_gas_mix = TCOMMS_ATMOS
|
||||
|
||||
|
||||
/turf/open/floor/plasteel/yellowsiding
|
||||
@@ -82,7 +82,7 @@
|
||||
/turf/open/floor/plasteel/freezer
|
||||
icon_state = "freezerfloor"
|
||||
/turf/open/floor/plasteel/freezer/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/plasteel/grimy
|
||||
icon_state = "grimy"
|
||||
@@ -111,7 +111,7 @@
|
||||
/turf/open/floor/plasteel/cult/narsie_act()
|
||||
return
|
||||
/turf/open/floor/plasteel/cult/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
|
||||
/turf/open/floor/plasteel/stairs
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
|
||||
/turf/open/floor/plating/asteroid/basalt/airless
|
||||
baseturfs = /turf/open/floor/plating/asteroid/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/plating/asteroid/basalt/Initialize()
|
||||
. = ..()
|
||||
@@ -131,7 +131,7 @@
|
||||
|
||||
|
||||
/turf/open/floor/plating/asteroid/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
turf_type = /turf/open/floor/plating/asteroid/airless
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@
|
||||
baseturfs = /turf/open/floor/plating/asteroid/snow
|
||||
icon_state = "snow"
|
||||
icon_plating = "snow"
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
slowdown = 2
|
||||
environment_type = "snow"
|
||||
flags_1 = NONE
|
||||
@@ -344,11 +344,11 @@
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/plating/asteroid/snow/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/plating/asteroid/snow/temperatre
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
|
||||
|
||||
/turf/open/floor/plating/asteroid/snow/atmosphere
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
planetary_atmos = FALSE
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
/turf/open/floor/plating/airless
|
||||
icon_state = "plating"
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/plating/abductor
|
||||
name = "alien floor"
|
||||
@@ -172,7 +172,7 @@
|
||||
desc = "A sheet of solid ice. Looks slippery."
|
||||
icon = 'icons/turf/floors/ice_turf.dmi'
|
||||
icon_state = "unsmooth"
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
temperature = 180
|
||||
planetary_atmos = TRUE
|
||||
baseturfs = /turf/open/floor/plating/ice
|
||||
@@ -215,7 +215,7 @@
|
||||
desc = "A section of heated plating, helps keep the snow from stacking up too high."
|
||||
icon = 'icons/turf/snow.dmi'
|
||||
icon_state = "snowplating"
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
temperature = 180
|
||||
attachment_holes = FALSE
|
||||
planetary_atmos = TRUE
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
to_chat(user, "<span class='notice'>The reinforcement rods are <b>wrenched</b> firmly in place.</span>")
|
||||
|
||||
/turf/open/floor/engine/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/engine/break_tile()
|
||||
return //unbreakable
|
||||
@@ -98,28 +98,28 @@
|
||||
/turf/open/floor/engine/n2o
|
||||
article = "an"
|
||||
name = "\improper N2O floor"
|
||||
initial_gas_mix = "n2o=6000;TEMP=293.15"
|
||||
initial_gas_mix = ATMOS_TANK_N2O
|
||||
|
||||
/turf/open/floor/engine/co2
|
||||
name = "\improper CO2 floor"
|
||||
initial_gas_mix = "co2=50000;TEMP=293.15"
|
||||
initial_gas_mix = ATMOS_TANK_CO2
|
||||
|
||||
/turf/open/floor/engine/plasma
|
||||
name = "plasma floor"
|
||||
initial_gas_mix = "plasma=70000;TEMP=293.15"
|
||||
initial_gas_mix = ATMOS_TANK_PLASMA
|
||||
|
||||
/turf/open/floor/engine/o2
|
||||
name = "\improper O2 floor"
|
||||
initial_gas_mix = "o2=100000;TEMP=293.15"
|
||||
initial_gas_mix = ATMOS_TANK_O2
|
||||
|
||||
/turf/open/floor/engine/n2
|
||||
article = "an"
|
||||
name = "\improper N2 floor"
|
||||
initial_gas_mix = "n2=100000;TEMP=293.15"
|
||||
initial_gas_mix = ATMOS_TANK_N2
|
||||
|
||||
/turf/open/floor/engine/air
|
||||
name = "air floor"
|
||||
initial_gas_mix = "o2=2644;n2=10580;TEMP=293.15"
|
||||
initial_gas_mix = ATMOS_TANK_AIRMIX
|
||||
|
||||
|
||||
|
||||
@@ -159,8 +159,8 @@
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
|
||||
/turf/open/floor/engine/cult/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/floor/engine/vacuum
|
||||
name = "vacuum floor"
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
return
|
||||
|
||||
/turf/open/lava/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
/turf/open/lava/Entered(atom/movable/AM)
|
||||
if(burn_stuff(AM))
|
||||
@@ -158,4 +158,4 @@
|
||||
baseturfs = /turf/open/lava/smooth/lava_land_surface
|
||||
|
||||
/turf/open/lava/smooth/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
smooth = SMOOTH_MORE|SMOOTH_BORDER
|
||||
canSmoothWith = null
|
||||
baseturfs = /turf/open/floor/plating/asteroid/airless
|
||||
initial_gas_mix = "TEMP=2.7"
|
||||
initial_gas_mix = AIRLESS_ATMOS
|
||||
opacity = 1
|
||||
density = TRUE
|
||||
blocks_air = 1
|
||||
@@ -241,7 +241,7 @@
|
||||
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
|
||||
turf_type = /turf/open/floor/plating/asteroid/snow/ice
|
||||
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
defer_change = TRUE
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@
|
||||
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
|
||||
turf_type = /turf/open/floor/plating/asteroid/snow/ice
|
||||
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
defer_change = TRUE
|
||||
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
|
||||
turf_type = /turf/open/floor/plating/asteroid/snow/ice
|
||||
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
defer_change = TRUE
|
||||
|
||||
|
||||
@@ -404,7 +404,7 @@
|
||||
smooth = SMOOTH_MORE|SMOOTH_BORDER
|
||||
canSmoothWith = list (/turf/closed)
|
||||
baseturfs = /turf/open/floor/plating/asteroid/snow
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
initial_gas_mix = FROZEN_ATMOS
|
||||
environment_type = "snow"
|
||||
turf_type = /turf/open/floor/plating/asteroid/snow
|
||||
defer_change = TRUE
|
||||
|
||||
@@ -686,6 +686,20 @@
|
||||
log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delay Game Start") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggledynamicvote()
|
||||
set category = "Server"
|
||||
set desc="Switches between secret/extended and dynamic voting"
|
||||
set name="Toggle Dynamic Vote"
|
||||
var/prev_dynamic_voting = CONFIG_GET(flag/dynamic_voting)
|
||||
CONFIG_SET(flag/dynamic_voting,!prev_dynamic_voting)
|
||||
if (!prev_dynamic_voting)
|
||||
to_chat(world, "<B>Vote is now between extended and dynamic chaos.</B>")
|
||||
else
|
||||
to_chat(world, "<B>Vote is now between extended and secret.</B>")
|
||||
log_admin("[key_name(usr)] [prev_dynamic_voting ? "disabled" : "enabled"] dynamic voting.")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled dynamic voting.</span>")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Dynamic Voting", "[prev_dynamic_voting ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/unprison(mob/M in GLOB.mob_list)
|
||||
set category = "Admin"
|
||||
set name = "Unprison"
|
||||
|
||||
@@ -121,6 +121,7 @@ GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
|
||||
/client/proc/everyone_random,
|
||||
/datum/admins/proc/toggleAI,
|
||||
/datum/admins/proc/toggleMulticam,
|
||||
/datum/admins/proc/toggledynamicvote,
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/toggle_random_events,
|
||||
|
||||
@@ -1449,9 +1449,7 @@
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
var/new_centre = input(usr,"Change the centre of the dynamic mode threat curve. A negative value will give a more peaceful round ; a positive value, a round with higher threat. Any number between -5 and +5 is allowed.", "Change curve centre", null) as num
|
||||
if (new_centre < -5 || new_centre > 5)
|
||||
return alert(usr, "Only values between -5 and +5 are allowed.", null, null, null, null)
|
||||
var/new_centre = input(usr,"Change the centre of the dynamic mode threat curve. A negative value will give a more peaceful round ; a positive value, a round with higher threat. Any number is allowed. This is adjusted by dynamic voting.", "Change curve centre", null) as num
|
||||
|
||||
log_admin("[key_name(usr)] changed the distribution curve center to [new_centre].")
|
||||
message_admins("[key_name(usr)] changed the distribution curve center to [new_centre]", 1)
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
if(used)
|
||||
to_chat(H, "You already used this contract!")
|
||||
return
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src)
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src, ignore_category = POLL_IGNORE_WIZARD)
|
||||
if(LAZYLEN(candidates))
|
||||
if(QDELETED(src))
|
||||
return
|
||||
@@ -182,6 +182,10 @@
|
||||
name = "syndicate medical teleporter"
|
||||
borg_to_spawn = "Medical"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/saboteur
|
||||
name = "syndicate saboteur teleporter"
|
||||
borg_to_spawn = "Saboteur"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/silicon/robot/R
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
@@ -191,6 +195,8 @@
|
||||
switch(borg_to_spawn)
|
||||
if("Medical")
|
||||
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
|
||||
if("Saboteur")
|
||||
R = new /mob/living/silicon/robot/modules/syndicate/saboteur(T)
|
||||
else
|
||||
R = new /mob/living/silicon/robot/modules/syndicate(T) //Assault borg by default
|
||||
|
||||
@@ -235,7 +241,7 @@
|
||||
return
|
||||
if(used)
|
||||
return
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, null, ROLE_ALIEN, 50, src)
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, null, ROLE_ALIEN, 50, src, ignore_category = POLL_IGNORE_DEMON)
|
||||
if(LAZYLEN(candidates))
|
||||
if(used || QDELETED(src))
|
||||
return
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
for(var/obj/item/abductor/gizmo/G in B.contents)
|
||||
console.AddGizmo(G)
|
||||
|
||||
/datum/outfit/abductor/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
/datum/outfit/abductor/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
..()
|
||||
if(!visualsOnly)
|
||||
link_to_console(H)
|
||||
@@ -49,7 +49,7 @@
|
||||
/obj/item/abductor/gizmo = 1
|
||||
)
|
||||
|
||||
/datum/outfit/abductor/scientist/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
/datum/outfit/abductor/scientist/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
..()
|
||||
if(!visualsOnly)
|
||||
var/obj/item/implant/abductor/beamplant = new
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
/obj/machinery/computer/camera_advanced/abductor/CreateEye()
|
||||
..()
|
||||
eyeobj.visible_icon = 1
|
||||
eyeobj.icon = 'icons/obj/abductor.dmi'
|
||||
eyeobj.icon_state = "camera_target"
|
||||
eyeobj.visible_icon = TRUE
|
||||
eyeobj.icon = 'icons/mob/cameramob.dmi'
|
||||
eyeobj.icon_state = "generic_camera"
|
||||
|
||||
/obj/machinery/computer/camera_advanced/abductor/GrantActions(mob/living/carbon/user)
|
||||
..()
|
||||
|
||||
@@ -9,7 +9,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
name = "Blob Overmind"
|
||||
real_name = "Blob Overmind"
|
||||
desc = "The overmind. It controls the blob."
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon = 'icons/mob/cameramob.dmi'
|
||||
icon_state = "marker"
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
move_on_shuttle = 1
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
name = "Spawn Sentient Disease"
|
||||
typepath = /datum/round_event/ghost_role/sentient_disease
|
||||
weight = 7
|
||||
gamemode_blacklist = list("dynamic")
|
||||
max_occurrences = 1
|
||||
min_players = 5
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ the new instance inside the host to be updated to the template's stats.
|
||||
name = "Sentient Disease"
|
||||
real_name = "Sentient Disease"
|
||||
desc = ""
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon = 'icons/mob/cameramob.dmi'
|
||||
icon_state = "marker"
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
move_on_shuttle = FALSE
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
/obj/item/borg_chameleon
|
||||
name = "cyborg chameleon projector"
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "shield0"
|
||||
flags_1 = CONDUCT_1
|
||||
item_flags = NOBLUDGEON
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
var/friendlyName
|
||||
var/savedName
|
||||
var/active = FALSE
|
||||
var/activationCost = 300
|
||||
var/activationUpkeep = 50
|
||||
var/disguise = null
|
||||
var/disguise_icon_override = null
|
||||
var/disguise_pixel_offset = null
|
||||
var/mob/listeningTo
|
||||
var/static/list/signalCache = list( // list here all signals that should break the camouflage
|
||||
COMSIG_PARENT_ATTACKBY,
|
||||
COMSIG_ATOM_ATTACK_HAND,
|
||||
COMSIG_MOVABLE_IMPACT_ZONE,
|
||||
COMSIG_ATOM_BULLET_ACT,
|
||||
COMSIG_ATOM_EX_ACT,
|
||||
COMSIG_ATOM_FIRE_ACT,
|
||||
COMSIG_ATOM_EMP_ACT,
|
||||
)
|
||||
var/mob/living/silicon/robot/user // needed for process()
|
||||
var/animation_playing = FALSE
|
||||
|
||||
var/list/engymodels = list("Default", "Default - Treads", "Heavy", "Sleek", "Marina", "Can", "Spider", "Loader","Handy", "Pup Dozer", "Vale")
|
||||
|
||||
|
||||
/obj/item/borg_chameleon/Initialize()
|
||||
. = ..()
|
||||
friendlyName = pick(GLOB.ai_names)
|
||||
|
||||
/obj/item/borg_chameleon/Destroy()
|
||||
listeningTo = null
|
||||
return ..()
|
||||
|
||||
/obj/item/borg_chameleon/dropped(mob/user)
|
||||
. = ..()
|
||||
disrupt(user)
|
||||
|
||||
/obj/item/borg_chameleon/equipped(mob/user)
|
||||
. = ..()
|
||||
disrupt(user)
|
||||
|
||||
/obj/item/borg_chameleon/attack_self(mob/living/silicon/robot/user)
|
||||
if (user && user.cell && user.cell.charge > activationCost)
|
||||
if (isturf(user.loc))
|
||||
toggle(user)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't use [src] while inside something!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least [activationCost] charge in your cell to use [src]!</span>")
|
||||
|
||||
/obj/item/borg_chameleon/proc/toggle(mob/living/silicon/robot/user)
|
||||
if(active)
|
||||
playsound(src, 'sound/effects/pop.ogg', 100, TRUE, -6)
|
||||
to_chat(user, "<span class='notice'>You deactivate \the [src].</span>")
|
||||
deactivate(user)
|
||||
else
|
||||
if(animation_playing)
|
||||
to_chat(user, "<span class='notice'>\the [src] is recharging.</span>")
|
||||
return
|
||||
var/borg_icon = input(user, "Select an icon!", "Robot Icon", null) as null|anything in engymodels
|
||||
if(!borg_icon)
|
||||
return FALSE
|
||||
switch(borg_icon)
|
||||
if("Default")
|
||||
disguise = "engineer"
|
||||
disguise_icon_override = 'icons/mob/robots.dmi'
|
||||
if("Default - Treads")
|
||||
disguise = "engi-tread"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
if("Loader")
|
||||
disguise = "loaderborg"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
if("Handy")
|
||||
disguise = "handyeng"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
if("Sleek")
|
||||
disguise = "sleekeng"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
if("Can")
|
||||
disguise = "caneng"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
if("Marina")
|
||||
disguise = "marinaeng"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
if("Spider")
|
||||
disguise = "spidereng"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
if("Heavy")
|
||||
disguise = "heavyeng"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
if("Pup Dozer")
|
||||
disguise = "pupdozer"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
disguise_pixel_offset = -16
|
||||
if("Vale")
|
||||
disguise = "valeeng"
|
||||
disguise_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
disguise_pixel_offset = -16
|
||||
animation_playing = TRUE
|
||||
to_chat(user, "<span class='notice'>You activate \the [src].</span>")
|
||||
playsound(src, 'sound/effects/seedling_chargeup.ogg', 100, TRUE, -6)
|
||||
var/start = user.filters.len
|
||||
var/X,Y,rsq,i,f
|
||||
for(i=1, i<=7, ++i)
|
||||
do
|
||||
X = 60*rand() - 30
|
||||
Y = 60*rand() - 30
|
||||
rsq = X*X + Y*Y
|
||||
while(rsq<100 || rsq>900)
|
||||
user.filters += filter(type="wave", x=X, y=Y, size=rand()*2.5+0.5, offset=rand())
|
||||
for(i=1, i<=7, ++i)
|
||||
f = user.filters[start+i]
|
||||
animate(f, offset=f:offset, time=0, loop=3, flags=ANIMATION_PARALLEL)
|
||||
animate(offset=f:offset-1, time=rand()*20+10)
|
||||
if (do_after(user, 50, target=user) && user.cell.use(activationCost))
|
||||
playsound(src, 'sound/effects/bamf.ogg', 100, TRUE, -6)
|
||||
to_chat(user, "<span class='notice'>You are now disguised as the Nanotrasen engineering borg \"[friendlyName]\".</span>")
|
||||
activate(user)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The chameleon field fizzles.</span>")
|
||||
do_sparks(3, FALSE, user)
|
||||
for(i=1, i<=min(7, user.filters.len), ++i) // removing filters that are animating does nothing, we gotta stop the animations first
|
||||
f = user.filters[start+i]
|
||||
animate(f)
|
||||
user.filters = null
|
||||
animation_playing = FALSE
|
||||
|
||||
/obj/item/borg_chameleon/process()
|
||||
if (user)
|
||||
if (!user.cell || !user.cell.use(activationUpkeep))
|
||||
disrupt(user)
|
||||
else
|
||||
return PROCESS_KILL
|
||||
|
||||
/obj/item/borg_chameleon/proc/activate(mob/living/silicon/robot/user)
|
||||
START_PROCESSING(SSobj, src)
|
||||
src.user = user
|
||||
savedName = user.name
|
||||
user.name = friendlyName
|
||||
user.module.cyborg_base_icon = disguise
|
||||
user.module.cyborg_icon_override = disguise_icon_override
|
||||
user.module.cyborg_pixel_offset = disguise_pixel_offset
|
||||
user.bubble_icon = "robot"
|
||||
active = TRUE
|
||||
user.update_icons()
|
||||
|
||||
if(listeningTo == user)
|
||||
return
|
||||
if(listeningTo)
|
||||
UnregisterSignal(listeningTo, signalCache)
|
||||
RegisterSignal(user, signalCache, .proc/disrupt)
|
||||
listeningTo = user
|
||||
|
||||
/obj/item/borg_chameleon/proc/deactivate(mob/living/silicon/robot/user)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(listeningTo)
|
||||
UnregisterSignal(listeningTo, signalCache)
|
||||
listeningTo = null
|
||||
do_sparks(5, FALSE, user)
|
||||
user.name = savedName
|
||||
user.module.cyborg_base_icon = initial(user.module.cyborg_base_icon)
|
||||
user.module.cyborg_icon_override = 'icons/mob/robots.dmi'
|
||||
user.bubble_icon = "syndibot"
|
||||
active = FALSE
|
||||
user.update_icons()
|
||||
user.pixel_x = 0 //this solely exists because of dogborgs. I want anyone who ever reads this code later on to know this. Don't ask me why it's here, doesn't work above update_icons()
|
||||
src.user = user
|
||||
|
||||
/obj/item/borg_chameleon/proc/disrupt(mob/living/silicon/robot/user)
|
||||
if(active)
|
||||
to_chat(user, "<span class='danger'>Your chameleon field deactivates.</span>")
|
||||
deactivate(user)
|
||||
@@ -74,6 +74,11 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
|
||||
new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS - tc_malus + CEILING(PLAYER_SCALING * actual_players, 1))
|
||||
|
||||
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_warops_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("Nuke ops spent [threat_spent] on war ops.")
|
||||
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
|
||||
|
||||
qdel(src)
|
||||
@@ -94,6 +99,14 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
|
||||
if(board.moved)
|
||||
to_chat(user, "The shuttle has already been moved! You have forfeit the right to declare war.")
|
||||
return FALSE
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if(mode.threat_level < CONFIG_GET(number/dynamic_warops_requirement))
|
||||
to_chat(user, "Due to the dynamic space in which the station resides, you are too deep into Nanotrasen territory to reasonably go loud.")
|
||||
return FALSE
|
||||
else if(mode.threat < CONFIG_GET(number/dynamic_warops_cost))
|
||||
to_chat(user, "Due to recent threats on the station, Nanotrasen is looking too closely for a war declaration to be wise.")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/nuclear_challenge/clownops
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
name = "Spawn Revenant" // Did you mean 'griefghost'?
|
||||
typepath = /datum/round_event/ghost_role/revenant
|
||||
weight = 7
|
||||
gamemode_blacklist = list("dynamic")
|
||||
max_occurrences = 1
|
||||
min_players = 5
|
||||
|
||||
|
||||
@@ -207,9 +207,20 @@
|
||||
owner.current.visible_message("<span class='deconversion_message'>The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.</span>", null, null, null, owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>The frame's firmware detects and deletes your neural reprogramming! You remember nothing of your time spent reprogrammed, you can't even remember the names or identities of anyone involved...</span>")
|
||||
|
||||
/datum/antagonist/rev/head/farewell()
|
||||
if((ishuman(owner.current) || ismonkey(owner.current)))
|
||||
if(owner.current.stat != DEAD)
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just remembered [owner.current.p_their()] real allegiance!</span>", null, null, null, owner.current)
|
||||
to_chat(owner, "<span class ='deconversion_message bold'>You have given up your cause of overthrowing the command staff. You are no longer a Head Revolutionary.</span>")
|
||||
else
|
||||
to_chat(owner, "<span class ='deconversion_message bold'>The sweet release of death. You are no longer a Head Revolutionary.</span>")
|
||||
else if(issilicon(owner.current))
|
||||
owner.current.visible_message("<span class='deconversion_message'>The frame beeps contentedly, suppressing the disloyal personality traits from the MMI before initalizing it.</span>", null, null, null, owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>The frame's firmware detects and suppresses your unwanted personality traits! You feel more content with the leadership around these parts.</span>")
|
||||
|
||||
//blunt trauma deconversions call this through species.dm spec_attacked_by()
|
||||
/datum/antagonist/rev/proc/remove_revolutionary(borged, deconverter)
|
||||
log_attack("[key_name(owner.current)] has been deconverted from the revolution by [key_name(deconverter)]!")
|
||||
log_attack("[key_name(owner.current)] has been deconverted from the revolution by [ismob(deconverter) ? key_name(deconverter) : deconverter]!")
|
||||
if(borged)
|
||||
message_admins("[ADMIN_LOOKUPFLW(owner.current)] has been borged while being a [name]")
|
||||
owner.special_role = null
|
||||
@@ -219,9 +230,8 @@
|
||||
owner.remove_antag_datum(type)
|
||||
|
||||
/datum/antagonist/rev/head/remove_revolutionary(borged,deconverter)
|
||||
if(!borged)
|
||||
return
|
||||
. = ..()
|
||||
if(borged || deconverter == "gamemode")
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/rev/head/equip_rev()
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
@@ -253,6 +263,8 @@
|
||||
/datum/team/revolution
|
||||
name = "Revolution"
|
||||
var/max_headrevs = 3
|
||||
var/list/ex_headrevs = list() // Dynamic removes revs on loss, used to keep a list for the roundend report.
|
||||
var/list/ex_revs = list()
|
||||
|
||||
/datum/team/revolution/proc/update_objectives(initial = FALSE)
|
||||
var/untracked_heads = SSjob.get_all_heads()
|
||||
@@ -296,9 +308,12 @@
|
||||
|
||||
addtimer(CALLBACK(src,.proc/update_heads),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
|
||||
|
||||
/datum/team/revolution/proc/save_members()
|
||||
ex_headrevs = get_antag_minds(/datum/antagonist/rev/head, TRUE)
|
||||
ex_revs = get_antag_minds(/datum/antagonist/rev, TRUE)
|
||||
|
||||
/datum/team/revolution/roundend_report()
|
||||
if(!members.len)
|
||||
if(!members.len && !ex_headrevs.len)
|
||||
return
|
||||
|
||||
var/list/result = list()
|
||||
@@ -318,8 +333,17 @@
|
||||
|
||||
|
||||
var/list/targets = list()
|
||||
var/list/datum/mind/headrevs = get_antag_minds(/datum/antagonist/rev/head)
|
||||
var/list/datum/mind/revs = get_antag_minds(/datum/antagonist/rev,TRUE)
|
||||
var/list/datum/mind/headrevs
|
||||
var/list/datum/mind/revs
|
||||
if(ex_headrevs.len)
|
||||
headrevs = ex_headrevs
|
||||
else
|
||||
headrevs = get_antag_minds(/datum/antagonist/rev/head, TRUE)
|
||||
|
||||
if(ex_revs.len)
|
||||
revs = ex_revs
|
||||
else
|
||||
revs = get_antag_minds(/datum/antagonist/rev, TRUE)
|
||||
if(headrevs.len)
|
||||
var/list/headrev_part = list()
|
||||
headrev_part += "<span class='header'>The head revolutionaries were:</span>"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
typepath = /datum/round_event/ghost_role/slaughter
|
||||
weight = 1 //Very rare
|
||||
max_occurrences = 1
|
||||
gamemode_blacklist = list("dynamic")
|
||||
earliest_start = 1 HOURS
|
||||
min_players = 20
|
||||
|
||||
|
||||
@@ -70,7 +70,17 @@
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_human_objectives()
|
||||
var/is_hijacker = FALSE
|
||||
if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks
|
||||
var/datum/game_mode/dynamic/mode
|
||||
var/is_dynamic = FALSE
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit)
|
||||
is_hijacker = (prob(10) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement))
|
||||
else
|
||||
var/indice_pop = min(10,round(GLOB.joined_player_list.len/mode.pop_per_requirement)+1)
|
||||
is_hijacker = (prob(10) && (mode.threat_level >= CONFIG_GET(number_list/dynamic_hijack_requirements)[indice_pop]))
|
||||
else if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks
|
||||
is_hijacker = prob(10)
|
||||
var/martyr_chance = prob(20)
|
||||
var/objective_count = is_hijacker //Hijacking counts towards number of objectives
|
||||
@@ -91,6 +101,10 @@
|
||||
var/datum/objective/hijack/hijack_objective = new
|
||||
hijack_objective.owner = owner
|
||||
add_objective(hijack_objective)
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on hijack.")
|
||||
return
|
||||
|
||||
|
||||
@@ -104,6 +118,10 @@
|
||||
var/datum/objective/martyr/martyr_objective = new
|
||||
martyr_objective.owner = owner
|
||||
add_objective(martyr_objective)
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on glorious death.")
|
||||
return
|
||||
|
||||
else
|
||||
@@ -139,7 +157,18 @@
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_human_objective() //Returns how many objectives are added
|
||||
.=1
|
||||
if(prob(50))
|
||||
var/assassin_prob = 50
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
assassin_prob = mode.threat_level*(2/3)
|
||||
if(prob(assassin_prob))
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on an assassination target.")
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
|
||||
@@ -383,7 +383,9 @@
|
||||
if(!istype(user) || on_cooldown)
|
||||
return
|
||||
var/turf/T = get_turf(user)
|
||||
if(!T)
|
||||
var/area/A = get_area(user)
|
||||
if(!T || !A || A.noteleport)
|
||||
to_chat(user, "<span class='warning'>You play \the [src], yet no sound comes out of it... Looks like it won't work here.</span>")
|
||||
return
|
||||
on_cooldown = TRUE
|
||||
last_user = user
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user