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/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..a16e7eab59 100644
--- a/code/game/gamemodes/bloodsucker/bloodsucker.dm
+++ b/code/game/gamemodes/bloodsucker/bloodsucker.dm
@@ -87,7 +87,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 +97,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/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 1c29848600..7bc9fd25f3 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -66,7 +66,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/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/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/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/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/html/changelogs/AutoChangeLog-pr-14306.yml b/html/changelogs/AutoChangeLog-pr-14306.yml
new file mode 100644
index 0000000000..61151e1e45
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14306.yml
@@ -0,0 +1,5 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - rscadd: "Supernova event"
+ - refactor: "Bloodsucker day/night cycle now processes on a subsystem instead of using while and sleep (!!)"
diff --git a/html/changelogs/AutoChangeLog-pr-14371.yml b/html/changelogs/AutoChangeLog-pr-14371.yml
new file mode 100644
index 0000000000..78bb11d051
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14371.yml
@@ -0,0 +1,10 @@
+author: "Sneakyrat"
+delete-after: True
+changes:
+ - bugfix: "Fixes precise insertion ui(when it asks you how many sheets you want to put in the mat container) so you can actually choose how much to put in and it will still work if your stack is bigger than the remaining space"
+ - bugfix: "Fixes precise insertion not working for remote mat containers"
+ - bugfix: "Fixes Protolathe/mechfab insert material animations not working"
+ - bugfix: "Fixes the material insertion animation for protolathes occurring on the circuit printer"
+ - bugfix: "Fixes the material insertion animation not actually playing when it was started"
+ - bugfix: "Fixes the material insertion animation for iron not being made"
+ - bugfix: "Fixes the material insertion animation sometimes not picking the right material for sheets that have multiple different materials in them"
diff --git a/html/changelogs/AutoChangeLog-pr-14380.yml b/html/changelogs/AutoChangeLog-pr-14380.yml
new file mode 100644
index 0000000000..7b24a4ab2c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-14380.yml
@@ -0,0 +1,5 @@
+author: "necromanceranne"
+delete-after: True
+changes:
+ - bugfix: "Properly segments all the augment sprites so that they correctly display."
+ - bugfix: "Properly labels the augment limb icon sprites."
diff --git a/icons/mob/augmentation/augments.dmi b/icons/mob/augmentation/augments.dmi
index e311b6605d..0e09afd482 100644
Binary files a/icons/mob/augmentation/augments.dmi and b/icons/mob/augmentation/augments.dmi differ
diff --git a/icons/mob/augmentation/augments_mining.dmi b/icons/mob/augmentation/augments_mining.dmi
index 61d8cc30e5..89ecf2fc6a 100644
Binary files a/icons/mob/augmentation/augments_mining.dmi and b/icons/mob/augmentation/augments_mining.dmi differ
diff --git a/icons/mob/augmentation/augments_security.dmi b/icons/mob/augmentation/augments_security.dmi
index e954c6e22a..a8fd8e9a5a 100644
Binary files a/icons/mob/augmentation/augments_security.dmi and b/icons/mob/augmentation/augments_security.dmi differ
diff --git a/icons/mob/augmentation/cosmetic_prosthetic/bishop.dmi b/icons/mob/augmentation/cosmetic_prosthetic/bishop.dmi
index 8641ef2d3c..056fea5d4e 100644
Binary files a/icons/mob/augmentation/cosmetic_prosthetic/bishop.dmi and b/icons/mob/augmentation/cosmetic_prosthetic/bishop.dmi differ
diff --git a/icons/mob/augmentation/cosmetic_prosthetic/cybersolutions.dmi b/icons/mob/augmentation/cosmetic_prosthetic/cybersolutions.dmi
index eeed0d0c01..2545387155 100644
Binary files a/icons/mob/augmentation/cosmetic_prosthetic/cybersolutions.dmi and b/icons/mob/augmentation/cosmetic_prosthetic/cybersolutions.dmi differ
diff --git a/icons/mob/augmentation/cosmetic_prosthetic/grayson.dmi b/icons/mob/augmentation/cosmetic_prosthetic/grayson.dmi
index 9ed6c5f06f..97d09d4517 100644
Binary files a/icons/mob/augmentation/cosmetic_prosthetic/grayson.dmi and b/icons/mob/augmentation/cosmetic_prosthetic/grayson.dmi differ
diff --git a/icons/mob/augmentation/cosmetic_prosthetic/hephaestus.dmi b/icons/mob/augmentation/cosmetic_prosthetic/hephaestus.dmi
index 4bb6b72fd0..bc0a068145 100644
Binary files a/icons/mob/augmentation/cosmetic_prosthetic/hephaestus.dmi and b/icons/mob/augmentation/cosmetic_prosthetic/hephaestus.dmi differ
diff --git a/icons/mob/augmentation/cosmetic_prosthetic/nanotrasen.dmi b/icons/mob/augmentation/cosmetic_prosthetic/nanotrasen.dmi
index 18c7738ba3..e3dee175c3 100644
Binary files a/icons/mob/augmentation/cosmetic_prosthetic/nanotrasen.dmi and b/icons/mob/augmentation/cosmetic_prosthetic/nanotrasen.dmi differ
diff --git a/icons/mob/augmentation/cosmetic_prosthetic/talon.dmi b/icons/mob/augmentation/cosmetic_prosthetic/talon.dmi
index 9e4b93fb54..e659e761ce 100644
Binary files a/icons/mob/augmentation/cosmetic_prosthetic/talon.dmi and b/icons/mob/augmentation/cosmetic_prosthetic/talon.dmi differ
diff --git a/icons/mob/augmentation/cosmetic_prosthetic/ward.dmi b/icons/mob/augmentation/cosmetic_prosthetic/ward.dmi
index b2622ef6a1..4651c57d74 100644
Binary files a/icons/mob/augmentation/cosmetic_prosthetic/ward.dmi and b/icons/mob/augmentation/cosmetic_prosthetic/ward.dmi differ
diff --git a/icons/mob/augmentation/cosmetic_prosthetic/xion.dmi b/icons/mob/augmentation/cosmetic_prosthetic/xion.dmi
index 823205742a..c27ad213c7 100644
Binary files a/icons/mob/augmentation/cosmetic_prosthetic/xion.dmi and b/icons/mob/augmentation/cosmetic_prosthetic/xion.dmi differ
diff --git a/icons/obj/machines/research.dmi b/icons/obj/machines/research.dmi
index 7dcd4e6bcb..8f9594c5dc 100644
Binary files a/icons/obj/machines/research.dmi and b/icons/obj/machines/research.dmi differ
diff --git a/icons/obj/robotics.dmi b/icons/obj/robotics.dmi
index 8d0627aa95..a9bf1fc261 100644
Binary files a/icons/obj/robotics.dmi and b/icons/obj/robotics.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 1e2c4a1341..c3aeafdc94 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2071,6 +2071,7 @@
#include "code\modules\events\spontaneous_appendicitis.dm"
#include "code\modules\events\stray_cargo.dm"
#include "code\modules\events\supermatter_surge.dm"
+#include "code\modules\events\supernova.dm"
#include "code\modules\events\travelling_trader.dm"
#include "code\modules\events\vent_clog.dm"
#include "code\modules\events\wisdomcow.dm"