Merge branch 'master' into cute-plushie
@@ -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"
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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\
|
||||
<span class='danger'>Operatives</span>: Secure the nuclear authentication disk and use your bananium fission explosive to HONK the station.\n\
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "meteor"
|
||||
config_tag = "meteor"
|
||||
false_report_weight = 1
|
||||
chaos = 9
|
||||
var/meteordelay = 2000
|
||||
var/nometeors = 0
|
||||
var/rampupdelta = 5
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
required_players = 20
|
||||
required_enemies = 1
|
||||
recommended_enemies = 1
|
||||
chaos = 9
|
||||
|
||||
restricted_jobs = list("Cyborg", "AI")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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\
|
||||
|
||||
@@ -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\
|
||||
<span class='danger'>Wizard</span>: Accomplish your objectives and cause mayhem on the station.\n\
|
||||
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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, "<span class='danger'>You can only have up to two prosthetic limbs!</span>")
|
||||
else
|
||||
//save the actual prosthetic data
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()!
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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..."
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -50,6 +50,30 @@
|
||||
-->
|
||||
<div class="commit sansserif">
|
||||
|
||||
<h2 class="date">11 March 2021</h2>
|
||||
<h3 class="author">Putnam3145 updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">Supernova event</li>
|
||||
<li class="refactor">Bloodsucker day/night cycle now processes on a subsystem instead of using while and sleep (!!)</li>
|
||||
<li class="rscadd">A chaos-weighting system for secret</li>
|
||||
</ul>
|
||||
<h3 class="author">Sneakyrat updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="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</li>
|
||||
<li class="bugfix">Fixes precise insertion not working for remote mat containers</li>
|
||||
<li class="bugfix">Fixes Protolathe/mechfab insert material animations not working</li>
|
||||
<li class="bugfix">Fixes the material insertion animation for protolathes occurring on the circuit printer</li>
|
||||
<li class="bugfix">Fixes the material insertion animation not actually playing when it was started</li>
|
||||
<li class="bugfix">Fixes the material insertion animation for iron not being made</li>
|
||||
<li class="bugfix">Fixes the material insertion animation sometimes not picking the right material for sheets that have multiple different materials in them</li>
|
||||
</ul>
|
||||
<h3 class="author">necromanceranne updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">Properly segments all the augment sprites so that they correctly display.</li>
|
||||
<li class="bugfix">Properly labels the augment limb icon sprites.</li>
|
||||
<li class="bugfix">Fixes going over the defined limit of roundstart prosthetics</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">10 March 2021</h2>
|
||||
<h3 class="author">Hatterhat updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "R3dtail"
|
||||
delete-after: True
|
||||
changes:
|
||||
- spellcheck: "Adds Periods and moves some words around."
|
||||
|
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 |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 68 KiB |
@@ -2069,6 +2069,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"
|
||||
|
||||