Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13
@@ -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"
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, "<span class='warning'>[I] is stuck to you and cannot be placed into [parent].</span>")
|
||||
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, "<span class='warning'>[I] is stuck to you and cannot be placed into [parent].</span>")
|
||||
return
|
||||
inserted = insert_item(I)
|
||||
qdel(I)
|
||||
|
||||
if(inserted)
|
||||
to_chat(user, "<span class='notice'>You insert a material total of [inserted] into [parent].</span>")
|
||||
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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
D.visible_message("<span class='warning'>[A] locks [D] into a restraining position!</span>", \
|
||||
"<span class='userdanger'>[A] locks you into a restraining position!</span>")
|
||||
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("<span class='warning'>[A] strikes [D]'s jaw with their hand!</span>", \
|
||||
"<span class='userdanger'>[A] strikes your jaw, disorienting you!</span>")
|
||||
@@ -196,7 +196,8 @@
|
||||
log_combat(A, D, "knocked out (Chokehold)(CQC)")
|
||||
D.visible_message("<span class='danger'>[A] puts [D] into a chokehold!</span>", \
|
||||
"<span class='userdanger'>[A] puts you into a chokehold!</span>")
|
||||
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, "<span class='notice'>Slam</span>: Grab Harm. Slam opponent into the ground, knocking them down.")
|
||||
to_chat(usr, "<span class='notice'>CQC Kick</span>: Harm Harm. Knocks opponent away. Knocks out stunned or knocked down opponents.")
|
||||
to_chat(usr, "<span class='notice'>Restrain</span>: Grab Grab. Locks opponents into a restraining position, disarm to knock them out with a chokehold.")
|
||||
to_chat(usr, "<span class='notice'>Restrain</span>: Grab Grab. Locks opponents into a restraining position, disarm to mute them with a chokehold.")
|
||||
to_chat(usr, "<span class='notice'>Pressure</span>: Disarm Grab. Decent stamina damage.")
|
||||
to_chat(usr, "<span class='notice'>Consecutive CQC</span>: Disarm Disarm Harm. Mainly offensive move, huge damage and decent stamina damage.")
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
target_trait = ZTRAIT_STATION
|
||||
|
||||
immunity_type = "rad"
|
||||
|
||||
|
||||
var/radiation_intensity = 100
|
||||
|
||||
/datum/weather/rad_storm/telegraph()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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("<span class='danger'>[target.name] blocks [src] and twists [user]'s arm behind [user.p_their()] back!</span>",
|
||||
target.visible_message("<span class='danger'>[target.name] blocks your attack!</span>",
|
||||
"<span class='userdanger'>You block the attack!</span>")
|
||||
user.Stun(40)
|
||||
return TRUE
|
||||
|
||||
/obj/item/melee/chainofcommand
|
||||
|
||||
@@ -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,"<span class = 'danger'>Solar Flares will bombard the station with dangerous UV in [TIME_BLOODSUCKER_DAY_WARN / 60] minutes. <b>Prepare to seek cover in a coffin or closet.</b></span>") // 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,"<span class = 'userdanger'>Solar Flares are about to bombard the station! You have [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds to find cover!</span>",\
|
||||
"<span class = 'danger'>In [TIME_BLOODSUCKER_DAY_FINAL_WARN / 10], your master will be at risk of a Solar Flare. Make sure they find cover!</span>")
|
||||
|
||||
// (FINAL LIL WARNING)
|
||||
while(time_til_cycle > 5)
|
||||
sleep(10)
|
||||
if(cancel_me)
|
||||
return
|
||||
//sleep(TIME_BLOODSUCKER_DAY_FINAL_WARN - 50)
|
||||
warn_daylight(3,"<span class = 'userdanger'>Seek cover, for Sol rises!</span>")
|
||||
|
||||
// Part 3: Night Ending
|
||||
while(time_til_cycle > 0)
|
||||
sleep(10)
|
||||
if(cancel_me)
|
||||
return
|
||||
//sleep(50)
|
||||
warn_daylight(4,"<span class = 'userdanger'>Solar flares bombard the station with deadly UV light!</span><br><span class = ''>Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk Final Death!</span>",\
|
||||
"<span class = 'danger'>Solar flares bombard the station with UV light!</span>")
|
||||
|
||||
// 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,"<span class = 'announce'>The solar flare has ended, and the daylight danger has passed...for now.</span>",\
|
||||
"<span class = 'announce'>The solar flare has ended, and the daylight danger has passed...for now.</span>")
|
||||
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,"<span class = 'danger'>Solar Flares will bombard the station with dangerous UV in [TIME_BLOODSUCKER_DAY_WARN / 60] minutes. <b>Prepare to seek cover in a coffin or closet.</b></span>") // 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,"<span class = 'userdanger'>Solar Flares are about to bombard the station! You have [TIME_BLOODSUCKER_DAY_FINAL_WARN] seconds to find cover!</span>",\
|
||||
"<span class = 'danger'>In [TIME_BLOODSUCKER_DAY_FINAL_WARN / 10], your master will be at risk of a Solar Flare. Make sure they find cover!</span>")
|
||||
if(5)
|
||||
warn_daylight(3,"<span class = 'userdanger'>Seek cover, for Sol rises!</span>")
|
||||
if(0)
|
||||
warn_daylight(4,"<span class = 'userdanger'>Solar flares bombard the station with deadly UV light!</span><br><span class = ''>Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk Final Death!</span>",\
|
||||
"<span class = 'danger'>Solar flares bombard the station with UV light!</span>")
|
||||
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)
|
||||
|
||||
@@ -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,"<span class = 'danger'>A supernova will bombard the station with dangerous UV in [90 / 60] minutes. <b>Prepare to seek cover in a coffin or closet.</b></span>")
|
||||
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
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 (!!)"
|
||||
@@ -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"
|
||||
@@ -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."
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
@@ -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"
|
||||
|
||||