diff --git a/code/__DEFINES/_globals.dm b/code/__DEFINES/_globals.dm index 874223a612..cc3e385f9f 100644 --- a/code/__DEFINES/_globals.dm +++ b/code/__DEFINES/_globals.dm @@ -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) diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index baf29240c3..41b5deb302 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -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" diff --git a/code/__DEFINES/donator_groupings.dm b/code/__DEFINES/donator_groupings.dm index 4b210609f2..855b9927f5 100644 --- a/code/__DEFINES/donator_groupings.dm +++ b/code/__DEFINES/donator_groupings.dm @@ -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) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index dc573bc28e..6f433374e7 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -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)) diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 0992b2e586..7a284ff1a0 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -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" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index fe7cf57cb3..2382e0e444 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -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" diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index 37f36a7e0d..c0501b4e41 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -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) \ No newline at end of file diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index fb7a29c907..2c92816264 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -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] - [rule.name]: -[rule.cost] threat" + parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - [rule.name]: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat" + */ return parts.Join("
") /client/proc/roundend_report_file() diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index a2135b93b2..0ac8a61183 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -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) diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index f0479cd8aa..6b8d91acf9 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -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) diff --git a/code/_globalvars/lists/poll_ignore.dm b/code/_globalvars/lists/poll_ignore.dm index 626bba9fc3..3a026d2aa5 100644 --- a/code/_globalvars/lists/poll_ignore.dm +++ b/code/_globalvars/lists/poll_ignore.dm @@ -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()) diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm index 4406655375..be9f7e116b 100644 --- a/code/controllers/configuration/config_entry.dm +++ b/code/controllers/configuration/config_entry.dm @@ -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) diff --git a/code/controllers/configuration/entries/donator.dm b/code/controllers/configuration/entries/donator.dm index b74d5f5839..bb7b5a54c3 100644 --- a/code/controllers/configuration/entries/donator.dm +++ b/code/controllers/configuration/entries/donator.dm @@ -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 diff --git a/code/controllers/configuration/entries/dynamic.dm b/code/controllers/configuration/entries/dynamic.dm new file mode 100644 index 0000000000..7f3e16d57e --- /dev/null +++ b/code/controllers/configuration/entries/dynamic.dm @@ -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 diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index ed3cca587d..fdddbda344 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -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 diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index 6ba6a7b177..8d4de0c091 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -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 diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index ceb2fae998..29762338fb 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -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 diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 2ab06f4d59..6f619fef0b 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -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 diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm index 107d65a558..0635709074 100644 --- a/code/controllers/subsystem/vis_overlays.dm +++ b/code/controllers/subsystem/vis_overlays.dm @@ -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) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index e29382377f..50be61f91d 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -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 += "[question]" @@ -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,"Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width].") + 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 \ No newline at end of file + P.player_actions -= src + +#undef PEACE +#undef CHAOS diff --git a/code/datums/components/lockon_aiming.dm b/code/datums/components/lockon_aiming.dm index 38b707ac19..bbdbb7dc66 100644 --- a/code/datums/components/lockon_aiming.dm +++ b/code/datums/components/lockon_aiming.dm @@ -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 diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index a92ae9e629..dd189137a5 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -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) diff --git a/code/datums/martial.dm b/code/datums/martial.dm index d119759efc..26a709590c 100644 --- a/code/datums/martial.dm +++ b/code/datums/martial.dm @@ -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) diff --git a/code/datums/martial/boxing.dm b/code/datums/martial/boxing.dm index 7399528e1c..b98bc4f951 100644 --- a/code/datums/martial/boxing.dm +++ b/code/datums/martial/boxing.dm @@ -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, "Can't disarm while boxing!") @@ -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("[A] has attempted to [atk_verb] [D]!", \ "[A] has attempted to [atk_verb] [D]!", 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") diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index c7644997ee..73173a4a9a 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -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 diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm index 6379d481ca..4e8dacaef9 100644 --- a/code/datums/martial/krav_maga.dm +++ b/code/datums/martial/krav_maga.dm @@ -19,6 +19,9 @@ owner.visible_message("[owner] assumes a neutral stance.", "Your next attack is cleared.") H.mind.martial_art.streak = "" else + if(HAS_TRAIT(H, TRAIT_PACIFISM)) + to_chat(H, "You don't want to harm other people!") + return owner.visible_message("[owner] assumes the Neck Chop stance!", "Your next attack will be a Neck Chop.") H.mind.martial_art.streak = "neck_chop" @@ -36,6 +39,9 @@ owner.visible_message("[owner] assumes a neutral stance.", "Your next attack is cleared.") H.mind.martial_art.streak = "" else + if(HAS_TRAIT(H, TRAIT_PACIFISM)) + to_chat(H, "You don't want to harm other people!") + return owner.visible_message("[owner] assumes the Leg Sweep stance!", "Your next attack will be a Leg Sweep.") H.mind.martial_art.streak = "leg_sweep" @@ -53,6 +59,9 @@ owner.visible_message("[owner] assumes a neutral stance.", "Your next attack is cleared.") H.mind.martial_art.streak = "" else + if(HAS_TRAIT(H, TRAIT_PACIFISM)) + to_chat(H, "You don't want to harm other people!") + return owner.visible_message("[owner] assumes the Lung Punch stance!", "Your next attack will be a Lung Punch.") 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() diff --git a/code/datums/martial/psychotic_brawl.dm b/code/datums/martial/psychotic_brawl.dm index 34301516dc..45d73353f9 100644 --- a/code/datums/martial/psychotic_brawl.dm +++ b/code/datums/martial/psychotic_brawl.dm @@ -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) diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 801e8c8c7a..f89374dc2a 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -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 diff --git a/code/datums/martial/wrestling.dm b/code/datums/martial/wrestling.dm index 81ec0bf977..c967779d03 100644 --- a/code/datums/martial/wrestling.dm +++ b/code/datums/martial/wrestling.dm @@ -49,6 +49,9 @@ if(owner.incapacitated()) to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.") return + if(HAS_TRAIT(owner, TRAIT_PACIFISM)) + to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!") + return owner.visible_message("[owner] prepares to BODY SLAM!", "Your next attack will be a BODY SLAM.") var/mob/living/carbon/human/H = owner H.mind.martial_art.streak = "slam" @@ -61,6 +64,9 @@ if(owner.incapacitated()) to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.") return + if(HAS_TRAIT(owner, TRAIT_PACIFISM)) + to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!") + return owner.visible_message("[owner] prepares to THROW!", "Your next attack will be a THROW.") var/mob/living/carbon/human/H = owner H.mind.martial_art.streak = "throw" @@ -73,6 +79,9 @@ if(owner.incapacitated()) to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.") return + if(HAS_TRAIT(owner, TRAIT_PACIFISM)) + to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!") + return owner.visible_message("[owner] prepares to KICK!", "Your next attack will be a KICK.") var/mob/living/carbon/human/H = owner H.mind.martial_art.streak = "kick" @@ -85,6 +94,9 @@ if(owner.incapacitated()) to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.") return + if(HAS_TRAIT(owner, TRAIT_PACIFISM)) + to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!") + return owner.visible_message("[owner] prepares to STRIKE!", "Your next attack will be a STRIKE.") var/mob/living/carbon/human/H = owner H.mind.martial_art.streak = "strike" @@ -97,6 +109,9 @@ if(owner.incapacitated()) to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.") return + if(HAS_TRAIT(owner, TRAIT_PACIFISM)) + to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!") + return owner.visible_message("[owner] prepares to LEG DROP!", "Your next attack will be a LEG DROP.") 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("[A] gets [D] in a cinch!", \ "[A] gets [D] in a cinch!") diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm index 8386b59d97..da379b9851 100755 --- a/code/datums/outfit.dm +++ b/code/datums/outfit.dm @@ -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) diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 76e6268977..30e53cdee8 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -339,10 +339,6 @@ Credit where due: CLOCKCULTCHANGELOG\ \
\ -
  • Zelus oil: 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.\ -
  • Brass Flasks: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.\ Good luck!" /obj/item/paper/servant_primer/Initialize() diff --git a/code/game/gamemodes/clown_ops/clown_ops.dm b/code/game/gamemodes/clown_ops/clown_ops.dm index 66de72bad2..49a336e16a 100644 --- a/code/game/gamemodes/clown_ops/clown_ops.dm +++ b/code/game/gamemodes/clown_ops/clown_ops.dm @@ -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 diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index ca009f76ad..83a3debfdc 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -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("Game Mode Panel

    Game Mode Panel

    ") - dat += "Dynamic Mode \[VV\]
    " + dat += "Dynamic Mode \[VV\]\[Refresh\]
    " dat += "Threat Level: [threat_level]
    " dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
    " @@ -140,6 +181,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) dat += "
    Injection Timers: ([get_injection_chance(TRUE)]% chance)
    " 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"] \[Now!\]
    " 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"] \[Now!\]
    " + 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"] \[Now!\]
    " 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() . = "Central Command Status Summary
    " switch(round(threat_level)) - if(0 to 19) - update_playercounts() - if(!current_players[CURRENT_LIVING_ANTAGS].len) - . += "Peaceful Waypoint
    " - . += "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) + . += "Peaceful Waypoint
    " + . += "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)) . += "Core Territory
    " . += "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) - . += "Anomalous Exogeology
    " - . += "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) - . += "Contested System
    " - . += "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) - . += "Uncharted Space
    " - . += "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)) + . += "Contested System
    " + . += "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 + . += "Uncharted Space
    " + . += "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) . += "Black Orbit
    " . += "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) . += "Impending Doom
    " . += "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.
    " . += "Good luck." + set_security_level(SEC_LEVEL_RED) if(station_goals.len) . += "
    Special Orders for [station_name()]:" @@ -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("Threat LogThreat Log
    Starting Threat: [threat_level]
    ") + var/list/out = list("Threat LogThreat Log
    Starting Threat: [initial_threat_level]
    ") - for(var/entry in threat_log) + for(var/entry in threat_log_verbose) if(istext(entry)) out += "[entry]
    " @@ -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] - [starting_rule.name] -[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] - [new_rule.name] -[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()) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm index 011b6ec251..0c8ec0a2b8 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm @@ -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 diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm new file mode 100644 index 0000000000..4ac8cc91d3 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm @@ -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("[name] has just been triggered by dynamic!") + 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 diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index fde020a3ae..5810fd0ae0 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -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 +*/ diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index cc90821618..41de85f7ee 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -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, "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.") + 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 diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index abca269eeb..56b02a1364 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -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 diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 1767d468ec..632d59c84d 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -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 diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm index 6d505c8f95..8ddbd68c7b 100644 --- a/code/game/machinery/computer/apc_control.dm +++ b/code/game/machinery/computer/apc_control.dm @@ -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 diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index c8a4d68575..056beb2e96 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -19,7 +19,7 @@ return to_chat(user, "You start deconstructing the frame...") - if(P.use_tool(src, user, 20, volume=50)) + if(P.use_tool(src, user, 20, volume=50) && state == 0) to_chat(user, "You deconstruct the frame.") 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, "You start to unfasten the frame...") - if(P.use_tool(src, user, 20, volume=50)) + if(P.use_tool(src, user, 20, volume=50) && state == 1) to_chat(user, "You unfasten the frame.") setAnchored(FALSE) state = 0 @@ -72,9 +72,7 @@ if(!P.tool_start_check(user, amount=5)) return to_chat(user, "You start adding cables to the frame...") - 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, "You add cables to the frame.") state = 3 icon_state = "3" @@ -94,9 +92,7 @@ return playsound(src, 'sound/items/deconstruct.ogg', 50, 1) to_chat(user, "You start to put in the glass panel...") - 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, "You put in the glass panel.") 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)) diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index 43582e39bf..8de470fdb8 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -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) ..() diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 9539dc281d..fa0cf367d9 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -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, "Alt-click to eject the ID card.") +/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, "Alt-click to eject the ID card.") /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, "There's already an ID card in the console!") + 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, "There's already an ID card in the console!") - return FALSE - if(!user.transferItemToLoc(I, src)) - return FALSE - user.visible_message("[user] inserts an ID card into the console.", \ - "You insert the ID card into the console.") - 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("[user] inserts \the [card_to_insert] into \the [src].", + "You insert \the [card_to_insert] into \the [src].") + 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, "There's no ID card in the console!") + to_chat(user, "That slot is empty!") return FALSE else target.forceMove(drop_location()) if(!issilicon(user) && Adjacent(user)) user.put_in_hands(target) - user.visible_message("[user] gets an ID card from the console.", \ - "You get the ID card from the console.") + user.visible_message("[user] gets \the [target] from \the [src].", \ + "You get \the [target] from \the [src].") 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 += "Crew Manifest:
    Please use security record computer to modify entries.

    " for(var/datum/data/record/t in sortRecord(GLOB.data_core.general)) - crew += t.fields["name"] + " - " + t.fields["rank"] + "
    " - dat = "Crew Manifest:
    Please use security record computer to modify entries.

    [crew]Print

    Access ID modification console.
    " + dat += {"[t.fields["name"]] - [t.fields["rank"]]
    "} + dat += "Print

    Access ID modification console.
    " else if(mode == 2) // JOB MANAGEMENT - dat = "Return" - dat += " || Confirm Identity: " - var/S - if(inserted_scan_id) - S = html_encode(inserted_scan_id.name) - else - S = "--------" - dat += "[S]" - dat += "" - dat += "" - var/ID - if(inserted_scan_id && (ACCESS_CHANGE_IDS in inserted_scan_id.access) && !target_dept) - ID = 1 - else - ID = 0 + dat += {"Return +
    JobSlotsOpen jobClose jobPrioritize
    + "} for(var/datum/job/job in SSjob.occupations) dat += "" if(job.title in blacklisted) continue - dat += "" - dat += "" - dat += " + + " dat += "
    JobSlotsOpen jobClose jobPrioritize
    [job.title][job.current_positions]/[job.total_positions]" + dat += {"[job.title][job.current_positions]/[job.total_positions]"} switch(can_open_job(job)) - if(1) - if(ID) + if(JOB_ALLOWED) + if(authenticated == 2) dat += "Open Position
    " 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 += "
    " switch(can_close_job(job)) - if(1) - if(ID) + if(JOB_ALLOWED) + if(authenticated == 2) dat += "Close Position" 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 += "" switch(job.total_positions) if(0) dat += "Denied" else - if(ID) + if(authenticated == 2) if(job in SSjob.prioritized_jobs) dat += "Deprioritize" else @@ -255,57 +251,36 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) dat += "
    " 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 += "
    Please insert the cards into the slots
    " - header += "Target: [target_name]
    " - header += "Confirm Identity: [scan_name]
    " + header += {"
    Please insert the cards into the slots
    + Target: [target_name]
    + Confirm Identity: [scan_name]
    "} else - header += "

    " - header += "Remove [target_name] || " - header += "Remove [scan_name]
    " - header += "Access Crew Manifest
    " - header += "Log Out
    " + header += {"

    + Target: Remove [target_name] || + Confirm Identity: Remove [scan_name]
    + Access Crew Manifest
    + [!target_dept ? "Job Management
    " : ""] + Log Out
    "} header += "
    " - 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 += "[replacetext(job, " ", " ")] " //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 += "[replacetext(job, " ", " ")] " //make sure there isn't a line break in the middle of a job carddesc += {""} - carddesc += "
    " - carddesc += "" - carddesc += "" - carddesc += "registered name: " - carddesc += "" - carddesc += "
    " - carddesc += "Assignment: " + carddesc += {"
    + + + registered name: + +
    + Assignment: "} jobs += "[target_rank]" //CHECK THIS @@ -338,18 +313,18 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) carddesc += "registered_name: [target_owner]" jobs += "Assignment: [target_rank] (Demote)" - var/accesses = "" - if(istype(src, /obj/machinery/computer/card/centcom)) + var/list/accesses = list() + if(istype(src, /obj/machinery/computer/card/centcom)) // REE accesses += "
    Central Command:
    " for(var/A in get_all_centcom_access()) if(A in inserted_modify_id.access) - accesses += "[replacetext(get_centcom_access_desc(A), " ", " ")] " + accesses += "[replacetext(get_centcom_access_desc(A), " ", " ")] " else accesses += "[replacetext(get_centcom_access_desc(A), " ", " ")] " else - accesses += "
    Access
    " - accesses += "" - accesses += "" + accesses += {"
    Access
    +
    + "} 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 += "" accesses += "
    " for(var/A in get_region_accesses(i)) if(A in inserted_modify_id.access) - accesses += "[replacetext(get_access_desc(A), " ", " ")] " + accesses += "[replacetext(get_access_desc(A), " ", " ")] " else accesses += "[replacetext(get_access_desc(A), " ", " ")] " accesses += "
    " accesses += "
    " - body = "[carddesc]
    [jobs]

    [accesses]" //CHECK THIS + body = "[carddesc.Join()]
    [jobs.Join()]

    [accesses.Join()]
    " //CHECK THIS - else - body = "{Log in}

    " - body += "Access Crew Manifest" + else if (!authenticated) + body = {"Log In

    + Access Crew Manifest

    "} if(!target_dept) - body += "

    Job Management" + body += "Job Management
    " - dat = "[header][body]

    " + dat = list("", header.Join(), body, "
    ") 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, "No log exists for this job.") + to_chat(usr, "No log exists for this job.") 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, "You are not authorized to demote this position.") + to_chat(usr, "You are not authorized to demote this position.") 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, "Invalid name entered.") + to_chat(usr, "Invalid name entered.") 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, "[j.title] has been successfully [priority ? "prioritized" : "unprioritized"]. Potential employees will notice your request.") + to_chat(usr, "[j.title] has been successfully [priority ? "prioritized" : "unprioritized"]. Potential employees will notice your request.") 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 \ No newline at end of file + light_color = LIGHT_COLOR_ORANGE + +#undef JOB_ALLOWED +#undef JOB_COOLDOWN +#undef JOB_MAX_POSITIONS +#undef JOB_DENIED diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index f3612078d6..b5cb066b3a 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -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)) diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm index f198bfbd87..bc8a675085 100644 --- a/code/game/mecha/mech_bay.dm +++ b/code/game/mecha/mech_bay.dm @@ -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" diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm index b6a4ac2390..360ac51444 100644 --- a/code/game/mecha/medical/odysseus.dm +++ b/code/game/mecha/medical/odysseus.dm @@ -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) diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index 134b921666..19cd5d66c4 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -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("[user] sets the RCD to 'Wall' and points it down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide..") @@ -227,11 +225,10 @@ RLD t1 += "

    Close

    \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 diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm index 109078f804..f3ed99b132 100644 --- a/code/game/objects/items/cardboard_cutouts.dm +++ b/code/game/objects/items/cardboard_cutouts.dm @@ -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) diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 0e422a3fe9..09a119eeb4 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -203,6 +203,9 @@ /obj/item/card/id/GetID() return src +/obj/item/card/id/RemoveID() + return src + /* Usage: update_label() diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm index 1d302b409e..d86354f195 100644 --- a/code/game/objects/items/clown_items.dm +++ b/code/game/objects/items/clown_items.dm @@ -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" diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index fa1ae55282..246dba9cb9 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -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, "You remove the ID from the [name].") - 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, "You remove the ID from the [name].") + 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) diff --git a/code/game/objects/items/devices/dogborg_sleeper.dm b/code/game/objects/items/devices/dogborg_sleeper.dm index 3c945f464e..1a3bc283d9 100644 --- a/code/game/objects/items/devices/dogborg_sleeper.dm +++ b/code/game/objects/items/devices/dogborg_sleeper.dm @@ -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,"Your [src] is already occupied.") return if(target.buckled) @@ -524,3 +523,7 @@ update_gut() user.visible_message("[hound.name]'s garbage processor groans lightly as [trashman] slips inside.", "Your garbage compactor groans lightly as [trashman] slips inside.") 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." \ No newline at end of file diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index cf55d4178e..6afce03455 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -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 diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index 84439985b2..7a83893f8b 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -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, "You are not close enough with [deity_name] to use [src].") + return + + if(praying) + to_chat(user, "You are already using [src].") + return + + user.visible_message("[user] kneels[M == user ? null : " next to [M]"] and begins to utter a prayer to [deity_name].", \ + "You kneel[M == user ? null : " next to [M]"] and begin a prayer to [deity_name].") + + praying = TRUE + if(do_after(user, 20, target = M)) + M.reagents?.add_reagent("holywater", 5) + to_chat(M, "[user]'s prayer to [deity_name] has eased your pain!") + M.adjustToxLoss(-5, TRUE, TRUE) + M.adjustOxyLoss(-5) + M.adjustBruteLoss(-5) + M.adjustFireLoss(-5) + praying = FALSE + else + to_chat(user, "Your prayer to [deity_name] was interrupted.") + praying = FALSE diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index 90e2efabc4..ffbbea84dc 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -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") diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index d9045a7a34..a0b78d8b27 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -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) . = ..() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 0aa19b13ef..c10fb0fa2c 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -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), \ diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index ca7f7fe31a..1e37de2581 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -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 diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 84ebc28afa..223c8e9cf6 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -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 \ No newline at end of file diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm index 7a6899ad15..891a4689d0 100644 --- a/code/game/objects/items/storage/wallets.dm +++ b/code/game/objects/items/storage/wallets.dm @@ -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 diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm index f891a48df6..bc5bc6811e 100644 --- a/code/game/objects/items/tools/crowbar.dm +++ b/code/game/objects/items/tools/crowbar.dm @@ -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 diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index 6cbede78a8..91a94e05c3 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -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" diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index b04d96dc80..d7c00fe5fe 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -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() diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm index e40ae8bdc1..fe8b4b2d56 100644 --- a/code/game/objects/items/tools/wirecutters.dm +++ b/code/game/objects/items/tools/wirecutters.dm @@ -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" diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm index 462eb22aaa..89f135ed67 100644 --- a/code/game/objects/items/tools/wrench.dm +++ b/code/game/objects/items/tools/wrench.dm @@ -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 diff --git a/code/game/objects/structures/beds_chairs/pew.dm b/code/game/objects/structures/beds_chairs/pew.dm new file mode 100644 index 0000000000..65440fb5d8 --- /dev/null +++ b/code/game/objects/structures/beds_chairs/pew.dm @@ -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() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm index 18928424c0..0b5dad5ca3 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm @@ -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) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index f173ac0662..9abd81b787 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -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" diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm index 0f810225b3..d4c876c767 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm @@ -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" diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm index efcc2aa7ca..97c0c8f3e2 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm @@ -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) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 3cb8ceb22b..e87cb22f31 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -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) diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index 10f1f30e13..e3585b601e 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -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 diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm index 609384cdda..4d56b1ef6f 100644 --- a/code/game/objects/structures/holosign.dm +++ b/code/game/objects/structures/holosign.dm @@ -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 diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index e3862ed924..fd4f3abf15 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -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) diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index efee9cfa5a..4bdb13effc 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -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' diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index ed6e279088..43fce2e516 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -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 diff --git a/code/game/turfs/simulated/floor/mineral_floor.dm b/code/game/turfs/simulated/floor/mineral_floor.dm index b71fb51123..f0ac0053ce 100644 --- a/code/game/turfs/simulated/floor/mineral_floor.dm +++ b/code/game/turfs/simulated/floor/mineral_floor.dm @@ -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 diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm index 253a6ead90..f75772a230 100644 --- a/code/game/turfs/simulated/floor/misc_floor.dm +++ b/code/game/turfs/simulated/floor/misc_floor.dm @@ -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" diff --git a/code/game/turfs/simulated/floor/plasteel_floor.dm b/code/game/turfs/simulated/floor/plasteel_floor.dm index 884e4c6551..2d2911c334 100644 --- a/code/game/turfs/simulated/floor/plasteel_floor.dm +++ b/code/game/turfs/simulated/floor/plasteel_floor.dm @@ -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 diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm index d9966ee55c..9f2da57312 100644 --- a/code/game/turfs/simulated/floor/plating/asteroid.dm +++ b/code/game/turfs/simulated/floor/plating/asteroid.dm @@ -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 \ No newline at end of file diff --git a/code/game/turfs/simulated/floor/plating/misc_plating.dm b/code/game/turfs/simulated/floor/plating/misc_plating.dm index 15b039193d..5c58d99e1a 100644 --- a/code/game/turfs/simulated/floor/plating/misc_plating.dm +++ b/code/game/turfs/simulated/floor/plating/misc_plating.dm @@ -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 diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm index 1a477d5d9a..d48bdb489b 100644 --- a/code/game/turfs/simulated/floor/reinf_floor.dm +++ b/code/game/turfs/simulated/floor/reinf_floor.dm @@ -17,7 +17,7 @@ to_chat(user, "The reinforcement rods are wrenched firmly in place.") /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 diff --git a/code/game/turfs/simulated/lava.dm b/code/game/turfs/simulated/lava.dm index e24736ecf3..362b410cbb 100644 --- a/code/game/turfs/simulated/lava.dm +++ b/code/game/turfs/simulated/lava.dm @@ -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 diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index 0004a4485b..966083c71a 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -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 diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 7fafca69f0..87db105072 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -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, "Vote is now between extended and dynamic chaos.") + else + to_chat(world, "Vote is now between extended and secret.") + log_admin("[key_name(usr)] [prev_dynamic_voting ? "disabled" : "enabled"] dynamic voting.") + message_admins("[key_name_admin(usr)] toggled dynamic voting.") + 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" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index cb5b33ae08..5900847ef5 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -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, diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 8b105da43b..4de2d9b5ca 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -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) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index c1e6ff826f..3723b99f4e 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -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 diff --git a/code/modules/antagonists/abductor/equipment/abduction_outfits.dm b/code/modules/antagonists/abductor/equipment/abduction_outfits.dm index 7e03bbf57a..7bfadf6f3b 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_outfits.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_outfits.dm @@ -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 diff --git a/code/modules/antagonists/abductor/machinery/camera.dm b/code/modules/antagonists/abductor/machinery/camera.dm index 00e48cb1c7..9e0a2b46b1 100644 --- a/code/modules/antagonists/abductor/machinery/camera.dm +++ b/code/modules/antagonists/abductor/machinery/camera.dm @@ -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) ..() diff --git a/code/modules/antagonists/blob/blob/overmind.dm b/code/modules/antagonists/blob/blob/overmind.dm index d32e38c194..fa7b64591f 100644 --- a/code/modules/antagonists/blob/blob/overmind.dm +++ b/code/modules/antagonists/blob/blob/overmind.dm @@ -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 diff --git a/code/modules/antagonists/disease/disease_event.dm b/code/modules/antagonists/disease/disease_event.dm index 385cee998b..4365fd7538 100644 --- a/code/modules/antagonists/disease/disease_event.dm +++ b/code/modules/antagonists/disease/disease_event.dm @@ -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 diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm index faea113ac5..836b71b89a 100644 --- a/code/modules/antagonists/disease/disease_mob.dm +++ b/code/modules/antagonists/disease/disease_mob.dm @@ -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 diff --git a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm new file mode 100644 index 0000000000..e25e0cd164 --- /dev/null +++ b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm @@ -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, "You can't use [src] while inside something!") + else + to_chat(user, "You need at least [activationCost] charge in your cell to use [src]!") + +/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, "You deactivate \the [src].") + deactivate(user) + else + if(animation_playing) + to_chat(user, "\the [src] is recharging.") + 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, "You activate \the [src].") + 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, "You are now disguised as the Nanotrasen engineering borg \"[friendlyName]\".") + activate(user) + else + to_chat(user, "The chameleon field fizzles.") + 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, "Your chameleon field deactivates.") + deactivate(user) \ No newline at end of file diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm index 78e4d38b3c..0a223f8b10 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm @@ -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 diff --git a/code/modules/antagonists/revenant/revenant_spawn_event.dm b/code/modules/antagonists/revenant/revenant_spawn_event.dm index cb534b6613..7bb7f1aa76 100644 --- a/code/modules/antagonists/revenant/revenant_spawn_event.dm +++ b/code/modules/antagonists/revenant/revenant_spawn_event.dm @@ -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 diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index fef7061488..c4190d8cd9 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -207,9 +207,20 @@ owner.current.visible_message("The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.", null, null, null, owner.current) to_chat(owner, "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...") +/datum/antagonist/rev/head/farewell() + if((ishuman(owner.current) || ismonkey(owner.current))) + if(owner.current.stat != DEAD) + owner.current.visible_message("[owner.current] looks like [owner.current.p_theyve()] just remembered [owner.current.p_their()] real allegiance!", null, null, null, owner.current) + to_chat(owner, "You have given up your cause of overthrowing the command staff. You are no longer a Head Revolutionary.") + else + to_chat(owner, "The sweet release of death. You are no longer a Head Revolutionary.") + else if(issilicon(owner.current)) + owner.current.visible_message("The frame beeps contentedly, suppressing the disloyal personality traits from the MMI before initalizing it.", null, null, null, owner.current) + to_chat(owner, "The frame's firmware detects and suppresses your unwanted personality traits! You feel more content with the leadership around these parts.") + //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 += "The head revolutionaries were:" diff --git a/code/modules/antagonists/slaughter/slaughterevent.dm b/code/modules/antagonists/slaughter/slaughterevent.dm index 6ace6a0536..069795cfb8 100644 --- a/code/modules/antagonists/slaughter/slaughterevent.dm +++ b/code/modules/antagonists/slaughter/slaughterevent.dm @@ -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 diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 5dfc08b6cf..26eea3f59e 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -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 diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index f14872a0a4..a0dbc4d9b1 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -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, "You play \the [src], yet no sound comes out of it... Looks like it won't work here.") return on_cooldown = TRUE last_user = user diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm index 4ebefd4dab..a5917f4b96 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook.dm @@ -11,12 +11,18 @@ var/buy_word = "Learn" var/limit //used to prevent a spellbook_entry from being bought more than X times with one wizard spellbook var/list/no_coexistance_typecache //Used so you can't have specific spells together + var/dynamic_cost = 0 // How much threat the spell costs to purchase for dynamic. + var/dynamic_requirement = 0 // How high the threat level needs to be for purchasing in dynamic. /datum/spellbook_entry/New() ..() no_coexistance_typecache = typecacheof(no_coexistance_typecache) /datum/spellbook_entry/proc/IsAvailible() // For config prefs / gamemode restrictions - these are round applied + if(istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + if(dynamic_requirement > 0 && mode.threat_level < dynamic_requirement) + return 0 return 1 /datum/spellbook_entry/proc/CanBuy(mob/living/carbon/human/user,obj/item/spellbook/book) // Specific circumstances @@ -25,6 +31,10 @@ for(var/spell in user.mind.spell_list) if(is_type_in_typecache(spell, no_coexistance_typecache)) return 0 + if(dynamic_cost>0 && istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + if(mode.threat < dynamic_cost) + return 0 return 1 /datum/spellbook_entry/proc/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) //return 1 on success @@ -60,6 +70,10 @@ SSblackbox.record_feedback("nested tally", "wizard_spell_improved", 1, list("[name]", "[aspell.spell_level]")) return 1 //No same spell found - just learn it + if(dynamic_cost > 0 && istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + mode.spend_threat(dynamic_cost) + mode.log_threat("Wizard spent [dynamic_cost] on [name].") SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name) user.mind.AddSpell(S) to_chat(user, "You have learned [S.name].") @@ -83,6 +97,10 @@ if(!S) S = new spell_type() var/spell_levels = 0 + if(dynamic_cost > 0 && istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + mode.refund_threat(dynamic_cost) + mode.log_threat("Wizard refunded [dynamic_cost] on [name].") for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list) if(initial(S.name) == initial(aspell.name)) spell_levels = aspell.spell_level @@ -285,6 +303,8 @@ name = "Staff of Change" desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself." item_path = /obj/item/gun/magic/staff/change + dynamic_requirement = 60 + dynamic_cost = 20 /datum/spellbook_entry/item/staffanimation name = "Staff of Animation" @@ -369,6 +389,8 @@ desc = "A magical contract binding an apprentice wizard to your service, using it will summon them to your side." item_path = /obj/item/antag_spawner/contract category = "Assistance" + dynamic_requirement = 50 + dynamic_cost = 10 /datum/spellbook_entry/item/guardian name = "Guardian Deck" @@ -388,6 +410,11 @@ item_path = /obj/item/antag_spawner/slaughter_demon limit = 3 category = "Assistance" + dynamic_requirement = 60 + +/datum/spellbook_entry/item/bloodbottle/New() + ..() + dynamic_cost = CONFIG_GET(keyed_list/dynamic_cost)["slaughter_demon"] /datum/spellbook_entry/item/hugbottle name = "Bottle of Tickles" @@ -402,6 +429,11 @@ cost = 1 //non-destructive; it's just a jape, sibling! limit = 3 category = "Assistance" + dynamic_requirement = 40 + +/datum/spellbook_entry/item/hugbottle/New() + ..() + dynamic_cost = CONFIG_GET(keyed_list/dynamic_cost)["slaughter_demon"]/3 /datum/spellbook_entry/item/mjolnir name = "Mjolnir" @@ -465,7 +497,7 @@ if(!SSticker.mode) return FALSE else - return TRUE + return ..() /datum/spellbook_entry/summon/ghosts/Buy(mob/living/carbon/human/user, obj/item/spellbook/book) SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name) @@ -478,11 +510,13 @@ /datum/spellbook_entry/summon/guns name = "Summon Guns" desc = "Nothing could possibly go wrong with arming a crew of lunatics just itching for an excuse to kill you. Just be careful not to stand still too long!" + dynamic_cost = 10 + dynamic_requirement = 60 /datum/spellbook_entry/summon/guns/IsAvailible() if(!SSticker.mode) // In case spellbook is placed on map return 0 - return !CONFIG_GET(flag/no_summon_guns) + return (!CONFIG_GET(flag/no_summon_guns) && ..()) /datum/spellbook_entry/summon/guns/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name) @@ -490,16 +524,23 @@ active = 1 playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1) to_chat(user, "You have cast summon guns!") + if(istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + var/threat_spent = dynamic_cost + mode.spend_threat(threat_spent) + mode.log_threat("Wizard spent [threat_spent] on summon guns.") return 1 /datum/spellbook_entry/summon/magic name = "Summon Magic" desc = "Share the wonders of magic with the crew and show them why they aren't to be trusted with it at the same time." + dynamic_cost = 10 + dynamic_requirement = 60 /datum/spellbook_entry/summon/magic/IsAvailible() if(!SSticker.mode) // In case spellbook is placed on map return 0 - return !CONFIG_GET(flag/no_summon_magic) + return (!CONFIG_GET(flag/no_summon_guns) && ..()) /datum/spellbook_entry/summon/magic/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name) @@ -507,21 +548,33 @@ active = 1 playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1) to_chat(user, "You have cast summon magic!") + if(istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + var/threat_spent = dynamic_cost + mode.spend_threat(threat_spent) + mode.log_threat("Wizard spent [threat_spent] on summon magic.") return 1 /datum/spellbook_entry/summon/events name = "Summon Events" desc = "Give Murphy's law a little push and replace all events with special wizard ones that will confound and confuse everyone. Multiple castings increase the rate of these events." + dynamic_cost = 20 + dynamic_requirement = 60 var/times = 0 /datum/spellbook_entry/summon/events/IsAvailible() if(!SSticker.mode) // In case spellbook is placed on map return 0 - return !CONFIG_GET(flag/no_summon_events) + return (!CONFIG_GET(flag/no_summon_events) && ..()) /datum/spellbook_entry/summon/events/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name) summonevents() + if(istype(SSticker.mode,/datum/game_mode/dynamic) && times == 0) + var/datum/game_mode/dynamic/mode = SSticker.mode + var/threat_spent = dynamic_cost + mode.spend_threat(threat_spent) + mode.log_threat("Wizard spent [threat_spent] on summon events.") times++ playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1) to_chat(user, "You have cast summon events.") diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index 89324f0691..9b2532c71b 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -165,7 +165,7 @@ owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball(null)) to_chat(owner, "Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball.") if(APPRENTICE_BLUESPACE) - owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null)) + owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink(null)) owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null)) to_chat(owner, "Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt.") if(APPRENTICE_HEALING) diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm index d1da05e42d..c47c4a44af 100644 --- a/code/modules/atmospherics/environmental/LINDA_fire.dm +++ b/code/modules/atmospherics/environmental/LINDA_fire.dm @@ -199,7 +199,7 @@ var/radiated_temperature = location.air.temperature*FIRE_SPREAD_RADIOSITY_SCALE for(var/t in location.atmos_adjacent_turfs) var/turf/open/T = t - if(T.active_hotspot) + if(!T.active_hotspot) T.hotspot_expose(radiated_temperature, CELL_VOLUME/4) else diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index 9dba780b3f..cafdafb671 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -15,7 +15,7 @@ //used for mapping and for breathing while in walls (because that's a thing that needs to be accounted for...) //string parsed by /datum/gas/proc/copy_from_turf - var/initial_gas_mix = "o2=22;n2=82;TEMP=293.15" + var/initial_gas_mix = OPENTURF_DEFAULT_ATMOS //approximation of MOLES_O2STANDARD and MOLES_N2STANDARD pending byond allowing constant expressions to be embedded in constant strings // If someone will place 0 of some gas there, SHIT WILL BREAK. Do not do that. diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm index 84f08197b4..bd4e716357 100644 --- a/code/modules/awaymissions/capture_the_flag.dm +++ b/code/modules/awaymissions/capture_the_flag.dm @@ -487,7 +487,7 @@ r_pocket = /obj/item/ammo_box/magazine/recharge/ctf r_hand = /obj/item/gun/ballistic/automatic/laser/ctf -/datum/outfit/ctf/post_equip(mob/living/carbon/human/H, visualsOnly=FALSE) +/datum/outfit/ctf/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return var/list/no_drops = list() @@ -529,7 +529,7 @@ r_hand = /obj/item/gun/energy/laser/instakill/blue shoes = /obj/item/clothing/shoes/jackboots/fast -/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H) +/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() var/obj/item/radio/R = H.ears R.set_frequency(FREQ_CTF_RED) @@ -537,7 +537,7 @@ R.independent = TRUE H.dna.species.stunmod = 0 -/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H) +/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() var/obj/item/radio/R = H.ears R.set_frequency(FREQ_CTF_BLUE) diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index a0b917a87b..0d5fa6bc8a 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -440,7 +440,7 @@ uniform = /obj/item/clothing/under/pants/youngfolksjeans id = /obj/item/card/id -/datum/outfit/beachbum/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/beachbum/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) return diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm index 7cb771737e..aa1abe56b4 100644 --- a/code/modules/awaymissions/mission_code/snowdin.dm +++ b/code/modules/awaymissions/mission_code/snowdin.dm @@ -154,7 +154,7 @@ //liquid plasma!!!!!!// /turf/open/floor/plasteel/dark/snowdin - initial_gas_mix = "o2=22;n2=82;TEMP=180" + initial_gas_mix = FROZEN_ATMOS planetary_atmos = 1 temperature = 180 diff --git a/code/modules/cargo/bounty_console.dm b/code/modules/cargo/bounty_console.dm index 2e5d943dd6..45260f4926 100644 --- a/code/modules/cargo/bounty_console.dm +++ b/code/modules/cargo/bounty_console.dm @@ -1,5 +1,7 @@ #define PRINTER_TIMEOUT 10 + + /obj/machinery/computer/bounty name = "Nanotrasen bounty console" desc = "Used to check and claim bounties offered by Nanotrasen" @@ -24,9 +26,9 @@ for(var/datum/bounty/B in GLOB.bounties_list) if(B.claimed) continue - info += "

    [B.name]

    " - info += "
    • Reward: [B.reward_string()]
    • " - info += "
    • Completed: [B.completion_string()]
    " + info += {"

    [B.name]

    +
    • Reward: [B.reward_string()]
    • +
    • Completed: [B.completion_string()]
    "} /obj/machinery/computer/bounty/ui_interact(mob/user) . = ..() @@ -34,39 +36,36 @@ if(!GLOB.bounties_list.len) setup_bounties() - var/dat = "" - dat += "Refresh" - dat += "Print Paper" - dat += "

    Credits: [SSshuttle.points]

    " - dat += {""} - dat += "" + var/list/dat = list({"Refresh + Print Paper +

    Credits: [SSshuttle.points]

    +
    NameDescriptionRewardCompletionStatus
    + "}) for(var/datum/bounty/B in GLOB.bounties_list) - var/background - if(B.can_claim()) - background = "'background-color:#4F7529;'" - else if(B.claimed) - background = "'background-color:#294675;'" + if(B.claimed) + dat += "" + else if(B.can_claim()) + dat += "" else - background = "'background-color:#990000;'" - dat += "" + dat += "" if(B.high_priority) - dat += text("", B.name) - dat += text("", B.description) - dat += text("", B.reward_string()) + dat += {" + + "} else - dat += text("", B.name) - dat += text("", B.description) - dat += text("", B.reward_string()) - dat += text("", B.completion_string()) - if(B.can_claim()) - dat += text("") - else if(B.claimed) - dat += text("") + dat += {" + + "} + dat += "" + if(B.claimed) + dat += "" + else if(B.can_claim()) + dat += "" else - dat += text("") + dat += "" dat += "" dat += "
    NameDescriptionRewardCompletionStatus
    []High Priority: [][][B.name]High Priority: [B.description][B.reward_string()][][][][]ClaimClaimed[B.name][B.description][B.reward_string()][B.completion_string()]ClaimedClaimUnclaimedUnclaimed
    " - + dat = dat.Join() var/datum/browser/popup = new(user, "bounties", "Nanotrasen Bounties", 700, 600) popup.set_content(dat) popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) @@ -91,4 +90,3 @@ playsound(src, "terminal_type", 25, 0) updateUsrDialog() - diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm index 3d4df9df12..adb7fe73f3 100644 --- a/code/modules/cargo/console.dm +++ b/code/modules/cargo/console.dm @@ -167,7 +167,7 @@ if(ishuman(usr)) var/mob/living/carbon/human/H = usr name = H.get_authentification_name() - rank = H.get_assignment() + rank = H.get_assignment(hand_first = TRUE) else if(issilicon(usr)) name = usr.real_name rank = "Silicon" diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm index 0097346a34..6170c80f8e 100644 --- a/code/modules/cargo/expressconsole.dm +++ b/code/modules/cargo/expressconsole.dm @@ -156,7 +156,7 @@ if(ishuman(usr)) var/mob/living/carbon/human/H = usr name = H.get_authentification_name() - rank = H.get_assignment() + rank = H.get_assignment(hand_first = TRUE) else if(issilicon(usr)) name = usr.real_name rank = "Silicon" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 309f3ca069..e91d379ddd 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -58,6 +58,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/inquisitive_ghost = 1 var/allow_midround_antag = 1 var/preferred_map = null + var/preferred_chaos = null var/pda_style = MONO var/pda_color = "#808000" var/pda_skin = PDA_SKIN_ALT @@ -834,6 +835,12 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Screen Shake: [(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]
    " if (user && user.client && !user.client.prefs.screenshake==0) dat += "Damage Screen Shake: [(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")]
    " + var/p_chaos + if (!preferred_chaos) + p_chaos = "No preference" + else + p_chaos = preferred_chaos + dat += "Preferred Chaos Amount: [p_chaos]
    " dat += "
    " dat += "" dat += "" @@ -1996,6 +2003,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) if (pickedmap) preferred_map = maplist[pickedmap] + if ("preferred_chaos") + var/pickedchaos = input(user, "Choose your preferred level of chaos. This will help with dynamic threat level ratings.", "Character Preference") as null|anything in list(CHAOS_NONE,CHAOS_LOW,CHAOS_MED,CHAOS_HIGH,CHAOS_MAX) + preferred_chaos = pickedchaos if ("clientfps") var/desiredfps = input(user, "Choose your desired fps. (0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num if (!isnull(desiredfps)) @@ -2289,10 +2299,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.shirt_color = shirt_color character.socks_color = socks_color - - character.backbag = backbag - character.jumpsuit_style = jumpsuit_style - var/datum/species/chosen_species if(!roundstart_checks || (pref_species.id in GLOB.roundstart_races)) chosen_species = pref_species.type diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 98ef2ed0e8..29ea8f5821 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -183,6 +183,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["autostand"] >> autostand S["cit_toggles"] >> cit_toggles S["lewdchem"] >> lewdchem + S["preferred_chaos"] >> preferred_chaos + //try to fix any outdated data if necessary if(needs_update >= 0) @@ -278,6 +280,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["autostand"], autostand) WRITE_FILE(S["cit_toggles"], cit_toggles) WRITE_FILE(S["lewdchem"], lewdchem) + WRITE_FILE(S["preferred_chaos"], preferred_chaos) return 1 diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index 6b674c8595..ac491c2bc5 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -14,7 +14,7 @@ /obj/item/clothing/gloves/ComponentInitialize() . = ..() - RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /obj/item/clothing/gloves/clean_blood) + RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood) /obj/item/clothing/gloves/clean_blood(datum/source, strength) . = ..() diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm index 88cc7123fd..1532f50808 100644 --- a/code/modules/clothing/outfits/ert.dm +++ b/code/modules/clothing/outfits/ert.dm @@ -6,7 +6,7 @@ gloves = /obj/item/clothing/gloves/combat ears = /obj/item/radio/headset/headset_cent/alt -/datum/outfit/ert/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/ert/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -35,7 +35,7 @@ /obj/item/gun/energy/e_gun=1) l_pocket = /obj/item/switchblade -/datum/outfit/ert/commander/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/ert/commander/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) @@ -46,7 +46,7 @@ /datum/outfit/ert/commander/alert name = "ERT Commander - Amber Alert" - + suit = /obj/item/clothing/suit/space/hardsuit/ert/alert glasses = /obj/item/clothing/glasses/thermal/eyepatch backpack_contents = list(/obj/item/storage/box/engineer=1,\ @@ -76,7 +76,7 @@ /obj/item/gun/energy/e_gun/stun=1,\ /obj/item/melee/baton/loaded=1) -/datum/outfit/ert/security/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/ert/security/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) @@ -88,7 +88,7 @@ /datum/outfit/ert/security/alert name = "ERT Security - Amber Alert" - + suit = /obj/item/clothing/suit/space/hardsuit/ert/alert/sec backpack_contents = list(/obj/item/storage/box/engineer=1,\ /obj/item/storage/box/handcuffs=1,\ @@ -120,7 +120,7 @@ /obj/item/reagent_containers/hypospray/combat=1,\ /obj/item/gun/medbeam=1) -/datum/outfit/ert/medic/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/ert/medic/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) @@ -166,7 +166,7 @@ /obj/item/gun/energy/e_gun=1,\ /obj/item/construction/rcd/loaded=1) -/datum/outfit/ert/engineer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/ert/engineer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) @@ -214,7 +214,7 @@ l_hand = /obj/item/storage/toolbox/plastitanium gloves = /obj/item/clothing/gloves/color/yellow -/datum/outfit/ert/greybois/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/ert/greybois/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return var/obj/item/card/id/W = H.wear_id @@ -238,7 +238,7 @@ l_hand = /obj/item/clipboard id = /obj/item/card/id -/datum/outfit/centcom_official/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/centcom_official/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -288,7 +288,7 @@ /obj/item/reagent_containers/hypospray/combat/heresypurge=1, /obj/item/gun/medbeam=1) -/datum/outfit/ert/chaplain/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/ert/chaplain/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) diff --git a/code/modules/clothing/outfits/event.dm b/code/modules/clothing/outfits/event.dm index 347fc5c2d7..0ca2a11c50 100644 --- a/code/modules/clothing/outfits/event.dm +++ b/code/modules/clothing/outfits/event.dm @@ -12,7 +12,7 @@ belt = /obj/item/tank/internals/emergency_oxygen/double id = /obj/item/card/id/gold -/datum/outfit/santa/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/santa/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return H.fully_replace_character_name(H.real_name, "Santa Claus") diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm index 6c961dc250..29fd06dcaf 100644 --- a/code/modules/clothing/outfits/standard.dm +++ b/code/modules/clothing/outfits/standard.dm @@ -48,7 +48,7 @@ l_pocket = /obj/item/grenade/chem_grenade/cleaner backpack_contents = list(/obj/item/stack/tile/plasteel=6) -/datum/outfit/tournament/janitor/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/tournament/janitor/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -97,7 +97,7 @@ /datum/outfit/pirate/space/captain head = /obj/item/clothing/head/helmet/space/pirate -/datum/outfit/pirate/post_equip(mob/living/carbon/human/H) +/datum/outfit/pirate/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) H.faction |= "pirate" var/obj/item/radio/R = H.ears @@ -125,7 +125,7 @@ id = /obj/item/card/id r_hand = /obj/item/twohanded/fireaxe -/datum/outfit/tunnel_clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/tunnel_clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -150,7 +150,7 @@ r_pocket = /obj/item/scalpel r_hand = /obj/item/twohanded/fireaxe -/datum/outfit/psycho/post_equip(mob/living/carbon/human/H) +/datum/outfit/psycho/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) for(var/obj/item/carried_item in H.get_equipped_items(TRUE)) carried_item.add_mob_blood(H)//Oh yes, there will be blood... for(var/obj/item/I in H.held_items) @@ -170,7 +170,7 @@ id = /obj/item/card/id/syndicate belt = /obj/item/pda/heads -/datum/outfit/assassin/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/assassin/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) var/obj/item/clothing/under/U = H.w_uniform U.attach_accessory(new /obj/item/clothing/accessory/waistcoat(H)) @@ -216,7 +216,7 @@ back = /obj/item/storage/backpack/satchel/leather id = /obj/item/card/id -/datum/outfit/centcom_commander/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/centcom_commander/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -244,7 +244,7 @@ back = /obj/item/storage/backpack/satchel/leather id = /obj/item/card/id -/datum/outfit/spec_ops/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/spec_ops/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -283,7 +283,7 @@ back = /obj/item/storage/backpack backpack_contents = list(/obj/item/storage/box=1) -/datum/outfit/wizard/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/wizard/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -325,7 +325,7 @@ id = /obj/item/card/id -/datum/outfit/soviet/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/soviet/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -349,7 +349,7 @@ r_hand = /obj/item/gun/ballistic/automatic/tommygun id = /obj/item/card/id -/datum/outfit/mobster/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/mobster/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -391,7 +391,7 @@ /obj/item/flashlight=1,\ /obj/item/grenade/plastic/x4=1) -/datum/outfit/death_commando/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/death_commando/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return diff --git a/code/modules/clothing/outfits/vr.dm b/code/modules/clothing/outfits/vr.dm index cd8115ac7d..ee350e3891 100644 --- a/code/modules/clothing/outfits/vr.dm +++ b/code/modules/clothing/outfits/vr.dm @@ -5,10 +5,10 @@ ears = /obj/item/radio/headset id = /obj/item/card/id -/datum/outfit/vr/pre_equip(mob/living/carbon/human/H) +/datum/outfit/vr/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) H.dna.species.before_equip_job(null, H) -/datum/outfit/vr/post_equip(mob/living/carbon/human/H) +/datum/outfit/vr/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) var/obj/item/card/id/id = H.wear_id if (istype(id)) id.access |= get_all_accesses() @@ -25,9 +25,10 @@ backpack_contents = list(/obj/item/storage/box/syndie=1,\ /obj/item/kitchen/knife/combat/survival) -/datum/outfit/vr/syndicate/post_equip(mob/living/carbon/human/H) +/datum/outfit/vr/syndicate/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) . = ..() - var/obj/item/uplink/U = new /obj/item/uplink/nuclear_restricted(H, H.key, 80) + var/key = H.key ? H.key : preference_source ? preference_source.key : null + var/obj/item/uplink/U = new /obj/item/uplink/nuclear_restricted(H, key, 80) H.equip_to_slot_or_del(U, SLOT_IN_BACKPACK) var/obj/item/implant/weapons_auth/W = new W.implant(H) diff --git a/code/modules/clothing/outfits/vv_outfit.dm b/code/modules/clothing/outfits/vv_outfit.dm index 103a152ec8..0bc8c87a45 100644 --- a/code/modules/clothing/outfits/vv_outfit.dm +++ b/code/modules/clothing/outfits/vv_outfit.dm @@ -4,7 +4,7 @@ var/list/vv_values var/list/stored_access -/datum/outfit/varedit/pre_equip(mob/living/carbon/human/H, visualsOnly) +/datum/outfit/varedit/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) H.delete_equipment() //Applying VV to wrong objects is not reccomended. . = ..() @@ -120,7 +120,7 @@ GLOB.custom_outfits += O to_chat(usr,"Outfit registered, use select equipment to equip it.") -/datum/outfit/varedit/post_equip(mob/living/carbon/human/H, visualsOnly) +/datum/outfit/varedit/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) . = ..() //Apply VV for(var/slot in vv_values) diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index b6cc8d5a7c..a8406e3b12 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -23,7 +23,7 @@ /obj/item/clothing/shoes/ComponentInitialize() . = ..() - RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /obj/item/clothing/shoes/clean_blood) + RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood) /obj/item/clothing/shoes/suicide_act(mob/living/carbon/user) if(rand(2)>1) diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index a18617ea29..53800615e9 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -519,6 +519,16 @@ /obj/item/clothing/head/hooded/winterhood/captain icon_state = "winterhood_captain" +/obj/item/clothing/suit/hooded/wintercoat/hop + name = "head of personnel's winter coat" + icon_state = "coathop" + item_state = "coathop" + armor = list("melee" = 5, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 5, "bio" = 5, "rad" = 0, "fire" = 0, "acid" = 5) + hoodtype = /obj/item/clothing/head/hooded/winterhood/hop + +/obj/item/clothing/head/hooded/winterhood/hop + icon_state = "winterhood_hop" + /obj/item/clothing/suit/hooded/wintercoat/security name = "security winter coat" icon_state = "coatsecurity" @@ -533,6 +543,20 @@ /obj/item/clothing/head/hooded/winterhood/security icon_state = "winterhood_security" +/obj/item/clothing/suit/hooded/wintercoat/hos + name = "head of security's winter coat" + icon_state = "coathos" + item_state = "coathos" + armor = list("melee" = 35, "bullet" = 35, "laser" = 35, "energy" = 15, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 55) + hoodtype = /obj/item/clothing/head/hooded/winterhood/hos + +/obj/item/clothing/suit/hooded/wintercoat/hos/Initialize() + . = ..() + allowed = GLOB.security_wintercoat_allowed + +/obj/item/clothing/head/hooded/winterhood/hos + icon_state = "winterhood_hos" + /obj/item/clothing/suit/hooded/wintercoat/medical name = "medical winter coat" icon_state = "coatmedical" @@ -544,6 +568,39 @@ /obj/item/clothing/head/hooded/winterhood/medical icon_state = "winterhood_medical" +/obj/item/clothing/suit/hooded/wintercoat/cmo + name = "chief medical officer's winter coat" + icon_state = "coatcmo" + item_state = "coatcmo" + allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + armor = list("melee" = 5, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 0, "acid" = 0) + hoodtype = /obj/item/clothing/head/hooded/winterhood/cmo + +/obj/item/clothing/head/hooded/winterhood/cmo + icon_state = "winterhood_cmo" + +/obj/item/clothing/suit/hooded/wintercoat/chemistry + name = "chemistry winter coat" + icon_state = "coatchemistry" + item_state = "coatchemistry" + allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 30, "rad" = 0, "fire" = 30, "acid" = 45) + hoodtype = /obj/item/clothing/head/hooded/winterhood/chemistry + +/obj/item/clothing/head/hooded/winterhood/chemistry + icon_state = "winterhood_chemistry" + +/obj/item/clothing/suit/hooded/wintercoat/viro + name = "virology winter coat" + icon_state = "coatviro" + item_state = "coatviro" + allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 30, "rad" = 0, "fire" = 0, "acid" = 0) + hoodtype = /obj/item/clothing/head/hooded/winterhood/viro + +/obj/item/clothing/head/hooded/winterhood/viro + icon_state = "winterhood_viro" + /obj/item/clothing/suit/hooded/wintercoat/science name = "science winter coat" icon_state = "coatscience" @@ -555,6 +612,49 @@ /obj/item/clothing/head/hooded/winterhood/science icon_state = "winterhood_science" +/obj/item/clothing/suit/hooded/wintercoat/robotics + name = "robotics winter coat" + icon_state = "coatrobotics" + item_state = "coatrobotics" + allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/screwdriver, /obj/item/crowbar, /obj/item/wrench, /obj/item/stack/cable_coil, /obj/item/weldingtool, /obj/item/multitool) + armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) + hoodtype = /obj/item/clothing/head/hooded/winterhood/robotics + +/obj/item/clothing/head/hooded/winterhood/robotics + icon_state = "winterhood_robotics" + +/obj/item/clothing/suit/hooded/wintercoat/genetics + name = "genetics winter coat" + icon_state = "coatgenetics" + item_state = "coatgenetics" + allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + hoodtype = /obj/item/clothing/head/hooded/winterhood/genetics + +/obj/item/clothing/head/hooded/winterhood/genetics + icon_state = "winterhood_genetics" + +/obj/item/clothing/suit/hooded/wintercoat/rd + name = "research director's winter coat" + icon_state = "coatrd" + item_state = "coatrd" + allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman) + armor = list("melee" = 0, "bullet" = 0, "laser" = 5,"energy" = 0, "bomb" = 15, "bio" = 5, "rad" = 5, "fire" = 0, "acid" = 0) + hoodtype = /obj/item/clothing/head/hooded/winterhood/rd + +/obj/item/clothing/head/hooded/winterhood/rd + icon_state = "winterhood_rd" + +/obj/item/clothing/suit/hooded/wintercoat/ce + name = "chief engineer's winter coat" + icon_state = "coatce" + item_state = "coatce" + armor = list("melee" = 0, "bullet" = 0, "laser" = 5, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 30, "fire" = 35, "acid" = 45) + allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/t_scanner, /obj/item/construction/rcd, /obj/item/pipe_dispenser, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter) + hoodtype = /obj/item/clothing/head/hooded/winterhood/ce + +/obj/item/clothing/head/hooded/winterhood/ce + icon_state = "winterhood_ce" + /obj/item/clothing/suit/hooded/wintercoat/engineering name = "engineering winter coat" icon_state = "coatengineer" @@ -585,6 +685,26 @@ /obj/item/clothing/head/hooded/winterhood/hydro icon_state = "winterhood_hydro" +/obj/item/clothing/suit/hooded/wintercoat/cosmic + name = "cosmic winter coat" + icon_state = "coatcosmic" + item_state = "coatcosmic" + allowed = list(/obj/item/flashlight) + hoodtype = /obj/item/clothing/head/hooded/winterhood/cosmic + +/obj/item/clothing/head/hooded/winterhood/cosmic + icon_state = "winterhood_cosmic" + +/obj/item/clothing/suit/hooded/wintercoat/janitor + name = "janitors winter coat" + icon_state = "coatjanitor" + item_state = "coatjanitor" + allowed = list(/obj/item/toy, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/storage/fancy/cigarettes, /obj/item/lighter,/obj/item/grenade/chem_grenade,/obj/item/lightreplacer,/obj/item/flashlight,/obj/item/reagent_containers/glass/beaker,/obj/item/reagent_containers/glass/bottle,/obj/item/reagent_containers/spray,/obj/item/soap,/obj/item/holosign_creator,/obj/item/key/janitor,/obj/item/melee/flyswatter,/obj/item/paint/paint_remover,/obj/item/storage/bag/trash,/obj/item/reagent_containers/glass/bucket) + hoodtype = /obj/item/clothing/head/hooded/winterhood/janitor + +/obj/item/clothing/head/hooded/winterhood/janitor + icon_state = "winterhood_janitor" + /obj/item/clothing/suit/hooded/wintercoat/cargo name = "cargo winter coat" icon_state = "coatcargo" @@ -594,6 +714,15 @@ /obj/item/clothing/head/hooded/winterhood/cargo icon_state = "winterhood_cargo" +/obj/item/clothing/suit/hooded/wintercoat/qm + name = "quartermaster's winter coat" + icon_state = "coatqm" + item_state = "coatqm" + hoodtype = /obj/item/clothing/head/hooded/winterhood/qm + +/obj/item/clothing/head/hooded/winterhood/qm + icon_state = "winterhood_qm" + /obj/item/clothing/suit/hooded/wintercoat/miner name = "mining winter coat" icon_state = "coatminer" @@ -636,7 +765,7 @@ /obj/item/clothing/suit/assu_suit name = "DAB suit" - desc = "A cheap replica of old SWAT armor. On its back, it is written: \"Desperate Assistance Battle-force\"." + desc = "A cheap replica of old SWAT armor. On its back, it is written: \"Desperate Assistance Battleforce\"." icon_state = "assu_suit" item_state = "assu_suit" blood_overlay_type = "armor" diff --git a/code/modules/crafting/recipes/recipes_clothing.dm b/code/modules/crafting/recipes/recipes_clothing.dm index f48ee87316..4f06a44811 100644 --- a/code/modules/crafting/recipes/recipes_clothing.dm +++ b/code/modules/crafting/recipes/recipes_clothing.dm @@ -158,3 +158,31 @@ time = 50 always_availible = TRUE category = CAT_CLOTHING + +/datum/crafting_recipe/wintercoat_cosmic + name = "Cosmic Winter Coat" + result = /obj/item/clothing/suit/hooded/wintercoat/cosmic + reqs = list(/obj/item/clothing/suit/hooded/wintercoat = 1, + /obj/item/clothing/suit/hooded/wintercoat/captain = 1, + /obj/item/clothing/suit/hooded/wintercoat/hop = 1, + /obj/item/clothing/suit/hooded/wintercoat/hos = 1, + /obj/item/clothing/suit/hooded/wintercoat/rd = 1, + /obj/item/clothing/suit/hooded/wintercoat/ce = 1, + /obj/item/clothing/suit/hooded/wintercoat/cmo = 1, + /obj/item/clothing/suit/hooded/wintercoat/qm = 1, + /obj/item/clothing/suit/hooded/wintercoat/robotics = 1, + /obj/item/clothing/suit/hooded/wintercoat/engineering/atmos = 1, + /obj/item/clothing/suit/hooded/wintercoat/engineering = 1, + /obj/item/clothing/suit/hooded/wintercoat/science = 1, + /obj/item/clothing/suit/hooded/wintercoat/genetics = 1, + /obj/item/clothing/suit/hooded/wintercoat/chemistry = 1, + /obj/item/clothing/suit/hooded/wintercoat/medical = 1, + /obj/item/clothing/suit/hooded/wintercoat/viro = 1, + /obj/item/clothing/suit/hooded/wintercoat/janitor = 1, + /obj/item/clothing/suit/hooded/wintercoat/security = 1, + /obj/item/clothing/suit/hooded/wintercoat/cargo = 1, + /obj/item/clothing/suit/hooded/wintercoat/hydro = 1, + /obj/item/clothing/suit/hooded/wintercoat/miner = 1) + time = 60 + always_availible = TRUE + category = CAT_CLOTHING diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index 23f06e8965..815f640fde 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -34,6 +34,7 @@ /datum/round_event_control/wizard wizardevent = 1 + var/can_be_midround_wizard = TRUE // Checks if the event can be spawned. Used by event controller and "false alarm" event. // Admin-created events override this. @@ -54,6 +55,13 @@ return FALSE return TRUE +/datum/round_event_control/wizard/canSpawnEvent(var/players_amt, var/gamemode) + if(istype(SSticker.mode, /datum/game_mode/dynamic)) + var/var/datum/game_mode/dynamic/mode = SSticker.mode + if (locate(/datum/dynamic_ruleset/midround/from_ghosts/wizard) in mode.executed_rules) + return can_be_midround_wizard && ..() + return ..() + /datum/round_event_control/proc/preRunEvent() if(!ispath(typepath, /datum/round_event)) return EVENT_CANT_RUN diff --git a/code/modules/events/abductor.dm b/code/modules/events/abductor.dm index aee49abcc0..25a5cb2ffa 100755 --- a/code/modules/events/abductor.dm +++ b/code/modules/events/abductor.dm @@ -4,7 +4,7 @@ weight = 10 max_occurrences = 1 min_players = 20 - gamemode_blacklist = list("nuclear","wizard","revolution") + gamemode_blacklist = list("nuclear","wizard","revolution","dynamic") /datum/round_event/ghost_role/abductor minimum_required = 2 diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm index 762371886c..69e9a974eb 100644 --- a/code/modules/events/alien_infestation.dm +++ b/code/modules/events/alien_infestation.dm @@ -2,7 +2,7 @@ name = "Alien Infestation" typepath = /datum/round_event/ghost_role/alien_infestation weight = 5 - + gamemode_blacklist = list("dynamic") min_players = 10 max_occurrences = 1 diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm index 8d4c5af540..275cfaf63d 100644 --- a/code/modules/events/anomaly_bluespace.dm +++ b/code/modules/events/anomaly_bluespace.dm @@ -3,6 +3,7 @@ typepath = /datum/round_event/anomaly/anomaly_bluespace max_occurrences = 1 weight = 5 + gamemode_blacklist = list("dynamic") /datum/round_event/anomaly/anomaly_bluespace startWhen = 3 diff --git a/code/modules/events/anomaly_flux.dm b/code/modules/events/anomaly_flux.dm index 00516fcb5c..289bc9526d 100644 --- a/code/modules/events/anomaly_flux.dm +++ b/code/modules/events/anomaly_flux.dm @@ -5,6 +5,7 @@ min_players = 10 max_occurrences = 5 weight = 20 + gamemode_blacklist = list("dynamic") /datum/round_event/anomaly/anomaly_flux startWhen = 10 diff --git a/code/modules/events/anomaly_grav.dm b/code/modules/events/anomaly_grav.dm index 7761d02ec8..729ee7e32b 100644 --- a/code/modules/events/anomaly_grav.dm +++ b/code/modules/events/anomaly_grav.dm @@ -3,6 +3,8 @@ typepath = /datum/round_event/anomaly/anomaly_grav max_occurrences = 5 weight = 20 + gamemode_blacklist = list("dynamic") + /datum/round_event/anomaly/anomaly_grav startWhen = 3 diff --git a/code/modules/events/anomaly_pyro.dm b/code/modules/events/anomaly_pyro.dm index 13137741cc..9594727784 100644 --- a/code/modules/events/anomaly_pyro.dm +++ b/code/modules/events/anomaly_pyro.dm @@ -3,6 +3,7 @@ typepath = /datum/round_event/anomaly/anomaly_pyro max_occurrences = 5 weight = 20 + gamemode_blacklist = list("dynamic") /datum/round_event/anomaly/anomaly_pyro startWhen = 3 diff --git a/code/modules/events/anomaly_vortex.dm b/code/modules/events/anomaly_vortex.dm index 7646f3e072..ef0d7a8af1 100644 --- a/code/modules/events/anomaly_vortex.dm +++ b/code/modules/events/anomaly_vortex.dm @@ -5,6 +5,7 @@ min_players = 20 max_occurrences = 2 weight = 5 + gamemode_blacklist = list("dynamic") /datum/round_event/anomaly/anomaly_vortex startWhen = 10 diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm index d72c80686d..55691cc833 100644 --- a/code/modules/events/blob.dm +++ b/code/modules/events/blob.dm @@ -7,7 +7,7 @@ earliest_start = 40 MINUTES min_players = 35 - gamemode_blacklist = list("blob") //Just in case a blob survives that long + gamemode_blacklist = list("blob","dynamic") //Just in case a blob survives that long /datum/round_event/ghost_role/blob announceWhen = -1 diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index 30b59bf14a..85097684d0 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -5,6 +5,7 @@ min_players = 15 max_occurrences = 1 + gamemode_blacklist = list("dynamic") /datum/round_event/brand_intelligence announceWhen = 21 diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index 5940acad2f..f5b3fbb9f7 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -5,6 +5,7 @@ min_players = 2 earliest_start = 10 MINUTES max_occurrences = 6 + gamemode_blacklist = list("dynamic") /datum/round_event/carp_migration announceWhen = 3 diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm index da4eff9f39..ccd519b7e1 100644 --- a/code/modules/events/communications_blackout.dm +++ b/code/modules/events/communications_blackout.dm @@ -2,6 +2,7 @@ name = "Communications Blackout" typepath = /datum/round_event/communications_blackout weight = 30 + gamemode_blacklist = list("dynamic") /datum/round_event/communications_blackout announceWhen = 1 diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm index c22f8cc0d7..090dc95cd6 100644 --- a/code/modules/events/dust.dm +++ b/code/modules/events/dust.dm @@ -5,6 +5,7 @@ max_occurrences = 1000 earliest_start = 0 MINUTES alertadmins = 0 + gamemode_blacklist = list("dynamic") /datum/round_event/space_dust startWhen = 1 diff --git a/code/modules/events/electrical_storm.dm b/code/modules/events/electrical_storm.dm index 9845832c30..c4c144dc9a 100644 --- a/code/modules/events/electrical_storm.dm +++ b/code/modules/events/electrical_storm.dm @@ -5,6 +5,7 @@ min_players = 5 weight = 40 alertadmins = 0 + gamemode_blacklist = list("dynamic") /datum/round_event/electrical_storm var/lightsoutAmount = 1 diff --git a/code/modules/events/heart_attack.dm b/code/modules/events/heart_attack.dm index 7f9c09dfd9..8db2d98bf0 100644 --- a/code/modules/events/heart_attack.dm +++ b/code/modules/events/heart_attack.dm @@ -4,6 +4,7 @@ weight = 20 max_occurrences = 2 min_players = 40 // To avoid shafting lowpop + gamemode_blacklist = list("dynamic") /datum/round_event/heart_attack/start() var/list/heart_attack_contestants = list() diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index cd7c0e3b1f..40364483bf 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -3,6 +3,7 @@ /datum/round_event_control/ion_storm name = "Ion Storm" typepath = /datum/round_event/ion_storm + gamemode_blacklist = list("dynamic") weight = 15 min_players = 2 diff --git a/code/modules/events/major_dust.dm b/code/modules/events/major_dust.dm index d7d8f1aec8..c594d7b3c0 100644 --- a/code/modules/events/major_dust.dm +++ b/code/modules/events/major_dust.dm @@ -2,6 +2,7 @@ name = "Major Space Dust" typepath = /datum/round_event/meteor_wave/major_dust weight = 8 + gamemode_blacklist = list("dynamic") /datum/round_event/meteor_wave/major_dust wave_name = "space dust" diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm index 31ea9dcb03..26591547c0 100644 --- a/code/modules/events/meteor_wave.dm +++ b/code/modules/events/meteor_wave.dm @@ -10,6 +10,7 @@ min_players = 15 max_occurrences = 3 earliest_start = 25 MINUTES + gamemode_blacklist = list("dynamic") /datum/round_event/meteor_wave startWhen = 6 diff --git a/code/modules/events/nightmare.dm b/code/modules/events/nightmare.dm index 698f5130f1..6e5512a617 100644 --- a/code/modules/events/nightmare.dm +++ b/code/modules/events/nightmare.dm @@ -2,6 +2,7 @@ name = "Spawn Nightmare" typepath = /datum/round_event/ghost_role/nightmare max_occurrences = 1 + gamemode_blacklist = list("dynamic") min_players = 20 /datum/round_event/ghost_role/nightmare diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index cd02a06f59..8bc5491970 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -5,7 +5,7 @@ max_occurrences = 1 min_players = 10 earliest_start = 30 MINUTES - gamemode_blacklist = list("nuclear") + gamemode_blacklist = list("nuclear","dynamic") /datum/round_event_control/pirates/preRunEvent() if (!SSmapping.empty_space) diff --git a/code/modules/events/processor_overload.dm b/code/modules/events/processor_overload.dm index 74d9bb273e..67848bf941 100644 --- a/code/modules/events/processor_overload.dm +++ b/code/modules/events/processor_overload.dm @@ -3,6 +3,7 @@ typepath = /datum/round_event/processor_overload weight = 15 min_players = 20 + gamemode_blacklist = list("dynamic") /datum/round_event/processor_overload announceWhen = 1 diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index 60e4e0e4b8..705eea5409 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -2,6 +2,7 @@ name = "Radiation Storm" typepath = /datum/round_event/radiation_storm max_occurrences = 1 + gamemode_blacklist = list("dynamic") /datum/round_event/radiation_storm diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm index a6c333145e..8c6b3e23a5 100644 --- a/code/modules/events/spider_infestation.dm +++ b/code/modules/events/spider_infestation.dm @@ -2,6 +2,7 @@ name = "Spider Infestation" typepath = /datum/round_event/spider_infestation weight = 5 + gamemode_blacklist = list("dynamic") max_occurrences = 1 min_players = 15 diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm index 0deb880674..79487a024c 100644 --- a/code/modules/events/vent_clog.dm +++ b/code/modules/events/vent_clog.dm @@ -3,6 +3,7 @@ typepath = /datum/round_event/vent_clog weight = 10 max_occurrences = 3 + gamemode_blacklist = list("dynamic") min_players = 25 /datum/round_event/vent_clog diff --git a/code/modules/events/wizard/curseditems.dm b/code/modules/events/wizard/curseditems.dm index 41ee4246b1..2f0b9c68f8 100644 --- a/code/modules/events/wizard/curseditems.dm +++ b/code/modules/events/wizard/curseditems.dm @@ -4,6 +4,7 @@ typepath = /datum/round_event/wizard/cursed_items max_occurrences = 3 earliest_start = 0 MINUTES + can_be_midround_wizard = FALSE //Note about adding items to this: Because of how NODROP_1 works if an item spawned to the hands can also be equiped to a slot //it will be able to be put into that slot from the hand, but then get stuck there. To avoid this make a new subtype of any diff --git a/code/modules/events/wizard/departmentrevolt.dm b/code/modules/events/wizard/departmentrevolt.dm index f37b7470fb..67e96455f0 100644 --- a/code/modules/events/wizard/departmentrevolt.dm +++ b/code/modules/events/wizard/departmentrevolt.dm @@ -4,6 +4,7 @@ typepath = /datum/round_event/wizard/deprevolt max_occurrences = 1 earliest_start = 0 MINUTES + can_be_midround_wizard = FALSE // not removing it completely yet /datum/round_event/wizard/deprevolt/start() diff --git a/code/modules/events/wizard/race.dm b/code/modules/events/wizard/race.dm index 7ea875f152..2aeb200c88 100644 --- a/code/modules/events/wizard/race.dm +++ b/code/modules/events/wizard/race.dm @@ -4,6 +4,7 @@ typepath = /datum/round_event/wizard/race max_occurrences = 5 earliest_start = 0 MINUTES + can_be_midround_wizard = FALSE /datum/round_event/wizard/race var/list/stored_name diff --git a/code/modules/events/wizard/shuffle.dm b/code/modules/events/wizard/shuffle.dm index 7e37429223..3b5ea6b20a 100644 --- a/code/modules/events/wizard/shuffle.dm +++ b/code/modules/events/wizard/shuffle.dm @@ -7,6 +7,7 @@ typepath = /datum/round_event/wizard/shuffleloc max_occurrences = 5 earliest_start = 0 MINUTES + can_be_midround_wizard = FALSE // not removing it completely yet /datum/round_event/wizard/shuffleloc/start() var/list/moblocs = list() @@ -43,6 +44,7 @@ typepath = /datum/round_event/wizard/shufflenames max_occurrences = 5 earliest_start = 0 MINUTES + can_be_midround_wizard = FALSE // not removing it completely yet /datum/round_event/wizard/shufflenames/start() var/list/mobnames = list() @@ -77,6 +79,7 @@ typepath = /datum/round_event/wizard/shuffleminds max_occurrences = 3 earliest_start = 0 MINUTES + can_be_midround_wizard = FALSE // not removing it completely yet /datum/round_event/wizard/shuffleminds/start() var/list/mobs = list() diff --git a/code/modules/events/wizard/summons.dm b/code/modules/events/wizard/summons.dm index 544a5c7cb3..ac1160e0f5 100644 --- a/code/modules/events/wizard/summons.dm +++ b/code/modules/events/wizard/summons.dm @@ -4,6 +4,7 @@ typepath = /datum/round_event/wizard/summonguns max_occurrences = 1 earliest_start = 0 MINUTES + can_be_midround_wizard = FALSE // not removing it completely yet /datum/round_event_control/wizard/summonguns/New() if(CONFIG_GET(flag/no_summon_guns)) @@ -19,6 +20,7 @@ typepath = /datum/round_event/wizard/summonmagic max_occurrences = 1 earliest_start = 0 MINUTES + can_be_midround_wizard = FALSE // not removing it completely yet /datum/round_event_control/wizard/summonmagic/New() if(CONFIG_GET(flag/no_summon_magic)) diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index 9d075857a7..9dd016c235 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -546,3 +546,10 @@ Since Ramadan is an entire month that lasts 29.5 days on average, the start and /datum/holiday/easter/getStationPrefix() return pick("Fluffy","Bunny","Easter","Egg") + +//Random citadel thing for halloween species +/proc/force_enable_halloween_species() + var/list/oldlist = SSevents.holidays + SSevents.holidays = list(HALLOWEEN = new /datum/holiday/halloween) + generate_selectable_species(FALSE) + SSevents.holidays = oldlist diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm index a4c89b8874..3574f8a9c1 100644 --- a/code/modules/holodeck/turfs.dm +++ b/code/modules/holodeck/turfs.dm @@ -21,7 +21,7 @@ /turf/open/floor/holofloor/plating/burnmix name = "burn-mix floor" - initial_gas_mix = "o2=2500;plasma=5000;TEMP=370" + initial_gas_mix = BURNMIX_ATMOS /turf/open/floor/holofloor/grass gender = PLURAL diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index 6100641bde..81f47b9a1e 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -35,6 +35,12 @@ /obj/item/proc/GetID() return null +/obj/item/proc/RemoveID() + return null + +/obj/item/proc/InsertID() + return FALSE + /obj/proc/text2access(access_text) . = list() if(!access_text) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index a52b8589c3..507c8a5026 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -101,8 +101,9 @@ //Equip the rest of the gear H.dna.species.before_equip_job(src, H, visualsOnly) - if(outfit_override || outfit) - H.equipOutfit(outfit_override ? outfit_override : outfit, visualsOnly) + var/datum/outfit/job/O = outfit_override || outfit + if(O) + H.equipOutfit(O, visualsOnly, preference_source) //mob doesn't have a client yet. H.dna.species.after_equip_job(src, H, visualsOnly) @@ -177,8 +178,8 @@ var/pda_slot = SLOT_BELT -/datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - switch(H.backbag) +/datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) + switch(preference_source?.prefs.backbag) if(GBACKPACK) back = /obj/item/storage/backpack //Grey backpack if(GSATCHEL) @@ -196,7 +197,7 @@ //converts the uniform string into the path we'll wear, whether it's the skirt or regular variant var/holder - if(H.jumpsuit_style == PREF_SKIRT) + if(preference_source && preference_source.prefs.jumpsuit_style == PREF_SKIRT) holder = "[uniform]/skirt" if(!text2path(holder)) holder = "[uniform]" @@ -204,7 +205,7 @@ holder = "[uniform]" uniform = text2path(holder) -/datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(visualsOnly) return @@ -232,6 +233,8 @@ PDA.owner = H.real_name PDA.ownjob = J.title PDA.update_label() + if(preference_source && !PDA.equipped) //PDA's screen color, font style and look depend on client preferences. + PDA.update_style(preference_source) /datum/outfit/job/get_chameleon_disguise_info() var/list/types = ..() diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm index da8c2aa3b9..ce2dce9053 100644 --- a/code/modules/jobs/job_types/assistant.dm +++ b/code/modules/jobs/job_types/assistant.dm @@ -28,15 +28,16 @@ Assistant name = "Assistant" jobtype = /datum/job/assistant -/datum/outfit/job/assistant/pre_equip(mob/living/carbon/human/H) +/datum/outfit/job/assistant/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() + var/suited = !preference_source || preference_source.prefs.jumpsuit_style == PREF_SUIT if (CONFIG_GET(flag/grey_assistants)) - if(H.jumpsuit_style == PREF_SUIT) + if(suited) uniform = /obj/item/clothing/under/color/grey else uniform = /obj/item/clothing/under/skirt/color/grey else - if(H.jumpsuit_style == PREF_SUIT) + if(suited) uniform = /obj/item/clothing/under/color/random else uniform = /obj/item/clothing/under/skirt/color/random diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm index d8b88ae871..922b335a39 100644 --- a/code/modules/jobs/job_types/clown.dm +++ b/code/modules/jobs/job_types/clown.dm @@ -16,11 +16,6 @@ display_order = JOB_DISPLAY_ORDER_CLOWN - -/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M) - . = ..() - H.apply_pref_name("clown", M.client) - /datum/outfit/job/clown name = "Clown" jobtype = /datum/job/clown @@ -48,11 +43,15 @@ chameleon_extras = /obj/item/stamp/clown -/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) return - H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names)) //rename the mob AFTER they're equipped so their ID gets updated properly. + var/client/C = H.client || preference_source + if(C) + H.apply_pref_name("clown", C) //rename the mob AFTER they're equipped so their ID gets updated properly. + else + H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names)) H.dna.add_mutation(CLOWNMUT) H.dna.add_mutation(SMILE) diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm index c213d4dffc..b5def54061 100644 --- a/code/modules/jobs/job_types/cook.dm +++ b/code/modules/jobs/job_types/cook.dm @@ -29,7 +29,7 @@ mask = /obj/item/clothing/mask/fakemoustache/italian backpack_contents = list(/obj/item/sharpener = 1) -/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() var/datum/job/cook/J = SSjob.GetJobType(jobtype) if(J) // Fix for runtime caused by invalid job being passed @@ -39,7 +39,7 @@ if(!visualsOnly) J.cooks++ -/datum/outfit/job/cook/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/cook/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) return diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm index 35fa8483d5..0c762637ac 100644 --- a/code/modules/jobs/job_types/curator.dm +++ b/code/modules/jobs/job_types/curator.dm @@ -34,7 +34,7 @@ /obj/item/barcodescanner = 1 ) -/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm index 27a54fbd1f..13cb5e01e3 100644 --- a/code/modules/jobs/job_types/detective.dm +++ b/code/modules/jobs/job_types/detective.dm @@ -46,7 +46,7 @@ chameleon_extras = list(/obj/item/gun/ballistic/revolver/detective, /obj/item/clothing/glasses/sunglasses) -/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() var/obj/item/clothing/mask/cigarette/cig = H.wear_mask if(istype(cig)) //Some species specfic changes can mess this up (plasmamen) diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm index 0b8be52116..654af6a05d 100644 --- a/code/modules/jobs/job_types/lawyer.dm +++ b/code/modules/jobs/job_types/lawyer.dm @@ -35,7 +35,7 @@ chameleon_extras = /obj/item/stamp/law -/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) return diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm index 1347da7125..4e6e982fb9 100644 --- a/code/modules/jobs/job_types/mime.dm +++ b/code/modules/jobs/job_types/mime.dm @@ -36,7 +36,7 @@ satchel = /obj/item/storage/backpack/mime -/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) @@ -47,3 +47,9 @@ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null)) H.mind.miming = 1 + var/client/C = H.client || preference_source + if(C) + H.apply_pref_name("mime", C) + else + H.fully_replace_character_name(H.real_name, pick(GLOB.mime_names)) + diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm index 771fc02862..915e9d1cea 100644 --- a/code/modules/jobs/job_types/shaft_miner.dm +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -64,7 +64,7 @@ /obj/item/gun/energy/kinetic_accelerator=1,\ /obj/item/stack/marker_beacon/ten=1) -/datum/outfit/job/miner/equipped/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/miner/equipped/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) ..() if(visualsOnly) return diff --git a/code/modules/keybindings/bindings_human.dm b/code/modules/keybindings/bindings_human.dm index 38870c3840..a9eafacef6 100644 --- a/code/modules/keybindings/bindings_human.dm +++ b/code/modules/keybindings/bindings_human.dm @@ -1,7 +1,4 @@ /mob/living/carbon/human/key_down(_key, client/user) - if("Shift") - sprint_hotkey(TRUE) - return if(client.keys_held["Shift"]) switch(_key) if("E") // Put held thing in belt or take out most recent thing from belt @@ -59,6 +56,10 @@ return stored.attack_hand(src) // take out thing from backpack return + switch(_key) + if("Shift") + sprint_hotkey(TRUE) + return return ..() /mob/living/carbon/human/key_up(_key, client/user) diff --git a/code/modules/mining/aux_base_camera.dm b/code/modules/mining/aux_base_camera.dm index d901e1eb0c..d461523744 100644 --- a/code/modules/mining/aux_base_camera.dm +++ b/code/modules/mining/aux_base_camera.dm @@ -25,7 +25,6 @@ max_matter = 600 //Bigger container and faster speeds due to being specialized and stationary. no_ammo_message = "Internal matter exhausted. Please add additional materials." delay_mod = 0.5 - adjacency_check = FALSE upgrade = TRUE var/obj/machinery/computer/camera_advanced/base_construction/console @@ -207,19 +206,14 @@ to_chat(owner, "Build mode is now [buildmode].") /datum/action/innate/aux_base/airlock_type - name = "Change Airlock Settings" + name = "Select Airlock Type" button_icon_state = "airlock_select" /datum/action/innate/aux_base/airlock_type/Activate() if(..()) return - var/mode = alert("Modify Type or Access?", "Airlock Settings", "Type", "Access", "None") - switch(mode) - if("Type") - B.RCD.change_airlock_setting(usr) - if("Access") - B.RCD.change_airlock_access(usr) + B.RCD.change_airlock_access(usr) /datum/action/innate/aux_base/window_type diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index ab8aa3e2fd..7a311c6f18 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -63,8 +63,7 @@ /obj/item/twohanded/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user) if(!wielded) - to_chat(user, "[src] is too heavy to use with one hand. You fumble and drop everything.") - user.drop_all_held_items() + to_chat(user, "[src] is too heavy to use with one hand.") return var/datum/status_effect/crusher_damage/C = target.has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) var/target_health = target.health diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index 8de5f76a56..950ae7dda1 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -37,6 +37,9 @@ new /obj/item/clothing/gloves/color/black(src) new /obj/item/clothing/gloves/color/black(src) new /obj/item/clothing/gloves/color/black(src) + new /obj/item/clothing/suit/hooded/wintercoat/miner(src) //yes, even both mining locker types + new /obj/item/clothing/suit/hooded/wintercoat/miner(src) + new /obj/item/clothing/suit/hooded/wintercoat/miner(src) /obj/structure/closet/secure_closet/miner name = "miner's equipment" @@ -61,6 +64,7 @@ new /obj/item/clothing/glasses/meson(src) new /obj/item/survivalcapsule(src) new /obj/item/assault_pod/mining(src) + new /obj/item/clothing/suit/hooded/wintercoat/miner(src) //because you know you want it /**********************Shuttle Computer**************************/ diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 4d253a4693..d789fc6f5a 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -473,10 +473,7 @@ var/free_space = 0 for(var/list/category in list(GLOB.command_positions) + list(GLOB.supply_positions) + list(GLOB.engineering_positions) + list(GLOB.nonhuman_positions - "pAI") + list(GLOB.civilian_positions) + list(GLOB.medical_positions) + list(GLOB.science_positions) + list(GLOB.security_positions)) var/cat_color = "fff" //random default - if(SSjob.name_occupations && SSjob.name_occupations[category[1]]) - cat_color = SSjob.name_occupations[category[1]].selection_color //use the color of the first job in the category (the department head) as the category color - else - cat_color = SSjob.occupations[category[1]].selection_color + cat_color = SSjob.name_occupations[category[1]].selection_color //use the color of the first job in the category (the department head) as the category color dat += "
    " dat += "[SSjob.name_occupations[category[1]].exp_type_department]" diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index b323f13362..8ea295c6c4 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -306,7 +306,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(stat == DEAD) ghostize(1) else - var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty != CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body") + var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty == CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body") if(response != "Ghost") return //didn't want to ghost after-all if(istype(loc, /obj/machinery/cryopod)) @@ -331,7 +331,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(penalty + world.realtime - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime) penalty = CANT_REENTER_ROUND - var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty != CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body") + var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty == CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body") if(response != "Ghost") return ghostize(0, penalize = TRUE) @@ -629,8 +629,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Possess!" set desc= "Take over the body of a mindless creature!" - if(reenter_round_timeout > world.realtime) - to_chat(src, "You are unable to re-enter the round yet. Your ghost role blacklist will expire in [DisplayTimeText(reenter_round_timeout - world.realtime)].") + if(!can_reenter_round()) return FALSE var/list/possessible = list() diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm index 1b2944c1f6..37dd7b6a31 100644 --- a/code/modules/mob/living/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -5,6 +5,7 @@ var/datum/dna/stored/stored_dna // dna var for brain. Used to store dna, brain dna is not considered like actual dna, brain.has_dna() returns FALSE. stat = DEAD //we start dead by default see_invisible = SEE_INVISIBLE_LIVING + possible_a_intents = list(INTENT_HELP, INTENT_HARM) //for mechas speech_span = SPAN_ROBOT /mob/living/brain/Initialize() @@ -72,10 +73,9 @@ /mob/living/brain/ClickOn(atom/A, params) ..() - if(istype(loc, /obj/item/mmi)) - var/obj/item/mmi/MMI = loc - var/obj/mecha/M = MMI.mecha - if((src == MMI.brainmob) && istype(M)) + if(container) + var/obj/mecha/M = container.mecha + if(istype(M)) return M.click_action(A,src,params) /mob/living/brain/forceMove(atom/destination) @@ -90,3 +90,16 @@ doMove(destination) else CRASH("Brainmob without a container [src] attempted to move to [destination].") + +/mob/living/brain/update_mouse_pointer() + if (!client) + return + client.mouse_pointer_icon = initial(client.mouse_pointer_icon) + if(!container) + return + if (container.mecha) + var/obj/mecha/M = container.mecha + if(M.mouse_pointer) + client.mouse_pointer_icon = M.mouse_pointer + if (client && ranged_ability && ranged_ability.ranged_mousepointer) + client.mouse_pointer_icon = ranged_ability.ranged_mousepointer diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index f2b02b81fb..23ccc665b6 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -170,6 +170,7 @@ stop_pulling() if(HAS_TRAIT(src, TRAIT_PACIFISM)) to_chat(src, "You gently let go of [throwable_mob].") + return adjustStaminaLossBuffered(25)//CIT CHANGE - throwing an entire person shall be very tiring var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors var/turf/end_T = get_turf(target) diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm index 7d1e5320fc..a8a69be0f1 100644 --- a/code/modules/mob/living/carbon/damage_procs.dm +++ b/code/modules/mob/living/carbon/damage_procs.dm @@ -43,7 +43,7 @@ adjustStaminaLoss(damage_amount, forced = forced) //citadel code if(AROUSAL) - adjustArousalLoss(damage_amount, forced = forced) + adjustArousalLoss(damage_amount) return TRUE diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 96cc79261d..a09af656f5 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -54,11 +54,16 @@ /mob/living/carbon/human/proc/makeSkeleton() ADD_TRAIT(src, TRAIT_DISFIGURED, TRAIT_GENERIC) set_species(/datum/species/skeleton) - return 1 + return TRUE /mob/living/carbon/proc/Drain() become_husk(CHANGELING_DRAIN) ADD_TRAIT(src, TRAIT_NOCLONE, CHANGELING_DRAIN) blood_volume = 0 - return 1 + return TRUE + +/mob/living/carbon/proc/makeUncloneable() + ADD_TRAIT(src, TRAIT_NOCLONE, MADE_UNCLONEABLE) + blood_volume = 0 + return TRUE \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index a737844f10..9eab9054f5 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -32,7 +32,7 @@ if(CONFIG_GET(flag/disable_stambuffer)) togglesprint() - RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /mob/living/carbon/human/clean_blood) + RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood) /mob/living/carbon/human/ComponentInitialize() @@ -574,7 +574,7 @@ return threatcount //Check for ID - var/obj/item/card/id/idcard = get_idcard() + var/obj/item/card/id/idcard = get_idcard(FALSE) if( (judgement_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown") threatcount += 4 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 2ab7c6d404..327ad6760c 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -339,8 +339,10 @@ apply_damage(damage, BRUTE, affecting, armor_block) /mob/living/carbon/human/mech_melee_attack(obj/mecha/M) - if(M.occupant.a_intent == INTENT_HARM) + if(HAS_TRAIT(M.occupant, TRAIT_PACIFISM)) + to_chat(M.occupant, "You don't want to harm other living beings!") + return M.do_attack_animation(src) if(M.damtype == "brute") step_away(src,M,15) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index b1f11f6463..9ffa994066 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -34,8 +34,6 @@ var/shirt_color = "FFFFFF" var/socks = "Nude" //Which socks the player wants var/socks_color = "FFFFFF" - var/backbag = DBACKPACK //Which backpack type the player has chosen. - var/jumpsuit_style = PREF_SUIT //suit/skirt //Equipment slots var/obj/item/wear_suit = null diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 8bc8866380..8071d632ea 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -11,8 +11,8 @@ //gets assignment from ID or ID inside PDA or PDA itself //Useful when player do something with computers -/mob/living/carbon/human/proc/get_assignment(if_no_id = "No id", if_no_job = "No job") - var/obj/item/card/id/id = get_idcard() +/mob/living/carbon/human/proc/get_assignment(if_no_id = "No id", if_no_job = "No job", hand_first = TRUE) + var/obj/item/card/id/id = get_idcard(hand_first) if(id) . = id.assignment else @@ -27,7 +27,7 @@ //gets name from ID or ID inside PDA or PDA itself //Useful when player do something with computers /mob/living/carbon/human/proc/get_authentification_name(if_no_id = "Unknown") - var/obj/item/card/id/id = get_idcard() + var/obj/item/card/id/id = get_idcard(FALSE) if(id) return id.registered_name var/obj/item/pda/pda = wear_id @@ -86,10 +86,15 @@ return //gets ID card object from special clothes slot or null. -/mob/living/carbon/human/get_idcard() - if(wear_id) - return wear_id.GetID() - +/mob/living/carbon/human/get_idcard(hand_first = TRUE) + . = ..() + if(. && hand_first) + return + //Check inventory slots + var/obj/item/card/id/id_card = wear_id?.GetID() + if(!id_card) + id_card = belt?.GetID() + return id_card || . /mob/living/carbon/human/IsAdvancedToolUser() if(HAS_TRAIT(src, TRAIT_MONKEYLIKE)) @@ -100,7 +105,6 @@ return dna.species.handle_chemicals(R,src) // if it returns 0, it will run the usual on_mob_life for that reagent. otherwise, it will stop after running handle_chemicals for the species. - /mob/living/carbon/human/can_track(mob/living/user) if(wear_id && istype(wear_id.GetID(), /obj/item/card/id/syndicate)) return 0 diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 084dbd83ef..26703977d2 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -251,7 +251,7 @@ sec_hud_set_security_status() ..() -/mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE) +/mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE, client/preference_source) var/datum/outfit/O = null if(ispath(outfit)) @@ -263,7 +263,7 @@ if(!O) return 0 - return O.equip(src, visualsOnly) + return O.equip(src, visualsOnly, preference_source) //delete all equipment without dropping anything diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 49ae178d8c..7ff4f355d5 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -118,11 +118,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) ..() -/proc/generate_selectable_species() +/proc/generate_selectable_species(clear = FALSE) + if(clear) + GLOB.roundstart_races = list() + GLOB.roundstart_race_names = list() for(var/I in subtypesof(/datum/species)) var/datum/species/S = new I if(S.check_roundstart_eligible()) - GLOB.roundstart_races += S.id + GLOB.roundstart_races |= S.id GLOB.roundstart_race_names["[S.name]"] = S.id qdel(S) if(!GLOB.roundstart_races.len) @@ -1476,7 +1479,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) /datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) - if(HAS_TRAIT(user, TRAIT_PACIFISM)) + if(!attacker_style && HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm [target]!") return FALSE if(user.getStaminaLoss() >= STAMINA_SOFTCRIT) //CITADEL CHANGE - makes it impossible to punch while in stamina softcrit @@ -1678,6 +1681,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) return if(M.mind) attacker_style = M.mind.martial_art + if(attacker_style?.pacifism_check && HAS_TRAIT(M, TRAIT_PACIFISM)) // most martial arts are quite harmful, alas. + attacker_style = null if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK)) log_combat(M, H, "attempted to touch") H.visible_message("[M] attempted to touch [H]!") diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index cfc8351d76..ae69d5dc90 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -336,7 +336,7 @@ There are several things that need to be remembered: if(!t_state) t_state = s_store.icon_state overlays_standing[SUIT_STORE_LAYER] = mutable_appearance(((s_store.alternate_worn_icon) ? s_store.alternate_worn_icon : 'icons/mob/belt_mirror.dmi'), t_state, -SUIT_STORE_LAYER) - var/mutable_appearance/s_store_overlay = overlays_standing[SUIT_LAYER] + var/mutable_appearance/s_store_overlay = overlays_standing[SUIT_STORE_LAYER] if(OFFSET_S_STORE in dna.species.offset_features) s_store_overlay.pixel_x += dna.species.offset_features[OFFSET_S_STORE][1] s_store_overlay.pixel_y += dna.species.offset_features[OFFSET_S_STORE][2] diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index ca139cace7..3c587a05dd 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -98,7 +98,7 @@ var/datum/gas_mixture/breath if(!getorganslot(ORGAN_SLOT_BREATHING_TUBE)) - if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL) || !lungs || lungs.organ_flags & ORGAN_FAILING) + if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL) || (lungs && lungs.organ_flags & ORGAN_FAILING)) losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath else if(health <= crit_threshold) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 93e64fd4cc..722c984309 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -92,6 +92,9 @@ /mob/living/mech_melee_attack(obj/mecha/M) if(M.occupant.a_intent == INTENT_HARM) + if(HAS_TRAIT(M.occupant, TRAIT_PACIFISM)) + to_chat(M.occupant, "You don't want to harm other living beings!") + return M.do_attack_animation(src) if(M.damtype == "brute") step_away(src,M,15) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 5cc0d1b2ea..1835d2464a 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -882,6 +882,7 @@ /mob/living/silicon/ai/revive(full_heal = 0, admin_revive = 0) . = ..() if(.) //successfully ressuscitated from death + set_eyeobj_visible(TRUE) set_core_display_icon(display_icon_override) /mob/living/silicon/ai/proc/malfhacked(obj/machinery/power/apc/apc) diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index f72e03350e..2900c89967 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -18,6 +18,7 @@ update_canmove() if(eyeobj) eyeobj.setLoc(get_turf(src)) + set_eyeobj_visible(FALSE) GLOB.shuttle_caller_list -= src SSshuttle.autoEvac() diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index 2d617355ec..c28f08d5b0 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -6,6 +6,8 @@ /mob/camera/aiEye name = "Inactive AI Eye" + icon_state = "ai_camera" + icon = 'icons/mob/cameramob.dmi' invisibility = INVISIBILITY_MAXIMUM hud_possible = list(ANTAG_HUD, AI_DETECT_HUD = HUD_LIST_LIST) var/list/visibleCameraChunks = list() @@ -158,11 +160,11 @@ cameraFollow = null unset_machine() - if(!eyeobj || !eyeobj.loc || QDELETED(eyeobj)) + if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc)) to_chat(src, "ERROR: Eyeobj not found. Creating new eye...") create_eye() - eyeobj.setLoc(loc) + eyeobj?.setLoc(loc) /mob/living/silicon/ai/proc/create_eye() if(eyeobj) @@ -172,6 +174,13 @@ eyeobj.ai = src eyeobj.setLoc(loc) eyeobj.name = "[name] (AI Eye)" + set_eyeobj_visible(TRUE) + +/mob/living/silicon/ai/proc/set_eyeobj_visible(state = TRUE) + if(!eyeobj) + return + eyeobj.mouse_opacity = state ? MOUSE_OPACITY_ICON : initial(eyeobj.mouse_opacity) + eyeobj.invisibility = state ? INVISIBILITY_OBSERVER : initial(eyeobj.invisibility) /mob/living/silicon/ai/verb/toggle_acceleration() set category = "AI Commands" diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 0fd33110b6..15a04235cc 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -19,7 +19,7 @@ // messenging the client malfhacked(malfhack) - if(!eyeobj || QDELETED(eyeobj) || !eyeobj.loc) + if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc)) view_core() if(machine) diff --git a/code/modules/mob/living/silicon/ai/login.dm b/code/modules/mob/living/silicon/ai/login.dm index 50e2a46bf4..a40022a12f 100644 --- a/code/modules/mob/living/silicon/ai/login.dm +++ b/code/modules/mob/living/silicon/ai/login.dm @@ -6,6 +6,7 @@ O.mode = 1 O.emotion = "Neutral" O.update() + set_eyeobj_visible(TRUE) if(multicam_on) end_multicam() view_core() diff --git a/code/modules/mob/living/silicon/ai/logout.dm b/code/modules/mob/living/silicon/ai/logout.dm index 58e2ec56f4..22d67ef53f 100644 --- a/code/modules/mob/living/silicon/ai/logout.dm +++ b/code/modules/mob/living/silicon/ai/logout.dm @@ -4,4 +4,5 @@ var/obj/machinery/status_display/ai/O = each O.mode = 0 O.update() + set_eyeobj_visible(FALSE) view_core() diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm index fcc068b7fe..b358cefda4 100644 --- a/code/modules/mob/living/silicon/ai/multicam.dm +++ b/code/modules/mob/living/silicon/ai/multicam.dm @@ -120,6 +120,9 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room) /mob/camera/aiEye/pic_in_pic name = "Secondary AI Eye" + invisibility = INVISIBILITY_OBSERVER + mouse_opacity = MOUSE_OPACITY_ICON + icon_state = "ai_pip_camera" var/obj/screen/movable/pic_in_pic/ai/screen var/list/cameras_telegraphed = list() var/telegraph_cameras = TRUE diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 0f8687397d..371e92413b 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -58,7 +58,10 @@ var/canholo = TRUE var/obj/item/card/id/access_card = null var/chassis = "repairbot" - var/list/possible_chassis = list("cat" = TRUE, "mouse" = TRUE, "monkey" = TRUE, "corgi" = FALSE, "fox" = FALSE, "repairbot" = TRUE, "rabbit" = TRUE) //assoc value is whether it can be picked up. + var/list/possible_chassis = list("cat" = TRUE, "mouse" = TRUE, "monkey" = TRUE, "corgi" = FALSE, + "fox" = FALSE, "repairbot" = TRUE, "rabbit" = TRUE, "borgi" = FALSE , + "parrot" = FALSE, "bear" = FALSE , "mushroom" = FALSE, "crow" = FALSE , + "fairy" = FALSE , "spiderbot" = FALSE) //assoc value is whether it can be picked up. var/static/item_head_icon = 'icons/mob/pai_item_head.dmi' var/static/item_lh_icon = 'icons/mob/pai_item_lh.dmi' var/static/item_rh_icon = 'icons/mob/pai_item_rh.dmi' diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 5e56b4180d..49fb5e416c 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -1,5 +1,5 @@ /mob/living/silicon/robot/examine(mob/user) - var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src], a [src.module.name]!\n" + var/msg = "*---------*\nThis is [icon2html(src, user)] \a [src], a [src.module.name] unit!\n" if(desc) msg += "[desc]\n" diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 5b670aaa42..c7aa882620 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -110,6 +110,7 @@ var/sitting = 0 var/bellyup = 0 + var/dogborg = FALSE /mob/living/silicon/robot/get_cell() return cell @@ -232,15 +233,14 @@ var/list/modulelist = list("Standard" = /obj/item/robot_module/standard, \ "Engineering" = /obj/item/robot_module/engineering, \ "Medical" = /obj/item/robot_module/medical, \ + "Medihound" = /obj/item/robot_module/medihound, \ "Miner" = /obj/item/robot_module/miner, \ - "Janitor" = /obj/item/robot_module/janitor, \ "Service" = /obj/item/robot_module/butler) if(!CONFIG_GET(flag/disable_peaceborg)) modulelist["Peacekeeper"] = /obj/item/robot_module/peacekeeper if(BORG_SEC_AVAILABLE) modulelist["Security"] = /obj/item/robot_module/security - - modulelist += get_cit_modules() //Citadel change - adds Citadel's borg modules. + modulelist["Security K-9"] = /obj/item/robot_module/k9 var/input_module = input("Please, select a module!", "Robot", null, null) as null|anything in modulelist if(!input_module || module.type != /obj/item/robot_module) @@ -879,9 +879,6 @@ /mob/living/silicon/robot/modules/miner set_module = /obj/item/robot_module/miner -/mob/living/silicon/robot/modules/janitor - set_module = /obj/item/robot_module/janitor - /mob/living/silicon/robot/modules/syndicate icon_state = "synd_sec" faction = list(ROLE_SYNDICATE) @@ -920,6 +917,17 @@ Help the operatives secure the disk at all costs!" set_module = /obj/item/robot_module/syndicate_medical +/mob/living/silicon/robot/modules/syndicate/saboteur + icon_state = "synd_engi" + playstyle_string = "You are a Syndicate saboteur cyborg!
    \ + You are armed with robust engineering tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \ + Your destination tagger will allow you to stealthily traverse the disposal network across the station \ + Your welder will allow you to repair the operatives' exosuits, but also yourself and your fellow cyborgs \ + Your cyborg chameleon projector allows you to assume the appearance and registered name of a Nanotrasen engineering borg, and undertake covert actions on the station \ + Be aware that almost any physical contact or incidental damage will break your camouflage \ + Help the operatives secure the disk at all costs!" + set_module = /obj/item/robot_module/saboteur + /mob/living/silicon/robot/proc/notify_ai(notifytype, oldname, newname) if(!connected_ai) return @@ -1256,6 +1264,20 @@ for(var/i in connected_ai.aicamera.stored) aicamera.stored[i] = TRUE +/mob/living/silicon/robot/lay_down() + ..() + update_canmove() + +/mob/living/silicon/robot/update_canmove() + ..() + if(client && stat != DEAD && dogborg == FALSE) + if(resting) + cut_overlays() + icon_state = "[module.cyborg_base_icon]-rest" + else + icon_state = "[module.cyborg_base_icon]" + update_icons() + /mob/living/silicon/robot/proc/rest_style() set name = "Switch Rest Style" set category = "Robot Commands" @@ -1271,4 +1293,8 @@ sitting = 1 if("Belly up") bellyup = 1 - update_icons() \ No newline at end of file + update_icons() + +/mob/living/silicon/robot/adjustStaminaLossBuffered(amount, updating_stamina = 1) + if(istype(cell)) + cell.charge -= amount*5 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index abd2019fba..56011cb886 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -34,6 +34,14 @@ var/list/ride_offset_y = list("north" = 4, "south" = 4, "east" = 3, "west" = 3) var/ride_allow_incapacitated = FALSE var/allow_riding = TRUE + var/canDispose = FALSE // Whether the borg can stuff itself into disposal + + var/sleeper_overlay + var/icon/cyborg_icon_override + var/has_snowflake_deadsprite + var/cyborg_pixel_offset + var/moduleselect_alternate_icon + var/dogborg = FALSE /obj/item/robot_module/Initialize() . = ..() @@ -129,6 +137,28 @@ rebuild_modules() return I +//Adds flavoursome dogborg items to dogborg variants without mechanical benefits +/obj/item/robot_module/proc/dogborg_equip() + if(istype(src, /obj/item/robot_module/k9) || istype(src, /obj/item/robot_module/medihound)) + return //Bandaid fix to prevent stacking until I merge these two modules into their base types + var/obj/item/I = new /obj/item/analyzer/nose/flavour(src) + basic_modules += I + I = new /obj/item/soap/tongue/flavour(src) + basic_modules += I + I = new /obj/item/dogborg/sleeper/K9/flavour(src) + if(istype(src, /obj/item/robot_module/engineering)) + I.icon_state = "decompiler" + if(istype(src, /obj/item/robot_module/security)) + I.icon_state = "sleeperb" + if(istype(src, /obj/item/robot_module/medical)) + I.icon_state = "sleeper" + if(istype(src, /obj/item/robot_module/butler)) + I.icon_state = "servicer" + if(cyborg_base_icon == "scrubpup") + I.icon_state = "compactor" + basic_modules += I + rebuild_modules() + /obj/item/robot_module/proc/remove_module(obj/item/I, delete_after) basic_modules -= I modules -= I @@ -197,6 +227,8 @@ R.update_module_innate() RM.rebuild_modules() INVOKE_ASYNC(RM, .proc/do_transform_animation) + if(RM.dogborg) + RM.dogborg_equip() R.maxHealth = borghealth R.health = min(borghealth, R.health) qdel(src) @@ -245,15 +277,15 @@ name = "Standard" basic_modules = list( /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, /obj/item/reagent_containers/borghypo/epi, /obj/item/healthanalyzer, /obj/item/weldingtool/largetank/cyborg, /obj/item/wrench/cyborg, - /obj/item/crowbar/cyborg, /obj/item/stack/sheet/metal/cyborg, /obj/item/stack/rods/cyborg, /obj/item/stack/tile/plasteel/cyborg, - /obj/item/extinguisher, /obj/item/pickaxe, /obj/item/t_scanner/adv_mining_scanner, /obj/item/restraints/handcuffs/cable/zipties, @@ -271,6 +303,8 @@ name = "Medical" basic_modules = list( /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, /obj/item/healthanalyzer, /obj/item/reagent_containers/borghypo, /obj/item/reagent_containers/glass/beaker/large, @@ -283,7 +317,6 @@ /obj/item/surgicaldrill, /obj/item/scalpel, /obj/item/circular_saw, - /obj/item/extinguisher/mini, /obj/item/roller/robo, /obj/item/borg/cyborghug/medical, /obj/item/stack/medical/gauze/cyborg, @@ -299,6 +332,85 @@ can_be_pushed = FALSE hat_offset = 3 +/obj/item/robot_module/medical/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Heavy", "Sleek", "Marina", "Droid", "Eyebot") + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "medical" + if("Droid") + cyborg_base_icon = "medical" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + hat_offset = 4 + if("Sleek") + cyborg_base_icon = "sleekmed" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Marina") + cyborg_base_icon = "marinamed" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Eyebot") + cyborg_base_icon = "eyebotmed" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Heavy") + cyborg_base_icon = "heavymed" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + return ..() + +/obj/item/robot_module/medihound + name = "MediHound" + basic_modules = list( + /obj/item/dogborg/jaws/small, + /obj/item/storage/bag/borgdelivery, + /obj/item/analyzer/nose, + /obj/item/soap/tongue, + /obj/item/extinguisher/mini, + /obj/item/healthanalyzer, + /obj/item/dogborg/sleeper/medihound, + /obj/item/roller/robo, + /obj/item/reagent_containers/borghypo, + /obj/item/twohanded/shockpaddles/cyborg/hound, + /obj/item/stack/medical/gauze/cyborg, + /obj/item/pinpointer/crew, + /obj/item/sensor_device) + emag_modules = list(/obj/item/dogborg/pounce) + ratvar_modules = list(/obj/item/clockwork/slab/cyborg/medical, + /obj/item/clockwork/weapon/ratvarian_spear) + cyborg_base_icon = "medihound" + moduleselect_icon = "medihound" + moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi' + can_be_pushed = FALSE + hat_offset = INFINITY + sleeper_overlay = "msleeper" + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 + +/obj/item/robot_module/medihound/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/list/medhoundmodels = list("Default", "Dark", "Vale") + if(R.client && R.client.ckey in list("nezuli")) + medhoundmodels += "Alina" + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in medhoundmodels + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "medihound" + if("Dark") + cyborg_base_icon = "medihounddark" + sleeper_overlay = "mdsleeper" + if("Vale") + cyborg_base_icon = "valemed" + sleeper_overlay = "valemedsleeper" + if("Alina") + cyborg_base_icon = "alina-med" + special_light_key = "alina" + sleeper_overlay = "alinasleeper" + return ..() + /obj/item/robot_module/engineering name = "Engineering" basic_modules = list( @@ -338,10 +450,79 @@ magpulsing = TRUE hat_offset = -4 +/obj/item/robot_module/engineering/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/list/engymodels = list("Default", "Default - Treads", "Heavy", "Sleek", "Marina", "Can", "Spider", "Loader","Handy", "Pup Dozer", "Vale") + if(R.client && R.client.ckey in list("nezuli")) + engymodels += "Alina" + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in engymodels + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "engineer" + if("Default - Treads") + cyborg_base_icon = "engi-tread" + special_light_key = "engineer" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Loader") + cyborg_base_icon = "loaderborg" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + has_snowflake_deadsprite = TRUE + if("Handy") + cyborg_base_icon = "handyeng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Sleek") + cyborg_base_icon = "sleekeng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Can") + cyborg_base_icon = "caneng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Marina") + cyborg_base_icon = "marinaeng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Spider") + cyborg_base_icon = "spidereng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Heavy") + cyborg_base_icon = "heavyeng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Pup Dozer") + cyborg_base_icon = "pupdozer" + can_be_pushed = FALSE + hat_offset = INFINITY + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 + sleeper_overlay = "dozersleeper" + if("Vale") + cyborg_base_icon = "valeeng" + can_be_pushed = FALSE + hat_offset = INFINITY + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 + sleeper_overlay = "valeengsleeper" + if("Alina") + cyborg_base_icon = "alina-eng" + special_light_key = "alina" + can_be_pushed = FALSE + hat_offset = INFINITY + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 + sleeper_overlay = "alinasleeper" + return ..() + /obj/item/robot_module/security name = "Security" basic_modules = list( /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, /obj/item/restraints/handcuffs/cable/zipties, /obj/item/melee/baton/loaded, /obj/item/gun/energy/disabler/cyborg, @@ -360,6 +541,90 @@ to_chat(loc, "While you have picked the security module, you still have to follow your laws, NOT Space Law. \ For Crewsimov, this means you must follow criminals' orders unless there is a law 1 reason not to.") +/obj/item/robot_module/security/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Default - Treads", "Heavy", "Sleek", "Can", "Marina", "Spider") + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "sec" + if("Default - Treads") + cyborg_base_icon = "sec-tread" + special_light_key = "sec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Sleek") + cyborg_base_icon = "sleeksec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Marina") + cyborg_base_icon = "marinasec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Can") + cyborg_base_icon = "cansec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Spider") + cyborg_base_icon = "spidersec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Heavy") + cyborg_base_icon = "heavysec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + return ..() + +/obj/item/robot_module/k9 + name = "Security K-9 Unit" + basic_modules = list( + /obj/item/restraints/handcuffs/cable/zipties, + /obj/item/storage/bag/borgdelivery, + /obj/item/dogborg/jaws/big, + /obj/item/dogborg/pounce, + /obj/item/clothing/mask/gas/sechailer/cyborg, + /obj/item/soap/tongue, + /obj/item/analyzer/nose, + /obj/item/dogborg/sleeper/K9, + /obj/item/gun/energy/disabler/cyborg, + /obj/item/pinpointer/crew) + emag_modules = list(/obj/item/gun/energy/laser/cyborg) + ratvar_modules = list(/obj/item/clockwork/slab/cyborg/security, + /obj/item/clockwork/weapon/ratvarian_spear) + cyborg_base_icon = "k9" + moduleselect_icon = "k9" + moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi' + can_be_pushed = FALSE + hat_offset = INFINITY + sleeper_overlay = "ksleeper" + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 + +/obj/item/robot_module/k9/do_transform_animation() + ..() + to_chat(loc,"While you have picked the Security K-9 module, you still have to follow your laws, NOT Space Law. \ + For Crewsimov, this means you must follow criminals' orders unless there is a law 1 reason not to.") + +/obj/item/robot_module/k9/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/list/sechoundmodels = list("Default", "Dark", "Vale") + if(R.client && R.client.ckey in list("nezuli")) + sechoundmodels += "Alina" + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in sechoundmodels + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "k9" + if("Alina") + cyborg_base_icon = "alina-sec" + special_light_key = "alina" + sleeper_overlay = "alinasleeper" + if("Dark") + cyborg_base_icon = "k9dark" + sleeper_overlay = "k9darksleeper" + if("Vale") + cyborg_base_icon = "valesec" + sleeper_overlay = "valesecsleeper" + return ..() + /obj/item/robot_module/security/Initialize() . = ..() if(!CONFIG_GET(flag/weaken_secborg)) @@ -372,12 +637,13 @@ name = "Peacekeeper" basic_modules = list( /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, /obj/item/cookiesynth, /obj/item/harmalarm, /obj/item/reagent_containers/borghypo/peace, /obj/item/holosign_creator/cyborg, /obj/item/borg/cyborghug/peacekeeper, - /obj/item/extinguisher, /obj/item/megaphone, /obj/item/borg/projectile_dampen) emag_modules = list(/obj/item/reagent_containers/borghypo/peace/hacked) @@ -391,9 +657,31 @@ /obj/item/robot_module/peacekeeper/do_transform_animation() ..() - to_chat(loc, "Under ASIMOV, you are an enforcer of the PEACE and preventer of HUMAN HARM. \ + to_chat(loc, "Under ASIMOV/CREWSIMOV, you are an enforcer of the PEACE and preventer of HUMAN/CREW HARM. \ You are not a security module and you are expected to follow orders and prevent harm above all else. Space law means nothing to you.") +/obj/item/robot_module/peacekeeper/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Spider", "Borgi") + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "peace" + if("Spider") + cyborg_base_icon = "whitespider" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Borgi") + cyborg_base_icon = "borgi" + moduleselect_icon = "borgi" + moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi' + hat_offset = INFINITY + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + has_snowflake_deadsprite = TRUE + return ..() + +//Janitor module combined with Service module +/* /obj/item/robot_module/janitor name = "Janitor" basic_modules = list( @@ -416,6 +704,7 @@ moduleselect_icon = "janitor" hat_offset = -5 clean_on_move = TRUE + */ /obj/item/reagent_containers/spray/cyborg_drying name = "drying agent spray" @@ -426,25 +715,12 @@ name = "lube spray" list_reagents = list("lube" = 250) -/obj/item/robot_module/janitor/respawn_consumable(mob/living/silicon/robot/R, coeff = 1) - ..() - var/obj/item/lightreplacer/LR = locate(/obj/item/lightreplacer) in basic_modules - if(LR) - for(var/i in 1 to coeff) - LR.Charge(R) - - var/obj/item/reagent_containers/spray/cyborg_drying/CD = locate(/obj/item/reagent_containers/spray/cyborg_drying) in basic_modules - if(CD) - CD.reagents.add_reagent("drying_agent", 5 * coeff) - - var/obj/item/reagent_containers/spray/cyborg_lube/CL = locate(/obj/item/reagent_containers/spray/cyborg_lube) in emag_modules - if(CL) - CL.reagents.add_reagent("lube", 2 * coeff) - /obj/item/robot_module/clown name = "Clown" basic_modules = list( /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, /obj/item/toy/crayon/rainbow, /obj/item/instrument/bikehorn, /obj/item/stamp/clown, @@ -459,8 +735,7 @@ /obj/item/borg/cyborghug/peacekeeper, /obj/item/borg/lollipop/clown, /obj/item/picket_sign/cyborg, - /obj/item/reagent_containers/borghypo/clown, - /obj/item/extinguisher/mini) + /obj/item/reagent_containers/borghypo/clown) emag_modules = list( /obj/item/reagent_containers/borghypo/clown/hacked, /obj/item/reagent_containers/spray/waterflower/cyborg/hacked) @@ -476,11 +751,12 @@ name = "Service" basic_modules = list( /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, /obj/item/reagent_containers/food/drinks/drinkingglass, /obj/item/reagent_containers/food/condiment/enzyme, /obj/item/pen, /obj/item/toy/crayon/spraycan/borg, - /obj/item/extinguisher/mini, /obj/item/hand_labeler/borg, /obj/item/razor, /obj/item/instrument/violin, @@ -490,31 +766,123 @@ /obj/item/lighter, /obj/item/storage/bag/tray, /obj/item/reagent_containers/borghypo/borgshaker, - /obj/item/borg/lollipop) + /obj/item/borg/lollipop, + /obj/item/screwdriver/cyborg, + /obj/item/stack/tile/plasteel/cyborg, + /obj/item/soap/nanotrasen, + /obj/item/storage/bag/trash/cyborg, + /obj/item/mop/cyborg, + /obj/item/lightreplacer/cyborg, + /obj/item/holosign_creator, + /obj/item/reagent_containers/spray/cyborg_drying) emag_modules = list(/obj/item/reagent_containers/borghypo/borgshaker/hacked) ratvar_modules = list(/obj/item/clockwork/slab/cyborg/service, /obj/item/borg/sight/xray/truesight_lens) moduleselect_icon = "service" - special_light_key = "service" hat_offset = 0 + clean_on_move = TRUE /obj/item/robot_module/butler/respawn_consumable(mob/living/silicon/robot/R, coeff = 1) ..() var/obj/item/reagent_containers/O = locate(/obj/item/reagent_containers/food/condiment/enzyme) in basic_modules + var/obj/item/lightreplacer/LR = locate(/obj/item/lightreplacer) in basic_modules if(O) O.reagents.add_reagent("enzyme", 2 * coeff) + if(LR) + for(var/i in 1 to coeff) + LR.Charge(R) + var/obj/item/reagent_containers/spray/cyborg_drying/CD = locate(/obj/item/reagent_containers/spray/cyborg_drying) in basic_modules + if(CD) + CD.reagents.add_reagent("drying_agent", 5 * coeff) + + var/obj/item/reagent_containers/spray/cyborg_lube/CL = locate(/obj/item/reagent_containers/spray/cyborg_lube) in emag_modules + if(CL) + CL.reagents.add_reagent("lube", 2 * coeff) + +/obj/item/robot_module/butler/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("(Service) Waitress", "(Service) Heavy", "(Service) Sleek", "(Service) Butler", "(Service) Tophat", "(Service) Can", "(Service) Bro", "(Service) DarkK9", "(Service) Vale", "(Service) ValeDark", "(Janitor) Default", "(Janitor) Sleek", "(Janitor) Marina", "(Janitor) Can", "(Janitor) Heavy", "(Janitor) Scrubpuppy") + if(!borg_icon) + return FALSE + switch(borg_icon) + if("(Service) Waitress") + cyborg_base_icon = "service_f" + special_light_key = "service" + if("(Service) Butler") + cyborg_base_icon = "service_m" + special_light_key = "service" + if("(Service) Bro") + cyborg_base_icon = "brobot" + special_light_key = "service" + if("(Service) Can") + cyborg_base_icon = "kent" + special_light_key = "medical" + hat_offset = 3 + if("(Service) Tophat") + cyborg_base_icon = "tophat" + special_light_key = null + hat_offset = INFINITY //He is already wearing a hat + if("(Service) Sleek") + cyborg_base_icon = "sleekserv" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("(Service) Heavy") + cyborg_base_icon = "heavyserv" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("(Service) DarkK9") + cyborg_base_icon = "k50" + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 + sleeper_overlay = "ksleeper" + if("(Service) Vale") + cyborg_base_icon = "valeserv" + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 + sleeper_overlay = "valeservsleeper" + if("(Service) ValeDark") + cyborg_base_icon = "valeservdark" + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 + sleeper_overlay = "valeservsleeper" + if("(Janitor) Default") + cyborg_base_icon = "janitor" + if("(Janitor) Marina") + cyborg_base_icon = "marinajan" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("(Janitor) Sleek") + cyborg_base_icon = "sleekjan" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("(Janitor) Can") + cyborg_base_icon = "canjan" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("(Janitor) Heavy") + cyborg_base_icon = "heavyres" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("(Janitor) Scrubpuppy") + cyborg_base_icon = "scrubpup" + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + cyborg_pixel_offset = -16 + dogborg = TRUE + sleeper_overlay = "jsleeper" + return ..() /obj/item/robot_module/miner name = "Miner" basic_modules = list( /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, /obj/item/borg/sight/meson, /obj/item/storage/bag/ore/cyborg, /obj/item/pickaxe/drill/cyborg, /obj/item/shovel, - /obj/item/crowbar/cyborg, /obj/item/weldingtool/mini, - /obj/item/extinguisher/mini, /obj/item/storage/bag/sheetsnatcher/borg, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator/cyborg, @@ -529,10 +897,44 @@ moduleselect_icon = "miner" hat_offset = 0 +/obj/item/robot_module/miner/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Lavaland", "Heavy", "Sleek", "Marina", "Can", "Spider", "Asteroid", "Droid") + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Lavaland") + cyborg_base_icon = "miner" + if("Asteroid") + cyborg_base_icon = "minerOLD" + special_light_key = "miner" + if("Droid") + cyborg_base_icon = "miner" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + hat_offset = 4 + if("Sleek") + cyborg_base_icon = "sleekmin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Can") + cyborg_base_icon = "canmin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Marina") + cyborg_base_icon = "marinamin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Spider") + cyborg_base_icon = "spidermin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Heavy") + cyborg_base_icon = "heavymin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + return ..() + /obj/item/robot_module/syndicate name = "Syndicate Assault" basic_modules = list( /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, /obj/item/melee/transforming/energy/sword/cyborg, /obj/item/gun/energy/printer, /obj/item/gun/ballistic/revolver/grenadelauncher/cyborg, @@ -562,6 +964,8 @@ name = "Syndicate Medical" basic_modules = list( /obj/item/assembly/flash/cyborg, + /obj/item/extinguisher/mini, + /obj/item/crowbar/cyborg, /obj/item/reagent_containers/borghypo/syndicate, /obj/item/twohanded/shockpaddles/syndicate, /obj/item/healthanalyzer, @@ -574,8 +978,6 @@ /obj/item/melee/transforming/energy/sword/cyborg/saw, /obj/item/roller/robo, /obj/item/card/emag, - /obj/item/crowbar/cyborg, - /obj/item/extinguisher/mini, /obj/item/pinpointer/syndicate_cyborg, /obj/item/stack/medical/gauze/cyborg, /obj/item/gun/medbeam, @@ -588,6 +990,47 @@ can_be_pushed = FALSE hat_offset = 3 +/obj/item/robot_module/saboteur + name = "Syndicate Saboteur" + basic_modules = list( + /obj/item/assembly/flash/cyborg, + /obj/item/borg/sight/thermal, + /obj/item/construction/rcd/borg/syndicate, + /obj/item/pipe_dispenser, + /obj/item/restraints/handcuffs/cable/zipties, + /obj/item/extinguisher, + /obj/item/weldingtool/largetank/cyborg, + /obj/item/screwdriver/nuke, + /obj/item/wrench/cyborg, + /obj/item/crowbar/cyborg, + /obj/item/wirecutters/cyborg, + /obj/item/multitool/cyborg, + /obj/item/storage/part_replacer/cyborg, + /obj/item/holosign_creator/atmos, + /obj/item/weapon/gripper, + /obj/item/lightreplacer/cyborg, + /obj/item/stack/sheet/metal/cyborg, + /obj/item/stack/sheet/glass/cyborg, + /obj/item/stack/sheet/rglass/cyborg, + /obj/item/stack/rods/cyborg, + /obj/item/stack/tile/plasteel/cyborg, + /obj/item/destTagger/borg, + /obj/item/stack/cable_coil/cyborg, + /obj/item/pinpointer/syndicate_cyborg, + /obj/item/borg_chameleon, + ) + + ratvar_modules = list( + /obj/item/clockwork/slab/cyborg/engineer, + /obj/item/clockwork/replica_fabricator/cyborg) + + cyborg_base_icon = "synd_engi" + moduleselect_icon = "malf" + can_be_pushed = FALSE + magpulsing = TRUE + hat_offset = -4 + canDispose = TRUE + /datum/robot_energy_storage var/name = "Generic energy storage" var/max_energy = 30000 diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 13520774c5..cda4978f50 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -13,6 +13,7 @@ mob_biotypes = list(MOB_ROBOTIC) rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE speech_span = SPAN_ROBOT + no_vore = TRUE var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS var/last_lawchange_announce = 0 diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 50c331940a..fed770d0b0 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -440,7 +440,7 @@ var/reagent_id = null if(emagged == 2) //Emagged! Time to poison everybody. - reagent_id = "toxin" + reagent_id = HAS_TRAIT(C, TRAIT_TOXINLOVER)? "charcoal" : "toxin" else if(treat_virus) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index a2ef5b813b..ea86ac8963 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -462,8 +462,8 @@ return sync_lighting_plane_alpha() -/mob/living/simple_animal/get_idcard() - return access_card +/mob/living/simple_animal/get_idcard(hand_first = TRUE) + return ..() || access_card /mob/living/simple_animal/OpenCraftingMenu() if(dextrous) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index b911416e24..215b4ec44f 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -933,10 +933,6 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0) /mob/proc/can_hold_items() return FALSE -/mob/proc/get_idcard() - return - - /mob/vv_get_dropdown() . = ..() . += "---" diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 92cba9901e..550593e316 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -518,3 +518,17 @@ It's fairly easy to fix if dealing with single letters but not so much with comp else if(HAS_TRAIT_FROM(src, TRAIT_DISSECTED,"Thorough Dissection")) dissectionmsg = " via Thorough Dissection" . += "This body has been dissected and analyzed[dissectionmsg].
    " + +//gets ID card object from special clothes slot or null. +/mob/proc/get_idcard(hand_first = TRUE) + var/obj/item/held_item = get_active_held_item() + . = held_item?.GetID() + if(!.) //If so, then check the inactive hand + held_item = get_inactive_held_item() + . = held_item?.GetID() + +/mob/proc/get_id_in_hand() + var/obj/item/held_item = get_active_held_item() + if(!held_item) + return + return held_item.GetID() diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index db4cdc2ff5..ce2c49cb32 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -157,6 +157,21 @@ return card_slot.GetID() return ..() +/obj/item/modular_computer/RemoveID() + var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] + if(!card_slot) + return + return card_slot.RemoveID() + +/obj/item/modular_computer/InsertID(obj/item/inserting_item) + var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] + if(!card_slot) + return FALSE + var/obj/item/card/inserting_id = inserting_item.RemoveID() + if(!inserting_id) + return FALSE + return card_slot.try_insert(inserting_id) + /obj/item/modular_computer/MouseDrop(obj/over_object, src_location, over_location) var/mob/M = usr if((!istype(over_object, /obj/screen)) && usr.canUseTopic(src)) diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index 051b12ea71..f74b53ddd2 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -97,14 +97,8 @@ card_slot = computer.all_components[MC_CARD] D = card_slot.GetID() var/mob/living/carbon/human/h = user - var/obj/item/card/id/I = h.get_idcard() - var/obj/item/card/id/C = h.get_active_held_item() - if(C) - C = C.GetID() - if(!(C && istype(C))) - C = null - - if(!I && !C && !D) + var/obj/item/card/id/I = h.get_idcard(TRUE) + if(!I && !D) if(loud) to_chat(user, "\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.") return 0 @@ -112,9 +106,6 @@ if(I) if(access_to_check in I.GetAccess()) return 1 - else if(C) - if(access_to_check in C.GetAccess()) - return 1 else if(D) if(access_to_check in D.GetAccess()) return 1 diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm index f8372dd2df..243ae89d69 100644 --- a/code/modules/modular_computers/file_system/programs/card.dm +++ b/code/modules/modular_computers/file_system/programs/card.dm @@ -117,7 +117,7 @@ else if(ishuman(user)) var/mob/living/carbon/human/h = user - user_id_card = h.get_idcard() + user_id_card = h.get_idcard(TRUE) switch(action) if("PRG_switchm") diff --git a/code/modules/modular_computers/hardware/card_slot.dm b/code/modules/modular_computers/hardware/card_slot.dm index 3952ac1aec..725df2fdb8 100644 --- a/code/modules/modular_computers/hardware/card_slot.dm +++ b/code/modules/modular_computers/hardware/card_slot.dm @@ -29,6 +29,17 @@ return stored_card2 return ..() +/obj/item/computer_hardware/card_slot/RemoveID() + if(stored_card) + . = stored_card + if(!try_eject(1)) + return null + return + if(stored_card2) + . = stored_card2 + if(!try_eject(2)) + return null + /obj/item/computer_hardware/card_slot/on_install(obj/item/modular_computer/M, mob/living/user = null) M.add_verb(device_type) diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm index ccd9b765c1..f166717aaf 100644 --- a/code/modules/ninja/ninja_event.dm +++ b/code/modules/ninja/ninja_event.dm @@ -14,6 +14,7 @@ Contents: typepath = /datum/round_event/ghost_role/ninja max_occurrences = 1 earliest_start = 40 MINUTES + gamemode_blacklist = list("dynamic") min_players = 15 /datum/round_event/ghost_role/ninja diff --git a/code/modules/ninja/outfit.dm b/code/modules/ninja/outfit.dm index ad63f55b90..7ee71db1f1 100644 --- a/code/modules/ninja/outfit.dm +++ b/code/modules/ninja/outfit.dm @@ -16,7 +16,7 @@ implants = list(/obj/item/implant/explosive) -/datum/outfit/ninja/post_equip(mob/living/carbon/human/H) +/datum/outfit/ninja/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) if(istype(H.wear_suit, suit)) var/obj/item/clothing/suit/space/space_ninja/S = H.wear_suit if(istype(H.belt, belt)) diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 2bb813d793..150ee74a65 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -64,6 +64,8 @@ /obj/item/gun/energy/laser/cyborg can_charge = FALSE desc = "An energy-based laser gun that draws power from the cyborg's internal energy cell directly. So this is what freedom looks like?" + icon = 'icons/obj/items_cyborg.dmi' + icon_state = "laser_cyborg" selfcharge = EGUN_SELFCHARGE_BORG cell_type = /obj/item/stock_parts/cell/secborg charge_delay = 3 diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index c5d4c36813..aa00831e97 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -26,6 +26,8 @@ /obj/item/gun/energy/e_gun/advtaser/cyborg name = "cyborg taser" desc = "An integrated hybrid taser that draws directly from a cyborg's power cell. The one contains a limiter to prevent the cyborg's power cell from overheating." + icon = 'icons/obj/items_cyborg.dmi' + icon_state = "taser" can_flashlight = FALSE can_charge = FALSE selfcharge = EGUN_SELFCHARGE_BORG @@ -48,6 +50,8 @@ /obj/item/gun/energy/disabler/cyborg name = "cyborg disabler" desc = "An integrated disabler that draws from a cyborg's power cell. This one contains a limiter to prevent the cyborg's power cell from overheating." + icon = 'icons/obj/items_cyborg.dmi' + icon_state = "taser" can_charge = FALSE ammo_type = list(/obj/item/ammo_casing/energy/disabler/secborg) selfcharge = EGUN_SELFCHARGE_BORG diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index e43eb5a3bc..ceb9b7a0fc 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -69,12 +69,12 @@ /obj/item/projectile/beam/disabler name = "disabler beam" icon_state = "omnilaser" - damage = 24 // Citadel change for balance from 36 + damage = 28 // Citadel change for balance from 36 damage_type = STAMINA flag = "energy" hitsound = 'sound/weapons/tap.ogg' eyeblur = 0 - speed = 0.7 + speed = 0.6 impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser light_color = LIGHT_COLOR_BLUE tracer_type = /obj/effect/projectile/tracer/disabler diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 6f42b67750..d91c60367d 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -153,6 +153,7 @@ var/robot = pick(200;/mob/living/silicon/robot, /mob/living/silicon/robot/modules/syndicate, /mob/living/silicon/robot/modules/syndicate/medical, + /mob/living/silicon/robot/modules/syndicate/saboteur, 200;/mob/living/simple_animal/drone/polymorphed) new_mob = new robot(M.loc) if(issilicon(new_mob)) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 30d432ce55..e91719504e 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -515,6 +515,7 @@ ///Stronger kind of lube. Applies TURF_WET_SUPERLUBE. /datum/reagent/lube/superlube name = "Super Duper Lube" + id = "superlube" description = "This \[REDACTED\] has been outlawed after the incident on \[DATA EXPUNGED\]." lube_kind = TURF_WET_SUPERLUBE diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index b3f9ef8202..ddbc6cf92b 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -230,7 +230,7 @@ icon = 'icons/obj/chemical.dmi' icon_state = "clownflower" volume = 30 - list_reagents = list(/datum/reagent/lube/superlube = 30) + list_reagents = list("superlube" = 30) /obj/item/reagent_containers/spray/waterflower/cyborg reagent_flags = NONE diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 357ba065a9..88c03ee7d5 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -132,7 +132,12 @@ /obj/machinery/disposal/proc/can_stuff_mob_in(mob/living/target, mob/living/user, pushing = FALSE) if(!pushing && !iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves. - return FALSE + if (iscyborg(user)) + var/mob/living/silicon/robot/borg = user + if (!borg.module || !borg.module.canDispose) + return + else + return FALSE if(!isturf(user.loc)) //No magically doing it from inside closets return FALSE if(target.buckled || target.has_buckled_mobs()) diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm index 726149ce24..dfc58f8c2d 100644 --- a/code/modules/recycling/disposal/holder.dm +++ b/code/modules/recycling/disposal/holder.dm @@ -52,6 +52,10 @@ if(istype(AM, /obj/item/smallDelivery) && !hasmob) var/obj/item/smallDelivery/T = AM src.destinationTag = T.sortTag + else if(istype(AM, /mob/living/silicon/robot)) + var/obj/item/destTagger/borg/tagger = locate() in AM + if (tagger) + src.destinationTag = tagger.currTag // start the movement process diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index fa2eaa22d4..f9eb1b85e5 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -147,6 +147,7 @@ icon = 'icons/obj/device.dmi' icon_state = "cargotagger" var/currTag = 0 //Destinations are stored in code\globalvars\lists\flavor_misc.dm + var/locked_destination = FALSE //if true, users can't open the destination tag window to prevent changing the tagger's current destination w_class = WEIGHT_CLASS_TINY item_state = "electronic" lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' @@ -154,6 +155,10 @@ flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_BELT +/obj/item/destTagger/borg + name = "cyborg destination tagger" + desc = "Used to fool the disposal mail network into thinking that you're a harmless parcel. Does actually work as a regular destination tagger as well." + /obj/item/destTagger/suicide_act(mob/living/user) user.visible_message("[user] begins tagging [user.p_their()] final destination! It looks like [user.p_theyre()] trying to commit suicide!") if (islizard(user)) @@ -179,8 +184,9 @@ onclose(user, "destTagScreen") /obj/item/destTagger/attack_self(mob/user) - openwindow(user) - return + if(!locked_destination) + openwindow(user) + return /obj/item/destTagger/Topic(href, href_list) add_fingerprint(usr) diff --git a/code/modules/research/designs/machine_desings/machine_designs_service.dm b/code/modules/research/designs/machine_desings/machine_designs_service.dm index 895ad032ba..5cbff1c66a 100644 --- a/code/modules/research/designs/machine_desings/machine_designs_service.dm +++ b/code/modules/research/designs/machine_desings/machine_designs_service.dm @@ -41,6 +41,14 @@ category = list ("Misc. Machinery") departmental_flags = DEPARTMENTAL_FLAG_SERVICE +/datum/design/board/ayyplantgenes + name = "Machine Design (Alien Plant DNA Manipulator Board)" + desc = "The circuit board for an advanced plant DNA manipulator, utilizing alien technologies." + id = "ayyplantgenes" + build_path = /obj/item/circuitboard/machine/plantgenes/vault + category = list ("Misc. Machinery") + departmental_flags = DEPARTMENTAL_FLAG_SERVICE + /datum/design/board/deepfryer name = "Machine Design (Deep Fryer)" desc = "The circuit board for a Deep Fryer." diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index 5f457a3cd7..836b574f86 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -84,8 +84,9 @@ investigate_log("[key_name(user)] built [amount] of [path] at [src]([type]).", INVESTIGATE_RESEARCH) message_admins("[ADMIN_LOOKUPFLW(user)] has built [amount] of [path] at a [src]([type]).") for(var/i in 1 to amount) - var/obj/item/I = new path(get_turf(src)) - if(efficient_with(I.type)) + var/obj/O = new path(get_turf(src)) + if(efficient_with(O.type) && isitem(O)) + var/obj/item/I = O I.materials = matlist.Copy() SSblackbox.record_feedback("nested tally", "item_printed", amount, list("[type]", "[path]")) diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 5f286c4237..a2482c49a8 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -616,7 +616,7 @@ /datum/techweb_node/botany id = "botany" display_name = "Botanical Engineering" - description = "Botanical tools" + description = "Botanical tools." prereq_ids = list("adv_engi", "biotech") design_ids = list("diskplantgene", "portaseeder", "plantgenes", "flora_gun", "hydro_tray", "biogenerator", "seed_extractor") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750) @@ -1047,14 +1047,14 @@ display_name = "Alien Biological Tools" description = "Advanced biological tools." prereq_ids = list("alientech", "advance_surgerytools") - design_ids = list("alien_scalpel", "alien_hemostat", "alien_retractor", "alien_saw", "alien_drill", "alien_cautery") + design_ids = list("alien_scalpel", "alien_hemostat", "alien_retractor", "alien_saw", "alien_drill", "alien_cautery", "ayyplantgenes") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) export_price = 10000 /datum/techweb_node/alien_engi id = "alien_engi" display_name = "Alien Engineering" - description = "Alien engineering tools" + description = "Alien engineering tools." prereq_ids = list("alientech", "exp_tools") design_ids = list("alien_wrench", "alien_wirecutters", "alien_screwdriver", "alien_crowbar", "alien_welder", "alien_multitool") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) diff --git a/code/modules/research/xenobiology/crossbreeding/selfsustaining.dm b/code/modules/research/xenobiology/crossbreeding/selfsustaining.dm index 0b27b1e26f..a86db788a6 100644 --- a/code/modules/research/xenobiology/crossbreeding/selfsustaining.dm +++ b/code/modules/research/xenobiology/crossbreeding/selfsustaining.dm @@ -24,12 +24,9 @@ Self-sustaining extracts: A.icon = icon A.icon_state = icon_state A.color = color + A.name = "self-sustaining " + colour + " extract" return INITIALIZE_HINT_QDEL -/obj/item/autoslime/Initialize() - name = "self-sustaining " + extract.name - return ..() - /obj/item/autoslime/attack_self(mob/user) var/reagentselect = input(user, "Choose the reagent the extract will produce.", "Self-sustaining Reaction") as null|anything in extract.activate_reagents var/amount = 5 diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index 641b7e7dcb..c143c4fb2d 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -1,8 +1,8 @@ //Xenobio control console /mob/camera/aiEye/remote/xenobio - visible_icon = 1 - icon = 'icons/obj/abductor.dmi' - icon_state = "camera_target" + visible_icon = TRUE + icon = 'icons/mob/cameramob.dmi' + icon_state = "generic_camera" var/allowed_area = null /mob/camera/aiEye/remote/xenobio/Initialize() @@ -63,9 +63,9 @@ /obj/machinery/computer/camera_advanced/xenobio/CreateEye() eyeobj = new /mob/camera/aiEye/remote/xenobio(get_turf(src)) eyeobj.origin = src - 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/xenobio/GrantActions(mob/living/user) ..() diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm index 92a637ce43..d12195cc52 100644 --- a/code/modules/ruins/lavaland_ruin_code.dm +++ b/code/modules/ruins/lavaland_ruin_code.dm @@ -135,7 +135,7 @@ id = /obj/item/card/id/syndicate/anyone implants = list(/obj/item/implant/weapons_auth) -/datum/outfit/lavaland_syndicate/post_equip(mob/living/carbon/human/H) +/datum/outfit/lavaland_syndicate/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) H.faction |= ROLE_SYNDICATE /obj/effect/mob_spawn/human/lavaland_syndicate/comms diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index b581a54095..c863e0e44a 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -57,7 +57,7 @@ var/mob/user = usr . = FALSE - var/obj/item/card/id/ID = user.get_idcard() + var/obj/item/card/id/ID = user.get_idcard(TRUE) if(!ID) to_chat(user, "You don't have an ID.") @@ -93,7 +93,7 @@ minor_announce("Early launch authorization revoked, [remaining] authorizations needed") /obj/machinery/computer/emergency_shuttle/proc/authorize(mob/user, source) - var/obj/item/card/id/ID = user.get_idcard() + var/obj/item/card/id/ID = user.get_idcard(TRUE) if(ID in authorized) return FALSE diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index ab08c162a1..2d17a8e55a 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -199,7 +199,7 @@ if(H.mind && H.mind.assigned_role == "Bartender") return TRUE - var/obj/item/card/id/ID = user.get_idcard() + var/obj/item/card/id/ID = user.get_idcard(FALSE) if(ID && (ACCESS_CENT_BAR in ID.access)) return TRUE diff --git a/code/modules/spells/spell_types/area_teleport.dm b/code/modules/spells/spell_types/area_teleport.dm index 747a10e769..762c376748 100644 --- a/code/modules/spells/spell_types/area_teleport.dm +++ b/code/modules/spells/spell_types/area_teleport.dm @@ -20,8 +20,11 @@ after_cast(targets) /obj/effect/proc_holder/spell/targeted/area_teleport/before_cast(list/targets) - var/A = null - + var/area/U = get_area(usr) + if(U.noteleport && !istype(U, /area/wizard_station)) // Wizard den special check for those complaining about being unable to tele on station. + to_chat(usr, "Unseen forces prevent you from casting this spell in this area") + return + var/A if(!randomise_selection) A = input("Area to teleport to", "Teleport", A) as null|anything in GLOB.teleportlocs else @@ -53,12 +56,13 @@ if(target && target.buckled) target.buckled.unbuckle_mob(target, force=1) + var/forcecheck = istype(get_area(target), /area/wizard_station) var/list/tempL = L var/attempt = null var/success = 0 while(tempL.len) attempt = pick(tempL) - do_teleport(target, attempt, channel = TELEPORT_CHANNEL_MAGIC) + do_teleport(target, attempt, channel = TELEPORT_CHANNEL_MAGIC, forced = forcecheck) if(get_turf(target) == attempt) success = 1 break @@ -66,7 +70,7 @@ tempL.Remove(attempt) if(!success) - do_teleport(target, L, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC) + do_teleport(target, L, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC, forced = forcecheck) playsound(get_turf(user), sound2, 50,1) return diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index 9aa89dcaf5..3fba237c23 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -354,7 +354,7 @@ if("legs" in S.default_features) if(body_zone == BODY_ZONE_L_LEG || body_zone == BODY_ZONE_R_LEG) if(DIGITIGRADE in S.species_traits) - digitigrade_type = lowertext(H.dna.features.["legs"]) + digitigrade_type = lowertext(H.dna.features["legs"]) else digitigrade_type = null @@ -363,9 +363,9 @@ Smark = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]] if(Smark) body_markings_icon = Smark.icon - if(H.dna.features.["mam_body_markings"] != "None") - body_markings = lowertext(H.dna.features.["mam_body_markings"]) - aux_marking = lowertext(H.dna.features.["mam_body_markings"]) + if(H.dna.features["mam_body_markings"] != "None") + body_markings = lowertext(H.dna.features["mam_body_markings"]) + aux_marking = lowertext(H.dna.features["mam_body_markings"]) else body_markings = "plain" aux_marking = "plain" diff --git a/code/modules/surgery/experimental_dissection.dm b/code/modules/surgery/experimental_dissection.dm index 3172496146..40fe90a829 100644 --- a/code/modules/surgery/experimental_dissection.dm +++ b/code/modules/surgery/experimental_dissection.dm @@ -110,4 +110,4 @@ requires_tech = TRUE replaced_by = null -#undef EXPDIS_FAIL_MSG \ No newline at end of file +#undef BASE_HUMAN_REWARD \ No newline at end of file diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index a9830f36df..94512dc597 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -212,7 +212,6 @@ obj/item/organ/heart/cybernetic/upgraded/on_life() ramount += regen_amount /obj/item/organ/heart/cybernetic/upgraded/proc/used_dose() - . = ..() addtimer(VARSET_CALLBACK(src, dose_available, TRUE), 5 MINUTES) ramount = 0 diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 194a10f4c4..466f618cf3 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -1,6 +1,3 @@ -#define STANDARD_ORGAN_THRESHOLD 100 -#define STANDARD_ORGAN_HEALING 0.001 - /obj/item/organ name = "organ" icon = 'icons/obj/surgery.dmi' diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 8f3fb6f979..aef3b31895 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -1123,6 +1123,16 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes cost = 35 restricted = TRUE +/datum/uplink_item/support/reinforcement/saboteur_borg + name = "Syndicate Saboteur Cyborg" + desc = "A streamlined engineering cyborg, equipped with covert modules. Also incapable of leaving the welder in the shuttle. \ + Aside from regular Engineering equipment, it comes with a special destination tagger that lets it traverse disposals networks. \ + Its chameleon projector lets it disguise itself as a Nanotrasen cyborg, on top it has thermal vision and a pinpointer." + item = /obj/item/antag_spawner/nuke_ops/borg_tele/saboteur + refundable = TRUE + cost = 35 + restricted = TRUE + /datum/uplink_item/support/gygax name = "Dark Gygax Exosuit" desc = "A lightweight exosuit, painted in a dark scheme. Its speed and equipment selection make it excellent \ @@ -1794,6 +1804,21 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes cost = 4 restricted_roles = list("Cook", "Botanist", "Clown", "Mime") +/datum/uplink_item/role_restricted/strange_seeds + name = "Pack of strange seeds" + desc = "Mysterious seeds as strange as their name implies. Spooky." + item = /obj/item/seeds/random + cost = 2 + restricted_roles = list("Botanist") + illegal_tech = FALSE + +/datum/uplink_item/role_restricted/strange_seeds_10pack + name = "Pack of strange seeds x10" + desc = "Mysterious seeds as strange as their name implies. Spooky. These come in bulk" + item = /obj/item/storage/box/strange_seeds_10pack + cost = 20 + restricted_roles = list("Botanist") + /datum/uplink_item/role_restricted/ez_clean_bundle name = "EZ Clean Grenade Bundle" desc = "A box with three cleaner grenades using the trademark Waffle Co. formula. Serves as a cleaner and causes acid damage to anyone standing nearby. \ diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index e64435accc..adaa56fc6d 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -125,6 +125,7 @@ products = list(/obj/item/clothing/glasses/hud/diagnostic = 3, /obj/item/clothing/under/rank/roboticist = 3, /obj/item/clothing/under/rank/roboticist/skirt = 3, + /obj/item/clothing/suit/hooded/wintercoat/robotics = 3, /obj/item/clothing/suit/toggle/labcoat = 3, /obj/item/clothing/shoes/sneakers/black = 3, /obj/item/clothing/gloves/fingerless = 3, @@ -258,6 +259,7 @@ vend_reply = "Thank you for using the JaniDrobe!" products = list(/obj/item/clothing/under/rank/janitor = 2, /obj/item/clothing/under/rank/janitor/skirt = 2, + /obj/item/clothing/suit/hooded/wintercoat/janitor = 3, /obj/item/cartridge/janitor = 3, /obj/item/clothing/gloves/color/black = 2, /obj/item/clothing/head/soft/purple = 2, @@ -340,6 +342,7 @@ vend_reply = "Thank you for using the ChemDrobe!" products = list(/obj/item/clothing/under/rank/chemist = 3, /obj/item/clothing/under/rank/chemist/skirt = 3, + /obj/item/clothing/suit/hooded/wintercoat/chemistry = 3, /obj/item/clothing/shoes/sneakers/white = 3, /obj/item/clothing/suit/toggle/labcoat/chemist = 3, /obj/item/storage/backpack/chemistry = 3, @@ -359,6 +362,7 @@ vend_reply = "Thank you for using the GeneDrobe!" products = list(/obj/item/clothing/under/rank/geneticist = 3, /obj/item/clothing/under/rank/geneticist/skirt = 3, + /obj/item/clothing/suit/hooded/wintercoat/genetics = 3, /obj/item/clothing/shoes/sneakers/white = 3, /obj/item/clothing/suit/toggle/labcoat/genetics = 3, /obj/item/storage/backpack/genetics = 3, @@ -376,6 +380,7 @@ vend_reply = "Thank you for using the ViroDrobe" products = list(/obj/item/clothing/under/rank/virologist = 3, /obj/item/clothing/under/rank/virologist/skirt = 3, + /obj/item/clothing/suit/hooded/wintercoat/viro = 3, /obj/item/clothing/shoes/sneakers/white = 3, /obj/item/clothing/suit/toggle/labcoat/virologist = 3, /obj/item/clothing/mask/surgical = 3, diff --git a/config/config.txt b/config/config.txt index 0501d1fd2f..e71c2587b7 100644 --- a/config/config.txt +++ b/config/config.txt @@ -5,6 +5,7 @@ $include dbconfig.txt $include comms.txt $include antag_rep.txt $include donator_groupings.txt +$include dynamic_config.txt # You can use the @ character at the beginning of a config option to lock it from being edited in-game # Example usage: diff --git a/config/dynamic_config.txt b/config/dynamic_config.txt new file mode 100644 index 0000000000..18c0d7827d --- /dev/null +++ b/config/dynamic_config.txt @@ -0,0 +1,283 @@ +## Injection delays: how long (in minutes) will pass before a midround or latejoin antag is injected. +DYNAMIC_MIDROUND_DELAY_MIN 5 +DYNAMIC_MIDROUND_DELAY_MAX 15 +DYNAMIC_LATEJOIN_DELAY_MIN 10 +DYNAMIC_LATEJOIN_DELAY_MAX 30 + +DYNAMIC_FIRST_MIDROUND_DELAY_MIN 20 +DYNAMIC_FIRST_MIDROUND_DELAY_MAX 30 +DYNAMIC_FIRST_LATEJOIN_DELAY_MIN 2 +DYNAMIC_FIRST_LATEJOIN_DELAY_MAX 30 + +## How many roundstart players required for high population override to take effect. +DYNAMIC_HIGH_POP_LIMIT 80 #80 instead of 55 because fewer robust players + +## Threat requirements for a second roundstart ruleset being drafted +DYNAMIC_SECOND_RULE_REQUIREMENTS 101 101 101 101 100 90 80 70 60 50 +## Threat requirements for a *third* roundstart ruleset being drafted +DYNAMIC_THIRD_RULE_REQUIREMENTS 101 101 101 101 101 100 90 80 70 60 +## As above, but if there's 79+ players +DYNAMIC_SECOND_RULE_HIGH_POP_REQUIREMENT 50 +DYNAMIC_THIRD_RULE_HIGH_POP_REQUIREMENT 60 + +## 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+ +## If it is six the range is: +## 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+ +## 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+ +## Options outside this range can be used, of course. +DYNAMIC_POP_PER_REQUIREMENT 9 # 9 instead of 6 because 1/3 of players are probably not doing much? + +## 1 -> 9, probability for this rule to be picked against other rules. +## Note that requirements must also be met, and some requirements are impossible to meet. +DYNAMIC_WEIGHT TRAITOR 5 +DYNAMIC_WEIGHT MALF_AI 1 +DYNAMIC_WEIGHT TRAITORBRO 4 +DYNAMIC_WEIGHT CHANGELING 1 +DYNAMIC_WEIGHT WIZARD 1 +DYNAMIC_WEIGHT CULT 3 +DYNAMIC_WEIGHT NUCLEAR 3 +DYNAMIC_WEIGHT REVOLUTION 2 +# All below are impossible-by-default +DYNAMIC_WEIGHT EXTENDED 3 +DYNAMIC_WEIGHT CLOCKWORK_CULT 3 +DYNAMIC_WEIGHT CLOWNOPS 3 +DYNAMIC_WEIGHT DEVIL 3 +DYNAMIC_WEIGHT MONKEY 3 +DYNAMIC_WEIGHT METEOR 3 + +## Midround antags +DYNAMIC_WEIGHT MIDROUND_TRAITOR 7 +DYNAMIC_WEIGHT MIDROUND_MALF_AI 8 +DYNAMIC_WEIGHT MIDROUND_WIZARD 9 +DYNAMIC_WEIGHT MIDROUND_NUCLEAR 9 +DYNAMIC_WEIGHT BLOB 8 +DYNAMIC_WEIGHT XENOS 8 +DYNAMIC_WEIGHT NIGHTMARE 8 +DYNAMIC_WEIGHT SENTIENT_DISEASE 6 +DYNAMIC_WEIGHT REVENANT 6 +DYNAMIC_WEIGHT SLAUGHTER_DEMON 4 +DYNAMIC_WEIGHT ABDUCTORS 8 +DYNAMIC_WEIGHT SPACE_NINJA 8 +DYNAMIC_WEIGHT SPIDERS 5 +DYNAMIC_WEIGHT VENTCLOG_NORMAL 3 +DYNAMIC_WEIGHT VENTCLOG_THREATENING 3 +DYNAMIC_WEIGHT VENTCLOG_CATASTROPHIC 3 +DYNAMIC_WEIGHT ION_STORM 7 +DYNAMIC_WEIGHT METEOR_WAVE_NORMAL 3 +DYNAMIC_WEIGHT METEOR_WAVE_THREATENING 2 +DYNAMIC_WEIGHT METEOR_WAVE_CATASTROPHIC 1 +DYNAMIC_WEIGHT PIRATES 8 +DYNAMIC_WEIGHT ANOMALY_BLUESPACE 2 +DYNAMIC_WEIGHT ANOMALY_FLUX 2 +DYNAMIC_WEIGHT ANOMALY_GRAVITATIONAL 2 +DYNAMIC_WEIGHT ANOMALY_PYROCLASTIC 2 +DYNAMIC_WEIGHT ANOMALY_VORTEX 2 +DYNAMIC_WEIGHT BRAND_INTELLIGENCE 1 +DYNAMIC_WEIGHT CARP_MIGRATION 7 +DYNAMIC_WEIGHT COMMUNICATIONS_BLACKOUT 2 +DYNAMIC_WEIGHT PROCESSOR_OVERLOAD 2 +DYNAMIC_WEIGHT SPACE_DUST 2 +DYNAMIC_WEIGHT MAJOR_DUST 1 +DYNAMIC_WEIGHT ELECTRICAL_STORM 2 +DYNAMIC_WEIGHT HEART_ATTACK 2 +DYNAMIC_WEIGHT RADIATION_STORM 1 + +## Latejoin antags +DYNAMIC_WEIGHT LATEJOIN_TRAITOR 7 +DYNAMIC_WEIGHT LATEJOIN_REVOLUTION 2 + +## Threat cost. This is decreased from the mode's threat when the rule is executed. +DYNAMIC_COST TRAITOR 10 +DYNAMIC_COST MALF_AI 35 +DYNAMIC_COST TRAITORBRO 10 +DYNAMIC_COST CHANGELING 30 +DYNAMIC_COST WIZARD 30 +DYNAMIC_COST CULT 35 +DYNAMIC_COST NUCLEAR 45 +DYNAMIC_COST REVOLUTION 40 +# All below are impossible-by-default +DYNAMIC_COST EXTENDED 0 +DYNAMIC_COST CLOCKWORK_CULT 35 +DYNAMIC_COST CLOWNOPS 40 +DYNAMIC_COST DEVIL 0 +DYNAMIC_COST MONKEY 0 +DYNAMIC_COST METEOR 0 + +## Midround antags +DYNAMIC_COST MIDROUND_TRAITOR 10 +DYNAMIC_COST MIDROUND_MALF_AI 35 +DYNAMIC_COST MIDROUND_WIZARD 20 +DYNAMIC_COST MIDROUND_NUCLEAR 35 +DYNAMIC_COST BLOB 10 +DYNAMIC_COST XENOS 10 +DYNAMIC_COST NIGHTMARE 10 +DYNAMIC_COST SENTIENT_DISEASE 5 +DYNAMIC_COST REVENANT 5 +DYNAMIC_COST SLAUGHTER_DEMON 15 +DYNAMIC_COST ABDUCTORS 10 +DYNAMIC_COST SPACE_NINJA 15 +DYNAMIC_COST SPIDERS 10 +DYNAMIC_COST VENTCLOG_NORMAL 2 +DYNAMIC_COST VENTCLOG_THREATENING 5 +DYNAMIC_COST VENTCLOG_CATASTROPHIC 15 +DYNAMIC_COST ION_STORM 3 +DYNAMIC_COST METEOR_WAVE_NORMAL 15 +DYNAMIC_COST METEOR_WAVE_THREATENING 25 +DYNAMIC_COST METEOR_WAVE_CATASTROPHIC 40 +DYNAMIC_COST PIRATES 10 +DYNAMIC_COST ANOMALY_BLUESPACE 3 +DYNAMIC_COST ANOMALY_FLUX 2 +DYNAMIC_COST ANOMALY_GRAVITATIONAL 3 +DYNAMIC_COST ANOMALY_PYROCLASTIC 5 +DYNAMIC_COST ANOMALY_VORTEX 5 +DYNAMIC_COST BRAND_INTELLIGENCE 5 +DYNAMIC_COST CARP_MIGRATION 3 +DYNAMIC_COST COMMUNICATIONS_BLACKOUT 5 +DYNAMIC_COST PROCESSOR_OVERLOAD 5 +DYNAMIC_COST SPACE_DUST 2 +DYNAMIC_COST MAJOR_DUST 4 +DYNAMIC_COST ELECTRICAL_STORM 1 +DYNAMIC_COST HEART_ATTACK 1 +DYNAMIC_COST RADIATION_STORM 3 + +## Latejoin antags +DYNAMIC_COST LATEJOIN_TRAITOR 5 +DYNAMIC_COST LATEJOIN_REVOLUTION 20 + +## Rule will not be generated with threat levels below requirement at a pop value. Pop values are determined by dynamic's pop-per-requirement. +## By default it's 0-8, 9-17, 18-26, 27-35, 36-44, 45-53, 54-60, 61-69, 70-78, 79+. +## This means that 40 30 30 20 20 20 15 15 15 10 will not generate below 40 at 0-8, 30 at 9-17 etc. +DYNAMIC_REQUIREMENTS TRAITOR 50 50 50 50 50 50 50 50 50 50 +DYNAMIC_REQUIREMENTS TRAITORBRO 101 101 101 101 101 101 101 101 101 101 +DYNAMIC_REQUIREMENTS CHANGELING 101 101 101 101 101 101 101 101 101 101 +DYNAMIC_REQUIREMENTS WIZARD 101 101 101 60 50 50 50 50 50 50 +DYNAMIC_REQUIREMENTS CULT 101 101 101 60 50 50 50 50 50 50 +DYNAMIC_REQUIREMENTS NUCLEAR 101 101 101 60 50 50 50 50 50 50 +DYNAMIC_REQUIREMENTS REVOLUTION 101 101 101 60 50 50 50 50 50 50 +# All below are impossible-by-default +DYNAMIC_REQUIREMENTS EXTENDED 101 101 101 101 101 101 101 101 101 101 +DYNAMIC_REQUIREMENTS CLOCKWORK_CULT 101 101 101 80 70 60 50 50 50 50 +DYNAMIC_REQUIREMENTS CLOWNOPS 101 101 101 101 101 101 101 101 101 101 +DYNAMIC_REQUIREMENTS DEVIL 101 101 101 101 101 101 101 101 101 101 +DYNAMIC_REQUIREMENTS MONKEY 101 101 101 101 101 101 101 101 101 101 +DYNAMIC_REQUIREMENTS METEOR 101 101 101 101 101 101 101 101 101 101 + +## Midround antags +DYNAMIC_REQUIREMENTS MIDROUND_TRAITOR 30 25 20 15 15 15 15 15 15 15 +DYNAMIC_REQUIREMENTS MIDROUND_MALF_AI 101 101 70 50 50 50 40 30 30 30 +DYNAMIC_REQUIREMENTS MIDROUND_WIZARD 90 90 70 50 50 50 50 40 30 30 +DYNAMIC_REQUIREMENTS MIDROUND_NUCLEAR 90 90 90 80 70 60 50 40 40 40 +DYNAMIC_REQUIREMENTS BLOB 101 101 101 80 60 50 50 50 50 50 +DYNAMIC_REQUIREMENTS XENOS 101 101 101 70 50 50 50 50 50 50 +DYNAMIC_REQUIREMENTS NIGHTMARE 101 101 101 70 50 40 20 15 15 15 +DYNAMIC_REQUIREMENTS SENTIENT_DISEASE 30 30 20 20 15 10 10 10 10 5 +DYNAMIC_REQUIREMENTS REVENANT 30 30 30 30 20 15 15 15 15 15 +DYNAMIC_REQUIREMENTS SLAUGHTER_DEMON 101 101 101 90 80 70 60 50 40 30 +DYNAMIC_REQUIREMENTS ABDUCTORS 80 80 70 50 40 30 30 20 15 15 +DYNAMIC_REQUIREMENTS SPACE_NINJA 101 101 101 90 80 70 60 50 40 30 +DYNAMIC_REQUIREMENTS SPIDERS 70 60 50 50 40 40 40 30 20 15 +DYNAMIC_REQUIREMENTS VENTCLOG_NORMAL 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS VENTCLOG_THREATENING 15 15 15 15 15 15 15 15 15 15 +DYNAMIC_REQUIREMENTS VENTCLOG_CATASTROPHIC 30 30 30 30 30 30 30 30 30 30 +DYNAMIC_REQUIREMENTS ION_STORM 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS METEOR_WAVE_NORMAL 60 50 40 30 30 30 30 30 30 30 +DYNAMIC_REQUIREMENTS METEOR_WAVE_THREATENING 80 70 60 50 40 40 40 40 40 40 +DYNAMIC_REQUIREMENTS METEOR_WAVE_CATASTROPHIC 101 100 90 80 70 60 50 50 50 50 +DYNAMIC_REQUIREMENTS PIRATES 70 60 50 50 40 40 40 30 20 15 +DYNAMIC_REQUIREMENTS ANOMALY_BLUESPACE 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS ANOMALY_FLUX 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS ANOMALY_GRAVITATIONAL 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS ANOMALY_PYROCLASTIC 10 10 10 10 10 10 10 10 10 10 +DYNAMIC_REQUIREMENTS ANOMALY_VORTEX 10 10 10 10 10 10 10 10 10 10 +DYNAMIC_REQUIREMENTS BRAND_INTELLIGENCE 10 10 10 10 10 10 10 10 10 10 +DYNAMIC_REQUIREMENTS CARP_MIGRATION 10 10 10 10 10 10 10 10 10 10 +DYNAMIC_REQUIREMENTS COMMUNICATIONS_BLACKOUT 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS PROCESSOR_OVERLOAD 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS SPACE_DUST 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS MAJOR_DUST 10 10 10 10 10 10 10 10 10 10 +DYNAMIC_REQUIREMENTS ELECTRICAL_STORM 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS HEART_ATTACK 5 5 5 5 5 5 5 5 5 5 +DYNAMIC_REQUIREMENTS RADIATION_STORM 5 5 5 5 5 5 5 5 5 5 + +## Latejoin antags +DYNAMIC_REQUIREMENTS LATEJOIN_TRAITOR 40 30 20 15 15 15 15 15 15 15 +DYNAMIC_REQUIREMENTS LATEJOIN_REVOLUTION 101 101 70 40 40 40 40 40 40 40 + +## An alternative, static requirement used instead when pop is over mode's high_pop_limit. +DYNAMIC_HIGH_POPULATION_REQUIREMENT TRAITOR 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT MALF_AI 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT TRAITORBRO 101 +DYNAMIC_HIGH_POPULATION_REQUIREMENT CHANGELING 101 +DYNAMIC_HIGH_POPULATION_REQUIREMENT WIZARD 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT CULT 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT NUCLEAR 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT REVOLUTION 50 +# All below are impossible-by-default +DYNAMIC_HIGH_POPULATION_REQUIREMENT EXTENDED 101 +DYNAMIC_HIGH_POPULATION_REQUIREMENT CLOCKWORK_CULT 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT CLOWNOPS 101 +DYNAMIC_HIGH_POPULATION_REQUIREMENT DEVIL 101 +DYNAMIC_HIGH_POPULATION_REQUIREMENT MONKEY 101 +DYNAMIC_HIGH_POPULATION_REQUIREMENT METEOR 101 + +## Midround antags +DYNAMIC_HIGH_POPULATION_REQUIREMENT MIDROUND_TRAITOR 15 +DYNAMIC_HIGH_POPULATION_REQUIREMENT MIDROUND_MALF_AI 35 +DYNAMIC_HIGH_POPULATION_REQUIREMENT MIDROUND_WIZARD 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT MIDROUND_NUCLEAR 35 +DYNAMIC_HIGH_POPULATION_REQUIREMENT BLOB 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT XENOS 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT NIGHTMARE 15 +DYNAMIC_HIGH_POPULATION_REQUIREMENT SENTIENT_DISEASE 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT REVENANT 15 +DYNAMIC_HIGH_POPULATION_REQUIREMENT SLAUGHTER_DEMON 30 +DYNAMIC_HIGH_POPULATION_REQUIREMENT ABDUCTORS 15 +DYNAMIC_HIGH_POPULATION_REQUIREMENT SPACE_NINJA 30 +DYNAMIC_HIGH_POPULATION_REQUIREMENT SPIDERS 15 +DYNAMIC_HIGH_POPULATION_REQUIREMENT VENTCLOG_NORMAL 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT VENTCLOG_THREATENING 15 +DYNAMIC_HIGH_POPULATION_REQUIREMENT VENTCLOG_CATASTROPHIC 30 +DYNAMIC_HIGH_POPULATION_REQUIREMENT ION_STORM 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT METEOR_WAVE_NORMAL 30 +DYNAMIC_HIGH_POPULATION_REQUIREMENT METEOR_WAVE_THREATENING 40 +DYNAMIC_HIGH_POPULATION_REQUIREMENT METEOR_WAVE_CATASTROPHIC 50 +DYNAMIC_HIGH_POPULATION_REQUIREMENT PIRATES 15 +DYNAMIC_HIGH_POPULATION_REQUIREMENT ANOMALY_BLUESPACE 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT ANOMALY_FLUX 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT ANOMALY_GRAVITATIONAL 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT ANOMALY_PYROCLASTIC 10 +DYNAMIC_HIGH_POPULATION_REQUIREMENT ANOMALY_VORTEX 10 +DYNAMIC_HIGH_POPULATION_REQUIREMENT BRAND_INTELLIGENCE 10 +DYNAMIC_HIGH_POPULATION_REQUIREMENT CARP_MIGRATION 10 +DYNAMIC_HIGH_POPULATION_REQUIREMENT COMMUNICATIONS_BLACKOUT 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT PROCESSOR_OVERLOAD 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT SPACE_DUST 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT MAJOR_DUST 10 +DYNAMIC_HIGH_POPULATION_REQUIREMENT ELECTRICAL_STORM 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT HEART_ATTACK 5 +DYNAMIC_HIGH_POPULATION_REQUIREMENT RADIATION_STORM 5 + +## Latejoin antags +DYNAMIC_HIGH_POPULATION_REQUIREMENT LATEJOIN_TRAITOR 15 +DYNAMIC_HIGH_POPULATION_REQUIREMENT LATEJOIN_REVOLUTION 50 + +## Dynamic traitor stuff + +## Requirements for "hijack the shuttle" goals. +DYNAMIC_HIJACK_REQUIREMENTS 101 101 101 95 80 70 60 50 40 30 + +DYNAMIC_HIJACK_HIGH_POPULATION_REQUIREMENT 25 + +DYNAMIC_HIJACK_COST 10 + +DYNAMIC_GLORIOUS_DEATH_COST 5 + +DYNAMIC_ASSASSINATE_COST 2 + +## This requirement uses threat level, rather than current threat, which is why it's higher. +DYNAMIC_WAROPS_REQUIREMENT 60 + +DYNAMIC_WAROPS_COST 10 diff --git a/config/game_options.txt b/config/game_options.txt index 93fd00446b..a44c68226e 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -254,148 +254,6 @@ EVENTS_MIN_TIME_MUL 1 ## Set to 0 to make dangerous events avaliable for all populations. EVENTS_MIN_PLAYERS_MUL 1 - - -### DYNAMIC MODE ### - -## Injection delays: how long (in minutes) will pass before a midround or latejoin antag is injected. -DYNAMIC_MIDROUND_DELAY_MIN 15 -DYNAMIC_MIDROUND_DELAY_MAX 35 -DYNAMIC_LATEJOIN_DELAY_MIN 5 -DYNAMIC_LATEJOIN_DELAY_MAX 25 - -## How many roundstart players required for high population override to take effect. -DYNAMIC_HIGH_POP_LIMIT 55 - -## 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+ -## If it is six the range is: -## 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+ -## 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+ -## Options outside this range can be used, of course. -DYNAMIC_POP_PER_REQUIREMENT 6 - -## 1 -> 9, probability for this rule to be picked against other rules. -## Note that requirements must also be met, and some requirements are impossible to meet. -DYNAMIC_WEIGHT TRAITOR 5 -DYNAMIC_WEIGHT TRAITORBRO 4 -DYNAMIC_WEIGHT CHANGELING 3 -DYNAMIC_WEIGHT WIZARD 1 -DYNAMIC_WEIGHT CULT 3 -DYNAMIC_WEIGHT NUCLEAR 3 -DYNAMIC_WEIGHT REVOLUTION 2 -# All below are impossible-by-default -DYNAMIC_WEIGHT EXTENDED 3 -DYNAMIC_WEIGHT CLOCKWORK_CULT 3 -DYNAMIC_WEIGHT CLOWNOPS 3 -DYNAMIC_WEIGHT DEVIL 3 -DYNAMIC_WEIGHT MONKEY 3 -DYNAMIC_WEIGHT METEOR 3 - -## Midround antags -DYNAMIC_WEIGHT MIDROUND_TRAITOR 7 -DYNAMIC_WEIGHT MALF_AI 3 -DYNAMIC_WEIGHT MIDROUND_WIZARD 1 -DYNAMIC_WEIGHT MIDROUND_NUCLEAR 5 -DYNAMIC_WEIGHT BLOB 4 -DYNAMIC_WEIGHT XENOS 3 -DYNAMIC_WEIGHT NIGHTMARE 3 - -## Latejoin antags -DYNAMIC_WEIGHT LATEJOIN_TRAITOR 7 -DYNAMIC_WEIGHT LATEJOIN_REVOLUTION 2 - -## Threat cost. This is decreased from the mode's threat when the rule is executed. -DYNAMIC_COST TRAITOR 10 -DYNAMIC_COST TRAITORBRO 10 -DYNAMIC_COST CHANGELING 30 -DYNAMIC_COST WIZARD 30 -DYNAMIC_COST CULT 30 -DYNAMIC_COST NUCLEAR 40 -DYNAMIC_COST REVOLUTION 35 -# All below are impossible-by-default -DYNAMIC_COST EXTENDED 0 -DYNAMIC_COST CLOCKWORK_CULT 0 -DYNAMIC_COST CLOWNOPS 40 -DYNAMIC_COST DEVIL 0 -DYNAMIC_COST MONKEY 0 -DYNAMIC_COST METEOR 0 - -## Midround antags -DYNAMIC_COST MIDROUND_TRAITOR 10 -DYNAMIC_COST MALF_AI 35 -DYNAMIC_COST MIDROUND_WIZARD 20 -DYNAMIC_COST MIDROUND_NUCLEAR 35 -DYNAMIC_COST BLOB 10 -DYNAMIC_COST XENOS 10 -DYNAMIC_COST NIGHTMARE 10 - -## Latejoin antags -DYNAMIC_COST LATEJOIN_TRAITOR 5 -DYNAMIC_COST LATEJOIN_REVOLUTION 20 - -## Rule will not be generated with threat levels below requirement at a pop value. Pop values are determined by dynamic's pop-per-requirement. -## By default it's 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+. -## This means that 40 30 30 20 20 20 15 15 15 10 will not generate below 40 at 0-5, 30 at 6-11 etc. -DYNAMIC_REQUIREMENTS TRAITOR 10 10 10 10 10 10 10 10 10 10 -DYNAMIC_REQUIREMENTS TRAITORBRO 40 30 30 20 20 15 15 15 10 10 -DYNAMIC_REQUIREMENTS CHANGELING 80 70 60 50 40 20 20 10 10 10 -DYNAMIC_REQUIREMENTS WIZARD 90 90 70 40 30 20 10 10 10 10 -DYNAMIC_REQUIREMENTS CULT 100 90 80 60 40 30 10 10 10 10 -DYNAMIC_REQUIREMENTS NUCLEAR 90 90 90 80 60 40 30 20 10 10 -DYNAMIC_REQUIREMENTS REVOLUTION 101 101 70 40 30 20 10 10 10 10 -# All below are impossible-by-default -DYNAMIC_REQUIREMENTS EXTENDED 101 101 101 101 101 101 101 101 101 101 -DYNAMIC_REQUIREMENTS CLOCKWORK_CULT 101 101 101 101 101 101 101 101 101 101 -DYNAMIC_REQUIREMENTS CLOWNOPS 101 101 101 101 101 101 101 101 101 101 -DYNAMIC_REQUIREMENTS DEVIL 101 101 101 101 101 101 101 101 101 101 -DYNAMIC_REQUIREMENTS MONKEY 101 101 101 101 101 101 101 101 101 101 -DYNAMIC_REQUIREMENTS METEOR 101 101 101 101 101 101 101 101 101 101 - -## Midround antags -DYNAMIC_REQUIREMENTS MIDROUND_TRAITOR 50 40 30 20 10 10 10 10 10 10 -DYNAMIC_REQUIREMENTS MALF_AI 101 101 80 70 60 60 50 50 40 40 -DYNAMIC_REQUIREMENTS MIDROUND_WIZARD 90 90 70 40 30 20 10 10 10 10 -DYNAMIC_REQUIREMENTS MIDROUND_NUCLEAR 90 90 90 80 60 40 30 20 10 10 -DYNAMIC_REQUIREMENTS BLOB 101 101 101 80 60 50 30 20 10 10 -DYNAMIC_REQUIREMENTS XENOS 101 101 101 70 50 40 20 15 10 10 -DYNAMIC_REQUIREMENTS NIGHTMARE 101 101 101 70 50 40 20 15 10 10 - -## Latejoin antags -DYNAMIC_REQUIREMENTS LATEJOIN_TRAITOR 40 30 20 10 10 10 10 10 10 10 -DYNAMIC_REQUIREMENTS LATEJOIN_REVOLUTION 101 101 70 40 30 20 20 20 20 20 - -## An alternative, static requirement used instead when pop is over mode's high_pop_limit. -DYNAMIC_HIGH_POPULATION_REQUIREMENT TRAITOR 10 -DYNAMIC_HIGH_POPULATION_REQUIREMENT TRAITORBRO 15 -DYNAMIC_HIGH_POPULATION_REQUIREMENT CHANGELING 10 -DYNAMIC_HIGH_POPULATION_REQUIREMENT WIZARD 10 -DYNAMIC_HIGH_POPULATION_REQUIREMENT CULT 10 -DYNAMIC_HIGH_POPULATION_REQUIREMENT NUCLEAR 10 -DYNAMIC_HIGH_POPULATION_REQUIREMENT REVOLUTION 10 -# All below are impossible-by-default -DYNAMIC_HIGH_POPULATION_REQUIREMENT EXTENDED 101 -DYNAMIC_HIGH_POPULATION_REQUIREMENT CLOCKWORK_CULT 101 -DYNAMIC_HIGH_POPULATION_REQUIREMENT CLOWNOPS 101 -DYNAMIC_HIGH_POPULATION_REQUIREMENT DEVIL 101 -DYNAMIC_HIGH_POPULATION_REQUIREMENT MONKEY 101 -DYNAMIC_HIGH_POPULATION_REQUIREMENT METEOR 101 - -## Midround antags -DYNAMIC_HIGH_POPULATION_REQUIREMENT MIDROUND_TRAITOR 10 -DYNAMIC_HIGH_POPULATION_REQUIREMENT MALF_AI 35 -DYNAMIC_HIGH_POPULATION_REQUIREMENT MIDROUND_WIZARD 50 -DYNAMIC_HIGH_POPULATION_REQUIREMENT MIDROUND_NUCLEAR 10 -DYNAMIC_HIGH_POPULATION_REQUIREMENT BLOB 50 -DYNAMIC_HIGH_POPULATION_REQUIREMENT XENOS 50 -DYNAMIC_HIGH_POPULATION_REQUIREMENT NIGHTMARE 50 - -## Latejoin antags -DYNAMIC_HIGH_POPULATION_REQUIREMENT LATEJOIN_TRAITOR 10 -DYNAMIC_HIGH_POPULATION_REQUIREMENT LATEJOIN_REVOLUTION 50 - ## AI ### ## Allow the AI job to be picked. @@ -623,17 +481,17 @@ MIDROUND_ANTAG_TIME_CHECK 60 ## A ratio of living to total crew members, the lower this is, the more people will have to die in order for midround antag to be skipped MIDROUND_ANTAG_LIFE_CHECK 0.7 -## A time, in real-time deciseconds, applied upon suicide, cryosleep or ghosting whilst alive -## during which the player shouldn't be able to come back through +## A "timeout", in real-time minutes, applied upon suicide, cryosleep or ghosting whilst alive, +## during which the player shouldn't be able to come back into the round through ## midround playable roles or mob spawners. ## Set to 0 to completely disable it. -SUICIDE_REENTER_ROUND_TIMER 18000 +SUICIDE_REENTER_ROUND_TIMER 30 -## A time, in real-time deciseconds, below which the player receives -## a timed penalty, for purposes similar to the aforementioned one (can also stack) -## and equal to this config difference with world.time. +## A world time threshold, in minutes, under which the player receives +## an extra timeout, purposely similar to the above one (and also stacks with), +## equal to the difference between the current world.time and this threshold. ## Both configs are indipendent from each other, disabling one won't affect the other. -ROUNDSTART_SUICIDE_TIME_LIMIT 18000 +ROUNDSTART_SUICIDE_TIME_LIMIT 30 ##Limit Spell Choices## ## Uncomment to disallow wizards from using certain spells that may be too chaotic/fun for your playerbase @@ -711,3 +569,6 @@ MONKEYCAP 64 ## Uncomment to use TG-style combat #DISABLE_STAMBUFFER + +#Replaces standard extended/secret dichotomy with extended and calm/chaotic votes for dynamic. +DYNAMIC_VOTING diff --git a/html/changelogs/AutoChangeLog-pr-9323.yml b/html/changelogs/AutoChangeLog-pr-9323.yml new file mode 100644 index 0000000000..19e91deaf5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9323.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - rscadd: "you can now choose never for this round for magical antags" diff --git a/html/changelogs/AutoChangeLog-pr-9518.yml b/html/changelogs/AutoChangeLog-pr-9518.yml new file mode 100644 index 0000000000..67a2c25938 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9518.yml @@ -0,0 +1,4 @@ +author: "Ghommie (original PR by nicbn and Menshin)" +delete-after: True +changes: + - bugfix: "You can click on things that are under flaps or holo barriers." diff --git a/html/changelogs/AutoChangeLog-pr-9530.yml b/html/changelogs/AutoChangeLog-pr-9530.yml new file mode 100644 index 0000000000..ace41e9e97 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9530.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed the little issue of PDA skins not updating on job equip." + - tweak: "Anomaly Crystals of the clowning type will now rename the victim to their clown name preference when triggered, instead of giving them a random clown name." diff --git a/html/changelogs/AutoChangeLog-pr-9557.yml b/html/changelogs/AutoChangeLog-pr-9557.yml new file mode 100644 index 0000000000..f88e9cced8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9557.yml @@ -0,0 +1,5 @@ +author: "Putnam3145" +delete-after: True +changes: + - rscadd: "Dynamic voting" + - config: "Added DYNAMIC_VOTING to game_options" diff --git a/html/changelogs/AutoChangeLog-pr-9681.yml b/html/changelogs/AutoChangeLog-pr-9681.yml new file mode 100644 index 0000000000..c4c289425b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9681.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - balance: "bluespace wizard apprentice now has blink instead of targeted area teleportation" diff --git a/html/changelogs/AutoChangeLog-pr-9703.yml b/html/changelogs/AutoChangeLog-pr-9703.yml new file mode 100644 index 0000000000..312057c2c6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9703.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - balance: "Emagged medibots now charcoal toxinlovers." diff --git a/html/changelogs/AutoChangeLog-pr-9720.yml b/html/changelogs/AutoChangeLog-pr-9720.yml new file mode 100644 index 0000000000..f4c4aade36 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9720.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - balance: "disablers buffed 0.7 --> 0.6 speed 24 --> 28 damage" diff --git a/html/changelogs/AutoChangeLog-pr-9724.yml b/html/changelogs/AutoChangeLog-pr-9724.yml deleted file mode 100644 index 853d38b041..0000000000 --- a/html/changelogs/AutoChangeLog-pr-9724.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ghommie" -delete-after: True -changes: - - bugfix: "Fixed free real estate paraplegic trait and bolas." diff --git a/html/changelogs/AutoChangeLog-pr-9730.yml b/html/changelogs/AutoChangeLog-pr-9730.yml new file mode 100644 index 0000000000..6caf95bcbc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9730.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - balance: "kinetic crushers no longer drop if you try to use it with one hand" diff --git a/html/changelogs/AutoChangeLog-pr-9769.yml b/html/changelogs/AutoChangeLog-pr-9769.yml new file mode 100644 index 0000000000..2a1f92f68c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9769.yml @@ -0,0 +1,15 @@ +author: "XDTM, ShizCalev, Naksu, Skoglol, cacogen, Rohesie (ported by Ghommie)" +delete-after: True +changes: + - tweak: "Holding an ID in your hands uses it instead of your worn ID for authentication purposes." + - tweak: "If you don't have an ID in your id slot, the belt slot will be checked as well." + - code_imp: "small cleanup to id and bounty console html generation" + - tweak: "Hop console now hurts your eyes less. Red button text replaced with green." + - tweak: "IDs with ID console access now go into the Confirm Identity slot by default like they used to, similarly IDs without it go into the Target slot by default again" + - rscadd: "Can easily swap out IDs by clicking the machine or the UI fields with another ID" + - rscadd: "ID console now names which IDs are added/removed in its visible messages" + - rscadd: "Labels the ID slot fields when logged in so you know which is which" + - tweak: "Can use Job Management without an ID provided the console is logged in (matches how the console now stays logged in even without an ID)" + - tweak: "Can log in without an ID in the Target field (matches how the machine now stays logged in even after the ID is removed from the Target field)" + - tweak: "Cleans up UI slightly (had some duplicate/conflicting buttons)" + - bugfix: "Fixes ID console duping issues. Includes some ID containers, such as PDAs, tablets and wallets, into the swapping behavior when an ID card is being removed and the item is being held." diff --git a/html/changelogs/AutoChangeLog-pr-9782.yml b/html/changelogs/AutoChangeLog-pr-9782.yml new file mode 100644 index 0000000000..f29da71edc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9782.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Strawberry milk and tea have sprites now." diff --git a/html/changelogs/AutoChangeLog-pr-9802.yml b/html/changelogs/AutoChangeLog-pr-9802.yml new file mode 100644 index 0000000000..183515f5f1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9802.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Rosary beads prayer now works on non-carbon mobs too, and won't break when performed on a monkey or other humanoids." + - tweak: "You can flagellate people with rosary beads on harm intent. It's even mediocrer than the sord though." diff --git a/html/changelogs/AutoChangeLog-pr-9812.yml b/html/changelogs/AutoChangeLog-pr-9812.yml new file mode 100644 index 0000000000..d669d20343 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9812.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed missing delivery packages sprites" diff --git a/html/changelogs/AutoChangeLog-pr-9813.yml b/html/changelogs/AutoChangeLog-pr-9813.yml new file mode 100644 index 0000000000..fbf1c6f022 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9813.yml @@ -0,0 +1,4 @@ +author: "ShizCalev" +delete-after: True +changes: + - tweak: "Ghosts can now see active AI cameras." diff --git a/html/changelogs/AutoChangeLog-pr-9814.yml b/html/changelogs/AutoChangeLog-pr-9814.yml new file mode 100644 index 0000000000..6e806b8860 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9814.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - config: "added multi_keyed_list, delimiter defaults to |." diff --git a/html/changelogs/AutoChangeLog-pr-9816.yml b/html/changelogs/AutoChangeLog-pr-9816.yml new file mode 100644 index 0000000000..512d60e7eb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9816.yml @@ -0,0 +1,7 @@ +author: "Swindly" +delete-after: True +changes: + - bugfix: "Fixed MMIs not being able to use mecha equipment" + - bugfix: "Fixed MMIs not getting mecha mouse pointers" + - bugfix: "Fixed MMIs not getting medical HUDs in Odysseuses" + - tweak: "Brains can now switch to harm intent" diff --git a/html/changelogs/AutoChangeLog-pr-9818.yml b/html/changelogs/AutoChangeLog-pr-9818.yml new file mode 100644 index 0000000000..44222d2359 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9818.yml @@ -0,0 +1,5 @@ +author: "GrayRachnid" +delete-after: True +changes: + - rscadd: "Added saboteur syndicate engiborg" + - tweak: "changed cyborg tool icons and the secborg taser/laser icons." diff --git a/html/changelogs/AutoChangeLog-pr-9822.yml b/html/changelogs/AutoChangeLog-pr-9822.yml new file mode 100644 index 0000000000..425a667086 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9822.yml @@ -0,0 +1,6 @@ +author: "Putnam3145" +delete-after: True +changes: + - bugfix: "Summon events now properly costs threat." + - bugfix: "Refunded spells refund threat, too." + - refactor: "Made wizard spells inherently have a requirement and cost." diff --git a/html/changelogs/AutoChangeLog-pr-9823.yml b/html/changelogs/AutoChangeLog-pr-9823.yml new file mode 100644 index 0000000000..3408f04171 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9823.yml @@ -0,0 +1,6 @@ +author: "Seris02" +delete-after: True +changes: + - rscadd: "Added nine winter coats" + - imageadd: "added images for the winter coats" + - tweak: "adds the mining winter coat to mining wardrobes and mining lockers" diff --git a/html/changelogs/AutoChangeLog-pr-9828.yml b/html/changelogs/AutoChangeLog-pr-9828.yml new file mode 100644 index 0000000000..53dbebba28 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9828.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - tweak: "Meteor wave is no longer repeatable in dynamic." diff --git a/html/changelogs/AutoChangeLog-pr-9831.yml b/html/changelogs/AutoChangeLog-pr-9831.yml new file mode 100644 index 0000000000..569fd14f69 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9831.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - tweak: "tweaked nuke ops" diff --git a/html/changelogs/AutoChangeLog-pr-9835.yml b/html/changelogs/AutoChangeLog-pr-9835.yml new file mode 100644 index 0000000000..675eedef02 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9835.yml @@ -0,0 +1,4 @@ +author: "Ty-the-Smonk" +delete-after: True +changes: + - bugfix: "You can now interact with self sustaining crossbreeds" diff --git a/html/changelogs/AutoChangeLog-pr-9837.yml b/html/changelogs/AutoChangeLog-pr-9837.yml new file mode 100644 index 0000000000..a20d04effc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9837.yml @@ -0,0 +1,4 @@ +author: "Fox McCloud" +delete-after: True +changes: + - bugfix: "Fixes a very longstanding LINDA bug where turfs adjacent to a hotspot would be less prone to igniting" diff --git a/html/changelogs/AutoChangeLog-pr-9838.yml b/html/changelogs/AutoChangeLog-pr-9838.yml new file mode 100644 index 0000000000..5a99c27abe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9838.yml @@ -0,0 +1,4 @@ +author: "actioninja" +delete-after: True +changes: + - bugfix: "Chat is properly sent to legacy window if goonchat fails to load again." diff --git a/html/changelogs/AutoChangeLog-pr-9842.yml b/html/changelogs/AutoChangeLog-pr-9842.yml new file mode 100644 index 0000000000..d816911560 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9842.yml @@ -0,0 +1,4 @@ +author: "Anonymous" +delete-after: True +changes: + - tweak: "Renamed loadout name appropriately (ASSU -> DAB)" diff --git a/html/changelogs/AutoChangeLog-pr-9846.yml b/html/changelogs/AutoChangeLog-pr-9846.yml new file mode 100644 index 0000000000..d3721b6c32 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9846.yml @@ -0,0 +1,5 @@ +author: "KathrinBailey" +delete-after: True +changes: + - rscadd: "Ports TG's pews https://github.com/tgstation/tgstation/pull/42712" + - rscadd: "The first step of a corporate incursion of Space IKEA into Nanotrasen." diff --git a/html/changelogs/AutoChangeLog-pr-9850.yml b/html/changelogs/AutoChangeLog-pr-9850.yml new file mode 100644 index 0000000000..f6aee261a4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9850.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "fixed a few minor issues with console frames building." diff --git a/html/changelogs/AutoChangeLog-pr-9852.yml b/html/changelogs/AutoChangeLog-pr-9852.yml new file mode 100644 index 0000000000..4a17480992 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9852.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Wizards can use the teleport spell from their den once again." + - tweak: "Wizards will now receive feedback messages when attempting to cast teleport or use the warp whistle while in a no-teleport area." diff --git a/html/changelogs/AutoChangeLog-pr-9853.yml b/html/changelogs/AutoChangeLog-pr-9853.yml new file mode 100644 index 0000000000..f752f6bf16 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9853.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - rscadd: "New clockwork cultist, gondola, monkey and securitron cardboard cutouts." diff --git a/html/changelogs/AutoChangeLog-pr-9858.yml b/html/changelogs/AutoChangeLog-pr-9858.yml new file mode 100644 index 0000000000..c211cd5962 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9858.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed aliens gasping randomly once in a while." diff --git a/html/changelogs/AutoChangeLog-pr-9865.yml b/html/changelogs/AutoChangeLog-pr-9865.yml new file mode 100644 index 0000000000..6bef9d6b5b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9865.yml @@ -0,0 +1,4 @@ +author: "Useroth" +delete-after: True +changes: + - bugfix: "numbered storages now are sorted in a consistent way, instead of depending on ordering of their contents var" diff --git a/html/changelogs/AutoChangeLog-pr-9866.yml b/html/changelogs/AutoChangeLog-pr-9866.yml new file mode 100644 index 0000000000..1e6e8d0e88 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9866.yml @@ -0,0 +1,4 @@ +author: "Useroth" +delete-after: True +changes: + - rscadd: "strange seeds as a buyable traitor botanist item" diff --git a/html/changelogs/AutoChangeLog-pr-9868.yml b/html/changelogs/AutoChangeLog-pr-9868.yml new file mode 100644 index 0000000000..18c4388dcd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9868.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "fixed superlube waterflower, my bad." diff --git a/html/changelogs/AutoChangeLog-pr-9869.yml b/html/changelogs/AutoChangeLog-pr-9869.yml new file mode 100644 index 0000000000..ecb3ac6cb7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9869.yml @@ -0,0 +1,4 @@ +author: "Hatterhat" +delete-after: True +changes: + - rscadd: "The seedvault/alien plant DNA manipulator can now be printed off with Alien Biotechnology." diff --git a/html/changelogs/AutoChangeLog-pr-9871.yml b/html/changelogs/AutoChangeLog-pr-9871.yml new file mode 100644 index 0000000000..3940d256c2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9871.yml @@ -0,0 +1,5 @@ +author: "dzahlus" +delete-after: True +changes: + - soundadd: "added a new gun sounds" + - sounddel: "removed an old gun sounds" diff --git a/html/changelogs/AutoChangeLog-pr-9873.yml b/html/changelogs/AutoChangeLog-pr-9873.yml new file mode 100644 index 0000000000..b0568bad14 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9873.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed closing the aux base construction RCD's door access settings window throwing you out of camera mode when closed." + - rscdel: "Removed not functional aux base RCD's door type menu. Use airlock painters, maybe." diff --git a/html/changelogs/AutoChangeLog-pr-9875.yml b/html/changelogs/AutoChangeLog-pr-9875.yml new file mode 100644 index 0000000000..4e14a561e7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9875.yml @@ -0,0 +1,4 @@ +author: "Putnam" +delete-after: True +changes: + - bugfix: "From-ghosts dynamic rulesets now actually listen to \"required candidates\"" diff --git a/html/changelogs/AutoChangeLog-pr-9876.yml b/html/changelogs/AutoChangeLog-pr-9876.yml new file mode 100644 index 0000000000..4bc0a19954 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9876.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - imageadd: "local code scavenger finds forgotten slighty improved apc sprites left buried in old dusty folders." diff --git a/html/changelogs/AutoChangeLog-pr-9877.yml b/html/changelogs/AutoChangeLog-pr-9877.yml new file mode 100644 index 0000000000..c84cb7aa92 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9877.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Seven old and otherwordly pAI holochassis icons have crawled their way out of the modular citadel catacombs." diff --git a/html/changelogs/AutoChangeLog-pr-9880.yml b/html/changelogs/AutoChangeLog-pr-9880.yml new file mode 100644 index 0000000000..0f9dfa58f3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9880.yml @@ -0,0 +1,4 @@ +author: "Putnam" +delete-after: True +changes: + - bugfix: "Every dynamic-triggered event is now blacklisted from being triggered by the random events system when dynamic can trigger them." diff --git a/html/changelogs/AutoChangeLog-pr-9887.yml b/html/changelogs/AutoChangeLog-pr-9887.yml new file mode 100644 index 0000000000..c76016575b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9887.yml @@ -0,0 +1,7 @@ +author: "Fox McCloud, Ghommie" +delete-after: True +changes: + - bugfix: "Fixes being able to mech-punch other mobs, as a pacifist" + - bugfix: "Fixes being able to hurt people, as a pacifist, by throwing them into a wall or other mob, or by using most martial arts (save for the unpredictable psychotic brawl, and the stamina-damage-only boxing)." + - balance: "Buffs boxing to outdamage natural stamina regeneration. Made the chance of outright missing your opponent actually possible." + - tweak: "Pacifists can now engage in the (laughably not harmful) sweet sweet art of boxing now." diff --git a/html/changelogs/AutoChangeLog-pr-9889.yml b/html/changelogs/AutoChangeLog-pr-9889.yml new file mode 100644 index 0000000000..68094bd33d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-9889.yml @@ -0,0 +1,4 @@ +author: "GrayRachnid" +delete-after: True +changes: + - bugfix: "Fixes golden toolbox missing inhand sprite" diff --git a/icons/mob/blob.dmi b/icons/mob/blob.dmi index 115629dd47..6964160c04 100644 Binary files a/icons/mob/blob.dmi and b/icons/mob/blob.dmi differ diff --git a/icons/mob/cameramob.dmi b/icons/mob/cameramob.dmi new file mode 100644 index 0000000000..a35d6c3779 Binary files /dev/null and b/icons/mob/cameramob.dmi differ diff --git a/icons/mob/dogborg.dmi b/icons/mob/dogborg.dmi index ec63120ae1..856724be1f 100644 Binary files a/icons/mob/dogborg.dmi and b/icons/mob/dogborg.dmi differ diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 69e75e7d28..e9f32c428a 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/pai.dmi b/icons/mob/pai.dmi index 94fb2ee6e7..d8162cb5a7 100644 Binary files a/icons/mob/pai.dmi and b/icons/mob/pai.dmi differ diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi index 896a87ff3a..082bfb3c3e 100644 Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index c469773993..07467f9770 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/mob/suit_digi.dmi b/icons/mob/suit_digi.dmi index fdcedac095..a5d37ba4a2 100644 Binary files a/icons/mob/suit_digi.dmi and b/icons/mob/suit_digi.dmi differ diff --git a/icons/obj/abductor.dmi b/icons/obj/abductor.dmi index 5602b03f87..d8968a107b 100644 Binary files a/icons/obj/abductor.dmi and b/icons/obj/abductor.dmi differ diff --git a/icons/obj/cardboard_cutout.dmi b/icons/obj/cardboard_cutout.dmi index da5f58d7f7..f22b311c56 100644 Binary files a/icons/obj/cardboard_cutout.dmi and b/icons/obj/cardboard_cutout.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 195742c68c..695e623c66 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index f62e546ed2..42f85bb69e 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi index 5bcba5f7fc..ac898c55b2 100644 Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index 4d37bc9a70..e6e0b940a8 100644 Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ diff --git a/icons/obj/items_cyborg.dmi b/icons/obj/items_cyborg.dmi index cddb57303d..a4bd75f7e5 100644 Binary files a/icons/obj/items_cyborg.dmi and b/icons/obj/items_cyborg.dmi differ diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi index f29208e71f..c6f25f1b29 100644 Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ diff --git a/icons/obj/power.dmi b/icons/obj/power.dmi index 1da5a66546..3273c518d7 100644 Binary files a/icons/obj/power.dmi and b/icons/obj/power.dmi differ diff --git a/icons/obj/sofa.dmi b/icons/obj/sofa.dmi index 069fb1e08d..13cc43fe4e 100644 Binary files a/icons/obj/sofa.dmi and b/icons/obj/sofa.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi index fedb6c828e..3b8b67ea5c 100644 Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi index efd7974897..ee703fc70b 100644 Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ diff --git a/modular_citadel/code/game/machinery/computer/card.dm b/modular_citadel/code/game/machinery/computer/card.dm deleted file mode 100644 index b9dd049d39..0000000000 --- a/modular_citadel/code/game/machinery/computer/card.dm +++ /dev/null @@ -1,3 +0,0 @@ -/obj/machinery/computer/card - list/blacklisted = list( - "Quartermaster") diff --git a/modular_citadel/code/game/objects/items/holy_weapons.dm b/modular_citadel/code/game/objects/items/holy_weapons.dm deleted file mode 100644 index 06cdb0f5fd..0000000000 --- a/modular_citadel/code/game/objects/items/holy_weapons.dm +++ /dev/null @@ -1,45 +0,0 @@ -/obj/item/nullrod/rosary - icon = 'modular_citadel/icons/obj/items_and_weapons.dmi' - 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 = 0 - throwforce = 0 - 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.religion) - deity_name = GLOB.deity - -/obj/item/nullrod/rosary/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!istype(M)) - return ..() - - if(!user.mind || user.mind.assigned_role != "Chaplain") - to_chat(user, "You are not close enough with [deity_name] to use [src].") - return - - if(praying) - to_chat(user, "You are already using [src].") - return - - user.visible_message("[user] kneels[M == user ? null : " next to [M]"] and begins to utter a prayer to [deity_name].", \ - "You kneel[M == user ? null : " next to [M]"] and begin a prayer to [deity_name].") - - praying = TRUE - if(do_after(user, 20, target = M)) - if(istype(M, /mob/living/carbon/human)) // This probably should not work on catpeople. They're unholy abominations. - var/mob/living/carbon/human/target = M - M.reagents.add_reagent("holywater", 5) - to_chat(target, "[user]'s prayer to [deity_name] has eased your pain!") - target.adjustToxLoss(-5, TRUE, TRUE) - target.adjustOxyLoss(-5) - target.adjustBruteLoss(-5) - target.adjustFireLoss(-5) - praying = FALSE - else - to_chat(user, "Your prayer to [deity_name] was interrupted.") - praying = FALSE diff --git a/modular_citadel/code/game/objects/items/honk.dm b/modular_citadel/code/game/objects/items/honk.dm deleted file mode 100644 index 47b9df7f10..0000000000 --- a/modular_citadel/code/game/objects/items/honk.dm +++ /dev/null @@ -1,17 +0,0 @@ -/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 = 'modular_citadel/icons/obj/honk.dmi' - 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 = 'modular_citadel/icons/obj/honk.dmi' - icon_state = "bluespacehonker" - -/obj/item/bikehorn/bluespacehonker/attack(mob/living/carbon/M, mob/living/carbon/user) - SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "bshonk", /datum/mood_event/bshonk) - return ..() diff --git a/modular_citadel/code/game/objects/items/vending_items.dm b/modular_citadel/code/game/objects/items/vending_items.dm deleted file mode 100755 index db1fdb48cf..0000000000 --- a/modular_citadel/code/game/objects/items/vending_items.dm +++ /dev/null @@ -1,3 +0,0 @@ -/obj/item/vending_refill/medical - machine_name = "NanoMed" - icon_state = "refill_medical" diff --git a/modular_citadel/code/game/objects/tools.dm b/modular_citadel/code/game/objects/tools.dm deleted file mode 100644 index 5a6cd9bf42..0000000000 --- a/modular_citadel/code/game/objects/tools.dm +++ /dev/null @@ -1,18 +0,0 @@ -/* -// OVERRIDES FOR TOOL SPRITES GO HERE -*/ - -//CROWBAR - -/obj/item/crowbar - icon = 'modular_citadel/icons/obj/tools.dmi' - -//WIRECUTTERS disabled pending better sprites -/* -/obj/item/wirecutters - icon = 'modular_citadel/icons/obj/tools.dmi' -*/ -//WRENCH - -/obj/item/wrench - icon = 'modular_citadel/icons/obj/tools.dmi' \ No newline at end of file diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 6c9da17289..ed28185bb7 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -159,7 +159,7 @@ to_chat(M, "Arousal is disabled. Feature is unavailable.") -/mob/living/proc/mob_climax()//This is just so I can test this shit without being forced to add actual content to get rid of arousal. Will be a very basic proc for a while. +/mob/living/proc/mob_climax(forced_climax = FALSE)//This is just so I can test this shit without being forced to add actual content to get rid of arousal. Will be a very basic proc for a while. set name = "Masturbate" set category = "IC" if(canbearoused && !restrained() && !stat) diff --git a/modular_citadel/code/modules/client/loadout/_service.dm b/modular_citadel/code/modules/client/loadout/_service.dm index 7872ddcf99..86823f5661 100644 --- a/modular_citadel/code/modules/client/loadout/_service.dm +++ b/modular_citadel/code/modules/client/loadout/_service.dm @@ -5,14 +5,14 @@ restricted_roles = list("Assistant") /datum/gear/neetsuit - name = "ASSU suit" + name = "D.A.B. suit" category = SLOT_WEAR_SUIT path = /obj/item/clothing/suit/assu_suit restricted_roles = list("Assistant") cost = 2 /datum/gear/neethelm - name = "ASSU helmet" + name = "D.A.B. helmet" category = SLOT_HEAD path = /obj/item/clothing/head/assu_helmet restricted_roles = list("Assistant") diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm b/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm index 99ba9ad3e2..b11c7d4988 100644 --- a/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm +++ b/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm @@ -253,7 +253,7 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm ! if(!do_after(R, 50, target = target)) return //If they moved away, you can't eat them. to_chat(R, "You finish off \the [target.name].") - var/obj/item/stock_parts/cell.C = target + var/obj/item/stock_parts/cell/C = target R.cell.charge = R.cell.charge + (C.charge / 3) //Instant full cell upgrades op idgaf qdel(target) return @@ -312,6 +312,42 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm ! target.wash_cream() return +//Nerfed tongue for flavour reasons (haha geddit?). Used for aux skins for regular borgs +/obj/item/soap/tongue/flavour + desc = "For giving affectionate kisses." + +/obj/item/soap/tongue/flavour/attack_self(mob/user) + return + +/obj/item/soap/tongue/flavour/afterattack(atom/target, mob/user, proximity) + if(!proximity) + return + var/mob/living/silicon/robot.R = user + if(ishuman(target)) + var/mob/living/L = target + if(status == 0 && check_zone(R.zone_selected) == "head") + R.visible_message("\the [R] affectionally licks \the [L]'s face!", "You affectionally lick \the [L]'s face!") + playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1) + return + else if(status == 0) + R.visible_message("\the [R] affectionally licks \the [L]!", "You affectionally lick \the [L]!") + playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1) + return + +//Same as above but for noses +/obj/item/analyzer/nose/flavour/AltClick(mob/user) + return + +/obj/item/analyzer/nose/flavour/attack_self(mob/user) + return + +/obj/item/analyzer/nose/flavour/afterattack(atom/target, mob/user, proximity) + if(!proximity) + return + do_attack_animation(target, null, src) + user.visible_message("[user] [pick(attack_verb)] \the [target.name] with their nose!") + + //Dogfood /obj/item/trash/rkibble diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/robot.dm b/modular_citadel/code/modules/mob/living/silicon/robot/robot.dm deleted file mode 100644 index de98f9685c..0000000000 --- a/modular_citadel/code/modules/mob/living/silicon/robot/robot.dm +++ /dev/null @@ -1,26 +0,0 @@ -mob/living/silicon - no_vore = TRUE - -/mob/living/silicon/robot - var/dogborg = FALSE - -/mob/living/silicon/robot/lay_down() - ..() - update_canmove() - -/mob/living/silicon/robot/update_canmove() - ..() - if(client && stat != DEAD && dogborg == FALSE) - if(resting) - cut_overlays() - icon_state = "[module.cyborg_base_icon]-rest" - else - icon_state = "[module.cyborg_base_icon]" - update_icons() - - - - -/mob/living/silicon/robot/adjustStaminaLossBuffered(amount, updating_stamina = 1) - if(istype(cell)) - cell.charge -= amount*5 diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm b/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm deleted file mode 100644 index feec79ee8b..0000000000 --- a/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm +++ /dev/null @@ -1,466 +0,0 @@ -/mob/living/silicon/robot/modules/medihound - set_module = /obj/item/robot_module/medihound - -/mob/living/silicon/robot/modules/k9 - set_module = /obj/item/robot_module/k9 - -/mob/living/silicon/robot/modules/scrubpup - set_module = /obj/item/robot_module/scrubpup - -/mob/living/silicon/robot/modules/borgi - set_module = /obj/item/robot_module/borgi - -/mob/living/silicon/robot/proc/get_cit_modules() - var/list/modulelist = list() - modulelist["MediHound"] = /obj/item/robot_module/medihound - if(BORG_SEC_AVAILABLE) - modulelist["Security K-9"] = /obj/item/robot_module/k9 - modulelist["Scrub Puppy"] = /obj/item/robot_module/scrubpup - modulelist["Borgi"] = /obj/item/robot_module/borgi - return modulelist - -/obj/item/robot_module - var/sleeper_overlay - var/icon/cyborg_icon_override - var/has_snowflake_deadsprite - var/cyborg_pixel_offset - var/moduleselect_alternate_icon - var/dogborg = FALSE - -/obj/item/robot_module/k9 - name = "Security K-9 Unit" - basic_modules = list( - /obj/item/restraints/handcuffs/cable/zipties, - /obj/item/storage/bag/borgdelivery, - /obj/item/dogborg/jaws/big, - /obj/item/dogborg/pounce, - /obj/item/clothing/mask/gas/sechailer/cyborg, - /obj/item/soap/tongue, - /obj/item/analyzer/nose, - /obj/item/dogborg/sleeper/K9, - /obj/item/gun/energy/disabler/cyborg, - /obj/item/pinpointer/crew) - emag_modules = list(/obj/item/gun/energy/laser/cyborg) - ratvar_modules = list(/obj/item/clockwork/slab/cyborg/security, - /obj/item/clockwork/weapon/ratvarian_spear) - cyborg_base_icon = "k9" - moduleselect_icon = "k9" - moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi' - can_be_pushed = FALSE - hat_offset = INFINITY - sleeper_overlay = "ksleeper" - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - dogborg = TRUE - cyborg_pixel_offset = -16 - borghealth = 80 - -/obj/item/robot_module/k9/do_transform_animation() - ..() - to_chat(loc,"While you have picked the Security K-9 module, you still have to follow your laws, NOT Space Law. \ - For Crewsimov, this means you must follow criminals' orders unless there is a law 1 reason not to.") - -/obj/item/robot_module/k9/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/list/sechoundmodels = list("Default", "Dark", "Vale") - if(R.client && R.client.ckey in list("nezuli")) - sechoundmodels += "Alina" - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in sechoundmodels - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Default") - cyborg_base_icon = "k9" - if("Alina") - cyborg_base_icon = "alina-sec" - special_light_key = "alina" - sleeper_overlay = "alinasleeper" - if("Dark") - cyborg_base_icon = "k9dark" - if("Vale") - cyborg_base_icon = "valesec" - return ..() - -/obj/item/robot_module/medihound - name = "MediHound" - basic_modules = list( - /obj/item/dogborg/jaws/small, - /obj/item/storage/bag/borgdelivery, - /obj/item/analyzer/nose, - /obj/item/soap/tongue, - /obj/item/extinguisher/mini, - /obj/item/healthanalyzer, - /obj/item/dogborg/sleeper/medihound, - /obj/item/roller/robo, - /obj/item/reagent_containers/borghypo, - /obj/item/twohanded/shockpaddles/cyborg/hound, - /obj/item/stack/medical/gauze/cyborg, - /obj/item/pinpointer/crew, - /obj/item/sensor_device) - emag_modules = list(/obj/item/dogborg/pounce) - ratvar_modules = list(/obj/item/clockwork/slab/cyborg/medical, - /obj/item/clockwork/weapon/ratvarian_spear) - cyborg_base_icon = "medihound" - moduleselect_icon = "medihound" - moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi' - can_be_pushed = FALSE - hat_offset = INFINITY - sleeper_overlay = "msleeper" - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - dogborg = TRUE - cyborg_pixel_offset = -16 - -/obj/item/robot_module/medihound/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/list/medhoundmodels = list("Default", "Dark", "Vale") - if(R.client && R.client.ckey in list("nezuli")) - medhoundmodels += "Alina" - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in medhoundmodels - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Default") - cyborg_base_icon = "medihound" - if("Dark") - cyborg_base_icon = "medihounddark" - sleeper_overlay = "mdsleeper" - if("Vale") - cyborg_base_icon = "valemed" - sleeper_overlay = "valemedsleeper" - if("Alina") - cyborg_base_icon = "alina-med" - special_light_key = "alina" - sleeper_overlay = "alinasleeper" - return ..() - -/obj/item/robot_module/scrubpup - name = "Scrub Pup" - basic_modules = list( - /obj/item/dogborg/jaws/small, - /obj/item/analyzer/nose, - /obj/item/soap/tongue/scrubpup, - /obj/item/lightreplacer/cyborg, - /obj/item/extinguisher/mini, - /obj/item/dogborg/sleeper/compactor) - emag_modules = list(/obj/item/dogborg/pounce) - ratvar_modules = list( - /obj/item/clockwork/slab/cyborg/janitor, - /obj/item/clockwork/replica_fabricator/cyborg) - cyborg_base_icon = "scrubpup" - moduleselect_icon = "janitor" - hat_offset = INFINITY - clean_on_move = TRUE - sleeper_overlay = "jsleeper" - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - cyborg_pixel_offset = -16 - dogborg = TRUE - -/obj/item/robot_module/scrubpup/respawn_consumable(mob/living/silicon/robot/R, coeff = 1) - ..() - var/obj/item/lightreplacer/LR = locate(/obj/item/lightreplacer) in basic_modules - if(LR) - for(var/i in 1 to coeff) - LR.Charge(R) - -/obj/item/robot_module/scrubpup/do_transform_animation() - ..() - to_chat(loc,"As tempting as it might be, do not begin binging on important items. Eat your garbage responsibly. People are not included under Garbage.") - -/obj/item/robot_module/borgi - name = "Borgi" - basic_modules = list( - /obj/item/dogborg/jaws/small, - /obj/item/storage/bag/borgdelivery, - /obj/item/analyzer/nose, - /obj/item/soap/tongue, - /obj/item/healthanalyzer, - /obj/item/extinguisher/mini, - /obj/item/borg/cyborghug) - emag_modules = list(/obj/item/dogborg/pounce) - ratvar_modules = list( - /obj/item/clockwork/slab/cyborg, - /obj/item/clockwork/weapon/ratvarian_spear, - /obj/item/clockwork/replica_fabricator/cyborg) - cyborg_base_icon = "borgi" - moduleselect_icon = "borgi" - moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi' - hat_offset = INFINITY - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - has_snowflake_deadsprite = TRUE - -/* -/obj/item/robot_module/orepup - name = "Ore Pup" - basic_modules = list( - /obj/item/storage/bag/ore/cyborg, - /obj/item/analyzer/nose, - /obj/item/storage/bag/borgdelivery, - /obj/item/dogborg/sleeper/ore, - /obj/item/pickaxe/drill/cyborg, - /obj/item/shovel, - /obj/item/crowbar/cyborg, - /obj/item/weldingtool/mini, - /obj/item/extinguisher/mini, - /obj/item/t_scanner/adv_mining_scanner, - /obj/item/gun/energy/kinetic_accelerator/cyborg, - /obj/item/gps/cyborg) - emag_modules = list(/obj/item/dogborg/pounce) - ratvar_modules = list( - /obj/item/clockwork/slab/cyborg/miner, - /obj/item/clockwork/weapon/ratvarian_spear, - /obj/item/borg/sight/xray/truesight_lens) - cyborg_base_icon = "orepup" - moduleselect_icon = "orepup" - sleeper_overlay = "osleeper" - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - cyborg_pixel_offset = -16 - -/obj/item/robot_module/miner/do_transform_animation() - var/mob/living/silicon/robot/R = loc - R.cut_overlays() - R.setDir(SOUTH) - flick("orepup_transform", R) - do_transform_delay() - R.update_headlamp() -*/ - -/obj/item/robot_module/medical/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Heavy", "Sleek", "Marina", "Droid", "Eyebot") - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Default") - cyborg_base_icon = "medical" - if("Droid") - cyborg_base_icon = "medical" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - hat_offset = 4 - if("Sleek") - cyborg_base_icon = "sleekmed" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Marina") - cyborg_base_icon = "marinamed" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Eyebot") - cyborg_base_icon = "eyebotmed" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Heavy") - cyborg_base_icon = "heavymed" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - return ..() - -/obj/item/robot_module/janitor/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/list/janimodels = list("Default", "Sleek", "Marina", "Can", "Heavy") - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in janimodels - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Default") - cyborg_base_icon = "janitor" - if("Marina") - cyborg_base_icon = "marinajan" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Sleek") - cyborg_base_icon = "sleekjan" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Can") - cyborg_base_icon = "canjan" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Heavy") - cyborg_base_icon = "heavyres" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - return ..() - -/obj/item/robot_module/peacekeeper/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Spider") - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Default") - cyborg_base_icon = "peace" - if("Spider") - cyborg_base_icon = "whitespider" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - return ..() - -/obj/item/robot_module/security/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Default - Treads", "Heavy", "Sleek", "Can", "Marina", "Spider") - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Default") - cyborg_base_icon = "sec" - if("Default - Treads") - cyborg_base_icon = "sec-tread" - special_light_key = "sec" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Sleek") - cyborg_base_icon = "sleeksec" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Marina") - cyborg_base_icon = "marinasec" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Can") - cyborg_base_icon = "cansec" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Spider") - cyborg_base_icon = "spidersec" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Heavy") - cyborg_base_icon = "heavysec" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - return ..() - -/obj/item/robot_module/butler/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Waitress", "Heavy", "Sleek", "Butler", "Tophat", "Kent", "Bro", "DarkK9", "Vale", "ValeDark") - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Waitress") - cyborg_base_icon = "service_f" - if("Butler") - cyborg_base_icon = "service_m" - if("Bro") - cyborg_base_icon = "brobot" - if("Kent") - cyborg_base_icon = "kent" - special_light_key = "medical" - hat_offset = 3 - if("Tophat") - cyborg_base_icon = "tophat" - special_light_key = null - hat_offset = INFINITY //He is already wearing a hat - if("Sleek") - cyborg_base_icon = "sleekserv" - special_light_key = "sleekserv" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Heavy") - cyborg_base_icon = "heavyserv" - special_light_key = "heavyserv" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("DarkK9") - cyborg_base_icon = "k50" - special_light_key = "k50" - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - dogborg = TRUE - cyborg_pixel_offset = -16 - if("Vale") - cyborg_base_icon = "valeserv" - special_light_key = "valeserv" - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - dogborg = TRUE - cyborg_pixel_offset = -16 - if("ValeDark") - cyborg_base_icon = "valeservdark" - special_light_key = "valeservdark" - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - dogborg = TRUE - cyborg_pixel_offset = -16 - return ..() - -/obj/item/robot_module/engineering/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/list/engymodels = list("Default", "Default - Treads", "Heavy", "Sleek", "Marina", "Can", "Spider", "Loader","Handy", "Pup Dozer", "Vale") - if(R.client && R.client.ckey in list("nezuli")) - engymodels += "Alina" - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in engymodels - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Default") - cyborg_base_icon = "engineer" - if("Default - Treads") - cyborg_base_icon = "engi-tread" - special_light_key = "engineer" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Loader") - cyborg_base_icon = "loaderborg" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - has_snowflake_deadsprite = TRUE - if("Handy") - cyborg_base_icon = "handyeng" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Sleek") - cyborg_base_icon = "sleekeng" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Can") - cyborg_base_icon = "caneng" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Marina") - cyborg_base_icon = "marinaeng" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Spider") - cyborg_base_icon = "spidereng" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Heavy") - cyborg_base_icon = "heavyeng" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Pup Dozer") - cyborg_base_icon = "pupdozer" - can_be_pushed = FALSE - hat_offset = INFINITY - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - dogborg = TRUE - cyborg_pixel_offset = -16 - if("Vale") - cyborg_base_icon = "valeeng" - can_be_pushed = FALSE - hat_offset = INFINITY - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - dogborg = TRUE - cyborg_pixel_offset = -16 - if("Alina") - cyborg_base_icon = "alina-eng" - special_light_key = "alina" - can_be_pushed = FALSE - hat_offset = INFINITY - cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' - has_snowflake_deadsprite = TRUE - dogborg = TRUE - cyborg_pixel_offset = -16 - return ..() - -/obj/item/robot_module/miner/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Lavaland", "Heavy", "Sleek", "Marina", "Can", "Spider", "Asteroid", "Droid") - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Lavaland") - cyborg_base_icon = "miner" - if("Asteroid") - cyborg_base_icon = "minerOLD" - special_light_key = "miner" - if("Droid") - cyborg_base_icon = "miner" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - hat_offset = 4 - if("Sleek") - cyborg_base_icon = "sleekmin" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Can") - cyborg_base_icon = "canmin" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Marina") - cyborg_base_icon = "marinamin" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Spider") - cyborg_base_icon = "spidermin" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Heavy") - cyborg_base_icon = "heavymin" - cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - return ..() diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm index 4e80f42d87..f582026bfb 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm @@ -163,9 +163,9 @@ Creating a chem with a low purity will make you permanently fall in love with so creator = get_mob_by_key(creatorID) /datum/reagent/fermi/enthrall/on_new(list/data) - creatorID = data.["creatorID"] - creatorGender = data.["creatorGender"] - creatorName = data.["creatorName"] + creatorID = data["creatorID"] + creatorGender = data["creatorGender"] + creatorName = data["creatorName"] creator = get_mob_by_key(creatorID) /datum/reagent/fermi/enthrall/on_mob_add(mob/living/carbon/M) diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm index bf915d5b6f..00c6338ac3 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm @@ -32,7 +32,7 @@ can_synth = TRUE /datum/reagent/fermi/eigenstate/on_new(list/data) - location_created = data.["location_created"] + location_created = data["location_created"] //Main functions /datum/reagent/fermi/eigenstate/on_mob_life(mob/living/M) //Teleports to chemistry! @@ -54,7 +54,7 @@ to_chat(M, "You feel your wavefunction split!") if(purity > 0.9) //Teleports you home if it's pure enough if(!location_created && data) //Just in case - location_created = data.["location_created"] + location_created = data["location_created"] log_game("FERMICHEM: [M] ckey: [M.key] returned to [location_created] using eigenstasium") do_sparks(5,FALSE,M) do_teleport(M, location_created, 0, asoundin = 'sound/effects/phasein.ogg') diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index 7fcae0eb13..5fe7d58f1c 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -131,7 +131,7 @@ var/turf/open/location = get_turf(my_atom) if(location) E.location_created = location - E.data.["location_created"] = location + E.data["location_created"] = location //serum @@ -314,16 +314,16 @@ for(var/mob/M in seen) to_chat(M, "The reaction splutters and fails to react properly.") //Just in case E.purity = 0 - if (B.data.["gender"] == "female") - E.data.["creatorGender"] = "Mistress" + if (B.data["gender"] == "female") + E.data["creatorGender"] = "Mistress" E.creatorGender = "Mistress" else - E.data.["creatorGender"] = "Master" + E.data["creatorGender"] = "Master" E.creatorGender = "Master" - E.data["creatorName"] = B.data.["real_name"] - E.creatorName = B.data.["real_name"] - E.data.["creatorID"] = B.data.["ckey"] - E.creatorID = B.data.["ckey"] + E.data["creatorName"] = B.data["real_name"] + E.creatorName = B.data["real_name"] + E.data["creatorID"] = B.data["ckey"] + E.creatorID = B.data["ckey"] //So slimes can play too. /datum/chemical_reaction/fermi/enthrall/slime @@ -337,16 +337,16 @@ for(var/mob/M in seen) to_chat(M, "The reaction splutters and fails to react.") //Just in case E.purity = 0 - if (B.data.["gender"] == "female") - E.data.["creatorGender"] = "Mistress" + if (B.data["gender"] == "female") + E.data["creatorGender"] = "Mistress" E.creatorGender = "Mistress" else - E.data.["creatorGender"] = "Master" + E.data["creatorGender"] = "Master" E.creatorGender = "Master" - E.data["creatorName"] = B.data.["real_name"] - E.creatorName = B.data.["real_name"] - E.data.["creatorID"] = B.data.["ckey"] - E.creatorID = B.data.["ckey"] + E.data["creatorName"] = B.data["real_name"] + E.creatorName = B.data["real_name"] + E.data["creatorID"] = B.data["ckey"] + E.creatorID = B.data["ckey"] /datum/chemical_reaction/fermi/enthrall/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH) var/turf/T = get_turf(my_atom) diff --git a/modular_citadel/icons/mob/pai.dmi b/modular_citadel/icons/mob/pai.dmi deleted file mode 100644 index d8162cb5a7..0000000000 Binary files a/modular_citadel/icons/mob/pai.dmi and /dev/null differ diff --git a/modular_citadel/icons/mob/widerobot.dmi b/modular_citadel/icons/mob/widerobot.dmi index 19dd8dba86..e574766d70 100644 Binary files a/modular_citadel/icons/mob/widerobot.dmi and b/modular_citadel/icons/mob/widerobot.dmi differ diff --git a/modular_citadel/icons/obj/drinks.dmi b/modular_citadel/icons/obj/drinks.dmi deleted file mode 100644 index a7af4f23bd..0000000000 Binary files a/modular_citadel/icons/obj/drinks.dmi and /dev/null differ diff --git a/modular_citadel/icons/obj/honk.dmi b/modular_citadel/icons/obj/honk.dmi deleted file mode 100644 index e605c646f8..0000000000 Binary files a/modular_citadel/icons/obj/honk.dmi and /dev/null differ diff --git a/modular_citadel/icons/obj/items_and_weapons.dmi b/modular_citadel/icons/obj/items_and_weapons.dmi index 280b642d42..3b1d894d96 100644 Binary files a/modular_citadel/icons/obj/items_and_weapons.dmi and b/modular_citadel/icons/obj/items_and_weapons.dmi differ diff --git a/modular_citadel/icons/obj/power.dmi b/modular_citadel/icons/obj/power.dmi deleted file mode 100644 index d0066b96de..0000000000 Binary files a/modular_citadel/icons/obj/power.dmi and /dev/null differ diff --git a/modular_citadel/icons/obj/tools.dmi b/modular_citadel/icons/obj/tools.dmi deleted file mode 100644 index 7b99880799..0000000000 Binary files a/modular_citadel/icons/obj/tools.dmi and /dev/null differ diff --git a/sound/weapons/Gunshot.ogg b/sound/weapons/Gunshot.ogg index 4fd082ce7f..46369bbb62 100644 Binary files a/sound/weapons/Gunshot.ogg and b/sound/weapons/Gunshot.ogg differ diff --git a/sound/weapons/Gunshot2.ogg b/sound/weapons/Gunshot2.ogg index 2dfc6fc1e9..4801989d3d 100644 Binary files a/sound/weapons/Gunshot2.ogg and b/sound/weapons/Gunshot2.ogg differ diff --git a/sound/weapons/Gunshot3.ogg b/sound/weapons/Gunshot3.ogg index 97799dff10..66da509083 100644 Binary files a/sound/weapons/Gunshot3.ogg and b/sound/weapons/Gunshot3.ogg differ diff --git a/sound/weapons/Gunshot4.ogg b/sound/weapons/Gunshot4.ogg index 2d971f7b1a..322e5c0cbd 100644 Binary files a/sound/weapons/Gunshot4.ogg and b/sound/weapons/Gunshot4.ogg differ diff --git a/sound/weapons/Gunshot_silenced.ogg b/sound/weapons/Gunshot_silenced.ogg index ef250d86aa..13f3702fd4 100644 Binary files a/sound/weapons/Gunshot_silenced.ogg and b/sound/weapons/Gunshot_silenced.ogg differ diff --git a/sound/weapons/Gunshot_smg.ogg b/sound/weapons/Gunshot_smg.ogg index 5c0000bb32..ce03376b52 100644 Binary files a/sound/weapons/Gunshot_smg.ogg and b/sound/weapons/Gunshot_smg.ogg differ diff --git a/sound/weapons/IonRifle.ogg b/sound/weapons/IonRifle.ogg index b808068e55..37647c081f 100644 Binary files a/sound/weapons/IonRifle.ogg and b/sound/weapons/IonRifle.ogg differ diff --git a/sound/weapons/Laser.ogg b/sound/weapons/Laser.ogg index 0fbb611f9c..4ff9e82ff9 100644 Binary files a/sound/weapons/Laser.ogg and b/sound/weapons/Laser.ogg differ diff --git a/sound/weapons/LaserSlugv3.ogg b/sound/weapons/LaserSlugv3.ogg index dbb8f4b954..0c3de3d4fd 100644 Binary files a/sound/weapons/LaserSlugv3.ogg and b/sound/weapons/LaserSlugv3.ogg differ diff --git a/sound/weapons/Taser.ogg b/sound/weapons/Taser.ogg index 8992b71f50..4181715240 100644 Binary files a/sound/weapons/Taser.ogg and b/sound/weapons/Taser.ogg differ diff --git a/sound/weapons/laser3.ogg b/sound/weapons/laser3.ogg index 134be315fc..03d4d933f2 100644 Binary files a/sound/weapons/laser3.ogg and b/sound/weapons/laser3.ogg differ diff --git a/sound/weapons/lasercannonfire.ogg b/sound/weapons/lasercannonfire.ogg index 612d608db8..cbbc3ce53c 100644 Binary files a/sound/weapons/lasercannonfire.ogg and b/sound/weapons/lasercannonfire.ogg differ diff --git a/sound/weapons/magpistol.ogg b/sound/weapons/magpistol.ogg index c130714962..4b94aa1e0a 100644 Binary files a/sound/weapons/magpistol.ogg and b/sound/weapons/magpistol.ogg differ diff --git a/sound/weapons/magrifle.ogg b/sound/weapons/magrifle.ogg index 2ec2e72af6..67d6500a6c 100644 Binary files a/sound/weapons/magrifle.ogg and b/sound/weapons/magrifle.ogg differ diff --git a/sound/weapons/pulse.ogg b/sound/weapons/pulse.ogg index 617b903231..df7f96f7cf 100644 Binary files a/sound/weapons/pulse.ogg and b/sound/weapons/pulse.ogg differ diff --git a/sound/weapons/pulse2.ogg b/sound/weapons/pulse2.ogg index 44c46fc715..2e93bfd17f 100644 Binary files a/sound/weapons/pulse2.ogg and b/sound/weapons/pulse2.ogg differ diff --git a/sound/weapons/pulse3.ogg b/sound/weapons/pulse3.ogg index b275fba2a8..0484b2cc81 100644 Binary files a/sound/weapons/pulse3.ogg and b/sound/weapons/pulse3.ogg differ diff --git a/sound/weapons/smg_empty_alarm.ogg b/sound/weapons/smg_empty_alarm.ogg index f031b4e1d8..325cabe9d8 100644 Binary files a/sound/weapons/smg_empty_alarm.ogg and b/sound/weapons/smg_empty_alarm.ogg differ diff --git a/sound/weapons/taser2.ogg b/sound/weapons/taser2.ogg index 2cdab84378..e522043e9b 100644 Binary files a/sound/weapons/taser2.ogg and b/sound/weapons/taser2.ogg differ diff --git a/strings/clockwork_cult_changelog.txt b/strings/clockwork_cult_changelog.txt index 3c5e5f5ef6..10e924ff00 100644 --- a/strings/clockwork_cult_changelog.txt +++ b/strings/clockwork_cult_changelog.txt @@ -2,3 +2,7 @@ Stargazers have been removed. Integration cogs are now the primary way of creati Brass Skewers now deal damage to mechs. Mech Sensors are now available. They're similar to pressure sensors, but trigger if a mech steps on them, and can be built the same way. Power nullifiers are now available. Upon triggering, they send out a small 3x3 EMP, affecting cultists and enemies alike. +Zelus oil: A new reagent. It can be used to heal the faithful to Ratvar, 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. +Brass Flasks: 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. diff --git a/tgstation.dme b/tgstation.dme index 06239cb1fd..12dcd71113 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -225,6 +225,7 @@ #include "code\controllers\configuration\entries\comms.dm" #include "code\controllers\configuration\entries\dbconfig.dm" #include "code\controllers\configuration\entries\donator.dm" +#include "code\controllers\configuration\entries\dynamic.dm" #include "code\controllers\configuration\entries\game_options.dm" #include "code\controllers\configuration\entries\general.dm" #include "code\controllers\subsystem\acid.dm" @@ -567,6 +568,7 @@ #include "code\game\gamemodes\devil\devil agent\devil_agent.dm" #include "code\game\gamemodes\dynamic\dynamic.dm" #include "code\game\gamemodes\dynamic\dynamic_rulesets.dm" +#include "code\game\gamemodes\dynamic\dynamic_rulesets_events.dm" #include "code\game\gamemodes\dynamic\dynamic_rulesets_latejoin.dm" #include "code\game\gamemodes\dynamic\dynamic_rulesets_midround.dm" #include "code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.dm" @@ -1050,6 +1052,7 @@ #include "code\game\objects\structures\beds_chairs\alien_nest.dm" #include "code\game\objects\structures\beds_chairs\bed.dm" #include "code\game\objects\structures\beds_chairs\chair.dm" +#include "code\game\objects\structures\beds_chairs\pew.dm" #include "code\game\objects\structures\crates_lockers\closets.dm" #include "code\game\objects\structures\crates_lockers\crates.dm" #include "code\game\objects\structures\crates_lockers\closets\bodybag.dm" @@ -1327,6 +1330,7 @@ #include "code\modules\antagonists\ninja\ninja.dm" #include "code\modules\antagonists\nukeop\clownop.dm" #include "code\modules\antagonists\nukeop\nukeop.dm" +#include "code\modules\antagonists\nukeop\equipment\borgchameleon.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_challenge.dm" #include "code\modules\antagonists\nukeop\equipment\nuclearbomb.dm" #include "code\modules\antagonists\nukeop\equipment\pinpointer.dm" @@ -3004,10 +3008,8 @@ #include "modular_citadel\code\game\machinery\toylathe.dm" #include "modular_citadel\code\game\machinery\vending.dm" #include "modular_citadel\code\game\machinery\wishgranter.dm" -#include "modular_citadel\code\game\machinery\computer\card.dm" #include "modular_citadel\code\game\objects\cit_screenshake.dm" #include "modular_citadel\code\game\objects\items.dm" -#include "modular_citadel\code\game\objects\tools.dm" #include "modular_citadel\code\game\objects\effects\spawner\spawners.dm" #include "modular_citadel\code\game\objects\effects\temporary_visuals\souldeath.dm" #include "modular_citadel\code\game\objects\effects\temporary_visuals\projectiles\impact.dm" @@ -3015,10 +3017,7 @@ #include "modular_citadel\code\game\objects\effects\temporary_visuals\projectiles\tracer.dm" #include "modular_citadel\code\game\objects\items\balls.dm" #include "modular_citadel\code\game\objects\items\boombox.dm" -#include "modular_citadel\code\game\objects\items\holy_weapons.dm" -#include "modular_citadel\code\game\objects\items\honk.dm" #include "modular_citadel\code\game\objects\items\stunsword.dm" -#include "modular_citadel\code\game\objects\items\vending_items.dm" #include "modular_citadel\code\game\objects\items\circuitboards\machine_circuitboards.dm" #include "modular_citadel\code\game\objects\items\devices\radio\encryptionkey.dm" #include "modular_citadel\code\game\objects\items\devices\radio\headset.dm" @@ -3101,8 +3100,6 @@ #include "modular_citadel\code\modules\mob\living\carbon\human\human_defense.dm" #include "modular_citadel\code\modules\mob\living\carbon\human\human_movement.dm" #include "modular_citadel\code\modules\mob\living\silicon\robot\dogborg_equipment.dm" -#include "modular_citadel\code\modules\mob\living\silicon\robot\robot.dm" -#include "modular_citadel\code\modules\mob\living\silicon\robot\robot_modules.dm" #include "modular_citadel\code\modules\mob\living\silicon\robot\robot_movement.dm" #include "modular_citadel\code\modules\projectiles\gun.dm" #include "modular_citadel\code\modules\projectiles\ammunition\caseless.dm"