[MIRROR] Reworks sabotage progression traitor objective [MDB IGNORE] (#19766)

* Reworks sabotage progression traitor objective (#73750)

## About The Pull Request

This one is a little bit of a more abstract change than my last traitor
objective rebalancing PR.

The idea here is that I think that the objectives which have you
sabotage a frequently used machine (lathes or the ORM, but we can maybe
expand it to others following this?) are potentially pretty good but
limitations in how the objective are tracked mean that people go about
them in a boring way which rarely inconveniences anyone.

I have reworked these objectives so that you can choose to apply a
provided item to the machine over 10 seconds. The next interaction
following this (clicking on it, or in the case of the ORM loading any
ore into it) will cause the machine to explode, destroying itself and
lightly damaging people nearby (explosion damage is... variable, but
it's a light explosion so it won't instantly kill anyone).
There is a 0.5 second grace period between the bomb triggering and the
explosion actually happening, which players can use to perform some kind
of tactical reaction or simply to feel regret.

Here's a video:
https://www.youtube.com/watch?v=xNIaHsA9YFE

Trapped machines will intermittently beep, though at a volume which is
hard to detect from more than two tiles away, and can be defused by
using a screwdriver on the machine.
If you choose to do this then you will get a little bonus to TC and
reputation, but only if the trap is successfully sprung. This means that
sabotaging a machine in an empty department is unlikely to lead to quick
success.
You can also still do it with screwdriver and crowbar way if you are
boring but this means you will only get reputation and not any
telecrystals.

The two objectives to destroy a radio server or the research machine
remain as they were.

Also I refactored how we set which machines are targets for these
objectives so it doesn't iterate over every machine in the world every
time.

## Why It's Good For The Game

Traitor objectives (and antagonist objectives in general) should:
- Present you with a somewhat engaging task
- Encourage you to interact with at least one other player (at least by
"attempting to sneak past them")
- Move the state of the round forward in some way, usually by creating
inconvenience for at least one other person

Prior to this change you could, and people often did, complete this
objective by accessing a machine that you already _have_ access to,
using a screwdriver and crowbar on it, and then reassembling it.
This prompts interaction with nobody, and inconveniences nobody.

Following this change people will be encouraged to:
- Actually destroy the machine.
- Probably harm somebody.
- Potentially cause some collateral damage.
- Make loud sounds and flashing lights to delight people of all ages.

Even if you opt to set the device in a little-used department and then
blow yourself up, that will prompt you to go and interact with someone
in medbay and will also look pretty suspicious in a way that's much
harder to track with the previous objective.

Also I might reuse this component again in the future, you never know.

## Changelog

🆑 Jacquerel, sprite by J(Clearly Lying)
balance: Traitor objectives which ask you to destroy lathes or the ORM
provide an optional bonus if you _booby trap_ the machine using a
provided tool. This causes the machine to explode the next time it is
interacted with.
balance: Performing the objective without rigging the machine to explode
awards no TC, using it awards more TC than it did previously.
/🆑

* Reworks sabotage progression traitor objective

---------

Co-authored-by: Jacquerel <hnevard@gmail.com>
Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-03-11 01:57:18 +00:00
committed by GitHub
co-authored by Jacquerel Gandalf
parent 18af69f81d
commit f4ba8c4017
12 changed files with 383 additions and 90 deletions
@@ -51,6 +51,8 @@
#define LINKED_UP (1<<0)
/// an obj/item is created! (obj/item/created_item)
#define COMSIG_GLOB_NEW_ITEM "!new_item"
/// an obj/machinery is created! (obj/machinery/created_machine)
#define COMSIG_GLOB_NEW_MACHINE "!new_machine"
/// a client (re)connected, after all /client/New() checks have passed : (client/connected_client)
#define COMSIG_GLOB_CLIENT_CONNECT "!client_connect"
/// a weather event of some kind occured
@@ -416,3 +416,6 @@
/// from /obj/item/detective_scanner/scan(): (mob/user, list/extra_data)
#define COMSIG_DETECTIVE_SCANNED "det_scanned"
/// from /obj/machinery/mineral/ore_redemption/pickup_item when it successfully picks something up
#define COMSIG_ORM_COLLECTED_ORE "orm_collected_ore"
@@ -21,6 +21,9 @@
#define COMPONENT_FORCE_PLACEMENT (1<<0)
#define COMPONENT_FORCE_FAIL_PLACEMENT (1<<1)
/// Called when a machine a traitor has booby trapped triggers its payload
#define COMSIG_TRAITOR_MACHINE_TRAP_TRIGGERED "traitor_machine_trap_triggered"
/// Called when a device a traitor has planted effects someone's mood. Pass the mind of the viewer.
#define COMSIG_DEMORALISING_EVENT "traitor_demoralise_event"
/// Called when you finish drawing some graffiti so we can register more signals on it. Pass the graffiti effect.
+1
View File
@@ -5,3 +5,4 @@
#define DOAFTER_SOURCE_CLIMBING_LADDER "doafter_climbingladder"
#define DOAFTER_SOURCE_SPIDER "doafter_spider"
#define DOAFTER_SOURCE_HEAL_TOUCH "doafter_heal_touch"
#define DOAFTER_SOURCE_PLANTING_DEVICE "doafter_planting_device"
@@ -0,0 +1,102 @@
/**
* Attached to an atom, creates an explosion when it is interacted with
*/
/datum/component/interaction_booby_trap
/// Explosion radius of light damage
var/explosion_light_range
/// Explosion radius of heavy damage
var/explosion_heavy_range
/// Sound to play when triggered
var/triggered_sound
/// Time to wait between being triggered and blowing up
var/trigger_delay
/// Looping sound to clue people in that something is up
var/datum/looping_sound/active_sound_loop
/// Using this tool on the atom will defuse the explosive
var/defuse_tool
/// List of additional signals which should make this explode
var/list/additional_triggers
/// Callback to run when we're going to explode
var/datum/callback/on_triggered_callback
/// Callback to run when we've been defused
var/datum/callback/on_defused_callback
/// Time until we explode
var/explode_timer
/datum/component/interaction_booby_trap/Initialize(
explosion_light_range = 3,
explosion_heavy_range = 1, // So we destroy some machine components
triggered_sound = 'sound/machines/triple_beep.ogg',
trigger_delay = 0.5 SECONDS,
sound_loop_type = /datum/looping_sound/trapped_machine_beep,
defuse_tool = TOOL_SCREWDRIVER,
additional_triggers = list(),
datum/callback/on_triggered_callback = null,
datum/callback/on_defused_callback = null,
)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
src.explosion_light_range = explosion_light_range
src.explosion_heavy_range = explosion_heavy_range
src.triggered_sound = triggered_sound
src.trigger_delay = trigger_delay
src.defuse_tool = defuse_tool
src.additional_triggers = additional_triggers
src.on_triggered_callback = on_triggered_callback
src.on_defused_callback = on_defused_callback
if (sound_loop_type)
active_sound_loop = new sound_loop_type(parent)
active_sound_loop.start()
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_touched))
RegisterSignal(parent, COMSIG_PARENT_EXAMINE_MORE, PROC_REF(on_examine))
if (defuse_tool)
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(defuse_tool), PROC_REF(on_defused))
if (length(additional_triggers))
RegisterSignals(parent, additional_triggers, PROC_REF(trigger_explosive))
/datum/component/interaction_booby_trap/Destroy(force, silent)
UnregisterSignal(parent, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_TOOL_ACT(defuse_tool), COMSIG_PARENT_EXAMINE_MORE) + additional_triggers)
QDEL_NULL(active_sound_loop)
QDEL_NULL(on_triggered_callback)
QDEL_NULL(on_defused_callback)
return ..()
/// Called when someone touches the parent atom with their hands, we want to blow up
/datum/component/interaction_booby_trap/proc/on_touched(atom/source)
SIGNAL_HANDLER
trigger_explosive(source)
return COMPONENT_CANCEL_ATTACK_CHAIN
/// Start a countdown until destruction
/datum/component/interaction_booby_trap/proc/trigger_explosive(atom/source)
SIGNAL_HANDLER
if (explode_timer)
return
explode_timer = addtimer(CALLBACK(src, PROC_REF(explode), source), 0.5 SECONDS)
source.balloon_alert_to_viewers("beep")
playsound(parent, triggered_sound, 50, FALSE)
return
/// Blow up the parent atom and delete ourselves
/datum/component/interaction_booby_trap/proc/explode(atom/source)
on_triggered_callback?.Invoke(source)
var/turf/origin_turf = get_turf(source)
new /obj/effect/temp_visual/explosion/fast(origin_turf)
EX_ACT(source, EXPLODE_HEAVY, source)
explosion(origin = origin_turf, light_impact_range = explosion_light_range, heavy_impact_range = explosion_heavy_range, explosion_cause = src)
qdel(src)
/// Defuse the bomb and delete ourselves
/datum/component/interaction_booby_trap/proc/on_defused(atom/source, mob/user, obj/item/tool)
SIGNAL_HANDLER
on_defused_callback?.Invoke(source, user, tool)
qdel(src)
return COMPONENT_BLOCK_TOOL_ATTACK
/// Give people a little hint
/datum/component/interaction_booby_trap/proc/on_examine(atom/source, mob/examiner, list/examine_list)
SIGNAL_HANDLER
var/defuse_hint = (defuse_tool) ? "Perhaps [tool_behaviour_name(defuse_tool)] could help..." : ""
examine_list += span_warning("There's a light flashing red inside the maintenance panel. [defuse_hint]")
@@ -18,3 +18,11 @@
mid_sounds = list('sound/items/taperecorder/taperecorder_hiss_mid.ogg' = 1)
start_sound = list('sound/items/taperecorder/taperecorder_hiss_start.ogg' = 1)
volume = 10
/datum/looping_sound/trapped_machine_beep
mid_sounds = list('sound/machines/beep.ogg' = 1)
mid_length = 10 SECONDS
mid_length_vary = 5 SECONDS
falloff_exponent = 10
falloff_distance = 1
volume = 5
+5
View File
@@ -183,6 +183,7 @@
if(HAS_TRAIT(SSstation, STATION_TRAIT_BOTS_GLITCHED))
randomize_language_if_on_station()
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_MACHINE, src)
return INITIALIZE_HINT_LATELOAD
@@ -1200,3 +1201,7 @@
if(isliving(user))
last_used_time = world.time
last_user_mobtype = user.type
/// Called if this machine is supposed to be a sabotage machine objective.
/obj/machinery/proc/add_as_sabotage_target()
return
@@ -1,76 +0,0 @@
/datum/traitor_objective_category/destroy_machinery
name = "Destroy Protolathe"
objectives = list(
/datum/traitor_objective/destroy_machinery = 1,
/datum/traitor_objective/destroy_machinery/high_risk = 1
)
/datum/traitor_objective/destroy_machinery
name = "Destroy the %MACHINE%"
description = "Destroy the %MACHINE% to cause disarray and disrupt the operations of the %JOB%'s department."
progression_reward = list(2 MINUTES, 8 MINUTES)
telecrystal_reward = list(0, 1)
progression_minimum = 0 MINUTES
progression_maximum = 10 MINUTES
/// The maximum amount of this type of objective a traitor can have.
var/maximum_allowed = 2
/// The possible target machinery and the jobs tied to each one.
var/list/applicable_jobs = list(
JOB_RESEARCH_DIRECTOR = /obj/machinery/rnd/production/protolathe/department/science,
JOB_CHIEF_MEDICAL_OFFICER = /obj/machinery/rnd/production/techfab/department/medical,
JOB_CHIEF_ENGINEER = /obj/machinery/rnd/production/protolathe/department/engineering,
JOB_HEAD_OF_PERSONNEL = /obj/machinery/rnd/production/techfab/department/service,
JOB_SHAFT_MINER = /obj/machinery/mineral/ore_redemption,
JOB_QUARTERMASTER = /obj/machinery/rnd/production/techfab/department/cargo,
)
/// Whether this can bypass the maximum_allowed value or not
var/allow_more_than_max = FALSE
/// The chosen job. Used to check for duplicates
var/chosen_job
/datum/traitor_objective/destroy_machinery/high_risk
progression_reward = list(5 MINUTES, 10 MINUTES)
telecrystal_reward = list(3, 4)
progression_minimum = 15 MINUTES
progression_maximum = 30 MINUTES
allow_more_than_max = TRUE
applicable_jobs = list(
JOB_STATION_ENGINEER = /obj/machinery/telecomms/hub,
JOB_SCIENTIST = /obj/machinery/rnd/server,
)
/datum/traitor_objective/destroy_machinery/can_generate_objective(datum/mind/generating_for, list/possible_duplicates)
if(length(possible_duplicates) >= maximum_allowed && !allow_more_than_max)
return FALSE
return TRUE
/datum/traitor_objective/destroy_machinery/generate_objective(datum/mind/generating_for, list/possible_duplicates)
for(var/datum/traitor_objective/destroy_machinery/objective as anything in possible_duplicates)
applicable_jobs -= objective.chosen_job
if(!length(applicable_jobs))
return FALSE
var/list/obj/machinery/possible_machines = list()
while(length(possible_machines) <= 0 && length(applicable_jobs) > 0)
var/target_head = pick(applicable_jobs)
var/obj/machinery/machine_to_find = applicable_jobs[target_head]
applicable_jobs -= target_head
chosen_job = target_head
for(var/obj/machinery/machine as anything in GLOB.machines)
if(istype(machine, machine_to_find) && is_station_level(machine.z))
possible_machines += machine
if(!length(possible_machines))
return FALSE
for(var/obj/machinery/machine as anything in possible_machines)
AddComponent(/datum/component/traitor_objective_register, machine, succeed_signals = list(COMSIG_PARENT_QDELETING))
replace_in_name("%JOB%", lowertext(chosen_job))
replace_in_name("%MACHINE%", possible_machines[1].name)
return TRUE
@@ -0,0 +1,242 @@
/// Datum which manages references to things we are instructed to destroy
GLOBAL_DATUM_INIT(objective_machine_handler, /datum/objective_target_machine_handler, new())
/// Marks a machine as a possible traitor sabotage target
/proc/add_sabotage_machine(source, typepath)
LAZYADD(GLOB.objective_machine_handler.machine_instances_by_path[typepath], source)
return typepath
/// Traitor objective to destroy a machine the crew cares about
/datum/traitor_objective_category/sabotage_machinery
name = "Sabotage Worksite"
objectives = list(
/datum/traitor_objective/sabotage_machinery/trap = 1,
/datum/traitor_objective/sabotage_machinery/destroy = 1,
)
/datum/traitor_objective/sabotage_machinery
name = "Sabotage the %MACHINE%"
description = "Abstract objective holder which shouldn't appear in your uplink."
abstract_type = /datum/traitor_objective/sabotage_machinery
/// The maximum amount of this type of objective a traitor can have, set to 0 for no limit.
var/maximum_allowed = 0
/// The possible target machinery and the jobs tied to each one.
var/list/applicable_jobs = list()
/// The chosen job. Used to check for duplicates
var/chosen_job
/datum/traitor_objective/sabotage_machinery/can_generate_objective(datum/mind/generating_for, list/possible_duplicates)
if(!maximum_allowed)
return TRUE
if(length(possible_duplicates) >= maximum_allowed)
return FALSE
return TRUE
/datum/traitor_objective/sabotage_machinery/generate_objective(datum/mind/generating_for, list/possible_duplicates)
var/list/possible_jobs = applicable_jobs.Copy()
for(var/datum/traitor_objective/sabotage_machinery/objective as anything in possible_duplicates)
possible_jobs -= objective.chosen_job
for(var/available_job in possible_jobs)
var/job_machine_path = possible_jobs[available_job]
if (!length(GLOB.objective_machine_handler.machine_instances_by_path[job_machine_path]))
possible_jobs -= available_job
if(!length(possible_jobs))
return FALSE
chosen_job = pick(possible_jobs)
var/list/obj/machinery/possible_machines = GLOB.objective_machine_handler.machine_instances_by_path[possible_jobs[chosen_job]]
for(var/obj/machinery/machine as anything in possible_machines)
prepare_machine(machine)
replace_in_name("%JOB%", lowertext(chosen_job))
replace_in_name("%MACHINE%", possible_machines[1].name)
return TRUE
/// Marks a given machine as our target
/datum/traitor_objective/sabotage_machinery/proc/prepare_machine(obj/machinery/machine)
AddComponent(/datum/component/traitor_objective_register, machine, succeed_signals = list(COMSIG_PARENT_QDELETING))
// Destroy machines which are in annoying locations, are annoying when destroyed, and aren't directly interacted with
/datum/traitor_objective/sabotage_machinery/destroy
name = "Destroy the %MACHINE%"
description = "Destroy the %MACHINE% to cause disarray and disrupt the operations of the %JOB%'s department."
progression_reward = list(5 MINUTES, 10 MINUTES)
telecrystal_reward = list(3, 4)
progression_minimum = 15 MINUTES
progression_maximum = 30 MINUTES
applicable_jobs = list(
JOB_STATION_ENGINEER = /obj/machinery/telecomms/hub,
JOB_SCIENTIST = /obj/machinery/rnd/server,
)
// Rig machines which are in public locations to explode when interacted with
/datum/traitor_objective/sabotage_machinery/trap
name = "Sabotage the %MACHINE%"
description = "Destroy the %MACHINE% to cause disarray and disrupt the operations of the %JOB%'s department. If you can get another crew member to destroy the machine using the provided booby trap, you will be rewarded with an additional %PROGRESSION% reputation and %TC% telecrystals."
progression_reward = list(2 MINUTES, 4 MINUTES)
telecrystal_reward = 0 // Only from completing the bonus objective
progression_minimum = 0 MINUTES
progression_maximum = 10 MINUTES
maximum_allowed = 2
applicable_jobs = list(
JOB_CHIEF_ENGINEER = /obj/machinery/rnd/production/protolathe/department/engineering,
JOB_CHIEF_MEDICAL_OFFICER = /obj/machinery/rnd/production/techfab/department/medical,
JOB_HEAD_OF_PERSONNEL = /obj/machinery/rnd/production/techfab/department/service,
JOB_QUARTERMASTER = /obj/machinery/rnd/production/techfab/department/cargo,
JOB_RESEARCH_DIRECTOR = /obj/machinery/rnd/production/protolathe/department/science,
JOB_SHAFT_MINER = /obj/machinery/mineral/ore_redemption,
)
/// Bonus reward to grant if you booby trap successfully
var/bonus_tc = 2
/// Bonus progression to grant if you booby trap successfully
var/bonus_progression = 5 MINUTES
/// The trap device we give out
var/obj/item/traitor_machine_trapper/tool
/datum/traitor_objective/sabotage_machinery/trap/generate_objective(datum/mind/generating_for, list/possible_duplicates)
. = ..()
if (!.)
return FALSE
replace_in_name("%TC%", bonus_tc)
replace_in_name("%PROGRESSION%", DISPLAY_PROGRESSION(bonus_progression))
return TRUE
/datum/traitor_objective/sabotage_machinery/trap/prepare_machine(obj/machinery/machine)
RegisterSignal(machine, COMSIG_TRAITOR_MACHINE_TRAP_TRIGGERED, PROC_REF(sabotage_success))
return ..()
/// Called when you successfully proc the booby trap, gives a bonus reward
/datum/traitor_objective/sabotage_machinery/trap/proc/sabotage_success(obj/machinery/machine)
progression_reward += bonus_progression
telecrystal_reward += bonus_tc
succeed_objective()
/datum/traitor_objective/sabotage_machinery/trap/generate_ui_buttons(mob/user)
var/list/buttons = list()
if(!tool)
buttons += add_ui_button("", "Pressing this will materialize an explosive trap in your hand, which you can conceal within the target machine", "wifi", "summon_gear")
return buttons
/datum/traitor_objective/sabotage_machinery/trap/ui_perform_action(mob/living/user, action)
. = ..()
switch(action)
if("summon_gear")
if(tool)
return
tool = new(user.drop_location())
user.put_in_hands(tool)
tool.balloon_alert(user, "a booby trap materializes in your hand")
tool.target_machine_path = applicable_jobs[chosen_job]
/// Item which you use on a machine to cause it to explode next time someone interacts with it
/obj/item/traitor_machine_trapper
name = "suspicious device"
desc = "It looks dangerous."
icon = 'icons/obj/weapons/items_and_weapons.dmi'
icon_state = "boobytrap"
/// Light explosion range, to hurt the person using the machine
var/explosion_range = 3
/// The type of object on which this can be planted on.
var/obj/machinery/target_machine_path
/// The time it takes to deploy the bomb.
var/deploy_time = 10 SECONDS
/obj/item/traitor_machine_trapper/examine(mob/user)
. = ..()
if(!user.mind?.has_antag_datum(/datum/antagonist/traitor))
return
if(target_machine_path)
. += span_notice("This device must be placed by <b>clicking on a [initial(target_machine_path.name)]</b> with it. It can be removed with a screwdriver.")
. += span_notice("Remember, you may leave behind fingerprints on the device. Wear <b>gloves</b> when handling it to be safe!")
/obj/item/traitor_machine_trapper/afterattack(atom/movable/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!user.Adjacent(target))
return
if(!istype(target, target_machine_path))
balloon_alert(user, "invalid target!")
return
. |= AFTERATTACK_PROCESSED_ITEM
balloon_alert(user, "planting device...")
if(!do_after(user, delay = deploy_time, target = src, interaction_key = DOAFTER_SOURCE_PLANTING_DEVICE))
return
target.AddComponent(\
/datum/component/interaction_booby_trap,\
additional_triggers = list(COMSIG_ORM_COLLECTED_ORE),\
on_triggered_callback = CALLBACK(src, PROC_REF(on_triggered)),\
on_defused_callback = CALLBACK(src, PROC_REF(on_defused)),\
)
RegisterSignal(target, COMSIG_PARENT_QDELETING, GLOBAL_PROC_REF(qdel), src)
moveToNullspace()
/// Called when applied trap is triggered, mark success
/obj/item/traitor_machine_trapper/proc/on_triggered(atom/machine)
SEND_SIGNAL(machine, COMSIG_TRAITOR_MACHINE_TRAP_TRIGGERED)
qdel(src)
/// Called when applied trap has been defused, retrieve this item from nullspace
/obj/item/traitor_machine_trapper/proc/on_defused(atom/machine, mob/defuser, obj/item/tool)
UnregisterSignal(machine, COMSIG_PARENT_QDELETING)
playsound(machine, 'sound/effects/structure_stress/pop3.ogg', 100, vary = TRUE)
forceMove(get_turf(machine))
visible_message(span_warning("A [src] falls out from the [machine]!"))
/// Datum which manages references to things we are instructed to destroy
/datum/objective_target_machine_handler
/// Existing instances of machines organised by typepath
var/list/machine_instances_by_path = list()
/datum/objective_target_machine_handler/New()
. = ..()
RegisterSignal(SSdcs, COMSIG_GLOB_NEW_MACHINE, PROC_REF(on_machine_created))
RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(finalise_valid_targets))
/// Adds a newly created machine to our list of machines, if we need it
/datum/objective_target_machine_handler/proc/on_machine_created(datum/source, obj/machinery/new_machine)
SIGNAL_HANDLER
new_machine.add_as_sabotage_target()
/// Confirm that everything added to the list is a valid target, then prevent new targets from being added
/datum/objective_target_machine_handler/proc/finalise_valid_targets()
SIGNAL_HANDLER
for (var/machine_type in machine_instances_by_path)
for (var/obj/machinery/machine as anything in machine_instances_by_path[machine_type])
var/turf/place = get_turf(machine)
if(!place || !is_station_level(place.z))
machine_instances_by_path[machine_type] -= machine
continue
RegisterSignal(machine, COMSIG_PARENT_QDELETING, PROC_REF(machine_destroyed))
UnregisterSignal(SSdcs, COMSIG_GLOB_NEW_MACHINE)
/datum/objective_target_machine_handler/proc/machine_destroyed(atom/machine)
SIGNAL_HANDLER
// Sadly can't do a direct typepath association because of some map helper subtypes
for (var/machine_type in machine_instances_by_path)
machine_instances_by_path[machine_type] -= machine
// Mark valid machines as targets, add a new entry here if you add a new potential target
/obj/machinery/telecomms/hub/add_as_sabotage_target()
return add_sabotage_machine(src, /obj/machinery/telecomms/hub) // Not always our specific type because of map helper subtypes
/obj/machinery/rnd/server/add_as_sabotage_target()
return add_sabotage_machine(src, type)
/obj/machinery/rnd/production/protolathe/department/add_as_sabotage_target()
return add_sabotage_machine(src, type)
/obj/machinery/rnd/production/techfab/department/add_as_sabotage_target()
return add_sabotage_machine(src, type)
/obj/machinery/mineral/ore_redemption/add_as_sabotage_target()
return add_sabotage_machine(src, type)
+15 -13
View File
@@ -48,34 +48,36 @@
. += span_notice("Alt-click to rotate the input and output direction.")
/// Turns ore into its refined type, and sends it to its material container
/obj/machinery/mineral/ore_redemption/proc/smelt_ore(obj/item/stack/ore/O)
if(QDELETED(O))
/obj/machinery/mineral/ore_redemption/proc/smelt_ore(obj/item/stack/ore/gathered_ore)
if(QDELETED(gathered_ore))
return
var/datum/component/material_container/mat_container = materials.mat_container
if (!mat_container)
return
if(O.refined_type == null)
if(gathered_ore.refined_type == null)
return
if(O?.refined_type)
points += O.points * point_upgrade * O.amount
if(gathered_ore?.refined_type)
points += gathered_ore.points * point_upgrade * gathered_ore.amount
var/material_amount = mat_container.get_item_material_amount(O, BREAKDOWN_FLAGS_ORM)
var/material_amount = mat_container.get_item_material_amount(gathered_ore, BREAKDOWN_FLAGS_ORM)
if(!material_amount)
qdel(O) //no materials, incinerate it
qdel(gathered_ore) //no materials, incinerate it
else if(!mat_container.has_space(material_amount * O.amount)) //if there is no space, eject it
unload_mineral(O)
else if(!mat_container.has_space(material_amount * gathered_ore.amount)) //if there is no space, eject it
unload_mineral(gathered_ore)
else
var/list/stack_mats = O.get_material_composition(BREAKDOWN_FLAGS_ORM)
var/list/stack_mats = gathered_ore.get_material_composition(BREAKDOWN_FLAGS_ORM)
var/mats = stack_mats & mat_container.materials
var/amount = O.amount
mat_container.insert_item(O, ore_multiplier, breakdown_flags=BREAKDOWN_FLAGS_ORM) //insert it
var/amount = gathered_ore.amount
mat_container.insert_item(gathered_ore, ore_multiplier, breakdown_flags=BREAKDOWN_FLAGS_ORM) //insert it
materials.silo_log(src, "smelted", amount, "someone", mats)
qdel(O)
qdel(gathered_ore)
SEND_SIGNAL(src, COMSIG_ORM_COLLECTED_ORE)
/// Returns the amount of a specific alloy design, based on the accessible materials
/obj/machinery/mineral/ore_redemption/proc/can_smelt_alloy(datum/design/D)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 92 KiB

+2 -1
View File
@@ -976,6 +976,7 @@
#include "code\datums\components\holderloving.dm"
#include "code\datums\components\igniter.dm"
#include "code\datums\components\infective.dm"
#include "code\datums\components\interaction_booby_trap.dm"
#include "code\datums\components\irradiated.dm"
#include "code\datums\components\itembound.dm"
#include "code\datums\components\itempicky.dm"
@@ -2686,12 +2687,12 @@
#include "code\modules\antagonists\traitor\objectives\demoralise_poster.dm"
#include "code\modules\antagonists\traitor\objectives\destroy_heirloom.dm"
#include "code\modules\antagonists\traitor\objectives\destroy_item.dm"
#include "code\modules\antagonists\traitor\objectives\destroy_machinery.dm"
#include "code\modules\antagonists\traitor\objectives\eyesnatching.dm"
#include "code\modules\antagonists\traitor\objectives\hack_comm_console.dm"
#include "code\modules\antagonists\traitor\objectives\kidnapping.dm"
#include "code\modules\antagonists\traitor\objectives\kill_pet.dm"
#include "code\modules\antagonists\traitor\objectives\locate_weakpoint.dm"
#include "code\modules\antagonists\traitor\objectives\sabotage_machinery.dm"
#include "code\modules\antagonists\traitor\objectives\sleeper_protocol.dm"
#include "code\modules\antagonists\traitor\objectives\steal.dm"
#include "code\modules\antagonists\traitor\objectives\final_objective\battlecruiser.dm"