merge fixes

This commit is contained in:
Seris02
2020-02-07 15:28:05 +08:00
198 changed files with 7137 additions and 6861 deletions
+1
View File
@@ -6,6 +6,7 @@
var/flags_1 = NONE
var/interaction_flags_atom = NONE
var/ghost_flags = NONE
var/datum/reagents/reagents = null
//This atom's HUD (med/sec, etc) images. Associative list.
+12 -3
View File
@@ -239,12 +239,20 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
. += "<b>Peaceful Waypoint</b></center><BR>"
. += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive. However, even deep in our territory there may be subversive elements, especially for such a high-value target as your station. Keep an eye out, but don't expect much trouble."
set_security_level(SEC_LEVEL_GREEN)
for(var/T in subtypesof(/datum/station_goal))
var/datum/station_goal/G = new T
if(!(G in station_goals))
station_goals += G
if(21 to 79)
var/perc_green = 100-round(100*((threat_level-21)/(79-21)))
if(prob(perc_green))
. += "<b>Core Territory</b></center><BR>"
. += "Your station orbits within reliably mundane, secure space. Although Nanotrasen has a firm grip on security in your region, the valuable resources and strategic position aboard your station make it a potential target for infiltrations. Monitor crew for non-loyal behavior, but expect a relatively tame shift free of large-scale destruction. We expect great things from your station."
set_security_level(SEC_LEVEL_GREEN)
for(var/T in subtypesof(/datum/station_goal))
var/datum/station_goal/G = new T
if(!(G in station_goals))
station_goals += G
else if(prob(perc_green))
. += "<b>Contested System</b></center><BR>"
. += "Your station's orbit passes along the edge of Nanotrasen's sphere of influence. While subversive elements remain the most likely threat against your station, hostile organizations are bolder here, where our grip is weaker. Exercise increased caution against elite Syndicate strike forces, or Executives forbid, some kind of ill-conceived unionizing attempt."
@@ -273,7 +281,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
if(GLOB.security_level >= SEC_LEVEL_BLUE)
priority_announce("A summary has been copied and printed to all communications consoles.", "Security level elevated.", "intercept")
else
priority_announce("Thanks to the tireless efforts of our security and intelligence divisions, there are currently no likely threats to [station_name()]. Have a secure shift!", "Security Report", "commandreport")
priority_announce("Thanks to the tireless efforts of our security and intelligence divisions, there are currently no likely threats to [station_name()]. All station construction projects have been authorized. Have a secure shift!", "Security Report", "commandreport")
// Yes, this is copy pasted from game_mode
/datum/game_mode/dynamic/check_finished(force_ending)
@@ -346,7 +354,8 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
generate_threat()
storyteller.start_injection_cooldowns()
SSevents.frequency_lower = storyteller.event_frequency_lower // 6 minutes by default
SSevents.frequency_upper = storyteller.event_frequency_upper // 20 minutes by default
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
initial_threat_level = threat_level
return TRUE
@@ -395,7 +404,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
/datum/game_mode/dynamic/post_setup(report)
update_playercounts()
for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules)
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_roundstart_rule, rule), rule.delay)
..()
@@ -47,6 +47,8 @@
assigned += M.mind
M.mind.special_role = antag_flag
M.mind.add_antag_datum(antag_datum)
log_admin("[M.name] was made into a [name] by dynamic.")
message_admins("[M.name] was made into a [name] by dynamic.")
return TRUE
//////////////////////////////////////////////
@@ -72,12 +74,6 @@
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1)
always_max_weight = TRUE
/datum/dynamic_ruleset/latejoin/infiltrator/execute()
. = ..()
for(var/datum/mind/M in assigned)
log_admin("[M.name] was made into a traitor by dynamic.")
message_admins("[M.name] was made into a traitor by dynamic.")
//////////////////////////////////////////////
// //
// REVOLUTIONARY PROVOCATEUR //
@@ -225,3 +221,25 @@
log_admin("[M.name] was made into a bloodsucker by dynamic.")
message_admins("[M.name] was made into a bloodsucker by dynamic.")
return TRUE
//////////////////////////////////////////////
// //
// COLLECTOR //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/latejoin/collector
name = "Contraband Collector"
config_tag = "latejoin_collector"
antag_datum = /datum/antagonist/collector
antag_flag = ROLE_MINOR_ANTAG
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 5
cost = 1
requirements = list(10,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
repeatable = TRUE
flags = TRAITOR_RULESET
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 2)
@@ -494,7 +494,7 @@
high_population_requirement = 50
repeatable_weight_decrease = 2
repeatable = TRUE
property_weights = list("story_potential" = 1, "trust" = 1, "extended" = 1, "valid" = 2, "integrity" = 2)
property_weights = list("story_potential" = 1, "trust" = 1, "extended" = 1, "valid" = 2, "integrity" = 1)
var/list/spawn_locs = list()
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute()
@@ -1,5 +1,6 @@
/datum/dynamic_storyteller
var/name = "none"
var/config_tag = null
var/desc = "A coder's idiocy."
var/list/property_weights = list()
var/curve_centre = 0
@@ -7,6 +8,8 @@
var/forced_threat_level = -1
var/flags = 0
var/weight = 3 // how many rounds need to have been recently played for this storyteller to be left out of the vote
var/event_frequency_lower = 6 MINUTES
var/event_frequency_upper = 20 MINUTES
var/datum/game_mode/dynamic/mode = null
/**
@@ -20,14 +23,6 @@ Property weights are:
"conversion" -- Basically a bool. Conversion antags, well, convert. It's its own class for a good reason.
*/
/datum/dynamic_storyteller/New()
..()
if (istype(SSticker.mode, /datum/game_mode/dynamic))
mode = SSticker.mode
GLOB.dynamic_curve_centre = curve_centre
GLOB.dynamic_curve_width = curve_width
GLOB.dynamic_forced_threat_level = forced_threat_level
/datum/dynamic_storyteller/proc/start_injection_cooldowns()
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_latejoin_delay_max + GLOB.dynamic_first_latejoin_delay_min)
mode.latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_first_latejoin_delay_min, GLOB.dynamic_first_latejoin_delay_max)) + world.time
@@ -42,7 +37,28 @@ Property weights are:
return
/datum/dynamic_storyteller/proc/on_start()
return
if (istype(SSticker.mode, /datum/game_mode/dynamic))
mode = SSticker.mode
GLOB.dynamic_curve_centre = curve_centre
GLOB.dynamic_curve_width = curve_width
if(flags & USE_PREF_WEIGHTS)
var/voters = 0
var/mean = 0
for(var/client/c in GLOB.clients)
var/vote = c.prefs.preferred_chaos
if(vote)
voters += 1
switch(vote)
if(CHAOS_NONE)
mean -= 5
if(CHAOS_LOW)
mean -= 2.5
if(CHAOS_HIGH)
mean += 2.5
if(CHAOS_MAX)
mean += 5
GLOB.dynamic_curve_centre += (mean/voters)
GLOB.dynamic_forced_threat_level = forced_threat_level
/datum/dynamic_storyteller/proc/get_midround_cooldown()
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
@@ -154,12 +170,15 @@ Property weights are:
/datum/dynamic_storyteller/cowabunga
name = "Chaotic"
config_tag = "chaotic"
curve_centre = 10
desc = "Chaos: high. Variation: high. Likely antags: clock cult, revs, wizard."
property_weights = list("extended" = -1, "chaos" = 10)
weight = 2
weight = 1
event_frequency_lower = 2 MINUTES
event_frequency_upper = 10 MINUTES
flags = WAROPS_ALWAYS_ALLOWED
var/refund_cooldown
var/refund_cooldown = 0
/datum/dynamic_storyteller/cowabunga/get_midround_cooldown()
return ..() / 4
@@ -169,12 +188,13 @@ Property weights are:
/datum/dynamic_storyteller/cowabunga/do_process()
if(refund_cooldown < world.time)
mode.refund_threat(10)
mode.log_threat("Cowabunga it is. Refunded 10 threat. Threat is now [mode.threat].")
refund_cooldown = world.time + 300 SECONDS
mode.refund_threat(20)
mode.log_threat("Cowabunga it is. Refunded 20 threat. Threat is now [mode.threat].")
refund_cooldown = world.time + 600 SECONDS
/datum/dynamic_storyteller/team
name = "Teamwork"
config_tag = "teamwork"
desc = "Chaos: high. Variation: low. Likely antags: nukies, clockwork cult, wizard, blob, xenomorph."
curve_centre = 2
curve_width = 1.5
@@ -187,6 +207,7 @@ Property weights are:
/datum/dynamic_storyteller/conversion
name = "Conversion"
config_tag = "conversion"
desc = "Chaos: high. Variation: medium. Likely antags: cults, bloodsuckers, revs."
curve_centre = 3
curve_width = 1
@@ -196,24 +217,33 @@ Property weights are:
/datum/dynamic_storyteller/classic
name = "Random"
config_tag = "random"
desc = "Chaos: varies. Variation: highest. No special weights attached."
weight = 6
flags = USE_PREF_WEIGHTS
curve_width = 4
/datum/dynamic_storyteller/memes
name = "Story"
config_tag = "story"
desc = "Chaos: varies. Variation: high. Likely antags: abductors, nukies, wizard, traitor."
weight = 4
flags = USE_PREF_WEIGHTS
curve_width = 4
property_weights = list("story_potential" = 10)
/datum/dynamic_storyteller/suspicion
name = "Intrigue"
config_tag = "intrigue"
desc = "Chaos: low. Variation: high. Likely antags: traitor, bloodsucker. Rare: revs, blood cult."
weight = 4
flags = USE_PREF_WEIGHTS
curve_width = 4
property_weights = list("trust" = -5)
/datum/dynamic_storyteller/liteextended
name = "Calm"
config_tag = "calm"
desc = "Chaos: low. Variation: medium. Likely antags: bloodsuckers, traitors, sentient disease, revenant."
curve_centre = -5
curve_width = 0.5
@@ -226,10 +256,12 @@ Property weights are:
/datum/dynamic_storyteller/extended
name = "Extended"
config_tag = "extended"
desc = "Chaos: none. Variation: none. Likely antags: none."
curve_centre = -20
weight = 2
weight = 0
curve_width = 0.5
/datum/dynamic_storyteller/extended/on_start()
..()
GLOB.dynamic_forced_extended = TRUE
+190 -35
View File
@@ -9,9 +9,10 @@ GLOBAL_LIST_EMPTY(objectives)
var/explanation_text = "Nothing" //What that person is supposed to do.
var/team_explanation_text //For when there are multiple owners.
var/datum/mind/target = null //If they are focused on a particular person.
var/target_amount = 0 //If they are focused on a particular number. Steal objectives have their own counter.
var/completed = 0 //currently only used for custom objectives.
var/martyr_compatible = 0 //If the objective is compatible with martyr objective, i.e. if you can still do it while dead.
var/target_amount = FALSE //If they are focused on a particular number. Steal objectives have their own counter.
var/completed = FALSE //currently only used for custom objectives.
var/completable = TRUE //Whether this objective shows greentext when completed
var/martyr_compatible = FALSE //If the objective is compatible with martyr objective, i.e. if you can still do it while dead.
/datum/objective/New(var/text)
GLOB.objectives += src // CITADEL EDIT FOR CRYOPODS
@@ -172,6 +173,26 @@ GLOBAL_LIST_EMPTY(objectives)
/datum/objective/assassinate/admin_edit(mob/admin)
admin_simple_target_pick(admin)
/datum/objective/assassinate/once
name = "kill once"
var/won = FALSE
/datum/objective/assassinate/once/update_explanation_text()
..()
if(target && target.current)
explanation_text = "Kill [target.name], the [!target_role_type ? target.assigned_role : target.special_role]. You only need to kill them once; if they come back, you've still succeeded."
START_PROCESSING(SSprocessing,src)
else
explanation_text = "Free Objective"
/datum/objective/assassinate/once/check_completion()
return won || ..()
/datum/objective/assassinate/once/process()
won = check_completion()
if(won)
STOP_PROCESSING(SSprocessing,src)
/datum/objective/assassinate/internal
var/stolen = 0 //Have we already eliminated this target?
@@ -365,6 +386,28 @@ GLOBAL_LIST_EMPTY(objectives)
return FALSE
return TRUE
/datum/objective/breakout
name = "breakout"
martyr_compatible = 1
var/target_role_type = 0
var/human_check = TRUE
/datum/objective/breakout/check_completion()
return !target || considered_escaped(target)
/datum/objective/breakout/find_target_by_role(role, role_type=0, invert=0)
if(!invert)
target_role_type = role_type
..()
return target
/datum/objective/breakout/update_explanation_text()
..()
if(target && target.current)
explanation_text = "Make sure [target.name], the [!target_role_type ? target.assigned_role : target.special_role] escapes on the shuttle or an escape pod alive and without being in custody."
else
explanation_text = "Free Objective"
/datum/objective/escape/escape_with_identity
name = "escape with identity"
var/target_real_name // Has to be stored because the target's real_name can change over the course of the round
@@ -582,7 +625,6 @@ GLOBAL_LIST_EMPTY(possible_items_special)
explanation_text = "Do not give up or lose [targetinfo.name]."
steal_target = targetinfo.targetitem
/datum/objective/download
name = "download"
@@ -786,40 +828,10 @@ GLOBAL_LIST_EMPTY(possible_items_special)
/datum/objective/destroy/internal
var/stolen = FALSE //Have we already eliminated this target?
/datum/objective/steal_five_of_type
name = "steal five of"
explanation_text = "Steal at least five items!"
var/list/wanted_items = list(/obj/item)
/datum/objective/steal_five_of_type/New()
..()
wanted_items = typecacheof(wanted_items)
/datum/objective/steal_five_of_type/summon_guns
name = "steal guns"
explanation_text = "Steal at least five guns!"
wanted_items = list(/obj/item/gun)
/datum/objective/steal_five_of_type/summon_magic
name = "steal magic"
explanation_text = "Steal at least five magical artefacts!"
wanted_items = list(/obj/item/spellbook, /obj/item/gun/magic, /obj/item/clothing/suit/space/hardsuit/wizard, /obj/item/scrying, /obj/item/antag_spawner/contract, /obj/item/necromantic_stone)
/datum/objective/steal_five_of_type/check_completion()
var/list/datum/mind/owners = get_owners()
var/stolen_count = 0
for(var/datum/mind/M in owners)
if(!isliving(M.current))
continue
var/list/all_items = M.current.GetAllContents() //this should get things in cheesewheels, books, etc.
for(var/obj/I in all_items) //Check for wanted items
if(is_type_in_typecache(I, wanted_items))
stolen_count++
return stolen_count >= 5
//Created by admin tools
/datum/objective/custom
name = "custom"
completable = FALSE
/datum/objective/custom/admin_edit(mob/admin)
var/expl = stripped_input(admin, "Custom objective:", "Objective", explanation_text)
@@ -997,4 +1009,147 @@ GLOBAL_LIST_EMPTY(possible_items_special)
command_staff_only = TRUE
/datum/objective/hoard
name = "hoard"
var/obj/item/hoarded_item = null
/datum/objective/hoard/get_target()
return hoarded_item
/datum/objective/hoard/proc/set_target(obj/item/I)
if(I)
hoarded_item = I
explanation_text = "Keep [I] on your person at all times."
return hoarded_item
else
explanation_text = "Free objective"
return
/datum/objective/hoard/check_completion()
var/list/datum/mind/owners = get_owners()
if(!hoarded_item)
return TRUE
for(var/datum/mind/M in owners)
if(!isliving(M.current))
continue
var/list/all_items = M.current.GetAllContents() //this should get things in cheesewheels, books, etc.
for(var/obj/I in all_items) //Check for items
if(I == hoarded_item)
return TRUE
return FALSE
/datum/objective/hoard/heirloom
name = "steal heirloom"
/datum/objective/hoard/heirloom/find_target()
set_target(pick(GLOB.family_heirlooms))
GLOBAL_LIST_EMPTY(traitor_contraband)
GLOBAL_LIST_EMPTY(cult_contraband)
/datum/objective/hoard/collector
name = "Hoard contraband"
/datum/objective/collector/New()
..()
if(!GLOB.traitor_contraband.len)//Only need to fill the list when it's needed.
GLOB.traitor_contraband = list(/obj/item/card/emag/empty,/obj/item/clothing/glasses/phantomthief,/obj/item/clothing/gloves/chameleon/broken)
if(!GLOB.cult_contraband.len)
GLOB.cult_contraband = list(/obj/item/clockwork/slab,/obj/item/clockwork/component/belligerent_eye,/obj/item/clockwork/component/belligerent_eye/lens_gem,/obj/item/shuttle_curse,/obj/item/cult_shift)
/datum/objective/hoard/collector/find_target()
var/obj/item/I
var/I_type
if(prob(50))
I_type = pick_n_take(GLOB.traitor_contraband) // always unique unless it's run out, in which case we refill it anyway
else
I_type = pick_n_take(GLOB.cult_contraband)
I = new I_type
I.forceMove(get_turf(owner))
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
H.equip_in_one_of_slots(I, list("backpack" = SLOT_IN_BACKPACK))
hoarded_item = I
GLOBAL_LIST_EMPTY(possible_sabotages)
// For saboteurs. Go in and cause some trouble somewhere. Not necessarily breaking things, just sufficiently troublemaking.
/datum/objective/sabotage
name = "sabotage"
var/datum/sabotage_objective/targetinfo = null //composition > inheritance.
/datum/objective/sabotage/get_target()
return targetinfo.sabotage_type
/datum/objective/sabotage/New()
..()
if(!GLOB.possible_sabotages.len)//Only need to fill the list when it's needed.
for(var/I in subtypesof(/datum/sabotage_objective))
new I
/datum/objective/sabotage/find_target()
var/list/datum/mind/owners = get_owners()
var/approved_targets = list()
check_sabotages:
for(var/datum/sabotage_objective/possible_sabotage in GLOB.possible_sabotages)
if(!is_unique_objective(possible_sabotage.sabotage_type) || possible_sabotage.check_conditions())
continue
for(var/datum/mind/M in owners)
if(M.current.mind.assigned_role in possible_sabotage.excludefromjob)
continue check_sabotages
approved_targets += possible_sabotage
return set_target(safepick(approved_targets))
/datum/objective/sabotage/proc/set_target(datum/sabotage_objective/sabo)
if(sabo)
targetinfo = sabo
explanation_text = "[targetinfo.name]"
give_special_equipment(targetinfo.special_equipment)
return sabo
else
explanation_text = "Free objective"
return
/datum/objective/sabotage/check_completion()
return targetinfo.check_conditions()
/datum/objective/flavor
name = "flavor"
completable = FALSE
var/flavor_file
/datum/objective/flavor/proc/get_flavor_list()
return world.file2list(flavor_file)
/datum/objective/flavor/proc/forge_objective()
var/flavor_list = get_flavor_list()
explanation_text = pick(flavor_list)
/datum/objective/flavor/traitor
name = "traitor flavor"
flavor_file = "strings/flavor_objectives/traitor.txt"
/datum/objective/flavor/traitor/get_flavor_list()
. = ..()
switch(owner.assigned_role)
if("Station Engineer", "Atmospheric Technician")
. += world.file2list("strings/flavor_objectives/traitor/engineering.txt")
if("Medical Doctor","Chemist","Virologist","Geneticist")
. += world.file2list("strings/flavor_objectives/traitor/medical.txt")
if("Scientist","Roboticist","Geneticist")
. += world.file2list("strings/flavor_objectives/traitor/science.txt")
if("Assistant")
. += world.file2list("strings/flavor_objectives/traitor/assistant.txt")
/datum/objective/flavor/ninja_helping
flavor_file = "strings/flavor_objectives/ninja_helping.txt"
/datum/objective/flavor/ninja_syndie
flavor_file = "strings/flavor_objectives/ninja_syndie.txt"
/datum/objective/flavor/wizard
flavor_file = "strings/flavor_objectives/wizard.txt"
+107
View File
@@ -0,0 +1,107 @@
/datum/sabotage_objective
var/name = "Free Objective"
var/sabotage_type = "nothing"
var/special_equipment = list()
var/list/excludefromjob = list()
/datum/sabotage_objective/New()
..()
if(sabotage_type!="nothing")
GLOB.possible_sabotages += src
/datum/sabotage_objective/proc/check_conditions()
return TRUE
/datum/sabotage_objective/processing
var/won = FALSE
/datum/sabotage_objective/processing/New()
..()
START_PROCESSING(SSprocessing, src)
/datum/sabotage_objective/processing/proc/check_condition_processing()
return 100
/datum/sabotage_objective/processing/process()
check_condition_processing()
if(won >= 100)
STOP_PROCESSING(SSprocessing,src)
/datum/sabotage_objective/processing/check_conditions()
return won
/datum/sabotage_objective/processing/power_sink
name = "Drain at least 1 gigajoule of power using a power sink."
sabotage_type = "powersink"
special_equipment = list(/obj/item/powersink)
var/sink_found = FALSE
var/count = 0
/datum/sabotage_objective/processing/power_sink/check_condition_processing()
count += 1
if(count==10 || sink_found) // doesn't need to fire that often unless a sink exists
var/sink_found_this_time = FALSE
for(var/datum/powernet/PN in GLOB.powernets)
for(var/obj/item/powersink/sink in PN.nodes)
sink_found_this_time = TRUE
won = max(won,sink.power_drained/1e9)
sink_found = sink_found_this_time
count = 0
return FALSE
/obj/item/paper/guides/antag/supermatter_sabotage
info = "Ways to sabotage a supermatter:<br>\
<ul>\
<li>Set the air alarm's operating mode to anything that isn't 'draught' (yes, anything, though 'off' works best). Or just smash the air alarm, that works too.</li>\
<li>Wrench a pipe (the junction to the cold loop is most effective, but some setups will robust through this no issue; best to try for multiple)</li>\
<li>Pump in as much carbon dioxide, oxygen, plasma or tritium as you can find (this will likely also cause a singularity or tesla delamination, so watch out!)</li>\
<li>Unset the filters on the cooling loop, or, perhaps more insidious, set them to oxygen/plasma.</li>\
<li>Deactivate the digital valve that sends the exhaust gases to space (note: only works on box station; others you must unwrench).</li>\
<li>There are many other ways; be creative!</li>\
</ul>"
/datum/sabotage_objective/processing/supermatter
name = "Sabotage the supermatter so that it goes under 50% integrity. If it is delaminated, you will fail."
sabotage_type = "supermatter"
special_equipment = list(/obj/item/paper/guides/antag/supermatter_sabotage)
var/list/supermatters = list()
excludefromjob = list("Chief Engineer", "Station Engineer", "Atmospheric Technician")
/datum/sabotage_objective/processing/supermatter/check_condition_processing()
if(!supermatters.len)
supermatters = list()
for(var/obj/machinery/power/supermatter_crystal/S in GLOB.machines)
// Delaminating, not within coverage, not on a tile.
if (!isturf(S.loc) || !(is_station_level(S.z) || is_mining_level(S.z)))
continue
supermatters.Add(S)
for(var/obj/machinery/power/supermatter_crystal/S in supermatters) // you can win this with a wishgranter... lol.
won = max(1-((S.get_integrity()-50)/50),won)
return FALSE
/datum/sabotage_objective/station_integrity
name = "Make sure the station is at less than 80% integrity by the end. Smash walls, windows etc. to reach this goal."
sabotage_type = "integrity"
/datum/sabotage_objective/station_integrity/check_conditions()
return 5-(max(SSticker.station_integrity*4,320)/80)
/datum/sabotage_objective/cloner
name = "Destroy all Nanotrasen cloning machines."
sabotage_type = "cloner"
/datum/sabotage_objective/cloner/check_conditions()
return !(locate(/obj/machinery/clonepod) in GLOB.machines)
/datum/sabotage_objective/ai_law
name = "Upload a hacked law to the AI."
sabotage_type = "ailaw"
special_equipment = list(/obj/item/aiModule/syndicate)
excludefromjob = list("Chief Engineer","Research Director","Head of Personnel","Captain","Chief Medical Officer","Head Of Security")
/datum/sabotage_objective/ai_law/check_conditions()
for (var/i in GLOB.ai_list)
var/mob/living/silicon/ai/aiPlayer = i
if(aiPlayer.mind && length(aiPlayer.laws.hacked))
return TRUE
return FALSE
+1 -1
View File
@@ -242,7 +242,7 @@ Class Procs:
else
if(interaction_flags_machine & INTERACT_MACHINE_REQUIRES_SILICON)
return FALSE
if(!Adjacent(user))
if(!Adjacent(user) && !isobserver(user))
var/mob/living/carbon/H = user
if(!(istype(H) && H.has_dna() && H.dna.check_mutation(TK)))
return FALSE
+4 -3
View File
@@ -120,7 +120,7 @@
/obj/machinery/defibrillator_mount/AltClick(mob/living/carbon/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
. = TRUE
if(!defib)
@@ -129,9 +129,10 @@
if(clamps_locked)
to_chat(user, "<span class='warning'>You try to tug out [defib], but the mount's clamps are locked tight!</span>")
return
if(!user.put_in_hands(defib))
if(!user.get_empty_held_indexes())
to_chat(user, "<span class='warning'>You need a free hand!</span>")
return
user.put_in_hands(defib)
user.visible_message("<span class='notice'>[user] unhooks [defib] from [src].</span>", \
"<span class='notice'>You slide out [defib] from [src] and unhook the charging cables.</span>")
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
@@ -147,4 +148,4 @@
materials = list(MAT_METAL = 300, MAT_GLASS = 100)
w_class = WEIGHT_CLASS_BULKY
result_path = /obj/machinery/defibrillator_mount
pixel_shift = -28
pixel_shift = -28
+89 -8
View File
@@ -189,6 +189,7 @@ GLOBAL_LIST_EMPTY(allCasters)
armor = list("melee" = 50, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
max_integrity = 200
integrity_failure = 50
ghost_flags = INTERACT_GHOST_READ
var/screen = 0
var/paper_remaining = 15
var/securityCaster = 0
@@ -196,6 +197,7 @@ GLOBAL_LIST_EMPTY(allCasters)
var/alert_delay = 500
var/alert = FALSE
var/scanned_user = "Unknown"
var/mob/active_user = null
var/msg = ""
var/datum/picture/picture
var/channel_name = ""
@@ -264,10 +266,10 @@ GLOBAL_LIST_EMPTY(allCasters)
/obj/machinery/newscaster/ui_interact(mob/user)
. = ..()
if(ishuman(user) || issilicon(user))
var/mob/living/human_or_robot_user = user
if(ishuman(user) || issilicon(user) || isobserver(user))
var/mob/M = user
var/dat
scan_user(human_or_robot_user)
scan_user(M)
switch(screen)
if(0)
dat += "Welcome to Newscasting Unit #[unit_no].<BR> Interface & News networks Operational."
@@ -279,7 +281,7 @@ GLOBAL_LIST_EMPTY(allCasters)
dat+= "<BR><A href='?src=[REF(src)];create_feed_story=1'>Submit new Feed story</A>"
dat+= "<BR><A href='?src=[REF(src)];menu_paper=1'>Print newspaper</A>"
dat+= "<BR><A href='?src=[REF(src)];refresh=1'>Re-scan User</A>"
dat+= "<BR><BR><A href='?src=[REF(human_or_robot_user)];mach_close=newscaster_main'>Exit</A>"
dat+= "<BR><BR><A href='?src=[REF(M)];mach_close=newscaster_main'>Exit</A>"
if(securityCaster)
var/wanted_already = 0
if(GLOB.news_network.wanted_issue.active)
@@ -501,24 +503,36 @@ GLOBAL_LIST_EMPTY(allCasters)
if(21)
dat+="<FONT COLOR='maroon'>Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.</FONT><BR><BR>"
dat+="<A href='?src=[REF(src)];setScreen=[0]'>Return</A>"
var/datum/browser/popup = new(human_or_robot_user, "newscaster_main", "Newscaster Unit #[unit_no]", 400, 600)
var/datum/browser/popup = new(M, "newscaster_main", "Newscaster Unit #[unit_no]", 400, 600)
popup.set_content(dat)
popup.set_title_image(human_or_robot_user.browse_rsc_icon(icon, icon_state))
popup.set_title_image(M.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/newscaster/Topic(href, href_list)
if(..())
return
if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && isturf(loc))) || hasSiliconAccessInArea(usr))
if(active_user && !isobserver(active_user) && get_dist(active_user,src)<=1 && usr!=active_user)
to_chat(usr, "<span class='warning'>You must wait for [active_user] to finish and move away.</span>")
return
if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && isturf(loc))) || hasSiliconAccessInArea(usr) || isobserver(usr))
usr.set_machine(src)
scan_user(usr)
if(href_list["set_channel_name"])
if(isobserver(usr) && !canGhostWrite(usr,src,"set a channel's name"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
channel_name = stripped_input(usr, "Provide a Feed Channel Name", "Network Channel Handler", "", MAX_NAME_LEN)
updateUsrDialog()
else if(href_list["set_channel_lock"])
if(isobserver(usr) && !canGhostWrite(usr,src,"locked a channel"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
c_locked = !c_locked
updateUsrDialog()
else if(href_list["submit_new_channel"])
if(isobserver(usr) && !canGhostWrite(usr,src,"created a new channel"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/list/existing_authors = list()
for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels)
if(FC.authorCensor)
@@ -541,6 +555,9 @@ GLOBAL_LIST_EMPTY(allCasters)
screen=5
updateUsrDialog()
else if(href_list["set_channel_receiving"])
if(isobserver(usr) && !canGhostWrite(usr,src,"tried to set the receiving channel"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/list/available_channels = list()
for(var/datum/newscaster/feed_channel/F in GLOB.news_network.network_channels)
if( (!F.locked || F.author == scanned_user) && !F.censored)
@@ -548,14 +565,23 @@ GLOBAL_LIST_EMPTY(allCasters)
channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels
updateUsrDialog()
else if(href_list["set_new_message"])
if(isobserver(usr) && !canGhostWrite(usr,src,"set the message of a new feed story"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/temp_message = trim(stripped_multiline_input(usr, "Write your Feed story", "Network Channel Handler", msg))
if(temp_message)
msg = temp_message
updateUsrDialog()
else if(href_list["set_attachment"])
if(isobserver(usr))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
AttachPhoto(usr)
updateUsrDialog()
else if(href_list["submit_new_message"])
if(isobserver(usr) && !canGhostWrite(usr,src,"added a new story"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
if(msg =="" || msg=="\[REDACTED\]" || scanned_user == "Unknown" || channel_name == "" )
screen=6
else
@@ -565,15 +591,27 @@ GLOBAL_LIST_EMPTY(allCasters)
msg = ""
updateUsrDialog()
else if(href_list["create_channel"])
if(isobserver(usr) && !canGhostWrite(usr,src,"created a channel"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
screen=2
updateUsrDialog()
else if(href_list["create_feed_story"])
if(isobserver(usr) && !canGhostWrite(usr,src,"created a feed story"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
screen=3
updateUsrDialog()
else if(href_list["menu_paper"])
if(isobserver(usr) && !canGhostWrite(usr,src,""))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
screen=8
updateUsrDialog()
else if(href_list["print_paper"])
if(isobserver(usr) && !canGhostWrite(usr,src,"printed a paper"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
if(!paper_remaining)
screen=21
else
@@ -581,12 +619,21 @@ GLOBAL_LIST_EMPTY(allCasters)
screen = 20
updateUsrDialog()
else if(href_list["menu_censor_story"])
if(isobserver(usr) && !canGhostWrite(usr,src,"censored a story"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
screen=10
updateUsrDialog()
else if(href_list["menu_censor_channel"])
if(isobserver(usr) && !canGhostWrite(usr,src,"censored a channel"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
screen=11
updateUsrDialog()
else if(href_list["menu_wanted"])
if(isobserver(usr) && !canGhostWrite(usr,src,""))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/already_wanted = 0
if(GLOB.news_network.wanted_issue.active)
already_wanted = 1
@@ -596,12 +643,21 @@ GLOBAL_LIST_EMPTY(allCasters)
screen = 14
updateUsrDialog()
else if(href_list["set_wanted_name"])
if(isobserver(usr) && !canGhostWrite(usr,src,"tried to set the name of a wanted person"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
channel_name = stripped_input(usr, "Provide the name of the Wanted person", "Network Security Handler")
updateUsrDialog()
else if(href_list["set_wanted_desc"])
if(isobserver(usr) && !canGhostWrite(usr,src,"tried to set the description of a wanted person"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
msg = stripped_input(usr, "Provide a description of the Wanted person and any other details you deem important", "Network Security Handler")
updateUsrDialog()
else if(href_list["submit_wanted"])
if(isobserver(usr) && !canGhostWrite(usr,src,"submitted a wanted poster"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/input_param = text2num(href_list["submit_wanted"])
if(msg == "" || channel_name == "" || scanned_user == "Unknown")
screen = 16
@@ -632,6 +688,9 @@ GLOBAL_LIST_EMPTY(allCasters)
screen=18
updateUsrDialog()
else if(href_list["censor_channel_author"])
if(isobserver(usr) && !canGhostWrite(usr,src,"tried to censor an author"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/datum/newscaster/feed_channel/FC = locate(href_list["censor_channel_author"])
if(FC.is_admin_channel)
alert("This channel was created by a Nanotrasen Officer. You cannot censor it.","Ok")
@@ -639,6 +698,9 @@ GLOBAL_LIST_EMPTY(allCasters)
FC.toggleCensorAuthor()
updateUsrDialog()
else if(href_list["censor_channel_story_author"])
if(isobserver(usr) && !canGhostWrite(usr,src,"tried to censor a story's author"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/datum/newscaster/feed_message/MSG = locate(href_list["censor_channel_story_author"])
if(MSG.is_admin_message)
alert("This message was created by a Nanotrasen Officer. You cannot censor its author.","Ok")
@@ -646,6 +708,9 @@ GLOBAL_LIST_EMPTY(allCasters)
MSG.toggleCensorAuthor()
updateUsrDialog()
else if(href_list["censor_channel_story_body"])
if(isobserver(usr) && !canGhostWrite(usr,src,"tried to censor a story"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/datum/newscaster/feed_message/MSG = locate(href_list["censor_channel_story_body"])
if(MSG.is_admin_message)
alert("This channel was created by a Nanotrasen Officer. You cannot censor it.","Ok")
@@ -653,11 +718,17 @@ GLOBAL_LIST_EMPTY(allCasters)
MSG.toggleCensorBody()
updateUsrDialog()
else if(href_list["pick_d_notice"])
if(isobserver(usr) && !canGhostWrite(usr,src,""))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/datum/newscaster/feed_channel/FC = locate(href_list["pick_d_notice"])
viewing_channel = FC
screen=13
updateUsrDialog()
else if(href_list["toggle_d_notice"])
if(isobserver(usr) && !canGhostWrite(usr,src,"tried to set a D-notice"))
to_chat(usr, "<span class='warning'>You can't do that.</span>")
return
var/datum/newscaster/feed_channel/FC = locate(href_list["toggle_d_notice"])
if(FC.is_admin_channel)
alert("This channel was created by a Nanotrasen Officer. You cannot place a D-Notice upon it.","Ok")
@@ -805,6 +876,12 @@ GLOBAL_LIST_EMPTY(allCasters)
picture = selection
/obj/machinery/newscaster/proc/scan_user(mob/living/user)
if(active_user)
if(active_user != user)
if(get_dist(active_user,src)<=1)
if(!isobserver(active_user))
to_chat(user, "<span class='warning'>Wait for [active_user] to finish and move away.</span>")
return
if(ishuman(user))
var/mob/living/carbon/human/human_user = user
if(human_user.wear_id)
@@ -824,9 +901,14 @@ GLOBAL_LIST_EMPTY(allCasters)
else if(issilicon(user))
var/mob/living/silicon/ai_user = user
scanned_user = "[ai_user.name] ([ai_user.job])"
else if (IsAdminGhost(user))
scanned_user = "Nanotrasen Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
else if (isobserver(user))
scanned_user = "Space-Time Anomaly #[rand(0,9)][rand(0,9)][rand(0,9)]"
else
throw EXCEPTION("Invalid user for this proc")
return
active_user = user
/obj/machinery/newscaster/proc/print_paper()
SSblackbox.record_feedback("amount", "newspapers_printed", 1)
@@ -859,7 +941,6 @@ GLOBAL_LIST_EMPTY(allCasters)
say("Attention! Wanted issue distributed!")
playsound(loc, 'sound/machines/warning-buzzer.ogg', 75, 1)
/obj/item/newspaper
name = "newspaper"
desc = "An issue of The Griffon, the newspaper circulating aboard Nanotrasen Space Stations."
@@ -10,7 +10,7 @@
var/list/gibamounts = list() //amount to spawn for each gib decal type we'll spawn.
var/list/gibdirections = list() //of lists of possible directions to spread each gib decal type towards.
/obj/effect/gibspawner/Initialize(mapload, mob/living/source_mob, list/datum/disease/diseases)
/obj/effect/gibspawner/Initialize(mapload, mob/living/source_mob, list/datum/disease/diseases, list/blood_dna)
. = ..()
if(gibtypes.len != gibamounts.len)
stack_trace("Gib list amount length mismatch!")
@@ -33,7 +33,7 @@
var/body_coloring = ""
if(source_mob)
if(!issilicon(source_mob))
dna_to_add = source_mob.get_blood_dna_list() //ez pz
dna_to_add = blood_dna || source_mob.get_blood_dna_list() //ez pz
if(ishuman(source_mob))
var/mob/living/carbon/human/H = source_mob
if(H.dna.species.use_skintones)
+4 -1
View File
@@ -128,6 +128,9 @@
return
. = ..()
/obj/item/card/emag/empty
uses = 0
/obj/item/emagrecharge
name = "electromagnet charging device"
desc = "A small cell with two prongs lazily jabbed into it. It looks like it's made for charging the small batteries found in electromagnetic devices, sadly this can't be recharged like a normal cell."
@@ -538,4 +541,4 @@ update_label("John Doe", "Clowny")
id_color = "#0000FF"
/obj/item/card/id/knight/captain
id_color = "#FFD700"
id_color = "#FFD700"
@@ -238,6 +238,14 @@
/obj/machinery/vending/cigarette = "ShadyCigs Deluxe",
/obj/machinery/vending/games = "\improper Good Clean Fun",
/obj/machinery/vending/autodrobe = "AutoDrobe",
/obj/machinery/vending/assist = "\improper Vendomat",
/obj/machinery/vending/engivend = "\improper Engi-Vend",
/obj/machinery/vending/engivend = "\improper YouTool",
/obj/machinery/vending/sustenance = "\improper Sustenance Vendor",
/obj/machinery/vending/dinnerware = "\improper Plasteel Chef's Dinnerware Vendor",
/obj/machinery/vending/cart = "\improper PTech",
/obj/machinery/vending/hydronutrients = "\improper NutriMax",
/obj/machinery/vending/hydroseeds = "\improper MegaSeed Servitor",
/obj/machinery/vending/wardrobe/sec_wardrobe = "SecDrobe",
/obj/machinery/vending/wardrobe/medi_wardrobe = "MediDrobe",
/obj/machinery/vending/wardrobe/engi_wardrobe = "EngiDrobe",
+2 -1
View File
@@ -100,7 +100,8 @@
bot_access_flags = CLEAN_BOT
/obj/item/cartridge/lawyer
name = "\improper P.R.O.V.E. cartridge"
name = "\improper S.P.A.M. cartridge"
desc = "Introducing the Station Public Announcement Messenger cartridge, featuring the unique ability to broadcast-mark messages, designed for lawyers across Nanotrasen to advertise their useful and important services."
icon_state = "cart-law"
access = CART_SECURITY
spam_enabled = 1
+3
View File
@@ -244,3 +244,6 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
/obj/item/storage/book/bible/syndicate/add_blood_DNA(list/blood_dna)
return FALSE
/obj/item/storage/book/bible/syndicate/empty
uses = 0
+1 -1
View File
@@ -189,7 +189,7 @@
L.Knockdown(stunpwr, override_stamdmg = 0)
L.apply_damage(stunpwr*0.55, STAMINA, user.zone_selected)
L.apply_damage(stunpwr*0.5, STAMINA, user.zone_selected)
L.apply_effect(EFFECT_STUTTER, stunforce)
SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK)
if(user)
+2
View File
@@ -453,6 +453,7 @@
force_wielded = 0
attack_verb = list("attacked", "struck", "hit")
total_mass_on = TOTAL_MASS_TOY_SWORD
sharpness = IS_BLUNT
/obj/item/twohanded/dualsaber/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return FALSE
@@ -472,6 +473,7 @@
attack_verb = list("attacked", "struck", "hit")
total_mass_on = TOTAL_MASS_TOY_SWORD
slowdown_wielded = 0
sharpness = IS_BLUNT
/obj/item/twohanded/dualsaber/hypereutactic/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return FALSE
+1 -1
View File
@@ -37,7 +37,7 @@
structureclimber.visible_message("<span class='warning'>[structureclimber] has been knocked off [src].", "You're knocked off [src]!", "You see [structureclimber] get knocked off [src].</span>")
/obj/structure/ui_act(action, params)
..()
. = ..()
add_fingerprint(usr)
/obj/structure/MouseDrop_T(atom/movable/O, mob/user)
+8 -2
View File
@@ -8,14 +8,16 @@
max_integrity = 1
armor = list("melee" = 0, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 20)
var/obj/item/holosign_creator/projector
var/init_vis_overlay = TRUE
/obj/structure/holosign/Initialize(mapload, source_projector)
. = ..()
if(source_projector)
projector = source_projector
projector.signs += src
SSvis_overlays.add_vis_overlay(src, icon, icon_state, ABOVE_MOB_LAYER, plane, dir, alpha, RESET_ALPHA) //you see mobs under it, but you hit them like they are above it
alpha = 0
if(init_vis_overlay)
SSvis_overlays.add_vis_overlay(src, icon, icon_state, ABOVE_MOB_LAYER, plane, dir, alpha, RESET_ALPHA) //you see mobs under it, but you hit them like they are above it
alpha = 0
/obj/structure/holosign/Destroy()
if(projector)
@@ -74,8 +76,10 @@
icon_state = "holo_fan"
density = FALSE
anchored = TRUE
layer = ABOVE_NORMAL_TURF_LAYER
CanAtmosPass = ATMOS_PASS_NO
alpha = 150
init_vis_overlay = FALSE
/obj/structure/holosign/barrier/atmos/Initialize()
. = ..()
@@ -100,7 +104,9 @@
max_integrity = 30
density = FALSE
anchored = TRUE
layer = ABOVE_NORMAL_TURF_LAYER
alpha = 150
init_vis_overlay = FALSE
CanAtmosPass = ATMOS_PASS_NO
resistance_flags = FIRE_PROOF
+3 -1
View File
@@ -362,8 +362,10 @@
. = ..()
if(.)
return
if(!user || !istype(user, /mob/living))
return FALSE
if(length(src_object.contents()))
to_chat(usr, "<span class='notice'>You start dumping out the contents...</span>")
to_chat(user, "<span class='notice'>You start dumping out the contents...</span>")
if(!do_after(usr,20,target=src_object.parent))
return FALSE
+1
View File
@@ -8,6 +8,7 @@ GLOBAL_LIST(topic_status_cache)
//This happens after the Master subsystem new(s) (it's a global datum)
//So subsystems globals exist, but are not initialised
/world/New()
enable_debugger()
log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!")