diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 42199174e7..c12ec20de2 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -22,7 +22,7 @@ #define COMPONENT_GLOB_BLOCK_CINEMATIC 1 // signals from globally accessible objects -/// from SSsun when the sun changes position : (azimuth) +/// from SSsun when the sun changes position : (primary_sun, suns) #define COMSIG_SUN_MOVED "sun_moved" ////////////////////////////////////////////////////////////////// diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 53fbd15651..32da3b5938 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -425,6 +425,7 @@ Example config: var/list/min_pop = Get(/datum/config_entry/keyed_list/min_pop) var/list/max_pop = Get(/datum/config_entry/keyed_list/max_pop) var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust) + var/desired_chaos_level = 9 - SSpersistence.get_recent_chaos() for(var/T in gamemode_cache) var/datum/game_mode/M = new T() if(!(M.config_tag in modes)) @@ -449,6 +450,17 @@ Example config: adjustment += repeated_mode_adjust[recent_round] recent_round = SSpersistence.saved_modes.Find(M.config_tag,recent_round+1,0) final_weight *= max(0,((100-adjustment)/100)) + if(Get(/datum/config_entry/flag/weigh_by_recent_chaos)) + var/chaos_level = M.get_chaos() + var/exponent = Get(/datum/config_entry/number/chaos_exponent) + var/delta = chaos_level - desired_chaos_level + if(desired_chaos_level > 5) + delta = abs(min(delta, 0)) + else if(desired_chaos_level < 5) + delta = max(delta, 0) + else + delta = abs(delta) + final_weight /= (delta + 1) ** exponent runnable_modes[M] = final_weight return runnable_modes diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 4034722417..76a5f5060c 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -7,6 +7,13 @@ /datum/config_entry/keyed_list/probability/ValidateListEntry(key_name) return key_name in config.modes +/datum/config_entry/keyed_list/chaos_level + key_mode = KEY_MODE_TEXT + value_mode = VALUE_MODE_NUM + +/datum/config_entry/keyed_list/chaos_level/ValidateListEntry(key_name) + return key_name in config.modes + /datum/config_entry/keyed_list/max_pop key_mode = KEY_MODE_TEXT value_mode = VALUE_MODE_NUM @@ -596,3 +603,8 @@ /// Dirtyness multiplier for making turfs dirty /datum/config_entry/number/turf_dirty_multiplier config_entry_value = 1 + +/datum/config_entry/flag/weigh_by_recent_chaos + +/datum/config_entry/number/chaos_exponent + config_entry_value = 1 diff --git a/code/controllers/subsystem/persistence/recent_votes_etc.dm b/code/controllers/subsystem/persistence/recent_votes_etc.dm index f1b902d6ab..3c36c7581e 100644 --- a/code/controllers/subsystem/persistence/recent_votes_etc.dm +++ b/code/controllers/subsystem/persistence/recent_votes_etc.dm @@ -3,6 +3,7 @@ */ /datum/controller/subsystem/persistence var/list/saved_modes = list(1,2,3) + var/list/saved_chaos = list(5,5,5) var/list/saved_dynamic_rules = list(list(),list(),list()) var/list/saved_storytellers = list("foo","bar","baz") var/list/average_dynamic_threat = 50 @@ -33,6 +34,14 @@ file_data["data"] = saved_modes fdel(json_file) WRITE_FILE(json_file, json_encode(file_data)) + saved_chaos[3] = saved_chaos[2] + saved_chaos[2] = saved_chaos[1] + saved_chaos[1] = SSticker.mode.get_chaos() + json_file = file("data/RecentChaos.json") + file_data = list() + file_data["data"] = saved_chaos + fdel(json_file) + WRITE_FILE(json_file, json_encode(file_data)) /datum/controller/subsystem/persistence/proc/CollectStoryteller(var/datum/game_mode/dynamic/mode) saved_storytellers.len = 3 @@ -105,3 +114,9 @@ if(!json) return saved_maps = json["maps"] + +/datum/controller/subsystem/persistence/proc/get_recent_chaos() + var/sum = 0 + for(var/n in saved_chaos) + sum += n + return sum/length(saved_chaos) diff --git a/code/controllers/subsystem/processing/weather.dm b/code/controllers/subsystem/processing/weather.dm index ca067953cc..4035149ef2 100644 --- a/code/controllers/subsystem/processing/weather.dm +++ b/code/controllers/subsystem/processing/weather.dm @@ -70,3 +70,8 @@ PROCESSING_SUBSYSTEM_DEF(weather) A = W break return A + +/datum/controller/subsystem/processing/weather/proc/get_weather_by_type(datum/weather/weather_datum_type) + for(var/V in processing) + if(istype(V,weather_datum_type)) + return V diff --git a/code/controllers/subsystem/sun.dm b/code/controllers/subsystem/sun.dm index 442329cf46..746b1be7a9 100644 --- a/code/controllers/subsystem/sun.dm +++ b/code/controllers/subsystem/sun.dm @@ -1,32 +1,63 @@ +#define OCCLUSION_DISTANCE 20 + +/datum/sun + var/azimuth = 0 // clockwise, top-down rotation from 0 (north) to 359 + var/power_mod = 1 // how much power this sun is outputting relative to standard + + +/datum/sun/vv_edit_var(var_name, var_value) + . = ..() + if(var_name == NAMEOF(src, azimuth)) + SSsun.complete_movement() + +/atom/proc/check_obscured(datum/sun/sun, distance = OCCLUSION_DISTANCE) + var/target_x = round(sin(sun.azimuth), 0.01) + var/target_y = round(cos(sun.azimuth), 0.01) + var/x_hit = x + var/y_hit = y + var/turf/hit + + for(var/run in 1 to distance) + x_hit += target_x + y_hit += target_y + hit = locate(round(x_hit, 1), round(y_hit, 1), z) + if(hit.opacity) + return TRUE + if(hit.x == 1 || hit.x == world.maxx || hit.y == 1 || hit.y == world.maxy) //edge of the map + break + return FALSE + SUBSYSTEM_DEF(sun) name = "Sun" wait = 1 MINUTES flags = SS_NO_TICK_CHECK - var/azimuth = 0 ///clockwise, top-down rotation from 0 (north) to 359 + var/list/datum/sun/suns = list() + var/datum/sun/primary_sun var/azimuth_mod = 1 ///multiplier against base_rotation var/base_rotation = 6 ///base rotation in degrees per fire /datum/controller/subsystem/sun/Initialize(start_timeofday) - azimuth = rand(0, 359) + primary_sun = new + suns += primary_sun + primary_sun.azimuth = rand(0, 359) azimuth_mod = round(rand(50, 200)/100, 0.01) // 50% - 200% of standard rotation if(prob(50)) azimuth_mod *= -1 return ..() /datum/controller/subsystem/sun/fire(resumed = FALSE) - azimuth += azimuth_mod * base_rotation - azimuth = round(azimuth, 0.01) - if(azimuth >= 360) - azimuth -= 360 - if(azimuth < 0) - azimuth += 360 + for(var/S in suns) + var/datum/sun/sun = S + sun.azimuth += azimuth_mod * base_rotation + sun.azimuth = round(sun.azimuth, 0.01) + if(sun.azimuth >= 360) + sun.azimuth -= 360 + if(sun.azimuth < 0) + sun.azimuth += 360 complete_movement() /datum/controller/subsystem/sun/proc/complete_movement() - SEND_SIGNAL(src, COMSIG_SUN_MOVED, azimuth) + SEND_SIGNAL(src, COMSIG_SUN_MOVED, primary_sun, suns) -/datum/controller/subsystem/sun/vv_edit_var(var_name, var_value) - . = ..() - if(var_name == NAMEOF(src, azimuth)) - complete_movement() +#undef OCCLUSION_DISTANCE diff --git a/code/datums/components/material_container.dm b/code/datums/components/material_container.dm index baf6d81e0f..cc988544b8 100644 --- a/code/datums/components/material_container.dm +++ b/code/datums/components/material_container.dm @@ -112,32 +112,87 @@ user_insert(I, user) //, mat_container_flags) /// Proc used for when player inserts materials -/datum/component/material_container/proc/user_insert(obj/item/I, mob/living/user) +/datum/component/material_container/proc/user_insert(obj/item/I, mob/living/user, datum/component/remote_materials/remote = null) set waitfor = FALSE - var/requested_amount var/active_held = user.get_active_held_item() // differs from I when using TK - if(istype(I, /obj/item/stack) && precise_insertion) - var/atom/current_parent = parent + var/inserted = 0 + + //handle stacks specially + if(istype(I, /obj/item/stack)) + var/atom/current_parent = remote ? remote.parent : parent //is the user using a remote materials component? var/obj/item/stack/S = I - requested_amount = input(user, "How much do you want to insert?", "Inserting [S.singular_name]s") as num|null + + //try to get ammount to use + var/requested_amount + if(precise_insertion) + requested_amount = input(user, "How much do you want to insert?", "Inserting [S.singular_name]s") as num|null + else + requested_amount= S.amount + if(isnull(requested_amount) || (requested_amount <= 0)) return - if(QDELETED(I) || QDELETED(user) || QDELETED(src) || parent != current_parent || user.physical_can_use_topic(current_parent) < UI_INTERACTIVE || user.get_active_held_item() != active_held) + if(QDELETED(I) || QDELETED(user) || QDELETED(src) || user.get_active_held_item() != active_held) return - if(!user.temporarilyRemoveItemFromInventory(I)) - to_chat(user, "[I] is stuck to you and cannot be placed into [parent].") - return - var/inserted = insert_item(I, stack_amt = requested_amount)//, breakdown_flags= mat_container_flags) + //are we still in range after the user input? + if((remote ? remote.parent : parent) != current_parent || user.physical_can_use_topic(current_parent) < UI_INTERACTIVE) + return + inserted = insert_stack(S, requested_amount) + else + if(!user.temporarilyRemoveItemFromInventory(I)) + to_chat(user, "[I] is stuck to you and cannot be placed into [parent].") + return + inserted = insert_item(I) + qdel(I) + if(inserted) to_chat(user, "You insert a material total of [inserted] into [parent].") - qdel(I) if(after_insert) after_insert.Invoke(I, last_inserted_id, inserted) - else if(I == active_held) - user.put_in_active_hand(I) + if(remote && remote.after_insert) + remote.after_insert.Invoke(I, last_inserted_id, inserted) + +//Inserts a number of sheets from a stack, returns the amount of sheets used. +/datum/component/material_container/proc/insert_stack(obj/item/stack/S, amt, multiplier = 1) + if(isnull(amt)) + amt = S.amount + + if(amt <= 0) + return FALSE + + if(amt > S.amount) + amt = S.amount + + var/material_amt = get_item_material_amount(S) + if(!material_amt) + return FALSE + + //get max number of sheets we have room to add + var/mat_per_sheet = material_amt/S.amount + amt = min(amt, round((max_amount - total_amount) / (mat_per_sheet))) + if(!amt) + return FALSE + + //add the mats and keep track of how much was added + var/starting_total = total_amount + for(var/MAT in materials) + materials[MAT] += S.mats_per_unit[MAT] * amt * multiplier + total_amount += S.mats_per_unit[MAT] * amt * multiplier + var/total_added = total_amount - starting_total + + //update last_inserted_id with mat making up majority of the stack + var/primary_mat + var/max_mat_value = 0 + for(var/MAT in materials) + if(S.mats_per_unit[MAT] > max_mat_value) + max_mat_value = S.mats_per_unit[MAT] + primary_mat = MAT + last_inserted_id = primary_mat + + S.use(amt) + return total_added /// Proc specifically for inserting items, returns the amount of materials entered. -/datum/component/material_container/proc/insert_item(obj/item/I, var/multiplier = 1, stack_amt) +/datum/component/material_container/proc/insert_item(obj/item/I, var/multiplier = 1) if(QDELETED(I)) return FALSE @@ -198,6 +253,7 @@ var/total_amount_saved = total_amount if(mat) materials[mat] += amt + total_amount += amt else for(var/i in materials) materials[i] += amt diff --git a/code/datums/components/remote_materials.dm b/code/datums/components/remote_materials.dm index 01038c11d3..b1d23ea3a8 100644 --- a/code/datums/components/remote_materials.dm +++ b/code/datums/components/remote_materials.dm @@ -15,13 +15,15 @@ handles linking back and forth. var/category var/allow_standalone var/local_size = INFINITY + var/datum/callback/after_insert -/datum/component/remote_materials/Initialize(category, mapload, allow_standalone = TRUE, force_connect = FALSE) +/datum/component/remote_materials/Initialize(category, mapload, allow_standalone = TRUE, force_connect = FALSE, _after_insert) if (!isatom(parent)) return COMPONENT_INCOMPATIBLE src.category = category src.allow_standalone = allow_standalone + after_insert = _after_insert RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy) @@ -67,7 +69,7 @@ handles linking back and forth. /datum/material/plastic, ) - mat_container = parent.AddComponent(/datum/component/material_container, allowed_mats, local_size, allowed_types=/obj/item/stack) + mat_container = parent.AddComponent(/datum/component/material_container, allowed_mats, local_size, allowed_types=/obj/item/stack, _after_insert = after_insert) /datum/component/remote_materials/proc/set_local_size(size) local_size = size @@ -103,7 +105,7 @@ handles linking back and forth. return COMPONENT_NO_AFTERATTACK else if(silo && istype(I, /obj/item/stack)) - if(silo.remote_attackby(parent, user, I)) + if(silo.remote_attackby(parent, user, I, src)) return COMPONENT_NO_AFTERATTACK /datum/component/remote_materials/proc/on_hold() diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index 96ba7bf965..4277cb1316 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -97,7 +97,7 @@ D.visible_message("[A] locks [D] into a restraining position!", \ "[A] locks you into a restraining position!") D.apply_damage(damage, STAMINA) - D.Stun(100) + D.Stun(10) restraining = TRUE addtimer(VARSET_CALLBACK(src, restraining, FALSE), 50, TIMER_UNIQUE) return TRUE @@ -175,7 +175,7 @@ return TRUE if(CHECK_MOBILITY(D, MOBILITY_MOVE) || !restraining) A.do_attack_animation(D, ATTACK_EFFECT_PUNCH) - if(damage >= stunthreshold) + if(damage >= stunthreshold) I = D.get_active_held_item() D.visible_message("[A] strikes [D]'s jaw with their hand!", \ "[A] strikes your jaw, disorienting you!") @@ -196,7 +196,8 @@ log_combat(A, D, "knocked out (Chokehold)(CQC)") D.visible_message("[A] puts [D] into a chokehold!", \ "[A] puts you into a chokehold!") - D.SetSleeping(400) + if(D.silent <= 10) + D.silent = clamp(D.silent + 10, 0, 10) restraining = FALSE if(A.grab_state < GRAB_NECK) A.setGrabState(GRAB_NECK) @@ -213,7 +214,7 @@ to_chat(usr, "Slam: Grab Harm. Slam opponent into the ground, knocking them down.") to_chat(usr, "CQC Kick: Harm Harm. Knocks opponent away. Knocks out stunned or knocked down opponents.") - to_chat(usr, "Restrain: Grab Grab. Locks opponents into a restraining position, disarm to knock them out with a chokehold.") + to_chat(usr, "Restrain: Grab Grab. Locks opponents into a restraining position, disarm to mute them with a chokehold.") to_chat(usr, "Pressure: Disarm Grab. Decent stamina damage.") to_chat(usr, "Consecutive CQC: Disarm Disarm Harm. Mainly offensive move, huge damage and decent stamina damage.") diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm index 4638508d1c..337be3e005 100644 --- a/code/datums/weather/weather_types/radiation_storm.dm +++ b/code/datums/weather/weather_types/radiation_storm.dm @@ -22,7 +22,7 @@ target_trait = ZTRAIT_STATION immunity_type = "rad" - + var/radiation_intensity = 100 /datum/weather/rad_storm/telegraph() diff --git a/code/game/gamemodes/bloodsucker/bloodsucker.dm b/code/game/gamemodes/bloodsucker/bloodsucker.dm index c54de16e2e..65321f5820 100644 --- a/code/game/gamemodes/bloodsucker/bloodsucker.dm +++ b/code/game/gamemodes/bloodsucker/bloodsucker.dm @@ -24,6 +24,7 @@ traitor_name = "Bloodsucker" antag_flag = ROLE_BLOODSUCKER false_report_weight = 1 + chaos = 4 restricted_jobs = list("AI","Cyborg") protected_jobs = list("Chaplain", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_players = 20 @@ -87,7 +88,7 @@ // Init Sunlight (called from datum_bloodsucker.on_gain(), in case game mode isn't even Bloodsucker /datum/game_mode/proc/check_start_sunlight() // Already Sunlight (and not about to cancel) - if(istype(bloodsucker_sunlight) && !bloodsucker_sunlight.cancel_me) + if(istype(bloodsucker_sunlight)) return bloodsucker_sunlight = new () @@ -97,7 +98,6 @@ if(!istype(bloodsucker_sunlight)) return if(bloodsuckers.len <= 0) - bloodsucker_sunlight.cancel_me = TRUE qdel(bloodsucker_sunlight) bloodsucker_sunlight = null diff --git a/code/game/gamemodes/brother/traitor_bro.dm b/code/game/gamemodes/brother/traitor_bro.dm index 718ed2c103..eda6b5f9e2 100644 --- a/code/game/gamemodes/brother/traitor_bro.dm +++ b/code/game/gamemodes/brother/traitor_bro.dm @@ -6,6 +6,7 @@ name = "traitor+brothers" config_tag = "traitorbro" required_players = 25 + chaos = 5 restricted_jobs = list("AI", "Cyborg") protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 8029685bf7..20ef83a54c 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -10,6 +10,7 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th config_tag = "changeling" antag_flag = ROLE_CHANGELING false_report_weight = 10 + chaos = 5 restricted_jobs = list("AI", "Cyborg") protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to ling role blacklist required_players = 15 diff --git a/code/game/gamemodes/changeling/traitor_chan.dm b/code/game/gamemodes/changeling/traitor_chan.dm index b010b08bc3..88a1cde8ce 100644 --- a/code/game/gamemodes/changeling/traitor_chan.dm +++ b/code/game/gamemodes/changeling/traitor_chan.dm @@ -2,6 +2,7 @@ name = "traitor+changeling" config_tag = "traitorchan" false_report_weight = 10 + chaos = 6 traitors_possible = 3 //hard limit on traitors if scaling is turned off restricted_jobs = list("AI", "Cyborg") required_players = 25 diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 29455afe56..d8ebf6f20c 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -134,6 +134,7 @@ Credit where due: config_tag = "clockwork_cult" antag_flag = ROLE_SERVANT_OF_RATVAR false_report_weight = 10 + chaos = 8 required_players = 24 //Fixing this directly for now since apparently config machine for forcing modes broke. required_enemies = 3 recommended_enemies = 5 diff --git a/code/game/gamemodes/clown_ops/clown_ops.dm b/code/game/gamemodes/clown_ops/clown_ops.dm index 108c67ad27..659d2de105 100644 --- a/code/game/gamemodes/clown_ops/clown_ops.dm +++ b/code/game/gamemodes/clown_ops/clown_ops.dm @@ -1,7 +1,7 @@ /datum/game_mode/nuclear/clown_ops name = "clown ops" config_tag = "clownops" - + chaos = 8 announce_span = "danger" announce_text = "Clown empire forces are approaching the station in an attempt to HONK it!\n\ Operatives: Secure the nuclear authentication disk and use your bananium fission explosive to HONK the station.\n\ diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 8ec4123201..ba9fad7a84 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -38,6 +38,7 @@ config_tag = "cult" antag_flag = ROLE_CULTIST false_report_weight = 10 + chaos = 8 restricted_jobs = list("AI", "Cyborg") protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_players = 30 diff --git a/code/game/gamemodes/devil/devil agent/devil_agent.dm b/code/game/gamemodes/devil/devil agent/devil_agent.dm index 789cff5c8f..ccfd6f1dd5 100644 --- a/code/game/gamemodes/devil/devil agent/devil_agent.dm +++ b/code/game/gamemodes/devil/devil agent/devil_agent.dm @@ -1,6 +1,7 @@ /datum/game_mode/devil/devil_agents name = "Devil Agents" config_tag = "devil_agents" + chaos = 5 required_players = 25 required_enemies = 3 recommended_enemies = 8 diff --git a/code/game/gamemodes/devil/devil_game_mode.dm b/code/game/gamemodes/devil/devil_game_mode.dm index 0f2e8f7858..9bf7fc0e82 100644 --- a/code/game/gamemodes/devil/devil_game_mode.dm +++ b/code/game/gamemodes/devil/devil_game_mode.dm @@ -3,6 +3,7 @@ config_tag = "devil" antag_flag = ROLE_DEVIL false_report_weight = 1 + chaos = 3 protected_jobs = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI") required_players = 0 required_enemies = 1 diff --git a/code/game/gamemodes/eldritch_cult/eldritch_cult.dm b/code/game/gamemodes/eldritch_cult/eldritch_cult.dm index a3e3c54dce..1693163fa2 100644 --- a/code/game/gamemodes/eldritch_cult/eldritch_cult.dm +++ b/code/game/gamemodes/eldritch_cult/eldritch_cult.dm @@ -3,6 +3,7 @@ config_tag = "heresy" antag_flag = ROLE_HERETIC false_report_weight = 5 + chaos = 5 restricted_jobs = list("AI", "Cyborg") protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to heretic role blacklist required_players = 15 diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm index 976f3e3eca..a6abcbefbd 100644 --- a/code/game/gamemodes/extended/extended.dm +++ b/code/game/gamemodes/extended/extended.dm @@ -3,6 +3,7 @@ config_tag = "secret_extended" false_report_weight = 5 required_players = 0 + chaos = 0 announce_span = "notice" announce_text = "Just have fun and enjoy the game!" diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 8bef236c5e..10c0154412 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -17,6 +17,7 @@ var/config_tag = null var/votable = 1 var/probability = 0 + var/chaos = 5 // 0-9, used for weighting round-to-round var/false_report_weight = 0 //How often will this show up incorrectly in a centcom report? var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm var/nuke_off_station = 0 //Used for tracking where the nuke hit @@ -623,3 +624,10 @@ /// Mode specific info for ghost game_info /datum/game_mode/proc/ghost_info() return + +/datum/game_mode/proc/get_chaos() + var/chaos_levels = CONFIG_GET(keyed_list/chaos_level) + if(config_tag in chaos_levels) + return chaos_levels[config_tag] + else + return chaos diff --git a/code/game/gamemodes/gangs/gangs.dm b/code/game/gamemodes/gangs/gangs.dm index 0dc4a520ef..100669c487 100644 --- a/code/game/gamemodes/gangs/gangs.dm +++ b/code/game/gamemodes/gangs/gangs.dm @@ -6,6 +6,7 @@ GLOBAL_LIST_EMPTY(gangs) name = "gang war" config_tag = "gang" antag_flag = ROLE_GANG + chaos = 9 restricted_jobs = list("AI", "Cyborg") protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_players = 15 diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm index afeebb770b..78fe6d9324 100644 --- a/code/game/gamemodes/meteor/meteor.dm +++ b/code/game/gamemodes/meteor/meteor.dm @@ -2,6 +2,7 @@ name = "meteor" config_tag = "meteor" false_report_weight = 1 + chaos = 9 var/meteordelay = 2000 var/nometeors = 0 var/rampupdelta = 5 diff --git a/code/game/gamemodes/monkey/monkey.dm b/code/game/gamemodes/monkey/monkey.dm index 76460ffbb8..c91252258a 100644 --- a/code/game/gamemodes/monkey/monkey.dm +++ b/code/game/gamemodes/monkey/monkey.dm @@ -11,6 +11,7 @@ required_players = 20 required_enemies = 1 recommended_enemies = 1 + chaos = 9 restricted_jobs = list("Cyborg", "AI") diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 48a298984c..dcf84e84db 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -2,6 +2,7 @@ name = "nuclear emergency" config_tag = "nuclear" false_report_weight = 10 + chaos = 9 required_players = 28 // 30 players - 3 players to be the nuke ops = 25 players remaining required_enemies = 2 recommended_enemies = 5 diff --git a/code/game/gamemodes/overthrow/overthrow.dm b/code/game/gamemodes/overthrow/overthrow.dm index dca0c1ade1..6a118567df 100644 --- a/code/game/gamemodes/overthrow/overthrow.dm +++ b/code/game/gamemodes/overthrow/overthrow.dm @@ -3,6 +3,7 @@ name = "overthrow" config_tag = "overthrow" antag_flag = ROLE_OVERTHROW + chaos = 5 restricted_jobs = list("AI", "Cyborg") protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_players = 20 // the core idea is of a swift, bloodless coup, so it shouldn't be as chaotic as revs. diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 9eed18d906..419a74d616 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -12,6 +12,7 @@ config_tag = "revolution" antag_flag = ROLE_REV false_report_weight = 10 + chaos = 8 restricted_jobs = list("AI", "Cyborg") protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") required_players = 20 diff --git a/code/game/gamemodes/traitor/double_agents.dm b/code/game/gamemodes/traitor/double_agents.dm index fc669d4855..c64e508cef 100644 --- a/code/game/gamemodes/traitor/double_agents.dm +++ b/code/game/gamemodes/traitor/double_agents.dm @@ -10,6 +10,7 @@ required_enemies = 5 recommended_enemies = 8 reroll_friendly = 0 + chaos = 7 traitor_name = "Nanotrasen Internal Affairs Agent" antag_flag = ROLE_INTERNAL_AFFAIRS diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 8b1b18660a..d42fe615cd 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -17,6 +17,7 @@ recommended_enemies = 4 reroll_friendly = 1 enemy_minimum_age = 0 + chaos = 2 announce_span = "danger" announce_text = "There are Syndicate agents on the station!\n\ diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index 23f065318e..d8cb851aad 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -12,6 +12,7 @@ recommended_enemies = 1 enemy_minimum_age = 7 round_ends_with_antag_death = 1 + chaos = 9 announce_span = "danger" announce_text = "There is a space wizard attacking the station!\n\ Wizard: Accomplish your objectives and cause mayhem on the station.\n\ diff --git a/code/game/machinery/aug_manipulator.dm b/code/game/machinery/aug_manipulator.dm index 6fdeae61a1..e496973d75 100644 --- a/code/game/machinery/aug_manipulator.dm +++ b/code/game/machinery/aug_manipulator.dm @@ -8,7 +8,19 @@ max_integrity = 200 var/obj/item/bodypart/storedpart var/initial_icon_state - var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', "security" = 'icons/mob/augmentation/augments_security.dmi', "mining" = 'icons/mob/augmentation/augments_mining.dmi') + var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', + "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', + "security" = 'icons/mob/augmentation/augments_security.dmi', + "mining" = 'icons/mob/augmentation/augments_mining.dmi', + "Talon" = 'icons/mob/augmentation/cosmetic_prosthetic/talon.dmi', + "Nanotrasen" = 'icons/mob/augmentation/cosmetic_prosthetic/nanotrasen.dmi', + "Hephaesthus" = 'icons/mob/augmentation/cosmetic_prosthetic/hephaestus.dmi', + "Bishop" = 'icons/mob/augmentation/cosmetic_prosthetic/bishop.dmi', + "Xion" = 'icons/mob/augmentation/cosmetic_prosthetic/xion.dmi', + "Grayson" = 'icons/mob/augmentation/cosmetic_prosthetic/grayson.dmi', + "Cybersolutions" = 'icons/mob/augmentation/cosmetic_prosthetic/cybersolutions.dmi', + "Ward" = 'icons/mob/augmentation/cosmetic_prosthetic/ward.dmi' + ) /obj/machinery/aug_manipulator/examine(mob/user) . = ..() diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 0303117b96..bbbfa7f1bd 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -65,7 +65,7 @@ /obj/machinery/mecha_part_fabricator/Initialize(mapload) stored_research = new - rmat = AddComponent(/datum/component/remote_materials, "mechfab", mapload && link_on_init) + rmat = AddComponent(/datum/component/remote_materials, "mechfab", mapload && link_on_init, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert)) RefreshParts() //Recalculating local material sizes if the fab isn't linked return ..() diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 25a5bcc800..90912f7409 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -721,24 +721,24 @@ /obj/item/disk/medical/defib_heal name = "Defibrillator Healing Disk" - desc = "An upgrade which increases the healing power of the defibrillator" + desc = "An upgrade which increases the healing power of the defibrillator." icon_state = "heal_disk" custom_materials = list(/datum/material/iron=16000, /datum/material/glass = 18000, /datum/material/gold = 6000, /datum/material/silver = 6000) /obj/item/disk/medical/defib_shock name = "Defibrillator Anti-Shock Disk" - desc = "A safety upgrade that guarantees only the patient will get shocked" + desc = "A safety upgrade that guarantees only the patient will get shocked." icon_state = "zap_disk" custom_materials = list(/datum/material/iron=16000, /datum/material/glass = 18000, /datum/material/gold = 6000, /datum/material/silver = 6000) /obj/item/disk/medical/defib_decay name = "Defibrillator Body-Decay Extender Disk" - desc = "An upgrade allowing the defibrillator to work on more decayed bodies" + desc = "An upgrade allowing the defibrillator to work on bodies that have decayed further." icon_state = "body_disk" custom_materials = list(/datum/material/iron=16000, /datum/material/glass = 18000, /datum/material/gold = 16000, /datum/material/silver = 6000, /datum/material/titanium = 2000) /obj/item/disk/medical/defib_speed name = "Defibrillator Fast Charge Disk" - desc = "An upgrade to the defibrillator capacitors, which let it charge faster" + desc = "An upgrade to the defibrillator capacitors, which lets it charge faster." icon_state = "fast_disk" custom_materials = list(/datum/material/iron=16000, /datum/material/glass = 8000, /datum/material/gold = 26000, /datum/material/silver = 26000) diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 15d10c4d11..1e2ae93df9 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -3,9 +3,8 @@ /obj/item/melee/proc/check_martial_counter(mob/living/carbon/human/target, mob/living/carbon/human/user) if(target.check_martial_melee_block()) - target.visible_message("[target.name] blocks [src] and twists [user]'s arm behind [user.p_their()] back!", + target.visible_message("[target.name] blocks your attack!", "You block the attack!") - user.Stun(40) return TRUE /obj/item/melee/chainofcommand diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm b/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm index 2cb50c6b3b..f26152f90e 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm @@ -7,98 +7,79 @@ // Over Time, tick down toward a "Solar Flare" of UV buffeting the station. This period is harmful to vamps. /obj/effect/sunlight //var/amDay = FALSE - var/cancel_me = FALSE var/amDay = FALSE var/time_til_cycle = 0 - var/nightime_duration = 900 //15 Minutes + var/nighttime_duration = 900 //15 Minutes + var/issued_XP = FALSE /obj/effect/sunlight/Initialize() . = ..() - INVOKE_ASYNC(src, .proc/countdown) - INVOKE_ASYNC(src, .proc/hud_tick) -/obj/effect/sunlight/proc/countdown() - set waitfor = FALSE +/obj/effect/sunlight/proc/start_countdown() + START_PROCESSING(SSweather, src) //it counts as weather right + time_til_cycle = nighttime_duration - while(!cancel_me) - - time_til_cycle = nightime_duration - - // Part 1: Night (all is well) - while(time_til_cycle > TIME_BLOODSUCKER_DAY_WARN) - sleep(10) - if(cancel_me) - return - //sleep(TIME_BLOODSUCKER_NIGHT - TIME_BLOODSUCKER_DAY_WARN) - warn_daylight(1,"Solar Flares will bombard the station with dangerous UV in [TIME_BLOODSUCKER_DAY_WARN / 60] minutes. Prepare to seek cover in a coffin or closet.") // time2text <-- use Help On - give_home_power() // Give VANISHING ACT power to all vamps with a lair! - - // Part 2: Night Ending - while(time_til_cycle > TIME_BLOODSUCKER_DAY_FINAL_WARN) - sleep(10) - if(cancel_me) - return - //sleep(TIME_BLOODSUCKER_DAY_WARN - TIME_BLOODSUCKER_DAY_FINAL_WARN) - message_admins("BLOODSUCKER NOTICE: Daylight beginning in [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds.)") - warn_daylight(2,"Solar Flares are about to bombard the station! You have [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds to find cover!",\ - "In [TIME_BLOODSUCKER_DAY_FINAL_WARN / 10], your master will be at risk of a Solar Flare. Make sure they find cover!") - - // (FINAL LIL WARNING) - while(time_til_cycle > 5) - sleep(10) - if(cancel_me) - return - //sleep(TIME_BLOODSUCKER_DAY_FINAL_WARN - 50) - warn_daylight(3,"Seek cover, for Sol rises!") - - // Part 3: Night Ending - while(time_til_cycle > 0) - sleep(10) - if(cancel_me) - return - //sleep(50) - warn_daylight(4,"Solar flares bombard the station with deadly UV light!
Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk Final Death!",\ - "Solar flares bombard the station with UV light!") - - // Part 4: Day - amDay = TRUE - message_admins("BLOODSUCKER NOTICE: Daylight Beginning (Lasts for [TIME_BLOODSUCKER_DAY / 60] minutes.)") - time_til_cycle = TIME_BLOODSUCKER_DAY - sleep(10) // One second grace period. - //var/daylight_time = TIME_BLOODSUCKER_DAY - var/issued_XP = FALSE - while(time_til_cycle > 0) +/obj/effect/sunlight/process() + // Update all Bloodsucker sunlight huds + for(var/datum/mind/M in SSticker.mode.bloodsuckers) + if(!istype(M) || !istype(M.current)) + continue + var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) + if(istype(bloodsuckerdatum)) + bloodsuckerdatum.update_sunlight(max(0, time_til_cycle), amDay) // This pings all HUDs + time_til_cycle-- + if(amDay) + if(time_til_cycle > 0 && time_til_cycle % 4 == 0) punish_vamps() - sleep(TIME_BLOODSUCKER_BURN_INTERVAL) - if(cancel_me) - return - //daylight_time -= TIME_BLOODSUCKER_BURN_INTERVAL - // Issue Level Up! if(!issued_XP && time_til_cycle <= 5) issued_XP = TRUE - vamps_rank_up() + // Cycle through all vamp antags and check if they're inside a closet. + for(var/datum/mind/M in SSticker.mode.bloodsuckers) + if(!istype(M) || !istype(M.current)) + continue + var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) + if(istype(bloodsuckerdatum)) + bloodsuckerdatum.RankUp() // Rank up! Must still be in a coffin to level! warn_daylight(5,"The solar flare has ended, and the daylight danger has passed...for now.",\ "The solar flare has ended, and the daylight danger has passed...for now.") amDay = FALSE - day_end() // Remove VANISHING ACT power from all vamps who have it! Clear Warnings (sunlight, locker protection) - nightime_duration += 100 //Each day makes the night a minute longer. - message_admins("BLOODSUCKER NOTICE: Daylight Ended. Resetting to Night (Lasts for [nightime_duration / 60] minutes.)") - - - -/obj/effect/sunlight/proc/hud_tick() - set waitfor = FALSE - while(!cancel_me) - // Update all Bloodsucker sunlight huds + issued_XP = FALSE for(var/datum/mind/M in SSticker.mode.bloodsuckers) if(!istype(M) || !istype(M.current)) continue var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) - if(istype(bloodsuckerdatum)) - bloodsuckerdatum.update_sunlight(max(0, time_til_cycle), amDay) // This pings all HUDs - sleep(10) - time_til_cycle -- + if(!istype(bloodsuckerdatum)) + continue + // Reset Warnings + bloodsuckerdatum.warn_sun_locker = FALSE + bloodsuckerdatum.warn_sun_burn = FALSE + // Remove Dawn Powers + for(var/datum/action/bloodsucker/P in bloodsuckerdatum.powers) + if(istype(P, /datum/action/bloodsucker/gohome)) + bloodsuckerdatum.powers -= P + P.Remove(M.current) + nighttime_duration += 100 //Each day makes the night a minute longer. + time_til_cycle = nighttime_duration + message_admins("BLOODSUCKER NOTICE: Daylight Ended. Resetting to Night (Lasts for [nighttime_duration / 60] minutes.)") + else + switch(time_til_cycle) + if(TIME_BLOODSUCKER_DAY_WARN) + //sleep(TIME_BLOODSUCKER_NIGHT - TIME_BLOODSUCKER_DAY_WARN) + warn_daylight(1,"Solar Flares will bombard the station with dangerous UV in [TIME_BLOODSUCKER_DAY_WARN / 60] minutes. Prepare to seek cover in a coffin or closet.") // time2text <-- use Help On + give_home_power() // Give VANISHING ACT power to all vamps with a lair! + if(TIME_BLOODSUCKER_DAY_FINAL_WARN) + message_admins("BLOODSUCKER NOTICE: Daylight beginning in [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds.)") + warn_daylight(2,"Solar Flares are about to bombard the station! You have [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds to find cover!",\ + "In [TIME_BLOODSUCKER_DAY_FINAL_WARN / 10], your master will be at risk of a Solar Flare. Make sure they find cover!") + if(5) + warn_daylight(3,"Seek cover, for Sol rises!") + if(0) + warn_daylight(4,"Solar flares bombard the station with deadly UV light!
Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk Final Death!",\ + "Solar flares bombard the station with UV light!") + amDay = TRUE + message_admins("BLOODSUCKER NOTICE: Daylight Beginning (Lasts for [TIME_BLOODSUCKER_DAY / 60] minutes.)") + time_til_cycle = TIME_BLOODSUCKER_DAY /obj/effect/sunlight/proc/warn_daylight(danger_level =0, vampwarn = "", vassalwarn = "") for(var/datum/mind/M in SSticker.mode.bloodsuckers) @@ -162,32 +143,6 @@ M.current.updatehealth() SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/daylight_2) -/obj/effect/sunlight/proc/day_end() - for(var/datum/mind/M in SSticker.mode.bloodsuckers) - if(!istype(M) || !istype(M.current)) - continue - var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) - if(!istype(bloodsuckerdatum)) - continue - // Reset Warnings - bloodsuckerdatum.warn_sun_locker = FALSE - bloodsuckerdatum.warn_sun_burn = FALSE - // Remove Dawn Powers - for(var/datum/action/bloodsucker/P in bloodsuckerdatum.powers) - if(istype(P, /datum/action/bloodsucker/gohome)) - bloodsuckerdatum.powers -= P - P.Remove(M.current) - -/obj/effect/sunlight/proc/vamps_rank_up() - set waitfor = FALSE - // Cycle through all vamp antags and check if they're inside a closet. - for(var/datum/mind/M in SSticker.mode.bloodsuckers) - if(!istype(M) || !istype(M.current)) - continue - var/datum/antagonist/bloodsucker/bloodsuckerdatum = M.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) - if(istype(bloodsuckerdatum)) - bloodsuckerdatum.RankUp() // Rank up! Must still be in a coffin to level! - /obj/effect/sunlight/proc/give_home_power() // It's late...! Give the "Vanishing Act" gohome power to bloodsuckers. for(var/datum/mind/M in SSticker.mode.bloodsuckers) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 9afc852f6b..16e1b45843 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1626,7 +1626,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) for(var/modified_limb in modified_limbs) if(modified_limbs[modified_limb][1] == LOADOUT_LIMB_PROSTHETIC && modified_limb != limb_type) number_of_prosthetics += 1 - if(number_of_prosthetics > MAXIMUM_LOADOUT_PROSTHETICS) + if(number_of_prosthetics == MAXIMUM_LOADOUT_PROSTHETICS) to_chat(user, "You can only have up to two prosthetic limbs!") else //save the actual prosthetic data diff --git a/code/modules/events/supernova.dm b/code/modules/events/supernova.dm new file mode 100644 index 0000000000..9766ab6212 --- /dev/null +++ b/code/modules/events/supernova.dm @@ -0,0 +1,67 @@ +/datum/round_event_control/supernova + name = "Supernova" + typepath = /datum/round_event/supernova + weight = 10 + max_occurrences = 2 + min_players = 2 + +/datum/round_event/supernova + announceWhen = 40 + startWhen = 1 + endWhen = 300 + var/power = 1 + var/datum/sun/supernova + var/storm_count = 0 + +/datum/round_event/supernova/setup() + announceWhen = rand(4, 60) + supernova = new + SSsun.suns += supernova + if(prob(50)) + power = rand(5,100) / 100 + else + power = rand(5,5000) / 100 + supernova.azimuth = rand(0, 359) + supernova.power_mod = 0 + +/datum/round_event/supernova/announce() + var/message = "Our tachyon-doppler array has detected a supernova in your vicinity. Peak flux from the supernova estimated to be [round(power,0.1)] times current solar flux. [power > 4 ? "Short burts of radiation may be possible, so please prepare accordingly." : ""]" + if(prob(power * 25)) + priority_announce(message) + else + print_command_report(message) + + +/datum/round_event/supernova/start() + supernova.power_mod = 0.00000002 * power + var/explosion_size = rand(1000000000, 999999999) + var/turf/epicenter = get_turf_in_angle(supernova.azimuth, SSmapping.get_station_center(), world.maxx / 2) + for(var/array in GLOB.doppler_arrays) + var/obj/machinery/doppler_array/A = array + A.sense_explosion(epicenter, explosion_size/2, explosion_size, 0, 107000000 / power, explosion_size/2, explosion_size, 0) + if(power > 1 && SSticker.mode.bloodsucker_sunlight?.time_til_cycle > 90) + var/obj/effect/sunlight/sucker_light = SSticker.mode.bloodsucker_sunlight + sucker_light.time_til_cycle = 90 + sucker_light.warn_daylight(1,"A supernova will bombard the station with dangerous UV in [90 / 60] minutes. Prepare to seek cover in a coffin or closet.") + sucker_light.give_home_power() + +/datum/round_event/supernova/tick() + var/midpoint = (endWhen-startWhen)/2 + switch(activeFor) + if(startWhen to midpoint) + supernova.power_mod = min(supernova.power_mod*1.2, power) + if(endWhen-10 to endWhen) + supernova.power_mod /= 4 + if(prob(round(supernova.power_mod / 2)) && storm_count < 3 && !SSweather.get_weather_by_type(/datum/weather/rad_storm)) + SSweather.run_weather(/datum/weather/rad_storm/supernova) + storm_count++ + +/datum/round_event/supernova/end() + SSsun.suns -= supernova + qdel(supernova) + +/datum/weather/rad_storm/supernova + weather_duration_lower = 50 + weather_duration_lower = 100 + telegraph_duration = 100 + radiation_intensity = 50 diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm index c8188cae8a..331bad9bfe 100644 --- a/code/modules/jobs/job_types/paramedic.dm +++ b/code/modules/jobs/job_types/paramedic.dm @@ -4,7 +4,7 @@ department_head = list("Chief Medical Officer") department_flag = MEDSCI faction = "Station" - total_positions = 3 + total_positions = 2 spawn_positions = 2 supervisors = "the chief medical officer" selection_color = "#74b5e0" diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm index b0055204f9..34b349b198 100644 --- a/code/modules/mining/machine_silo.dm +++ b/code/modules/mining/machine_silo.dm @@ -47,7 +47,7 @@ GLOBAL_LIST_EMPTY(silo_access_logs) return ..() -/obj/machinery/ore_silo/proc/remote_attackby(obj/machinery/M, mob/user, obj/item/stack/I) +/obj/machinery/ore_silo/proc/remote_attackby(obj/machinery/M, mob/user, obj/item/stack/I, remote = null) var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) // stolen from /datum/component/material_container/proc/OnAttackBy if(user.a_intent != INTENT_HELP) @@ -63,7 +63,7 @@ GLOBAL_LIST_EMPTY(silo_access_logs) return // assumes unlimited space... var/amount = I.amount - materials.user_insert(I, user) + materials.user_insert(I, user, remote) silo_log(M, "deposited", amount, "sheets", item_mats) return TRUE diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 0baa78f0ea..3eaefebc56 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -334,7 +334,9 @@ I.moveToNullspace() else I.forceMove(newloc) - I.dropped(src, silent) + on_item_dropped(I) + if(I.dropped(src) == ITEM_RELOCATED_BY_DROPPED) + return FALSE return TRUE //This is a SAFE proc. Use this instead of equip_to_slot()! diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 855c579926..92aa95bfb7 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -1,5 +1,4 @@ #define SOLAR_GEN_RATE 1500 -#define OCCLUSION_DISTANCE 20 /obj/machinery/power/solar name = "solar panel" @@ -14,8 +13,8 @@ integrity_failure = 0.33 var/id - var/obscured = FALSE - var/sunfrac = 0 //[0-1] measure of obscuration -- multipllier against power generation + var/list/obscured = list() + var/total_flux = 0 // multipllier against power generation -- measured by obscuration of all suns var/azimuth_current = 0 //[0-360) degrees, which direction are we facing? var/azimuth_target = 0 //same but what way we're going to face next time we turn var/obj/machinery/power/solar_control/control @@ -133,40 +132,28 @@ ///trace towards sun to see if we're in shadow /obj/machinery/power/solar/proc/occlusion_setup() - obscured = TRUE - - var/distance = OCCLUSION_DISTANCE - var/target_x = round(sin(SSsun.azimuth), 0.01) - var/target_y = round(cos(SSsun.azimuth), 0.01) - var/x_hit = x - var/y_hit = y - var/turf/hit - - for(var/run in 1 to distance) - x_hit += target_x - y_hit += target_y - hit = locate(round(x_hit, 1), round(y_hit, 1), z) - if(hit.opacity) - return - if(hit.x == 1 || hit.x == world.maxx || hit.y == 1 || hit.y == world.maxy) //edge of the map - break - obscured = FALSE + obscured = list() + for(var/S in SSsun.suns) + if(check_obscured(S)) + obscured |= S ///calculates the fraction of the sunlight that the panel receives /obj/machinery/power/solar/proc/update_solar_exposure() needs_to_update_solar_exposure = FALSE - sunfrac = 0 - if(obscured) - return 0 - - var/sun_azimuth = SSsun.azimuth - if(azimuth_current == sun_azimuth) //just a quick optimization for the most frequent case - . = 1 - else - //dot product of sun and panel -- Lambert's Cosine Law - . = cos(azimuth_current - sun_azimuth) - . = clamp(round(., 0.01), 0, 1) - sunfrac = . + total_flux = 0 + for(var/S in SSsun.suns) + if(S in obscured) + continue + var/datum/sun/sun = S + var/sun_azimuth = sun.azimuth + var/cur_pow = 0 + if(azimuth_current == sun_azimuth) //just a quick optimization for the most frequent case + cur_pow = sun.power_mod + else + //dot product of sun and panel -- Lambert's Cosine Law + cur_pow = cos(azimuth_current - sun_azimuth) * sun.power_mod + cur_pow = clamp(round(cur_pow, 0.01), 0, 1) + total_flux += cur_pow /obj/machinery/power/solar/process() if(stat & BROKEN) @@ -177,10 +164,10 @@ update_turn() if(needs_to_update_solar_exposure) update_solar_exposure() - if(sunfrac <= 0) + if(total_flux <= 0) return - var/sgen = SOLAR_GEN_RATE * sunfrac * efficiency + var/sgen = SOLAR_GEN_RATE * total_flux * efficiency add_avail(sgen) if(control) control.gen += sgen @@ -385,7 +372,7 @@ track = mode if(mode == SOLAR_TRACK_AUTO) if(connected_tracker) - connected_tracker.sun_update(SSsun, SSsun.azimuth) + connected_tracker.sun_update(SSsun, SSsun.primary_sun, SSsun.suns) else track = SOLAR_TRACK_OFF return TRUE @@ -483,4 +470,3 @@ Congratulations, you should have a working solar array. If you are having troubl "} #undef SOLAR_GEN_RATE -#undef OCCLUSION_DISTANCE diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm index 0627a55de0..86168979c2 100644 --- a/code/modules/power/tracker.dm +++ b/code/modules/power/tracker.dm @@ -41,10 +41,10 @@ control = null ///Tell the controller to turn the solar panels -/obj/machinery/power/tracker/proc/sun_update(datum/source, azimuth) - setDir(angle2dir(azimuth)) +/obj/machinery/power/tracker/proc/sun_update(datum/source, datum/sun/primary_sun, list/datum/sun/suns) + setDir(angle2dir(primary_sun.azimuth)) if(control && control.track == SOLAR_TRACK_AUTO) - control.set_panels(azimuth) + control.set_panels(primary_sun.azimuth) /obj/machinery/power/tracker/proc/Make(obj/item/solar_assembly/S) if(!S) diff --git a/code/modules/reagents/chemistry/recipes/drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm index 8de4b1248f..cd55d00cf1 100644 --- a/code/modules/reagents/chemistry/recipes/drugs.dm +++ b/code/modules/reagents/chemistry/recipes/drugs.dm @@ -88,9 +88,9 @@ mix_message = "The mixture boils off a yellow, smelly vapor..."//Sulfur burns off, leaving the camphor /datum/chemical_reaction/anaphroplus - name = "pentacamphor" + name = "hexacamphor" id = /datum/reagent/drug/anaphrodisiacplus results = list(/datum/reagent/drug/anaphrodisiacplus = 1) - required_reagents = list(/datum/reagent/drug/aphrodisiac = 5, /datum/reagent/acetone = 1) - required_temp = 300 + required_reagents = list(/datum/reagent/drug/anaphrodisiac = 6, /datum/reagent/acetone = 1) + required_temp = 400 mix_message = "The mixture thickens and heats up slighty..." diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index 072fa54c6f..319b4a2199 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -30,7 +30,7 @@ stored_research = new host_research = SSresearch.science_tech update_research() - materials = AddComponent(/datum/component/remote_materials, "lathe", mapload) + materials = AddComponent(/datum/component/remote_materials, "lathe", mapload, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert)) RefreshParts() /obj/machinery/rnd/production/Destroy() diff --git a/code/modules/research/machinery/circuit_imprinter.dm b/code/modules/research/machinery/circuit_imprinter.dm index c1c386cb31..a8ce7305a3 100644 --- a/code/modules/research/machinery/circuit_imprinter.dm +++ b/code/modules/research/machinery/circuit_imprinter.dm @@ -22,3 +22,6 @@ /obj/machinery/rnd/production/circuit_imprinter/disconnect_console() linked_console.linked_imprinter = null ..() + +/obj/machinery/rnd/production/circuit_imprinter/AfterMaterialInsert() //doesnt use have an animation like lathes do + return diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm index 2237284a64..f39f5b1584 100644 --- a/code/modules/research/rdmachines.dm +++ b/code/modules/research/rdmachines.dm @@ -94,13 +94,13 @@ ..() /obj/machinery/rnd/proc/AfterMaterialInsert(item_inserted, id_inserted, amount_inserted) - var/stack_name + var/mat_name if(istype(item_inserted, /obj/item/stack/ore/bluespace_crystal)) - stack_name = "bluespace" + mat_name = "bluespace" use_power(MINERAL_MATERIAL_AMOUNT / 10) else - var/obj/item/stack/S = item_inserted - stack_name = S.name + var/datum/material/M = id_inserted + mat_name = M.name use_power(min(1000, (amount_inserted / 100))) - add_overlay("protolathe_[stack_name]") - addtimer(CALLBACK(src, /atom/proc/cut_overlay, "protolathe_[stack_name]"), 10) + add_overlay("protolathe_[mat_name]") + addtimer(CALLBACK(src, /atom/proc/cut_overlay, "protolathe_[mat_name]"), 10) diff --git a/config/game_options.txt b/config/game_options.txt index 7776d87d4e..b9d763e5b0 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -72,6 +72,14 @@ ALERT_DELTA Destruction of the station is imminent. All crew are instructed to o ## Uncomment to not send a roundstart intercept report. Gamemodes may override this. #NO_INTERCEPT_REPORT +## Comment to disable weighting modes by how chaotic recent mode rolls were. +WEIGH_BY_RECENT_CHAOS + +## The weight adjustment will be proportional to this power relative to the "ideal" weight range. +## e.g. if we have a weight range of 0-5, and an exponent of 1, 6 will be weighted 1/2, 7 1/3 etc. +## if exponent is 2, it'll be 1/4, 1/9 etc. +CHAOS_EXPONENT 1 + ## Probablities for game modes chosen in 'secret' and 'random' modes. ## Default probablity is 1, increase to make that mode more likely to be picked. ## Set to 0 to disable that mode. @@ -154,6 +162,11 @@ FORCE_ANTAG_COUNT CLOCKWORK_CULT #FORCE_ANTAG_COUNT WIZARD #FORCE_ANTAG_COUNT MONKEY +## A config for how much each game mode's chaos level is. +## All of them have reasonable defaults, but this can be used to adjust them. +## 0-9, where 0 is lowest chaos (should only be extended) and 9 is highest (wizard? nukies?) +#CHAOS_LEVEL EXTENDED 0 + ## Uncomment these for overrides of the minimum / maximum number of players in a round type. ## If you set any of these occasionally check to see if you still need them as the modes ## will still be actively rebalanced around the SUGGESTED populations, not your overrides. diff --git a/html/changelog.html b/html/changelog.html index f8fc2f8ca3..5aa56b1cfe 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,30 @@ -->
+

11 March 2021

+

Putnam3145 updated:

+ +

Sneakyrat updated:

+ +

necromanceranne updated:

+ +

10 March 2021

Hatterhat updated: