From ca09aeaeefdf51ef83b2eb63786eaae86b651d1f Mon Sep 17 00:00:00 2001 From: skull132 Date: Wed, 28 Jun 2017 23:15:50 +0300 Subject: [PATCH] Remove Global Iterators (#2842) Removes the global iterators, which mechs use heavily, and replaces it with standard process() calls from SSfast_process and SSprocessing. --- baystation12.dme | 1 - code/datums/helper_datums/global_iterator.dm | 159 -- code/game/mecha/combat/marauder.dm | 6 +- .../mecha/equipment/tools/medical_tools.dm | 1119 +++++++------ code/game/mecha/equipment/tools/tools.dm | 1465 ++++++++--------- code/game/mecha/mecha.dm | 796 ++++----- code/modules/cargo/randomstock.dm | 24 +- 7 files changed, 1601 insertions(+), 1969 deletions(-) delete mode 100644 code/datums/helper_datums/global_iterator.dm diff --git a/baystation12.dme b/baystation12.dme index c7452e26f4c..164d4cf7a97 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -263,7 +263,6 @@ #include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\events.dm" #include "code\datums\helper_datums\getrev.dm" -#include "code\datums\helper_datums\global_iterator.dm" #include "code\datums\helper_datums\teleport.dm" #include "code\datums\helper_datums\topic_input.dm" #include "code\datums\observation\_debug.dm" diff --git a/code/datums/helper_datums/global_iterator.dm b/code/datums/helper_datums/global_iterator.dm deleted file mode 100644 index d025a6171b1..00000000000 --- a/code/datums/helper_datums/global_iterator.dm +++ /dev/null @@ -1,159 +0,0 @@ -/* -README: - -The global_iterator datum is supposed to provide a simple and robust way to -create some constantly "looping" processes with ability to stop and restart them at will. -Generally, the only thing you want to play with (meaning, redefine) is the process() proc. -It must contain all the things you want done. - -Control functions: - new - used to create datum. First argument (optional) - var list(to use in process() proc) as list, - second (optional) - autostart control. - If autostart == TRUE, the loop will be started immediately after datum creation. - - start(list/arguments) - starts the loop. Takes arguments(optional) as a list, which is then used - by process() proc. Returns null if datum already active, 1 if loop started succesfully and 0 if there's - an error in supplied arguments (not list or empty list). - - stop() - stops the loop. Returns null if datum is already inactive and 1 on success. - - set_delay(new_delay) - sets the delay between iterations. Pretty selfexplanatory. - Returns 0 on error(new_delay is not numerical), 1 otherwise. - - set_process_args(list/arguments) - passes the supplied arguments to the process() proc. - - active() - Returns 1 if datum is active, 0 otherwise. - - toggle() - toggles datum state. Returns new datum state (see active()). - -Misc functions: - - get_last_exec_time() - Returns the time of last iteration. - - get_last_exec_time_as_text() - Returns the time of last iteration as text - - -Control vars: - - delay - delay between iterations - - check_for_null - if equals TRUE, on each iteration the supplied arguments will be checked for nulls. - If some varible equals null (and null only), the loop is stopped. - Usefull, if some var unexpectedly becomes null - due to object deletion, for example. - Of course, you can also check the variables inside process() proc to prevent runtime errors. - -Data storage vars: - - result - stores the value returned by process() proc -*/ - -/datum/global_iterator - var/control_switch = 0 - var/delay = 10 - var/list/arg_list = new - var/last_exec = null - var/check_for_null = 1 - var/forbid_garbage = 0 - var/result - var/state = 0 - - New(list/arguments=null,autostart=1) - delay = delay>0?(delay):1 - if(forbid_garbage) //prevents garbage collection with tag != null - tag = "\ref[src]" - set_process_args(arguments) - if(autostart) - start() - return - - proc/main() - state = 1 - while(src && control_switch) - last_exec = world.timeofday - if(check_for_null && has_null_args()) - stop() - return 0 - result = process(arglist(arg_list)) - for(var/sleep_time=delay;sleep_time>0;sleep_time--) //uhh, this is ugly. But I see no other way to terminate sleeping proc. Such disgrace. - if(!control_switch) - return 0 - sleep(1) - return 0 - - proc/start(list/arguments=null) - if(active()) - return - if(arguments) - if(!set_process_args(arguments)) - return 0 - if(!state_check()) //the main loop is sleeping, wait for it to terminate. - return - control_switch = 1 - spawn() - state = main() - return 1 - - proc/stop() - if(!active()) - return - control_switch = 0 - spawn(-1) //report termination error but don't wait for state_check(). - state_check() - return 1 - - proc/state_check() - var/lag = 0 - while(state) - sleep(1) - if(++lag>10) - CRASH("The global_iterator loop \ref[src] failed to terminate in designated timeframe. This may be caused by server lagging.") - return 1 - - process() - return - - proc/active() - return control_switch - - proc/has_null_args() - if(null in arg_list) - return 1 - return 0 - - - proc/set_delay(new_delay) - if(isnum(new_delay)) - delay = max(1, round(new_delay)) - return 1 - else - return 0 - - proc/get_last_exec_time() - return (last_exec||0) - - proc/get_last_exec_time_as_text() - return (time2text(last_exec)||"Wasn't executed yet") - - proc/set_process_args(list/arguments) - if(arguments && istype(arguments, /list) && arguments.len) - arg_list = arguments - return 1 - else -// world << "Invalid arguments supplied for [src.type], ref = \ref[src]" - return 0 - - proc/toggle_null_checks() - check_for_null = !check_for_null - return check_for_null - - proc/toggle() - if(!stop()) - start() - return active() - -/datum/global_iterator/Destroy() - tag = null - arg_list.Cut() - stop() - return QDEL_HINT_HARDDEL - //Do not call ..() diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm index 7f4693f2e66..c71f1cfcd3f 100644 --- a/code/game/mecha/combat/marauder.dm +++ b/code/game/mecha/combat/marauder.dm @@ -99,7 +99,7 @@ src.occupant_message("Unable to move while connected to the air system port") last_message = world.time return 0 - if(!thrusters && src.pr_inertial_movement.active()) + if(!thrusters && (current_processes & MECHA_PROC_MOVEMENT)) return 0 if(state || !has_charge(step_energy_drain)) return 0 @@ -115,9 +115,9 @@ if(move_result) if(istype(src.loc, /turf/space)) if(!src.check_for_support()) - src.pr_inertial_movement.start(list(src,direction)) + start_process(MECHA_PROC_MOVEMENT) + float_direction = direction if(thrusters) - src.pr_inertial_movement.set_process_args(list(src,direction)) tmp_step_energy_drain = step_energy_drain*2 can_move = 0 diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm index 98a49af28a3..26e855bd86b 100644 --- a/code/game/mecha/equipment/tools/medical_tools.dm +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -13,220 +13,202 @@ required_type = /obj/mecha/medical salvageable = 0 - New() - ..() - pr_mech_sleeper = new /datum/global_iterator/mech_sleeper(list(src),0) - pr_mech_sleeper.set_delay(equip_cooldown) +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Destroy() + for(var/A in src) + var/atom/movable/AM = A + AM.forceMove(get_turf(src)) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Exit(atom/movable/O) + return 0 + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/action(var/mob/living/carbon/target) + if(!action_checks(target)) return + if(!istype(target)) + return + if(target.buckled) + occupant_message("[target] will not fit into the sleeper because they are buckled to [target.buckled].") + return + if(occupant) + occupant_message("The sleeper is already occupied") + return + for(var/mob/living/carbon/slime/M in range(1,target)) + if(M.Victim == target) + occupant_message("[target] will not fit into the sleeper because they have a slime latched onto their head.") + return + occupant_message("You start putting [target] into [src].") + chassis.visible_message("[chassis] starts putting [target] into [src].") + var/C = chassis.loc + var/T = target.loc + if(do_after_cooldown(target)) + if(chassis.loc!=C || target.loc!=T) + return + if(occupant) + occupant_message("The sleeper is already occupied!") + return + target.forceMove(src) + occupant = target + target.reset_view(src) - Destroy() - qdel(pr_mech_sleeper) - for(var/atom/movable/AM in src) - AM.forceMove(get_turf(src)) - return ..() + set_ready_state(0) + START_PROCESSING(SSprocessing, src) + occupant_message("[target] successfully loaded into [src]. Life support functions engaged.") + chassis.visible_message("[chassis] loads [target] into [src].") + log_message("[target] loaded. Life support functions engaged.") + return - Exit(atom/movable/O) +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/go_out() + if(!occupant) + return + occupant.forceMove(get_turf(src)) + occupant_message("[occupant] ejected. Life support functions disabled.") + log_message("[occupant] ejected. Life support functions disabled.") + occupant.reset_view() + + occupant = null + STOP_PROCESSING(SSprocessing, src) + set_ready_state(1) + return + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/detach() + if(occupant) + occupant_message("Unable to detach [src] - equipment occupied.") + return + STOP_PROCESSING(SSprocessing, src) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/get_equip_info() + var/output = ..() + if(output) + var/temp = "" + if(occupant) + temp = "
\[Occupant: [occupant] (Health: [occupant.health]%)\]
View stats|Eject" + return "[output] [temp]" + return + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Topic(href,href_list) + ..() + var/datum/topic_input/filter = new /datum/topic_input(href,href_list) + if(filter.get("eject")) + go_out() + if(filter.get("view_stats")) + chassis.occupant << browse(get_occupant_stats(),"window=msleeper") + onclose(chassis.occupant, "msleeper") + return + if(filter.get("inject")) + inject_reagent(filter.getType("inject",/datum/reagent),filter.getObj("source")) + return + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_stats() + if(!occupant) + return + return {" + + [occupant] statistics + + + + +

Health statistics

+
+ [get_occupant_dam()] +
+

Reagents in bloodstream

+
+ [get_occupant_reagents()] +
+
+ [get_available_reagents()] +
+ + "} + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_dam() + var/t1 + switch(occupant.stat) + if(0) + t1 = "Conscious" + if(1) + t1 = "Unconscious" + if(2) + t1 = "*dead*" + else + t1 = "Unknown" + return {"Health: [occupant.health]% ([t1])
+ Core Temperature: [src.occupant.bodytemperature-T0C]°C ([src.occupant.bodytemperature*1.8-459.67]°F)
+ Brute Damage: [occupant.getBruteLoss()]%
+ Respiratory Damage: [occupant.getOxyLoss()]%
+ Toxin Content: [occupant.getToxLoss()]%
+ Burn Severity: [occupant.getFireLoss()]%
+ "} + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_reagents() + if(occupant.reagents) + for(var/datum/reagent/R in occupant.reagents.reagent_list) + if(R.volume > 0) + . += "[R]: [round(R.volume,0.01)]
" + return . || "None" + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_available_reagents() + var/output + var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun) in chassis + if(SG && SG.reagents && islist(SG.reagents.reagent_list)) + for(var/datum/reagent/R in SG.reagents.reagent_list) + if(R.volume > 0) + output += "Inject [R.name]
" + return output + + +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/inject_reagent(var/datum/reagent/R,var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG) + if(!R || !occupant || !SG || !(SG in chassis.equipment)) return 0 + var/to_inject = min(R.volume, inject_amount) + if(to_inject && occupant.reagents.get_reagent_amount(R.id) + to_inject <= inject_amount*2) + occupant_message("Injecting [occupant] with [to_inject] units of [R.name].") + log_message("Injecting [occupant] with [to_inject] units of [R.name].") + SG.reagents.trans_id_to(occupant,R.id,to_inject) + update_equip_info() + return - action(var/mob/living/carbon/target) - if(!action_checks(target)) - return - if(!istype(target)) - return - if(target.buckled) - occupant_message("[target] will not fit into the sleeper because they are buckled to [target.buckled].") - return - if(occupant) - occupant_message("The sleeper is already occupied") - return - for(var/mob/living/carbon/slime/M in range(1,target)) - if(M.Victim == target) - occupant_message("[target] will not fit into the sleeper because they have a slime latched onto their head.") - return - occupant_message("You start putting [target] into [src].") - chassis.visible_message("[chassis] starts putting [target] into the [src].") - var/C = chassis.loc - var/T = target.loc - if(do_after_cooldown(target)) - if(chassis.loc!=C || target.loc!=T) - return - if(occupant) - occupant_message("The sleeper is already occupied!") - return - target.forceMove(src) - occupant = target - target.reset_view(src) - /* - if(target.client) - target.client.perspective = EYE_PERSPECTIVE - target.client.eye = chassis - */ - set_ready_state(0) - pr_mech_sleeper.start() - occupant_message("[target] successfully loaded into [src]. Life support functions engaged.") - chassis.visible_message("[chassis] loads [target] into [src].") - log_message("[target] loaded. Life support functions engaged.") - return +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/update_equip_info() + if(..()) + send_byjax(chassis.occupant,"msleeper.browser","lossinfo",get_occupant_dam()) + send_byjax(chassis.occupant,"msleeper.browser","reagents",get_occupant_reagents()) + send_byjax(chassis.occupant,"msleeper.browser","injectwith",get_available_reagents()) + return 1 + return - proc/go_out() - if(!occupant) - return - occupant.forceMove(get_turf(src)) - occupant_message("[occupant] ejected. Life support functions disabled.") - log_message("[occupant] ejected. Life support functions disabled.") - occupant.reset_view() - /* - if(occupant.client) - occupant.client.eye = occupant.client.mob - occupant.client.perspective = MOB_PERSPECTIVE - */ - occupant = null - pr_mech_sleeper.stop() +/obj/item/mecha_parts/mecha_equipment/tool/sleeper/process() + if(!chassis) set_ready_state(1) + return PROCESS_KILL + if(!chassis.has_charge(energy_drain)) + set_ready_state(1) + log_message("Deactivated.") + occupant_message("[src] deactivated - no power.") + return PROCESS_KILL + var/mob/living/carbon/M = occupant + if(!M) return - - detach() - if(occupant) - occupant_message("Unable to detach [src] - equipment occupied.") - return - pr_mech_sleeper.stop() - return ..() - - get_equip_info() - var/output = ..() - if(output) - var/temp = "" - if(occupant) - temp = "
\[Occupant: [occupant] (Health: [occupant.health]%)\]
View stats|Eject" - return "[output] [temp]" - return - - Topic(href,href_list) - ..() - var/datum/topic_input/filter = new /datum/topic_input(href,href_list) - if(filter.get("eject")) - go_out() - if(filter.get("view_stats")) - chassis.occupant << browse(get_occupant_stats(),"window=msleeper") - onclose(chassis.occupant, "msleeper") - return - if(filter.get("inject")) - inject_reagent(filter.getType("inject",/datum/reagent),filter.getObj("source")) - return - - proc/get_occupant_stats() - if(!occupant) - return - return {" - - [occupant] statistics - - - - -

Health statistics

-
- [get_occupant_dam()] -
-

Reagents in bloodstream

-
- [get_occupant_reagents()] -
-
- [get_available_reagents()] -
- - "} - - proc/get_occupant_dam() - var/t1 - switch(occupant.stat) - if(0) - t1 = "Conscious" - if(1) - t1 = "Unconscious" - if(2) - t1 = "*dead*" - else - t1 = "Unknown" - return {"Health: [occupant.health]% ([t1])
- Core Temperature: [src.occupant.bodytemperature-T0C]°C ([src.occupant.bodytemperature*1.8-459.67]°F)
- Brute Damage: [occupant.getBruteLoss()]%
- Respiratory Damage: [occupant.getOxyLoss()]%
- Toxin Content: [occupant.getToxLoss()]%
- Burn Severity: [occupant.getFireLoss()]%
- "} - - proc/get_occupant_reagents() - if(occupant.reagents) - for(var/datum/reagent/R in occupant.reagents.reagent_list) - if(R.volume > 0) - . += "[R]: [round(R.volume,0.01)]
" - return . || "None" - - proc/get_available_reagents() - var/output - var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun) in chassis - if(SG && SG.reagents && islist(SG.reagents.reagent_list)) - for(var/datum/reagent/R in SG.reagents.reagent_list) - if(R.volume > 0) - output += "Inject [R.name]
" - return output - - - proc/inject_reagent(var/datum/reagent/R,var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG) - if(!R || !occupant || !SG || !(SG in chassis.equipment)) - return 0 - var/to_inject = min(R.volume, inject_amount) - if(to_inject && occupant.reagents.get_reagent_amount(R.id) + to_inject <= inject_amount*2) - occupant_message("Injecting [occupant] with [to_inject] units of [R.name].") - log_message("Injecting [occupant] with [to_inject] units of [R.name].") - SG.reagents.trans_id_to(occupant,R.id,to_inject) - update_equip_info() - return - + if(M.health > 0) + M.adjustOxyLoss(-1) + M.updatehealth() + M.AdjustStunned(-4) + M.AdjustWeakened(-4) + M.AdjustStunned(-4) + M.Paralyse(2) + M.Weaken(2) + M.Stun(2) + if(M.reagents.get_reagent_amount("inaprovaline") < 5) + M.reagents.add_reagent("inaprovaline", 5) + chassis.use_power(energy_drain) update_equip_info() - if(..()) - send_byjax(chassis.occupant,"msleeper.browser","lossinfo",get_occupant_dam()) - send_byjax(chassis.occupant,"msleeper.browser","reagents",get_occupant_reagents()) - send_byjax(chassis.occupant,"msleeper.browser","injectwith",get_available_reagents()) - return 1 - return - -/datum/global_iterator/mech_sleeper - - process(var/obj/item/mecha_parts/mecha_equipment/tool/sleeper/S) - if(!S.chassis) - S.set_ready_state(1) - return stop() - if(!S.chassis.has_charge(S.energy_drain)) - S.set_ready_state(1) - S.log_message("Deactivated.") - S.occupant_message("[src] deactivated - no power.") - return stop() - var/mob/living/carbon/M = S.occupant - if(!M) - return - if(M.health > 0) - M.adjustOxyLoss(-1) - M.updatehealth() - M.AdjustStunned(-4) - M.AdjustWeakened(-4) - M.AdjustStunned(-4) - M.Paralyse(2) - M.Weaken(2) - M.Stun(2) - if(M.reagents.get_reagent_amount("inaprovaline") < 5) - M.reagents.add_reagent("inaprovaline", 5) - S.chassis.use_power(S.energy_drain) - S.update_equip_info() - return - /obj/item/mecha_parts/mecha_equipment/tool/cable_layer name = "Cable Layer" @@ -238,133 +220,133 @@ var/max_cable = 1000 required_type = /obj/mecha/working - New() - cable = new(src) - cable.amount = 0 - ..() +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/New() + cable = new(src) + cable.amount = 0 + ..() - attach() - ..() - event = chassis.events.addEvent("onMove",src,"layCable") +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/attach() + ..() + event = chassis.events.addEvent("onMove",src,"layCable") + return + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/detach() + chassis.events.clearEvent("onMove",event) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/destroy() + chassis.events.clearEvent("onMove",event) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/action(var/obj/item/stack/cable_coil/target) + if(!action_checks(target)) return + var/result = load_cable(target) + var/message + if(isnull(result)) + message = "Unable to load [target] - no cable found." + else if(!result) + message = "Reel is full." + else + message = "[result] meters of cable successfully loaded." + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + occupant_message(message) + return - detach() - chassis.events.clearEvent("onMove",event) - return ..() - - destroy() - chassis.events.clearEvent("onMove",event) - return ..() - - action(var/obj/item/stack/cable_coil/target) - if(!action_checks(target)) - return - var/result = load_cable(target) - var/message - if(isnull(result)) - message = "Unable to load [target] - no cable found." - else if(!result) - message = "Reel is full." +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/Topic(href,href_list) + ..() + if(href_list["toggle"]) + set_ready_state(!equip_ready) + occupant_message("[src] [equip_ready?"dea":"a"]ctivated.") + log_message("[equip_ready?"Dea":"A"]ctivated.") + return + if(href_list["cut"]) + if(cable && cable.amount) + var/m = round(input(chassis.occupant,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1) + m = min(m, cable.amount) + if(m) + use_cable(m) + var/obj/item/stack/cable_coil/CC = new (get_turf(chassis)) + CC.amount = m else - message = "[result] meters of cable successfully loaded." - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - occupant_message(message) + occupant_message("There's no more cable on the reel.") + return + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/get_equip_info() + var/output = ..() + if(output) + return "[output] \[Cable: [cable ? cable.amount : 0] m\][(cable && cable.amount) ? "- [!equip_ready?"Dea":"A"]ctivate|Cut" : null]" + return + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/load_cable(var/obj/item/stack/cable_coil/CC) + if(istype(CC) && CC.amount) + var/cur_amount = cable? cable.amount : 0 + var/to_load = max(max_cable - cur_amount,0) + if(to_load) + to_load = min(CC.amount, to_load) + if(!cable) + cable = new(src) + cable.amount = 0 + cable.amount += to_load + CC.use(to_load) + return to_load + else + return 0 + return + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/use_cable(amount) + if(!cable || cable.amount<1) + set_ready_state(1) + occupant_message("Cable depleted, [src] deactivated.") + log_message("Cable depleted, [src] deactivated.") return - - Topic(href,href_list) - ..() - if(href_list["toggle"]) - set_ready_state(!equip_ready) - occupant_message("[src] [equip_ready?"dea":"a"]ctivated.") - log_message("[equip_ready?"Dea":"A"]ctivated.") - return - if(href_list["cut"]) - if(cable && cable.amount) - var/m = round(input(chassis.occupant,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1) - m = min(m, cable.amount) - if(m) - use_cable(m) - var/obj/item/stack/cable_coil/CC = new (get_turf(chassis)) - CC.amount = m - else - occupant_message("There's no more cable on the reel.") + if(cable.amount < amount) + occupant_message("No enough cable to finish the task.") return + cable.use(amount) + update_equip_info() + return 1 - get_equip_info() - var/output = ..() - if(output) - return "[output] \[Cable: [cable ? cable.amount : 0] m\][(cable && cable.amount) ? "- [!equip_ready?"Dea":"A"]ctivate|Cut" : null]" - return +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/reset() + last_piece = null - proc/load_cable(var/obj/item/stack/cable_coil/CC) - if(istype(CC) && CC.amount) - var/cur_amount = cable? cable.amount : 0 - var/to_load = max(max_cable - cur_amount,0) - if(to_load) - to_load = min(CC.amount, to_load) - if(!cable) - cable = new(src) - cable.amount = 0 - cable.amount += to_load - CC.use(to_load) - return to_load - else - return 0 - return +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/dismantleFloor(var/turf/new_turf) + if(istype(new_turf, /turf/simulated/floor)) + var/turf/simulated/floor/T = new_turf + if(!T.is_plating()) + T.make_plating(!(T.broken || T.burnt)) + return new_turf.is_plating() - proc/use_cable(amount) - if(!cable || cable.amount<1) - set_ready_state(1) - occupant_message("Cable depleted, [src] deactivated.") - log_message("Cable depleted, [src] deactivated.") - return - if(cable.amount < amount) - occupant_message("No enough cable to finish the task.") - return - cable.use(amount) - update_equip_info() - return 1 - - proc/reset() - last_piece = null - - proc/dismantleFloor(var/turf/new_turf) - if(istype(new_turf, /turf/simulated/floor)) - var/turf/simulated/floor/T = new_turf - if(!T.is_plating()) - T.make_plating(!(T.broken || T.burnt)) - return new_turf.is_plating() - - proc/layCable(var/turf/new_turf) - if(equip_ready || !istype(new_turf) || !dismantleFloor(new_turf)) +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/layCable(var/turf/new_turf) + if(equip_ready || !istype(new_turf) || !dismantleFloor(new_turf)) + return reset() + var/fdirn = turn(chassis.dir,180) + for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already + if(LC.d1 == fdirn || LC.d2 == fdirn) return reset() - var/fdirn = turn(chassis.dir,180) - for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already - if(LC.d1 == fdirn || LC.d2 == fdirn) - return reset() - if(!use_cable(1)) - return reset() - var/obj/structure/cable/NC = new(new_turf) - NC.cableColor("red") - NC.d1 = 0 - NC.d2 = fdirn - NC.updateicon() + if(!use_cable(1)) + return reset() + var/obj/structure/cable/NC = new(new_turf) + NC.cableColor("red") + NC.d1 = 0 + NC.d2 = fdirn + NC.updateicon() - var/datum/powernet/PN - if(last_piece && last_piece.d2 != chassis.dir) - last_piece.d1 = min(last_piece.d2, chassis.dir) - last_piece.d2 = max(last_piece.d2, chassis.dir) - last_piece.updateicon() - PN = last_piece.powernet + var/datum/powernet/PN + if(last_piece && last_piece.d2 != chassis.dir) + last_piece.d1 = min(last_piece.d2, chassis.dir) + last_piece.d2 = max(last_piece.d2, chassis.dir) + last_piece.updateicon() + PN = last_piece.powernet - if(!PN) - PN = new() - PN.add_cable(NC) - NC.mergeConnectedNetworks(NC.d2) + if(!PN) + PN = new() + PN.add_cable(NC) + NC.mergeConnectedNetworks(NC.d2) - //NC.mergeConnectedNetworksOnTurf() - last_piece = NC - return 1 + //NC.mergeConnectedNetworksOnTurf() + last_piece = NC + return 1 /obj/item/mecha_parts/mecha_equipment/tool/syringe_gun name = "syringe gun" @@ -379,265 +361,274 @@ var/synth_speed = 5 //[num] reagent units per cycle energy_drain = 10 var/mode = 0 //0 - fire syringe, 1 - analyze reagents. - var/datum/global_iterator/mech_synth/synth + range = MELEE|RANGED equip_cooldown = 10 origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4, TECH_MAGNET = 4, TECH_DATA = 3) required_type = /obj/mecha/medical - New() - ..() - flags |= NOREACT - syringes = new - known_reagents = list("inaprovaline"="Inaprovaline","anti_toxin"="Dylovene") - processed_reagents = new - create_reagents(max_volume) - synth = new (list(src),0) + var/last_tick = 0 - detach() - synth.stop() - return ..() +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/New() + ..() + flags |= NOREACT + syringes = new + known_reagents = list("inaprovaline"="Inaprovaline","anti_toxin"="Dylovene") + processed_reagents = new + create_reagents(max_volume) - critfail() - ..() - flags &= ~NOREACT +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/Destroy() + STOP_PROCESSING(SSfast_process, src) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/detach() + STOP_PROCESSING(SSfast_process, src) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/critfail() + ..() + flags &= ~NOREACT + return + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/get_equip_info() + var/output = ..() + if(output) + return "[output] \[[mode? "Analyze" : "Launch"]\]
\[Syringes: [syringes.len]/[max_syringes] | Reagents: [reagents.total_volume]/[reagents.maximum_volume]\]
Reagents list" + return + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/action(atom/movable/target) + if(!action_checks(target)) return - - get_equip_info() - var/output = ..() - if(output) - return "[output] \[[mode? "Analyze" : "Launch"]\]
\[Syringes: [syringes.len]/[max_syringes] | Reagents: [reagents.total_volume]/[reagents.maximum_volume]\]
Reagents list" + if(istype(target,/obj/item/weapon/reagent_containers/syringe)) + return load_syringe(target) + if(istype(target,/obj/item/weapon/storage))//Loads syringes from boxes + for(var/obj/item/weapon/reagent_containers/syringe/S in target.contents) + load_syringe(S) return - - action(atom/movable/target) - if(!action_checks(target)) - return - if(istype(target,/obj/item/weapon/reagent_containers/syringe)) - return load_syringe(target) - if(istype(target,/obj/item/weapon/storage))//Loads syringes from boxes - for(var/obj/item/weapon/reagent_containers/syringe/S in target.contents) - load_syringe(S) - return - if(mode) - return analyze_reagents(target) - if(!syringes.len) - occupant_message("No syringes loaded.") - return - if(reagents.total_volume<=0) - occupant_message("No available reagents to load syringe with.") - return - set_ready_state(0) - chassis.use_power(energy_drain) - var/turf/trg = get_turf(target) - var/obj/item/weapon/reagent_containers/syringe/S = syringes[1] - S.forceMove(get_turf(chassis)) - reagents.trans_to_obj(S, min(S.volume, reagents.total_volume)) - syringes -= S - S.icon = 'icons/obj/chemical.dmi' - S.icon_state = "syringeproj" - playsound(chassis, 'sound/items/syringeproj.ogg', 50, 1) - log_message("Launched [S] from [src], targeting [target].") - spawn(-1) - src = null //if src is deleted, still process the syringe - for(var/i=0, i<6, i++) - if(!S) - break - if(step_towards(S,trg)) - var/list/mobs = new - for(var/mob/living/carbon/M in S.loc) - mobs += M - var/mob/living/carbon/M = safepick(mobs) - if(M) - S.icon_state = initial(S.icon_state) - S.icon = initial(S.icon) - S.reagents.trans_to_mob(M, S.reagents.total_volume, CHEM_BLOOD) - M.take_organ_damage(2) - S.visible_message(" [M] was hit by the syringe!") - break - else if(S.loc == trg) - S.icon_state = initial(S.icon_state) - S.icon = initial(S.icon) - S.update_icon() - break - else - S.icon_state = initial(S.icon_state) - S.icon = initial(S.icon) - S.update_icon() - break - sleep(1) - do_after_cooldown() - return 1 - - - Topic(href,href_list) - ..() - var/datum/topic_input/filter = new (href,href_list) - if(filter.get("toggle_mode")) - mode = !mode - update_equip_info() - return - if(filter.get("select_reagents")) - processed_reagents.len = 0 - var/m = 0 - var/message - for(var/i=1 to known_reagents.len) - if(m>=synth_speed) - break - var/reagent = filter.get("reagent_[i]") - if(reagent && (reagent in known_reagents)) - message = "[m ? ", " : null][known_reagents[reagent]]" - processed_reagents += reagent - m++ - if(processed_reagents.len) - message += " added to production" - synth.start() - occupant_message(message) - occupant_message("Reagent processing started.") - log_message("Reagent processing started.") - return - if(filter.get("show_reagents")) - chassis.occupant << browse(get_reagents_page(),"window=msyringegun") - if(filter.get("purge_reagent")) - var/reagent = filter.get("purge_reagent") - if(reagent) - reagents.del_reagent(reagent) - return - if(filter.get("purge_all")) - reagents.clear_reagents() - return + if(mode) + return analyze_reagents(target) + if(!syringes.len) + occupant_message("No syringes loaded.") return - - proc/get_reagents_page() - var/output = {" - - Reagent Synthesizer - - - - -

Current reagents:

-
- [get_current_reagents()] -
-

Reagents production:

-
- [get_reagents_form()] -
- - - "} - return output - - proc/get_reagents_form() - var/r_list = get_reagents_list() - var/inputs - if(r_list) - inputs += "" - inputs += "" - inputs += "" - var/output = {"
- [r_list || "No known reagents"] - [inputs] -
- [r_list? "Only the first [synth_speed] selected reagent\s will be added to production" : null] - "} - return output - - proc/get_reagents_list() - var/output - for(var/i=1 to known_reagents.len) - var/reagent_id = known_reagents[i] - output += {" [known_reagents[reagent_id]]
"} - return output - - proc/get_current_reagents() - var/output - for(var/datum/reagent/R in reagents.reagent_list) - if(R.volume > 0) - output += "[R]: [round(R.volume,0.001)] - Purge Reagent
" - if(output) - output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - Purge All" - return output || "None" - - proc/load_syringe(obj/item/weapon/reagent_containers/syringe/S) - if(syringes.len= 2) - occupant_message("The syringe is too far away.") - return 0 - for(var/obj/structure/D in S.loc)//Basic level check for structures in the way (Like grilles and windows) - if(!(D.CanPass(S,src.loc))) - occupant_message("Unable to load syringe.") - return 0 - for(var/obj/machinery/door/D in S.loc)//Checks for doors - if(!(D.CanPass(S,src.loc))) - occupant_message("Unable to load syringe.") - return 0 - S.reagents.trans_to_obj(src, S.reagents.total_volume) - S.forceMove(src) - syringes += S - occupant_message("Syringe loaded.") - update_equip_info() - return 1 - occupant_message("The [src] syringe chamber is full.") - return 0 - - proc/analyze_reagents(atom/A) - if(get_dist(src,A) >= 4) - occupant_message("The object is too far away.") - return 0 - if(!A.reagents || istype(A,/mob)) - occupant_message("No reagent info gained from [A].") - return 0 - occupant_message("Analyzing reagents...") - for(var/datum/reagent/R in A.reagents.reagent_list) - if(R.reagent_state == 2 && add_known_reagent(R.id,R.name)) - occupant_message("Reagent analyzed, identified as [R.name] and added to database.") - send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form()) - occupant_message("Analyzis complete.") - return 1 - - proc/add_known_reagent(r_id,r_name) - set_ready_state(0) - do_after_cooldown() - if(!(r_id in known_reagents)) - known_reagents += r_id - known_reagents[r_id] = r_name - return 1 - return 0 - - - update_equip_info() - if(..()) - send_byjax(chassis.occupant,"msyringegun.browser","reagents",get_current_reagents()) - send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form()) - return 1 + if(reagents.total_volume<=0) + occupant_message("No available reagents to load syringe with.") return + set_ready_state(0) + chassis.use_power(energy_drain) + var/turf/trg = get_turf(target) + var/obj/item/weapon/reagent_containers/syringe/S = syringes[1] + S.forceMove(get_turf(chassis)) + reagents.trans_to_obj(S, min(S.volume, reagents.total_volume)) + syringes -= S + S.icon = 'icons/obj/chemical.dmi' + S.icon_state = "syringeproj" + playsound(chassis, 'sound/items/syringeproj.ogg', 50, 1) + log_message("Launched [S] from [src], targeting [target].") - on_reagent_change() - ..() + INVOKE_ASYNC(src, .proc/action_callback, S, trg) + + do_after_cooldown() + return 1 + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/action_callback(obj/item/weapon/reagent_containers/syringe/S, turf/trg) + for(var/i=0, i<6, i++) + if(!S || !trg) + return + if(step_towards(S, trg)) + var/list/mobs = list() + for(var/mob/living/carbon/M in S.loc) + mobs += M + var/mob/living/carbon/M = safepick(mobs) + if(M) + S.icon_state = initial(S.icon_state) + S.icon = initial(S.icon) + S.reagents.trans_to_mob(M, S.reagents.total_volume, CHEM_BLOOD) + M.take_organ_damage(2) + S.visible_message(" [M] was hit by the syringe!") + return + else if(S.loc == trg) + S.icon_state = initial(S.icon_state) + S.icon = initial(S.icon) + S.update_icon() + return + else + S.icon_state = initial(S.icon_state) + S.icon = initial(S.icon) + S.update_icon() + break + sleep(1) + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/Topic(href,href_list) + ..() + var/datum/topic_input/filter = new (href,href_list) + if(filter.get("toggle_mode")) + mode = !mode update_equip_info() return + if(filter.get("select_reagents")) + processed_reagents.len = 0 + var/m = 0 + var/message + for(var/i=1 to known_reagents.len) + if(m>=synth_speed) + break + var/reagent = filter.get("reagent_[i]") + if(reagent && (reagent in known_reagents)) + message = "[m ? ", " : null][known_reagents[reagent]]" + processed_reagents += reagent + m++ + if(processed_reagents.len) + message += " added to production" + START_PROCESSING(SSprocessing, src) + occupant_message(message) + occupant_message("Reagent processing started.") + log_message("Reagent processing started.") + return + if(filter.get("show_reagents")) + chassis.occupant << browse(get_reagents_page(),"window=msyringegun") + if(filter.get("purge_reagent")) + var/reagent = filter.get("purge_reagent") + if(reagent) + reagents.del_reagent(reagent) + return + if(filter.get("purge_all")) + reagents.clear_reagents() + return + return -/datum/global_iterator/mech_synth - delay = 100 +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_page() + var/output = {" + + Reagent Synthesizer + + + + +

Current reagents:

+
+ [get_current_reagents()] +
+

Reagents production:

+
+ [get_reagents_form()] +
+ + + "} + return output - process(var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/S) - if(!S.chassis) - return stop() - var/energy_drain = S.energy_drain*10 - if(!S.processed_reagents.len || S.reagents.total_volume >= S.reagents.maximum_volume || !S.chassis.has_charge(energy_drain)) - S.occupant_message("Reagent processing stopped.") - S.log_message("Reagent processing stopped.") - return stop() - var/amount = S.synth_speed / S.processed_reagents.len - for(var/reagent in S.processed_reagents) - S.reagents.add_reagent(reagent,amount) - S.chassis.use_power(energy_drain) +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_form() + var/r_list = get_reagents_list() + var/inputs + if(r_list) + inputs += "" + inputs += "" + inputs += "" + var/output = {"
+ [r_list || "No known reagents"] + [inputs] +
+ [r_list? "Only the first [synth_speed] selected reagent\s will be added to production" : null] + "} + return output + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_list() + var/output + for(var/i=1 to known_reagents.len) + var/reagent_id = known_reagents[i] + output += {" [known_reagents[reagent_id]]
"} + return output + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_current_reagents() + var/output + for(var/datum/reagent/R in reagents.reagent_list) + if(R.volume > 0) + output += "[R]: [round(R.volume,0.001)] - Purge Reagent
" + if(output) + output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - Purge All" + return output || "None" + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/load_syringe(obj/item/weapon/reagent_containers/syringe/S) + if(syringes.len= 2) + occupant_message("The syringe is too far away.") + return 0 + for(var/obj/structure/D in S.loc)//Basic level check for structures in the way (Like grilles and windows) + if(!(D.CanPass(S,src.loc))) + occupant_message("Unable to load syringe.") + return 0 + for(var/obj/machinery/door/D in S.loc)//Checks for doors + if(!(D.CanPass(S,src.loc))) + occupant_message("Unable to load syringe.") + return 0 + S.reagents.trans_to_obj(src, S.reagents.total_volume) + S.forceMove(src) + syringes += S + occupant_message("Syringe loaded.") + update_equip_info() return 1 + occupant_message("The [src] syringe chamber is full.") + return 0 + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/analyze_reagents(atom/A) + if(get_dist(src,A) >= 4) + occupant_message("The object is too far away.") + return 0 + if(!A.reagents || istype(A,/mob)) + occupant_message("No reagent info gained from [A].") + return 0 + occupant_message("Analyzing reagents...") + for(var/datum/reagent/R in A.reagents.reagent_list) + if(R.reagent_state == 2 && add_known_reagent(R.id,R.name)) + occupant_message("Reagent analyzed, identified as [R.name] and added to database.") + send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form()) + occupant_message("Analyzis complete.") + return 1 + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/add_known_reagent(r_id,r_name) + set_ready_state(0) + do_after_cooldown() + if(!(r_id in known_reagents)) + known_reagents += r_id + known_reagents[r_id] = r_name + return 1 + return 0 + + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/update_equip_info() + if(..()) + send_byjax(chassis.occupant,"msyringegun.browser","reagents",get_current_reagents()) + send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form()) + return 1 + return + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/on_reagent_change() + ..() + update_equip_info() + return + +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/process() + // delay = 10 Only work every 10 ds. + if ((last_tick + 10) > world.time) + return + + last_tick = world.time + + if(!chassis) + return PROCESS_KILL + var/tmp_energy_drain = energy_drain*10 + if(!processed_reagents.len || reagents.total_volume >= reagents.maximum_volume || !chassis.has_charge(tmp_energy_drain)) + occupant_message("Reagent processing stopped.") + log_message("Reagent processing stopped.") + return PROCESS_KILL + var/amount = synth_speed / processed_reagents.len + for(var/reagent in processed_reagents) + reagents.add_reagent(reagent,amount) + chassis.use_power(tmp_energy_drain) diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index dff97b271d6..9f46306cce5 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -7,65 +7,65 @@ var/obj/mecha/working/ripley/cargo_holder required_type = /obj/mecha/working - attach(obj/mecha/M as obj) - ..() - cargo_holder = M - return +/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/attach(obj/mecha/M as obj) + ..() + cargo_holder = M + return - action(atom/target) - if(!action_checks(target)) return - if(!cargo_holder) return +/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/action(atom/target) + if(!action_checks(target)) return + if(!cargo_holder) return - //loading - if(istype(target,/obj)) - var/obj/O = target - if(O.buckled_mob) - return - if(locate(/mob/living) in O) - occupant_message("You can't load living things into the cargo compartment.") - return - if(O.anchored) - occupant_message("[target] is firmly secured.") - return - if(cargo_holder.cargo.len >= cargo_holder.cargo_capacity) - occupant_message("Not enough room in cargo compartment.") - return + //loading + if(istype(target,/obj)) + var/obj/O = target + if(O.buckled_mob) + return + if(locate(/mob/living) in O) + occupant_message("You can't load living things into the cargo compartment.") + return + if(O.anchored) + occupant_message("[target] is firmly secured.") + return + if(cargo_holder.cargo.len >= cargo_holder.cargo_capacity) + occupant_message("Not enough room in cargo compartment.") + return - occupant_message("You lift [target] and start to load it into cargo compartment.") - chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.") - set_ready_state(0) - chassis.use_power(energy_drain) - O.anchored = 1 - var/T = chassis.loc - if(do_after_cooldown(target)) - if(T == chassis.loc && src == chassis.selected) - cargo_holder.cargo += O - O.loc = chassis - O.anchored = 0 - occupant_message("[target] succesfully loaded.") - log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") - else - occupant_message("You must hold still while handling objects.") - O.anchored = initial(O.anchored) - - //attacking - else if(istype(target,/mob/living)) - var/mob/living/M = target - if(M.stat>1) return - if(chassis.occupant.a_intent == I_HURT) - M.take_overall_damage(dam_force) - M.adjustOxyLoss(round(dam_force/2)) - M.updatehealth() - occupant_message("You squeeze [target] with [src.name]. Something cracks.") - chassis.visible_message("[chassis] squeezes [target].") + occupant_message("You lift [target] and start to load it into cargo compartment.") + chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.") + set_ready_state(0) + chassis.use_power(energy_drain) + O.anchored = 1 + var/T = chassis.loc + if(do_after_cooldown(target)) + if(T == chassis.loc && src == chassis.selected) + cargo_holder.cargo += O + O.loc = chassis + O.anchored = 0 + occupant_message("[target] succesfully loaded.") + log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") else - step_away(M,chassis) - occupant_message("You push [target] out of the way.") - chassis.visible_message("[chassis] pushes [target] out of the way.") - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() - return 1 + occupant_message("You must hold still while handling objects.") + O.anchored = initial(O.anchored) + + //attacking + else if(istype(target,/mob/living)) + var/mob/living/M = target + if(M.stat>1) return + if(chassis.occupant.a_intent == I_HURT) + M.take_overall_damage(dam_force) + M.adjustOxyLoss(round(dam_force/2)) + M.updatehealth() + occupant_message("You squeeze [target] with [src.name]. Something cracks.") + chassis.visible_message("[chassis] squeezes [target].") + else + step_away(M,chassis) + occupant_message("You push [target] out of the way.") + chassis.visible_message("[chassis] pushes [target] out of the way.") + set_ready_state(0) + chassis.use_power(energy_drain) + do_after_cooldown() + return 1 /obj/item/mecha_parts/mecha_equipment/tool/drill name = "drill" @@ -76,52 +76,53 @@ force = 15 required_type = list(/obj/mecha/working/ripley, /obj/mecha/combat) - action(atom/target) - if(!action_checks(target)) return - if(isobj(target)) - var/obj/target_obj = target - if(!target_obj.vars.Find("unacidable") || target_obj.unacidable) return - set_ready_state(0) - chassis.use_power(energy_drain) - chassis.visible_message("\The [chassis] starts to drill \the [target]", "You hear a large drill.") - occupant_message("You start to drill \the [target]") - var/T = chassis.loc - var/C = target.loc //why are these backwards? we may never know -Pete - if(do_after_cooldown(target)) - if(T == chassis.loc && src == chassis.selected) - if(istype(target, /turf/simulated/wall)) - var/turf/simulated/wall/W = target - if(W.reinf_material) - occupant_message("\The [target] is too durable to drill through.") - else - log_message("Drilled through \the [target]") - target.ex_act(2) - else if(istype(target, /turf/simulated/mineral)) - for(var/turf/simulated/mineral/M in range(chassis,1)) - if(get_dir(chassis,M)&chassis.dir) - M.GetDrilled() - log_message("Drilled through \the [target]") - if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) - var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo - if(ore_box) - for(var/obj/item/weapon/ore/ore in range(chassis,1)) - if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) - else if(istype(target, /turf/simulated/floor/asteroid)) - for(var/turf/simulated/floor/asteroid/M in range(chassis,1)) - if(get_dir(chassis,M)&chassis.dir) - M.gets_dug() - log_message("Drilled through \the [target]") - if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) - var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo - if(ore_box) - for(var/obj/item/weapon/ore/ore in range(chassis,1)) - if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) - else if(target.loc == C) +/obj/item/mecha_parts/mecha_equipment/tool/drill/action(atom/target) + if(!action_checks(target)) return + if(isobj(target)) + var/obj/target_obj = target + if(target_obj.unacidable) + return + set_ready_state(0) + chassis.use_power(energy_drain) + chassis.visible_message("\The [chassis] starts to drill \the [target]", "You hear a large drill.") + occupant_message("You start to drill \the [target]") + var/T = chassis.loc + var/C = target.loc //why are these backwards? we may never know -Pete + if(do_after_cooldown(target)) + if(T == chassis.loc && src == chassis.selected) + if(istype(target, /turf/simulated/wall)) + var/turf/simulated/wall/W = target + if(W.reinf_material) + occupant_message("\The [target] is too durable to drill through.") + else log_message("Drilled through \the [target]") target.ex_act(2) - return 1 + else if(istype(target, /turf/simulated/mineral)) + for(var/turf/simulated/mineral/M in range(chassis,1)) + if(get_dir(chassis,M)&chassis.dir) + M.GetDrilled() + log_message("Drilled through \the [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(chassis,1)) + if(get_dir(chassis,ore)&chassis.dir) + ore.Move(ore_box) + else if(istype(target, /turf/simulated/floor/asteroid)) + for(var/turf/simulated/floor/asteroid/M in range(chassis,1)) + if(get_dir(chassis,M)&chassis.dir) + M.gets_dug() + log_message("Drilled through \the [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(chassis,1)) + if(get_dir(chassis,ore)&chassis.dir) + ore.Move(ore_box) + else if(target.loc == C) + log_message("Drilled through \the [target]") + target.ex_act(2) + return 1 /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill name = "diamond drill" @@ -131,48 +132,48 @@ equip_cooldown = 20 force = 15 - action(atom/target) - if(!action_checks(target)) return - if(isobj(target)) - var/obj/target_obj = target - if(target_obj.unacidable) return - set_ready_state(0) - chassis.use_power(energy_drain) - chassis.visible_message("\The [chassis] starts to drill \the [target]", "You hear a large drill.") - occupant_message("You start to drill \the [target]") - var/T = chassis.loc - var/C = target.loc //why are these backwards? we may never know -Pete - if(do_after_cooldown(target)) - if(T == chassis.loc && src == chassis.selected) - if(istype(target, /turf/simulated/wall)) - var/turf/simulated/wall/W = target - if(!W.reinf_material || do_after_cooldown(target))//To slow down how fast mechs can drill through the station - log_message("Drilled through \the [target]") - target.ex_act(3) - else if(istype(target, /turf/simulated/mineral)) - for(var/turf/simulated/mineral/M in range(chassis,1)) - if(get_dir(chassis,M)&chassis.dir) - M.GetDrilled() +/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill/action(atom/target) + if(!action_checks(target)) return + if(isobj(target)) + var/obj/target_obj = target + if(target_obj.unacidable) return + set_ready_state(0) + chassis.use_power(energy_drain) + chassis.visible_message("\The [chassis] starts to drill \the [target]", "You hear a large drill.") + occupant_message("You start to drill \the [target]") + var/T = chassis.loc + var/C = target.loc //why are these backwards? we may never know -Pete + if(do_after_cooldown(target)) + if(T == chassis.loc && src == chassis.selected) + if(istype(target, /turf/simulated/wall)) + var/turf/simulated/wall/W = target + if(!W.reinf_material || do_after_cooldown(target))//To slow down how fast mechs can drill through the station log_message("Drilled through \the [target]") - if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) - var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo - if(ore_box) - for(var/obj/item/weapon/ore/ore in range(chassis,1)) - if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) - else if(istype(target,/turf/simulated/floor/asteroid)) - for(var/turf/simulated/floor/asteroid/M in range(target,1)) - M.gets_dug() - log_message("Drilled through \the [target]") - if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) - var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo - if(ore_box) - for(var/obj/item/weapon/ore/ore in range(target,1)) + target.ex_act(3) + else if(istype(target, /turf/simulated/mineral)) + for(var/turf/simulated/mineral/M in range(chassis,1)) + if(get_dir(chassis,M)&chassis.dir) + M.GetDrilled() + log_message("Drilled through \the [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(chassis,1)) + if(get_dir(chassis,ore)&chassis.dir) ore.Move(ore_box) - else if(target.loc == C) - log_message("Drilled through \the [target]") - target.ex_act(2) - return 1 + else if(istype(target,/turf/simulated/floor/asteroid)) + for(var/turf/simulated/floor/asteroid/M in range(target,1)) + M.gets_dug() + log_message("Drilled through \the [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(target,1)) + ore.Move(ore_box) + else if(target.loc == C) + log_message("Drilled through \the [target]") + target.ex_act(2) + return 1 /obj/item/mecha_parts/mecha_equipment/tool/extinguisher name = "extinguisher" @@ -186,64 +187,66 @@ var/spray_amount = 5 //units of liquid per particle. 5 is enough to wet the floor - it's a big fire extinguisher, so should be fine var/max_water = 1000 - New() - reagents = new/datum/reagents(max_water) - reagents.my_atom = src - reagents.add_reagent("water", max_water) - ..() +/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/New() + reagents = new/datum/reagents(max_water) + reagents.my_atom = src + reagents.add_reagent("water", max_water) + ..() + return + +/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/action(atom/target) //copypasted from extinguisher. TODO: Rewrite from scratch. + if(!action_checks(target) || get_dist(chassis, target)>3) return + if(get_dist(chassis, target)>2) return + set_ready_state(0) + if(do_after_cooldown(target)) + if( istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1) + var/obj/o = target + var/amount = o.reagents.trans_to_obj(src, 200) + occupant_message("[amount] units transferred into internal tank.") + playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6) + return + + if (src.reagents.total_volume < 1) + occupant_message("\The [src] is empty.") + return + + playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3) + + var/direction = get_dir(chassis,target) + + var/turf/T = get_turf(target) + var/turf/T1 = get_step(T,turn(direction, 90)) + var/turf/T2 = get_step(T,turn(direction, -90)) + + var/list/the_targets = list(T,T1,T2) + + for(var/a = 1 to 5) + INVOKE_ASYNC(src, .proc/action_callback, T, T1, T2, the_targets, a) + return 1 + +/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/proc/action_callback(turf/T, turf/T1, turf/T2, list/target_list = list(), var/a = 1) + var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(chassis)) + var/turf/my_target + if(a == 1) + my_target = T + else if(a == 2) + my_target = T1 + else if(a == 3) + my_target = T2 + else + my_target = target_list + W.create_reagents(5) + if(!W || !src) return + reagents.trans_to_obj(W, spray_amount) + W.set_color() + W.set_up(my_target) - action(atom/target) //copypasted from extinguisher. TODO: Rewrite from scratch. - if(!action_checks(target) || get_dist(chassis, target)>3) return - if(get_dist(chassis, target)>2) return - set_ready_state(0) - if(do_after_cooldown(target)) - if( istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1) - var/obj/o = target - var/amount = o.reagents.trans_to_obj(src, 200) - occupant_message("[amount] units transferred into internal tank.") - playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6) - return +/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/get_equip_info() + return "[..()] \[[src.reagents.total_volume]\]" - if (src.reagents.total_volume < 1) - occupant_message("\The [src] is empty.") - return - - playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3) - - var/direction = get_dir(chassis,target) - - var/turf/T = get_turf(target) - var/turf/T1 = get_step(T,turn(direction, 90)) - var/turf/T2 = get_step(T,turn(direction, -90)) - - var/list/the_targets = list(T,T1,T2) - - for(var/a = 1 to 5) - spawn(0) - var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(chassis)) - var/turf/my_target - if(a == 1) - my_target = T - else if(a == 2) - my_target = T1 - else if(a == 3) - my_target = T2 - else - my_target = pick(the_targets) - W.create_reagents(5) - if(!W || !src) - return - reagents.trans_to_obj(W, spray_amount) - W.set_color() - W.set_up(my_target) - return 1 - - get_equip_info() - return "[..()] \[[src.reagents.total_volume]\]" - - on_reagent_change() - return +/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/on_reagent_change() + return /obj/item/mecha_parts/mecha_equipment/tool/rcd @@ -257,97 +260,95 @@ var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock. var/disabled = 0 //malf - action(atom/target) - if(istype(target,/area/shuttle)||istype(target, /turf/space/transit))//>implying these are ever made -Sieve - disabled = 1 - else - disabled = 0 - if(!istype(target, /turf) && !istype(target, /obj/machinery/door/airlock)) - target = get_turf(target) - if(!action_checks(target) || disabled || get_dist(chassis, target)>3) return - playsound(chassis, 'sound/machines/click.ogg', 50, 1) - //meh +/obj/item/mecha_parts/mecha_equipment/tool/rcd/action(atom/target) + if(istype(target,/area/shuttle)||istype(target, /turf/space/transit))//>implying these are ever made -Sieve + disabled = 1 + else + disabled = 0 + if(!istype(target, /turf) && !istype(target, /obj/machinery/door/airlock)) + target = get_turf(target) + if(!action_checks(target) || disabled || get_dist(chassis, target)>3) return + playsound(chassis, 'sound/machines/click.ogg', 50, 1) + //meh + switch(mode) + if(0) + if (istype(target, /turf/simulated/wall)) + occupant_message("Deconstructing [target]...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + chassis.spark_system.queue() + target:ChangeTurf(/turf/simulated/floor/plating) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.use_power(energy_drain) + else if (istype(target, /turf/simulated/floor)) + var/turf/T = target + occupant_message("Deconstructing [T]...") + set_ready_state(0) + if(do_after_cooldown(T)) + if(disabled) return + chassis.spark_system.queue() + T.ChangeTurf(T.baseturf) + playsound(T, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.use_power(energy_drain) + else if (istype(target, /obj/machinery/door/airlock)) + occupant_message("Deconstructing [target]...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + chassis.spark_system.queue() + qdel(target) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.use_power(energy_drain) + if(1) + if(istype(target, /turf/space) || istype(target,get_base_turf_by_area(target))) + occupant_message("Building Floor...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + target:ChangeTurf(/turf/simulated/floor/plating) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.spark_system.queue() + chassis.use_power(energy_drain*2) + else if(istype(target, /turf/simulated/floor)) + occupant_message("Building Wall...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + target:ChangeTurf(/turf/simulated/wall) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.spark_system.queue() + chassis.use_power(energy_drain*2) + if(2) + if(istype(target, /turf/simulated/floor)) + occupant_message("Building Airlock...") + set_ready_state(0) + if(do_after_cooldown(target)) + if(disabled) return + chassis.spark_system.queue() + var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target) + T.autoclose = 1 + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + playsound(target, 'sound/effects/sparks2.ogg', 50, 1) + chassis.use_power(energy_drain*2) + return + + +/obj/item/mecha_parts/mecha_equipment/tool/rcd/Topic(href,href_list) + ..() + if(href_list["mode"]) + mode = text2num(href_list["mode"]) switch(mode) if(0) - if (istype(target, /turf/simulated/wall)) - occupant_message("Deconstructing [target]...") - set_ready_state(0) - if(do_after_cooldown(target)) - if(disabled) return - chassis.spark_system.queue() - target:ChangeTurf(/turf/simulated/floor/plating) - playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.use_power(energy_drain) - else if (istype(target, /turf/simulated/floor)) - var/turf/T = target - occupant_message("Deconstructing [T]...") - set_ready_state(0) - if(do_after_cooldown(T)) - if(disabled) return - chassis.spark_system.queue() - T.ChangeTurf(T.baseturf) - playsound(T, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.use_power(energy_drain) - else if (istype(target, /obj/machinery/door/airlock)) - occupant_message("Deconstructing [target]...") - set_ready_state(0) - if(do_after_cooldown(target)) - if(disabled) return - chassis.spark_system.queue() - qdel(target) - playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.use_power(energy_drain) + occupant_message("Switched RCD to Deconstruct.") if(1) - if(istype(target, /turf/space) || istype(target,get_base_turf_by_area(target))) - occupant_message("Building Floor...") - set_ready_state(0) - if(do_after_cooldown(target)) - if(disabled) return - target:ChangeTurf(/turf/simulated/floor/plating) - playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.spark_system.queue() - chassis.use_power(energy_drain*2) - else if(istype(target, /turf/simulated/floor)) - occupant_message("Building Wall...") - set_ready_state(0) - if(do_after_cooldown(target)) - if(disabled) return - target:ChangeTurf(/turf/simulated/wall) - playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.spark_system.queue() - chassis.use_power(energy_drain*2) + occupant_message("Switched RCD to Construct.") if(2) - if(istype(target, /turf/simulated/floor)) - occupant_message("Building Airlock...") - set_ready_state(0) - if(do_after_cooldown(target)) - if(disabled) return - chassis.spark_system.queue() - var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target) - T.autoclose = 1 - playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) - playsound(target, 'sound/effects/sparks2.ogg', 50, 1) - chassis.use_power(energy_drain*2) - return - - - Topic(href,href_list) - ..() - if(href_list["mode"]) - mode = text2num(href_list["mode"]) - switch(mode) - if(0) - occupant_message("Switched RCD to Deconstruct.") - if(1) - occupant_message("Switched RCD to Construct.") - if(2) - occupant_message("Switched RCD to Construct Airlock.") - return - - get_equip_info() - return "[..()] \[D|C|A\]" - + occupant_message("Switched RCD to Construct Airlock.") + return +/obj/item/mecha_parts/mecha_equipment/tool/rcd/get_equip_info() + return "[..()] \[D|C|A\]" /obj/item/mecha_parts/mecha_equipment/teleporter @@ -359,15 +360,15 @@ energy_drain = 1000 range = RANGED - action(atom/target) - if(!action_checks(target) || src.loc.z == 2) return - var/turf/T = get_turf(target) - if(T) - set_ready_state(0) - chassis.use_power(energy_drain) - do_teleport(chassis, T, 4) - do_after_cooldown() - return +/obj/item/mecha_parts/mecha_equipment/teleporter/action(atom/target) + if(!action_checks(target) || src.loc.z == 2) return + var/turf/T = get_turf(target) + if(T) + set_ready_state(0) + chassis.use_power(energy_drain) + do_teleport(chassis, T, 4) + do_after_cooldown() + return /obj/item/mecha_parts/mecha_equipment/wormhole_generator @@ -380,45 +381,44 @@ range = RANGED - action(atom/target) - if(!action_checks(target) || src.loc.z == 2) return - var/list/theareas = list() - for(var/area/AR in orange(100, chassis)) - if(AR in theareas) continue - theareas += AR - if(!theareas.len) - return - var/area/thearea = pick(theareas) - var/list/L = list() - var/turf/pos = get_turf(src) - for(var/turf/T in get_area_turfs(thearea.type)) - if(!T.density && pos.z == T.z) - var/clear = 1 - for(var/obj/O in T) - if(O.density) - clear = 0 - break - if(clear) - L+=T - if(!L.len) - return - var/turf/target_turf = pick(L) - if(!target_turf) - return - chassis.use_power(energy_drain) - set_ready_state(0) - var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target)) - P.target = target_turf - P.creator = null - P.icon = 'icons/obj/objects.dmi' - P.failchance = 0 - P.icon_state = "anom" - P.name = "wormhole" - do_after_cooldown() - src = null - spawn(rand(150,300)) - qdel(P) +/obj/item/mecha_parts/mecha_equipment/wormhole_generator/action(atom/target) + if(!action_checks(target) || src.loc.z == 2) return + var/list/theareas = list() + for(var/area/AR in orange(100, chassis)) + if(AR in theareas) continue + theareas += AR + if(!theareas.len) return + var/area/thearea = pick(theareas) + var/list/L = list() + var/turf/pos = get_turf(src) + for(var/turf/T in get_area_turfs(thearea.type)) + if(!T.density && pos.z == T.z) + var/clear = 1 + for(var/obj/O in T) + if(O.density) + clear = 0 + break + if(clear) + L+=T + if(!L.len) + return + var/turf/target_turf = pick(L) + if(!target_turf) + return + chassis.use_power(energy_drain) + set_ready_state(0) + var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target)) + P.target = target_turf + P.creator = null + P.icon = 'icons/obj/objects.dmi' + P.failchance = 0 + P.icon_state = "anom" + P.name = "wormhole" + do_after_cooldown() + QDEL_IN(P, rand(150,300)) + + return /obj/item/mecha_parts/mecha_equipment/gravcatapult name = "gravitational catapult" @@ -434,66 +434,71 @@ var/last_fired = 0 //Concept stolen from guns. var/fire_delay = 10 //Used to prevent spam-brute against humans. - action(atom/movable/target) +/obj/item/mecha_parts/mecha_equipment/gravcatapult/action(atom/movable/target) + if(world.time >= last_fired + fire_delay) + last_fired = world.time + else + if (world.time % 3) + occupant_message("[src] is not ready to fire again!") + return 0 - if(world.time >= last_fired + fire_delay) - last_fired = world.time - else - if (world.time % 3) - occupant_message("[src] is not ready to fire again!") - return 0 - - switch(mode) - if(1) - if(!action_checks(target) && !locked) return - if(!locked) - if(!istype(target) || target.anchored) - occupant_message("Unable to lock on [target]") - return - locked = target - occupant_message("Locked on [target]") - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + switch(mode) + if(1) + if(!action_checks(target) && !locked) return + if(!locked) + if(!istype(target) || target.anchored) + occupant_message("Unable to lock on [target]") return - else if(target!=locked) - if(locked in view(chassis)) - locked.throw_at(target, 14, 1.5, chassis) - locked = null - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() - else - locked = null - occupant_message("Lock on [locked] disengaged.") - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - if(2) - if(!action_checks(target)) return - var/list/atoms = list() - if(isturf(target)) - atoms = range(target,3) + locked = target + occupant_message("Locked on [target]") + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return + else if(target!=locked) + if(locked in view(chassis)) + locked.throw_at(target, 14, 1.5, chassis) + locked = null + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + set_ready_state(0) + chassis.use_power(energy_drain) + do_after_cooldown() else - atoms = orange(target,3) - for(var/atom/movable/A in atoms) - if(A.anchored) continue - spawn(0) - var/iter = 5-get_dist(A,target) - for(var/i=0 to iter) - step_away(A,target) - sleep(2) - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() + locked = null + occupant_message("Lock on [locked] disengaged.") + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + if(2) + if(!action_checks(target)) return + var/list/atoms = list() + if(isturf(target)) + atoms = range(target,3) + else + atoms = orange(target,3) + for(var/atom/movable/A in atoms) + if(A.anchored) + continue + INVOKE_ASYNC(src, .proc/action_callback, A, target) + set_ready_state(0) + chassis.use_power(energy_drain) + do_after_cooldown() + return + +/obj/item/mecha_parts/mecha_equipment/gravcatapult/proc/action_callback(atom/movable/A, atom/movable/target) + if (!A || !target) return - get_equip_info() - return "[..()] [mode==1?"([locked||"Nothing"])":null] \[S|P\]" + var/iter = 5-get_dist(A,target) + for(var/i=0 to iter) + step_away(A, target) + sleep(2) - Topic(href, href_list) - ..() - if(href_list["mode"]) - mode = text2num(href_list["mode"]) - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - return +/obj/item/mecha_parts/mecha_equipment/gravcatapult/get_equip_info() + return "[..()] [mode==1?"([locked||"Nothing"])":null] \[S|P\]" + +/obj/item/mecha_parts/mecha_equipment/gravcatapult/Topic(href, href_list) + ..() + if(href_list["mode"]) + mode = text2num(href_list["mode"]) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return /obj/item/mecha_parts/mecha_equipment/armor_booster @@ -507,37 +512,37 @@ var/damage_coeff = 1 var/melee - attach(obj/mecha/M as obj) - ..() +/obj/item/mecha_parts/mecha_equipment/armor_booster/attach(obj/mecha/M as obj) + ..() + activate_boost() + return + +/obj/item/mecha_parts/mecha_equipment/armor_booster/detach() + if(equip_ready) + deactivate_boost() + ..() + return + +/obj/item/mecha_parts/mecha_equipment/armor_booster/get_equip_info() + if(!chassis) return + return "* [src.name]" + +/obj/item/mecha_parts/mecha_equipment/armor_booster/proc/activate_boost() + if(!src.chassis) + return 0 + return 1 + +/obj/item/mecha_parts/mecha_equipment/armor_booster/proc/deactivate_boost() + if(!src.chassis) + return 0 + return 1 + +/obj/item/mecha_parts/mecha_equipment/armor_booster/set_ready_state(state) + if(state && !equip_ready) activate_boost() - return - - detach() - if(equip_ready) - deactivate_boost() - ..() - return - - get_equip_info() - if(!chassis) return - return "* [src.name]" - - proc/activate_boost() - if(!src.chassis) - return 0 - return 1 - - proc/deactivate_boost() - if(!src.chassis) - return 0 - return 1 - - set_ready_state(state) - if(state && !equip_ready) - activate_boost() - else if(equip_ready) - deactivate_boost() - ..() + else if(equip_ready) + deactivate_boost() + ..() /obj/item/mecha_parts/mecha_equipment/armor_booster/anticcw_armor_booster //what is that noise? A BAWWW from TK mutants. @@ -549,18 +554,18 @@ damage_coeff = 0.8 melee = 1 - activate_boost() - if(..()) - chassis.m_deflect_coeff *= deflect_coeff - chassis.m_damage_coeff *= damage_coeff - chassis.mhit_power_use += energy_drain +/obj/item/mecha_parts/mecha_equipment/armor_booster/anticcw_armor_booster/activate_boost() + if(..()) + chassis.m_deflect_coeff *= deflect_coeff + chassis.m_damage_coeff *= damage_coeff + chassis.mhit_power_use += energy_drain - deactivate_boost() - if(..()) - chassis.m_deflect_coeff /= deflect_coeff - chassis.m_damage_coeff /= damage_coeff - chassis.mhit_power_use -= energy_drain +/obj/item/mecha_parts/mecha_equipment/armor_booster/anticcw_armor_booster/deactivate_boost() + if(..()) + chassis.m_deflect_coeff /= deflect_coeff + chassis.m_damage_coeff /= damage_coeff + chassis.mhit_power_use -= energy_drain /obj/item/mecha_parts/mecha_equipment/armor_booster/antiproj_armor_booster @@ -572,17 +577,17 @@ damage_coeff = 0.8 melee = 0 - activate_boost() - if(..()) - chassis.r_deflect_coeff *= deflect_coeff - chassis.r_damage_coeff *= damage_coeff - chassis.rhit_power_use += energy_drain +/obj/item/mecha_parts/mecha_equipment/armor_booster/antiproj_armor_booster/activate_boost() + if(..()) + chassis.r_deflect_coeff *= deflect_coeff + chassis.r_damage_coeff *= damage_coeff + chassis.rhit_power_use += energy_drain - deactivate_boost() - if(..()) - chassis.r_deflect_coeff /= deflect_coeff - chassis.r_damage_coeff /= damage_coeff - chassis.rhit_power_use -= energy_drain +/obj/item/mecha_parts/mecha_equipment/armor_booster/antiproj_armor_booster/deactivate_boost() + if(..()) + chassis.r_deflect_coeff /= deflect_coeff + chassis.r_damage_coeff /= damage_coeff + chassis.rhit_power_use -= energy_drain /obj/item/mecha_parts/mecha_equipment/repair_droid @@ -594,89 +599,77 @@ energy_drain = 100 range = 0 var/health_boost = 2 - var/datum/global_iterator/pr_repair_droid - var/icon/droid_overlay + var/image/droid_overlay var/list/repairable_damage = list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH) - New() - ..() - pr_repair_droid = new /datum/global_iterator/mecha_repair_droid(list(src),0) - pr_repair_droid.set_delay(equip_cooldown) - return +/obj/item/mecha_parts/mecha_equipment/repair_droid/Destroy() + STOP_PROCESSING(SSprocessing, src) + return ..() - Destroy() - qdel(pr_repair_droid) - pr_repair_droid = null - return ..() +/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/mecha/M as obj) + ..() + droid_overlay = new(icon, icon_state = "repair_droid") + M.add_overlay(droid_overlay) + return - attach(obj/mecha/M as obj) - ..() - droid_overlay = new(src.icon, icon_state = "repair_droid") - M.overlays += droid_overlay - return +/obj/item/mecha_parts/mecha_equipment/repair_droid/destroy() + chassis.cut_overlay(droid_overlay) + STOP_PROCESSING(SSprocessing, src) + ..() + return - destroy() - chassis.overlays -= droid_overlay - ..() - return +/obj/item/mecha_parts/mecha_equipment/repair_droid/detach() + chassis.cut_overlay(droid_overlay) + STOP_PROCESSING(SSprocessing, src) + ..() + return - detach() - chassis.overlays -= droid_overlay - pr_repair_droid.stop() - ..() - return +/obj/item/mecha_parts/mecha_equipment/repair_droid/get_equip_info() + if(!chassis) return + return "* [src.name] - [ isprocessing ?"Dea":"A"]ctivate" - get_equip_info() - if(!chassis) return - return "* [src.name] - [pr_repair_droid.active()?"Dea":"A"]ctivate" - - - Topic(href, href_list) - ..() - if(href_list["toggle_repairs"]) - chassis.overlays -= droid_overlay - if(pr_repair_droid.toggle()) - droid_overlay = new(src.icon, icon_state = "repair_droid_a") - log_message("Activated.") - else - droid_overlay = new(src.icon, icon_state = "repair_droid") - log_message("Deactivated.") - set_ready_state(1) - chassis.overlays += droid_overlay - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - return - - -/datum/global_iterator/mecha_repair_droid - - process(var/obj/item/mecha_parts/mecha_equipment/repair_droid/RD as obj) - if(!RD.chassis) - stop() - RD.set_ready_state(1) - return - var/health_boost = RD.health_boost - var/repaired = 0 - if(RD.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) - health_boost *= -2 - else if(RD.chassis.hasInternalDamage() && prob(15)) - for(var/int_dam_flag in RD.repairable_damage) - if(RD.chassis.hasInternalDamage(int_dam_flag)) - RD.chassis.clearInternalDamage(int_dam_flag) - repaired = 1 - break - if(health_boost<0 || RD.chassis.health < initial(RD.chassis.health)) - RD.chassis.health += min(health_boost, initial(RD.chassis.health)-RD.chassis.health) - repaired = 1 - if(repaired) - if(RD.chassis.use_power(RD.energy_drain)) - RD.set_ready_state(0) - else - stop() - RD.set_ready_state(1) - return +/obj/item/mecha_parts/mecha_equipment/repair_droid/Topic(href, href_list) + ..() + if(href_list["toggle_repairs"]) + chassis.cut_overlay(droid_overlay) + if(!isprocessing) + START_PROCESSING(SSprocessing, src) + droid_overlay = new(src.icon, icon_state = "repair_droid_a") + log_message("Activated.") else - RD.set_ready_state(1) - return + STOP_PROCESSING(SSprocessing, src) + droid_overlay = new(src.icon, icon_state = "repair_droid") + log_message("Deactivated.") + set_ready_state(1) + chassis.add_overlay(droid_overlay) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return + +/obj/item/mecha_parts/mecha_equipment/repair_droid/process() + if(!chassis) + set_ready_state(1) + return PROCESS_KILL + var/temp_health_boost = health_boost + var/repaired = 0 + if(chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + temp_health_boost *= -2 + else if(chassis.hasInternalDamage() && prob(15)) + for(var/int_dam_flag in repairable_damage) + if(chassis.hasInternalDamage(int_dam_flag)) + chassis.clearInternalDamage(int_dam_flag) + repaired = 1 + break + if(temp_health_boost<0 || chassis.health < initial(chassis.health)) + chassis.health += min(temp_health_boost, initial(chassis.health) - chassis.health) + repaired = 1 + if(repaired) + if(chassis.use_power(energy_drain)) + set_ready_state(0) + else + set_ready_state(1) + return PROCESS_KILL + else + set_ready_state(1) /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay @@ -687,80 +680,71 @@ equip_cooldown = 10 energy_drain = 0 range = 0 - var/datum/global_iterator/pr_energy_relay var/coeff = 100 var/list/use_channels = list(EQUIP,ENVIRON,LIGHT) + var/last_tick = 0 - New() - ..() - pr_energy_relay = new /datum/global_iterator/mecha_energy_relay(list(src),0) - pr_energy_relay.set_delay(equip_cooldown) +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Destroy() + STOP_PROCESSING(SSfast_process, src) + return ..() + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/detach() + STOP_PROCESSING(SSfast_process, src) + ..() + return + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_power_channel(var/area/A) + var/pow_chan + if(A) + for(var/c in use_channels) + if(A.powered(c)) + pow_chan = c + break + return pow_chan + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Topic(href, href_list) + ..() + if(href_list["toggle_relay"]) + if(!isprocessing) + START_PROCESSING(SSfast_process, src) + set_ready_state(0) + log_message("Activated.") + else + STOP_PROCESSING(SSfast_process, src) + set_ready_state(1) + log_message("Deactivated.") + return + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info() + if(!chassis) return + return "* [src.name] - [ isprocessing ?"Dea":"A"]ctivate" + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/process() + if ((last_tick + 10) > world.time) return - Destroy() - qdel(pr_energy_relay) - pr_energy_relay = null - return ..() + last_tick = world.time - detach() - pr_energy_relay.stop() - ..() - return - - attach(obj/mecha/M) - ..() - return - - proc/get_power_channel(var/area/A) - var/pow_chan + if(!chassis || chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + set_ready_state(1) + return PROCESS_KILL + var/cur_charge = chassis.get_charge() + if(isnull(cur_charge) || !chassis.cell) + set_ready_state(1) + occupant_message("No powercell detected.") + return PROCESS_KILL + if(cur_charge* [src.name] - [pr_energy_relay.active()?"Dea":"A"]ctivate" - -/datum/global_iterator/mecha_energy_relay - - process(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/ER) - if(!ER.chassis || ER.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) - stop() - ER.set_ready_state(1) - return - var/cur_charge = ER.chassis.get_charge() - if(isnull(cur_charge) || !ER.chassis.cell) - stop() - ER.set_ready_state(1) - ER.occupant_message("No powercell detected.") - return - if(cur_charge3\] - [ isprocessing ?"Dea":"A"]ctivate" + return - Topic(href, href_list) - ..() - if(href_list["toggle"]) - if(pr_mech_generator.toggle()) - set_ready_state(0) - log_message("Activated.") - else - set_ready_state(1) - log_message("Deactivated.") - return - - get_equip_info() - var/output = ..() - if(output) - return "[output] \[[fuel]: [round(fuel.amount*fuel.perunit,0.1)] cm3\] - [pr_mech_generator.active()?"Dea":"A"]ctivate" - return - - action(target) - if(chassis) - var/result = load_fuel(target) - var/message - if(isnull(result)) - message = "[fuel] traces in target minimal. [target] cannot be used as fuel." - else if(!result) - message = "Unit is full." - else - message = "[result] unit\s of [fuel] successfully loaded." - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - occupant_message(message) - return - - proc/load_fuel(var/obj/item/stack/material/P) - if(P.type == fuel.type && P.amount) - var/to_load = max(max_fuel - fuel.amount*fuel.perunit,0) - if(to_load) - var/units = min(max(round(to_load / P.perunit),1),P.amount) - if(units) - fuel.amount += units - P.use(units) - return units - else - return 0 - return - - attackby(weapon,mob/user) - var/result = load_fuel(weapon) +/obj/item/mecha_parts/mecha_equipment/generator/action(target) + if(chassis) + var/result = load_fuel(target) + var/message if(isnull(result)) - user.visible_message("[user] tries to shove [weapon] into [src]. What a dumb-ass.","[fuel] traces minimal. [weapon] cannot be used as fuel.") + message = "[fuel] traces in target minimal. [target] cannot be used as fuel." else if(!result) - user << "Unit is full." + message = "Unit is full." else - user.visible_message("[user] loads [src] with [fuel].","[result] unit\s of [fuel] successfully loaded.") + message = "[result] unit\s of [fuel] successfully loaded." + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + occupant_message(message) + return + +/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(var/obj/item/stack/material/P) + if(P.type == fuel.type && P.amount) + var/to_load = max(max_fuel - fuel.amount*fuel.perunit,0) + if(to_load) + var/units = min(max(round(to_load / P.perunit),1),P.amount) + if(units) + fuel.amount += units + P.use(units) + return units + else + return 0 + return + +/obj/item/mecha_parts/mecha_equipment/generator/attackby(weapon,mob/user) + var/result = load_fuel(weapon) + if(isnull(result)) + user.visible_message("[user] tries to shove [weapon] into [src]. What a dumb-ass.","[fuel] traces minimal. [weapon] cannot be used as fuel.") + else if(!result) + user << "Unit is full." + else + user.visible_message("[user] loads [src] with [fuel].","[result] unit\s of [fuel] successfully loaded.") + return + +/obj/item/mecha_parts/mecha_equipment/generator/critfail() + ..() + var/turf/simulated/T = get_turf(src) + if(!T) + return + var/datum/gas_mixture/GM = new + if(prob(10)) + T.assume_gas("phoron", 100, 1500+T0C) + T.visible_message("The [src] suddenly disgorges a cloud of heated phoron.") + destroy() + else + T.assume_gas("phoron", 5, istype(T) ? T.air.temperature : T20C) + T.visible_message("The [src] suddenly disgorges a cloud of phoron.") + T.assume_air(GM) + return + +/obj/item/mecha_parts/mecha_equipment/generator/process() + // Process every 10 ds. + if ((last_tick + 10) > world.time) return - critfail() - ..() - var/turf/simulated/T = get_turf(src) - if(!T) - return - var/datum/gas_mixture/GM = new - if(prob(10)) - T.assume_gas("phoron", 100, 1500+T0C) - T.visible_message("The [src] suddenly disgorges a cloud of heated phoron.") - destroy() - else - T.assume_gas("phoron", 5, istype(T) ? T.air.temperature : T20C) - T.visible_message("The [src] suddenly disgorges a cloud of phoron.") - T.assume_air(GM) - return + last_tick = world.time -/datum/global_iterator/mecha_generator + if(!chassis) + set_ready_state(1) + return PROCESS_KILL + if(fuel.amount<=0) + log_message("Deactivated - no fuel.") + set_ready_state(1) + return PROCESS_KILL + var/cur_charge = chassis.get_charge() + if(isnull(cur_charge)) + set_ready_state(1) + occupant_message("No powercell detected.") + log_message("Deactivated.") + return PROCESS_KILL - process(var/obj/item/mecha_parts/mecha_equipment/generator/EG) - if(!EG.chassis) - stop() - EG.set_ready_state(1) - return 0 - if(EG.fuel.amount<=0) - stop() - EG.log_message("Deactivated - no fuel.") - EG.set_ready_state(1) - return 0 - var/cur_charge = EG.chassis.get_charge() - if(isnull(cur_charge)) - EG.set_ready_state(1) - EG.occupant_message("No powercell detected.") - EG.log_message("Deactivated.") - stop() - return 0 - var/use_fuel = EG.fuel_per_cycle_idle - if(cur_charge[target] succesfully loaded.") - chassis.log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") - else - chassis.occupant_message("You must hold still while handling objects.") - O.anchored = initial(O.anchored) - else - chassis.occupant_message("Not enough room in cargo compartment.") +/obj/item/mecha_parts/mecha_equipment/tool/safety_clamp/action(atom/target) + if(!action_checks(target)) return + if(!cargo_holder) return + if(istype(target,/obj)) + var/obj/O = target + if(!O.anchored) + if(cargo_holder.cargo.len < cargo_holder.cargo_capacity) + chassis.occupant_message("You lift [target] and start to load it into cargo compartment.") + chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.") + set_ready_state(0) + chassis.use_power(energy_drain) + O.anchored = 1 + var/T = chassis.loc + if(do_after_cooldown(target)) + if(T == chassis.loc && src == chassis.selected) + cargo_holder.cargo += O + O.forceMove(chassis) + O.anchored = 0 + chassis.occupant_message("[target] succesfully loaded.") + chassis.log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") + else + chassis.occupant_message("You must hold still while handling objects.") + O.anchored = initial(O.anchored) else - chassis.occupant_message("[target] is firmly secured.") + chassis.occupant_message("Not enough room in cargo compartment.") + else + chassis.occupant_message("[target] is firmly secured.") - else if(istype(target,/mob/living)) - var/mob/living/M = target - if(M.stat>1) return - if(chassis.occupant.a_intent == I_HURT) - chassis.occupant_message("You obliterate [target] with [src.name], leaving blood and guts everywhere.") - chassis.visible_message("[chassis] destroys [target] in an unholy fury.") - if(chassis.occupant.a_intent == I_DISARM) - chassis.occupant_message("You tear [target]'s limbs off with [src.name].") - chassis.visible_message("[chassis] rips [target]'s arms off.") - else - step_away(M,chassis) - chassis.occupant_message("You smash into [target], sending them flying.") - chassis.visible_message("[chassis] tosses [target] like a piece of paper.") - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() - return 1 + else if(istype(target,/mob/living)) + var/mob/living/M = target + if(M.stat>1) return + if(chassis.occupant.a_intent == I_HURT) + chassis.occupant_message("You obliterate [target] with [src.name], leaving blood and guts everywhere.") + chassis.visible_message("[chassis] destroys [target] in an unholy fury.") + if(chassis.occupant.a_intent == I_DISARM) + chassis.occupant_message("You tear [target]'s limbs off with [src.name].") + chassis.visible_message("[chassis] rips [target]'s arms off.") + else + step_away(M,chassis) + chassis.occupant_message("You smash into [target], sending them flying.") + chassis.visible_message("[chassis] tosses [target] like a piece of paper.") + set_ready_state(0) + chassis.use_power(energy_drain) + do_after_cooldown() + return 1 /obj/item/mecha_parts/mecha_equipment/tool/passenger name = "passenger compartment" @@ -1051,11 +1021,6 @@ return occupant.forceMove(get_turf(src)) occupant.reset_view() - /* - if(occupant.client) - occupant.client.eye = occupant.client.mob - occupant.client.perspective = MOB_PERSPECTIVE - */ occupant = null return diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 2be5df04575..202568480df 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -1,19 +1,22 @@ -#define MECHA_INT_FIRE 1 -#define MECHA_INT_TEMP_CONTROL 2 -#define MECHA_INT_SHORT_CIRCUIT 4 -#define MECHA_INT_TANK_BREACH 8 -#define MECHA_INT_CONTROL_LOST 16 +#define MECHA_INT_FIRE 1 << 0 +#define MECHA_INT_TEMP_CONTROL 1 << 1 +#define MECHA_INT_SHORT_CIRCUIT 1 << 2 +#define MECHA_INT_TANK_BREACH 1 << 3 +#define MECHA_INT_CONTROL_LOST 1 << 4 -#define MELEE 1 +#define MECHA_PROC_MOVEMENT 1 << 0 +#define MECHA_PROC_DAMAGE 1 << 1 +#define MECHA_PROC_INT_TEMP 1 << 2 + +#define MELEE 1 #define RANGED 2 - -#define NOMINAL 0 -#define FIRSTRUN 1 -#define POWER 2 -#define DAMAGE 3 -#define IMAGE 4 -#define WEAPONDOWN 5 +#define NOMINAL 0 +#define FIRSTRUN 1 +#define POWER 2 +#define DAMAGE 3 +#define IMAGE 4 +#define WEAPONDOWN 5 /obj/mecha name = "Mecha" @@ -21,7 +24,7 @@ icon = 'icons/mecha/mecha.dmi' w_class = 20 density = 1 //Dense. To raise the heat. - opacity = 1 ///opaque. Menacing. + opacity = 1 //opaque. Menacing. anchored = 1 //no pulling around. unacidable = 1 //and no deleting hoomans inside layer = MOB_LAYER //icon draw layer @@ -30,7 +33,7 @@ var/can_move = 1 var/mob/living/carbon/occupant = null var/step_in = 10 //make a step in step_in/10 sec. - var/dir_in = 2//What direction will the mech face when entered/powered on? Defaults to South. + var/dir_in = 2 //What direction will the mech face when entered/powered on? Defaults to South. var/step_energy_drain = 10 var/health = 300 //health is health var/deflect_chance = 10 //chance to deflect incoming projectiles, hits, or lesser the effect of ex_act. @@ -42,6 +45,9 @@ var/rhit_power_use = 0 var/mhit_power_use = 0 + // These control what toggleable processes are executed within process(). + var/current_processes = MECHA_PROC_INT_TEMP + //the values in this list show how much damage will pass through, not how much will be absorbed. var/list/damage_absorption = list("brute"=0.8,"fire"=1.2,"bullet"=0.9,"laser"=1,"energy"=1,"bomb"=1) var/obj/item/weapon/cell/cell @@ -68,14 +74,8 @@ var/internal_damage_threshold = 50 //health percentage below which internal damage is possible var/internal_damage = 0 //contains bitflags - var/list/operation_req_access = list()//required access level for mecha operation - var/list/internals_req_access = list(access_engine,access_robotics)//required access level to open cell compartment - - var/datum/global_iterator/pr_int_temp_processor //normalizes internal air mixture temperature - var/datum/global_iterator/pr_inertial_movement //controls intertial movement in spesss - var/datum/global_iterator/pr_give_air //moves air from tank to cabin - var/datum/global_iterator/pr_internal_damage //processes internal damage - var/datum/global_iterator/mecha_manage_warnings/pr_manage_warnings //Handles warning sounds for low power/health + var/list/operation_req_access = list() // required access level for mecha operation + var/list/internals_req_access = list(access_engine,access_robotics) // required access level to open cell compartment var/wreckage @@ -89,10 +89,25 @@ var/power_alert_status = 0 var/damage_alert_status = 0 - var/noexplode = 0//Used for cases where an exosuit is spawned and turned into wreckage + var/noexplode = 0 // Used for cases where an exosuit is spawned and turned into wreckage can_hold_mob = TRUE + // Warning variables. + var/sound/powerloop //Looping alert sounds played at alert 1 + var/sound/damageloop + + var/damage_warning_delay = 200 // Basic delay between warnings in alert status 2 + var/power_warning_delay = 200 // Starts at 20 seconds but the delay will increase with each warning + + var/last_power_warning = 0 + var/last_damage_warning = 0 + + var/float_direction = 0 + + // Process() iterator count. + var/process_ticks = 0 + /obj/mecha/drain_power(var/drain_check) if(drain_check) @@ -112,7 +127,6 @@ add_cabin() add_airtank() //All mecha currently have airtanks. No need to check unless changes are made. add_cell() - add_iterators() removeVerb(/obj/mecha/verb/disconnect_from_port) log_message("[src.name] created.") loc.Entered(src) @@ -121,13 +135,17 @@ spark_system = bind_spark(src, 2) +/obj/mecha/Initialize() + . = ..() + + START_PROCESSING(SSfast_process, src) + /obj/mecha/Destroy() + STOP_PROCESSING(SSfast_process, src) + src.go_out() for(var/mob/M in src) //Let's just be ultra sure - M.Move(loc) - - if(loc) - loc.Exited(src) + M.forceMove(loc) if(!noexplode && prob(30)) explosion(get_turf(loc), 0, 0, 1, 3) @@ -161,16 +179,35 @@ cell = null internal_tank = null - QDEL_NULL(pr_int_temp_processor) - QDEL_NULL(pr_inertial_movement) - QDEL_NULL(pr_give_air) - QDEL_NULL(pr_internal_damage) - QDEL_NULL(pr_manage_warnings) QDEL_NULL(spark_system) mechas_list -= src //global mech list return ..() +// The main process loop to replace the ancient global iterators. +// It's a bit hardcoded but I don't see anyone else adding stuff to +// mechas, and it's easy enough to modify. +/obj/mecha/process() + var/static/max_ticks = 16 + + if (current_processes & MECHA_PROC_MOVEMENT) + process_inertial_movement() + + if ((current_processes & MECHA_PROC_DAMAGE) && !(process_ticks % 2)) + process_internal_damage() + + if ((current_processes & MECHA_PROC_INT_TEMP) && !(process_ticks % 4)) + process_preserve_temp() + + if (!(process_ticks % 3)) + process_tank_give_air() + + if (!(process_ticks % 16)) + process_warnings() + + // Max value is 16. So we let it run between [0, 16] with this. + process_ticks = (process_ticks + 1) % 17 + //////////////////////// ////// Helpers ///////// //////////////////////// @@ -202,13 +239,6 @@ radio.icon_state = icon_state radio.subspace_transmission = 1 -/obj/mecha/proc/add_iterators() - pr_int_temp_processor = new /datum/global_iterator/mecha_preserve_temp(list(src)) - pr_inertial_movement = new /datum/global_iterator/mecha_inertial_movement(null,0) - pr_give_air = new /datum/global_iterator/mecha_tank_give_air(list(src)) - pr_internal_damage = new /datum/global_iterator/mecha_internal_damage(list(src),0) - pr_manage_warnings = new /datum/global_iterator/mecha_manage_warnings(list(src)) - /obj/mecha/proc/do_after_mecha(delay as num) sleep(delay) if(src) @@ -256,7 +286,7 @@ return -/obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits. +/obj/mecha/proc/drop_item() //Derpfix, but may be useful in future for engineering exosuits. return /obj/mecha/hear_talk(mob/M as mob, text) @@ -267,29 +297,6 @@ //////////////////////////// ///// Action processing //// //////////////////////////// -/* -/atom/DblClick(object,location,control,params) - var/mob/M = src.mob - if(M && M.in_contents_of(/obj/mecha)) - - if(mech_click == world.time) return - mech_click = world.time - - if(!istype(object, /atom)) return - if(istype(object, /obj/screen)) - var/obj/screen/using = object - if(using.screen_loc == ui_acti || using.screen_loc == ui_iarrowleft || using.screen_loc == ui_iarrowright)//ignore all HUD objects save 'intent' and its arrows - return ..() - else - return - var/obj/mecha/Mech = M.loc - spawn() //this helps prevent clickspam fest. - if (Mech) - Mech.click_action(object,M) -// else -// return ..() -*/ - /obj/mecha/proc/click_action(atom/target,mob/user) if(!src.occupant || src.occupant != user ) return if(user.stat) return @@ -369,7 +376,7 @@ user << "You unscrew and pry out the powercell." log_message("Powercell removed.") if ("Tracking Beacon") - if (beacon && beacon.loc == src)//safety + if (beacon && beacon.loc == src) // safety beacon.uninstall(user) /obj/mecha/proc/melee_action(atom/target) @@ -407,7 +414,7 @@ /obj/mecha/proc/do_move(direction) if(!can_move) return 0 - if(src.pr_inertial_movement.active()) + if(current_processes & MECHA_PROC_MOVEMENT) return 0 if(!has_charge(step_energy_drain)) return 0 @@ -423,7 +430,8 @@ use_power(step_energy_drain) if(istype(src.loc, /turf/space)) if(!src.check_for_support()) - src.pr_inertial_movement.start(list(src,direction)) + float_direction = direction + start_process(MECHA_PROC_MOVEMENT) src.log_message("Movement control lost. Inertial movement started.") if(do_after_mecha(step_in)) can_move = 1 @@ -455,7 +463,7 @@ if(istype(O, /obj/effect/portal)) //derpfix src.anchored = 0 O.Crossed(src) - spawn(0)//countering portal teleport spawn(0), hurr + spawn(0) // countering portal teleport spawn(0), hurr src.anchored = 1 else if(!O.anchored) step(obstacle,src.dir) @@ -488,15 +496,13 @@ destr.destroy() return -/obj/mecha/proc/hasInternalDamage(int_dam_flag=null) +/obj/mecha/proc/hasInternalDamage(int_dam_flag = null) return int_dam_flag ? internal_damage&int_dam_flag : internal_damage /obj/mecha/proc/setInternalDamage(int_dam_flag) - if(!pr_internal_damage) return - internal_damage |= int_dam_flag - pr_internal_damage.start() + start_process(MECHA_PROC_DAMAGE) log_append_to_last("Internal damage of type [int_dam_flag].",1) occupant << sound('sound/machines/warning-buzzer.ogg',wait=0) return @@ -506,7 +512,7 @@ switch(int_dam_flag) if(MECHA_INT_TEMP_CONTROL) occupant_message("Life support system reactivated.") - pr_int_temp_processor.start() + start_process(MECHA_PROC_INT_TEMP) if(MECHA_INT_FIRE) occupant_message("Internal fire extinquished.") if(MECHA_INT_TANK_BREACH) @@ -713,28 +719,6 @@ src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) return -/*Will fix later -Sieve -/obj/mecha/attack_blob(mob/user as mob) - src.log_message("Attack by blob. Attacker - [user].",1) - if(!prob(src.deflect_chance)) - src.take_damage(6) - src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - playsound(src.loc, 'sound/effects/blobattack.ogg', 50, 1, -1) - user << "You smash at the armored suit!" - for (var/mob/V in viewers(src)) - if(V.client && !(V.blinded)) - V.show_message("\The [user] smashes against [src.name]'s armor!", 1) - else - src.log_append_to_last("Armor saved.") - playsound(src.loc, 'sound/effects/blobattack.ogg', 50, 1, -1) - user << "Your attack had no effect!" - src.occupant_message("\The [user]'s attack is stopped by the armor.") - for (var/mob/V in viewers(src)) - if(V.client && !(V.blinded)) - V.show_message("\The [user] rebounds off the [src.name] armor!", 1) - return -*/ - /obj/mecha/emp_act(severity) if(get_charge()) use_power((4000)/severity) @@ -884,17 +868,6 @@ return -/* -/obj/mecha/attack_ai(var/mob/living/silicon/ai/user as mob) - if(!istype(user, /mob/living/silicon/ai)) - return - var/output = {"Assume direct control over [src]? - Yes
- "} - user << browse(output, "window=mecha_attack_ai") - return -*/ - ///////////////////////////////////// //////// Atmospheric stuff //////// ///////////////////////////////////// @@ -985,21 +958,19 @@ set category = "Exosuit Interface" set src = usr.loc - var/brokesomething = 0//true if we break anything - var/done = 0//Set true if we fail to break something. We won't try to break anything for the rest of the proc + var/brokesomething = 0 // true if we break anything + var/done = 0 // Set true if we fail to break something. We won't try to break anything for the rest of the proc if(!src.occupant) return if(usr!=src.occupant) return - - if ((world.time - lastcrash) < crash_cooldown)//prevent spamming it and breaking things too quickly + if ((world.time - lastcrash) < crash_cooldown) // prevent spamming it and breaking things too quickly return - if (!use_power(step_energy_drain*20))//Forcefully crashing into something costs 20x the power of taking a normal step + if (!use_power(step_energy_drain*20)) // Forcefully crashing into something costs 20x the power of taking a normal step occupant << "[src] lacks the remaining power to do that!" return 0 - //TODO: Add in a check for exosuit thrusters here after reworking them. //Exosuits with thrusters should be able to use crash in space, and without the 0.5sec windup time if (!check_for_support()) @@ -1010,16 +981,10 @@ occupant << "You take a step back, and then..." sleep(5) - - //Crashing is done in five stages - - - //1. We check if we can move into the tile. If so, then we just lunge forward clumsily var/turf/target = get_step(src, dir) - if (target.Enter(src, null)) mechstep(dir) sleep(2) @@ -1028,8 +993,6 @@ done = 1 return - - //2. We check for anything blocking us from leaving the tile. IE windoors or window panes, //and if they're present try to smash them //Failing to break any object we crash into will return and end execution @@ -1038,13 +1001,7 @@ if(!obstacle.CheckExit(src, target)) brokesomething++ if (!crash_into(obstacle)) - done = 1//If it survived the impact then we stop breaking things for this proc - - - - - - + done = 1 // If it survived the impact then we stop breaking things for this proc //3. Now we hit the turf itself, if it's a wall if (!done && !target.CanPass(src, target)) @@ -1053,8 +1010,6 @@ if (!target.CanPass(src, target)) done = 1 - - //4. Now we search the target tile for any dense objects that also block us. //This could be girders left behind from the wall we just destroyed if (!done) @@ -1062,9 +1017,7 @@ if (A.density && A != src && A != occupant && A.loc != src) brokesomething++ if (!crash_into(A)) - done = 1//If it survived the impact then we stop breaking things for this proc - - + done = 1 // If it survived the impact then we stop breaking things for this proc //If we hit any >0 number of things, whether they broke or not, we play the impact sound exactly once, and we send admin logs if (brokesomething) @@ -1072,7 +1025,6 @@ occupant.attack_log += "\[[time_stamp()]\] driving [name] crashed into [brokesomething] objects at ([target.x];[target.y];[target.z]) " msg_admin_attack("[key_name_admin(occupant)] driving [name] crashed into [brokesomething] objects at (JMP)",ckey=key_name(occupant)) - //5. If we get here, then we've broken through everything that could stop us //Step forward into the tile and display a victory message! //Its also possible to get here if we crashed against something that offered no resistance @@ -1081,7 +1033,7 @@ //No damage will be taken in this case if (!done && target.Enter(src, null)) if (health <= 0) - return 0//This prevents bugginess if the exosuit breaks while crashing into stuff + return 0 // This prevents bugginess if the exosuit breaks while crashing into stuff mechstep(dir) if (brokesomething) @@ -1089,22 +1041,18 @@ return else //if we fail to step forward, then we do the attack animation instead - target = get_step(src, dir)//re-fetch target just incase + target = get_step(src, dir) // re-fetch target just incase do_attack_animation(target) - /obj/mecha/proc/crash_into(var/atom/A) - var/aname = A.name//Cache this mainly because turfs change name when broken + var/aname = A.name // Cache this mainly because turfs change name when broken var/oldtype = A.type if (health <= 0) - return 0//This prevents bugginess if the exosuit explodes/dies while crashing into stuff - + return 0 // This prevents bugginess if the exosuit explodes/dies while crashing into stuff var/damage = crash_damage(A) - - if (istype(A, /mob/living)) var/mob/living/M = A occupant.attack_log += "\[[time_stamp()]\] Crashed into [key_name(M)]with exosuit [name] " @@ -1114,12 +1062,12 @@ A.ex_act(3) sleep(1) - if (!QDELETED(A) && A.type == oldtype)//We check if the object has been qdel'd or (for turfs) changed type + if (!QDELETED(A) && A.type == oldtype) // We check if the object has been qdel'd or (for turfs) changed type src.visible_message("[src.name] crashes into the [aname]!") take_damage(damage) - return 0//If it survived the impact then we stop breaking things for this proc + return 0 // If it survived the impact then we stop breaking things for this proc else - take_damage(damage*0.5)//An object that breaks hurts less than one that resists the impact + take_damage(damage*0.5) // An object that breaks hurts less than one that resists the impact return 1 @@ -1127,18 +1075,18 @@ /obj/mecha/proc/crash_damage(var/A) if (istype(A, /mob/living)) var/mob/living/M = A - return min((M.mob_size / 3),2)//Crashing into a cow or cyborg hurts more than crashing into a dog + return min((M.mob_size / 3),2) // Crashing into a cow or cyborg hurts more than crashing into a dog //2 is a fallback for mobs with undefined size else if (istype(A, /obj/structure/window)) - return 1.5//windows are fragile + return 1.5 // windows are fragile else if (istype(A, /obj/structure/grille)) - return 3//Grilles are flexible and flimsy structures + return 3 // Grilles are flexible and flimsy structures else if (istype(A, /obj/machinery)) return 3 else if (istype(A, /obj/structure)) return 6 - else if (istype(A, /turf))//walls are tough + else if (istype(A, /turf)) // walls are tough return 8 else return 3 @@ -1229,11 +1177,7 @@ usr << "The [src.name] is already occupied!" src.log_append_to_last("Permission denied.") return -/* - if (usr.abiotic()) - usr << "Subject cannot have abiotic items on." - return -*/ + var/passed if(src.dna) if(usr.dna.unique_enzymes==src.dna) @@ -1248,7 +1192,6 @@ if(M.Victim == usr) usr << "You're too busy getting your life sucked out of you." return -// usr << "You start climbing into [src.name]" visible_message("\The [usr] starts to climb into [src.name]") @@ -1264,10 +1207,6 @@ /obj/mecha/proc/moved_inside(var/mob/living/carbon/human/H as mob) if(H && H.client && H in range(1)) H.reset_view(src) - /* - H.client.perspective = EYE_PERSPECTIVE - H.client.eye = src - */ H.stop_pulling() H.forceMove(src) src.occupant = H @@ -1276,7 +1215,7 @@ src.log_append_to_last("[H] moved in as pilot.") src.icon_state = src.reset_icon() set_dir(dir_in) - pr_manage_warnings.resume_sounds(src) + resume_sounds() playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) if(cell && !hasInternalDamage() && cell.charge >= cell.maxcharge && health >= initial(health)) narrator_message(NOMINAL) @@ -1291,19 +1230,9 @@ set popup_menu = 0 if(usr!=src.occupant) return - //pr_update_stats.start() src.occupant << browse(src.get_stats_html(), "window=exosuit") return -/* -/obj/mecha/verb/force_eject() - set category = "Object" - set name = "Force Eject" - set src in view(5) - src.go_out() - return -*/ - /obj/mecha/verb/eject() set name = "Eject" set category = "Exosuit Interface" @@ -1318,8 +1247,8 @@ /obj/mecha/proc/go_out() if(!src.occupant) return - pr_manage_warnings.stop_sound(1, src)//We stop any looping warning sounds - pr_manage_warnings.stop_sound(2, src) + stop_sound(1) // We stop any looping warning sounds + stop_sound(2) var/atom/movable/mob_container if(ishuman(occupant)) mob_container = src.occupant @@ -1328,35 +1257,10 @@ mob_container = brain.container else return - if(mob_container.forceMove(src.loc))//ejecting mob container - /* - if(ishuman(occupant) && (return_pressure() > HAZARD_HIGH_PRESSURE)) - use_internal_tank = 0 - var/datum/gas_mixture/environment = get_turf_air() - if(environment) - var/env_pressure = environment.return_pressure() - var/pressure_delta = (cabin.return_pressure() - env_pressure) - //Can not have a pressure delta that would cause environment pressure > tank pressure - - var/transfer_moles = 0 - if(pressure_delta > 0) - transfer_moles = pressure_delta*environment.volume/(cabin.return_temperature() * R_IDEAL_GAS_EQUATION) - - //Actually transfer the gas - var/datum/gas_mixture/removed = cabin.air_contents.remove(transfer_moles) - loc.assume_air(removed) - - occupant.SetStunned(5) - occupant.SetWeakened(5) - occupant << "You were blown out of the mech!" - */ + if(mob_container.forceMove(src.loc)) // ejecting mob container src.log_message("[mob_container] moved out.") occupant.reset_view() - /* - if(src.occupant.client) - src.occupant.client.eye = src.occupant.client.mob - src.occupant.client.perspective = MOB_PERSPECTIVE - */ + src.occupant << browse(null, "window=exosuit") if(istype(mob_container, /obj/item/device/mmi)) var/obj/item/device/mmi/mmi = mob_container @@ -1656,7 +1560,7 @@ file = 'sound/mecha/weapdestrnano.ogg' else - playsound(src.loc, file, 100, 0, -6.6, environment=1)//using padded room environment to reduce echo + playsound(src.loc, file, 100, 0, -6.6, environment=1) // using padded room environment to reduce echo ///////////////// ///// Topic ///// @@ -1847,54 +1751,6 @@ return */ - - -/* - - if (href_list["ai_take_control"]) - var/mob/living/silicon/ai/AI = locate(href_list["ai_take_control"]) - var/duration = text2num(href_list["duration"]) - var/mob/living/silicon/ai/O = new /mob/living/silicon/ai(src) - var/cur_occupant = src.occupant - O.invisibility = 0 - O.canmove = 1 - O.name = AI.name - O.real_name = AI.real_name - O.anchored = 1 - O.aiRestorePowerRoutine = 0 - O.control_disabled = 1 // Can't control things remotely if you're stuck in a card! - O.laws = AI.laws - O.stat = AI.stat - O.oxyloss = AI.getOxyLoss() - O.fireloss = AI.getFireLoss() - O.bruteloss = AI.getBruteLoss() - O.toxloss = AI.toxloss - O.updatehealth() - src.occupant = O - if(AI.mind) - AI.mind.transfer_to(O) - AI.name = "Inactive AI" - AI.real_name = "Inactive AI" - AI.icon_state = "ai-empty" - spawn(duration) - AI.name = O.name - AI.real_name = O.real_name - if(O.mind) - O.mind.transfer_to(AI) - AI.control_disabled = 0 - AI.laws = O.laws - AI.oxyloss = O.getOxyLoss() - AI.fireloss = O.getFireLoss() - AI.bruteloss = O.getBruteLoss() - AI.toxloss = O.toxloss - AI.updatehealth() - qdel(O) - if (!AI.stat) - AI.icon_state = "ai" - else - AI.icon_state = "ai-crash" - src.occupant = cur_occupant -*/ return /////////////////////// @@ -1980,281 +1836,263 @@ //Does a number of checks at probability, and alters some configuration values if succeeded /obj/mecha/proc/misconfigure_systems(var/probability) if (prob(probability)) - internal_tank_valve = rand(0,10000)//Screw up the cabin air pressure. + internal_tank_valve = rand(0,10000) // Screw up the cabin air pressure. //This will probably kill the pilot if they dont check it before climbing in if (prob(probability)) - state = 1//Enable maintenance mode. It won't move. + state = 1 // Enable maintenance mode. It won't move. if (prob(probability)) - use_internal_tank = !use_internal_tank//Flip internal tank mode on or off + use_internal_tank = !use_internal_tank // Flip internal tank mode on or off if (prob(probability)) - toggle_lights()//toggle the lights - if (prob(probability))//Some settings to screw up the radio + toggle_lights() // toggle the lights + if (prob(probability)) // Some settings to screw up the radio radio.broadcasting = !radio.broadcasting if (prob(probability)) radio.listening = !radio.listening if (prob(probability)) radio.set_frequency(rand(1200,1600)) if (prob(probability)) - maint_access = 0//Disallow maintenance mode -////////////////////////////////////////// -//////// Mecha global iterators //////// -////////////////////////////////////////// -/datum/global_iterator/mecha_manage_warnings + maint_access = 0 // Disallow maintenance mode + +///////////////////////////////////////// +//////// Mecha process() helpers //////// +///////////////////////////////////////// +/obj/mecha/proc/stop_process(process) + current_processes &= ~process + +/obj/mecha/proc/start_process(process) + current_processes |= process + +///////////////////////////////////////////////// +//////// Mecha process() subcomponents //////// +///////////////////////////////////////////////// + +// Handles the internal alarms for a mech. +// Called every 16 iterations (80 deciseconds). +/obj/mecha/proc/process_warnings() //power/damage alerts have 3 different statuses //0 = fine, no alert //1 = Alert just started. Plays a looping sound for a few minutes //2 = Alert status has lasted a while. Stops the looping sound and just plays an occasional warning. - delay = 80 - var/sound/powerloop //Looping alert sounds played at alert 1 - var/sound/damageloop + var/static/looptime = 1800 //time we stay in stage 1 - var/looptime = 1800//time we stay in stage 1 + if (!cell) + if(power_alert_status || damage_alert_status) + // No cell will kill warnings. + // Makes sense, caution systems are battery powered. + power_alert_status = 0 // cancel the alert status + power_warning_delay = initial(power_warning_delay) // Reset the delay + stop_sound(1) - var/damage_warning_delay = 200//Basic delay between warnings in alert status 2 - var/power_warning_delay = 200//Starts at 20 seconds but the delay will increase with each warning + damage_alert_status = 0 + damage_warning_delay = initial(damage_warning_delay) // Reset the delay + stop_sound(2) + return + if (!power_alert_status && cell) // If we're in the fine status + if (cell.charge < (cell.maxcharge*0.3)) // but power is below 30% + power_alert_status = 1 // Switch to the alert status + narrator_message(POWER) // And send a vocal warning + log_append_to_last("Entered critical power alert.") - var/last_power_warning = 0 - var/last_damage_warning = 0 + //No 'else' here, we want this to run in the same proc if the alert status was just enabled + if (power_alert_status) // IF we're in either warning status - process(var/obj/mecha/mecha) - - if (!mecha) + if (cell.charge >= (cell.maxcharge*0.3)) // But power has risen back above danger levels + power_alert_status = 0 // cancel the alert status + power_warning_delay = initial(power_warning_delay) // Reset the delay + stop_sound(1) + occupant << "[src] power levels have returned to within safe operating parameters. Power alert status cancelled." + log_append_to_last("Power alert cleared") return - if (!mecha.cell) - if((mecha.power_alert_status || mecha.damage_alert_status)) - // No cell will kill warnings. - // Makes sense, caution systems are battery powered. - mecha.power_alert_status = 0//cancel the alert status - power_warning_delay = initial(power_warning_delay)//Reset the delay - stop_sound(1, mecha) - mecha.damage_alert_status = 0 - damage_warning_delay = initial(damage_warning_delay)//Reset the delay - stop_sound(2, mecha) + if (power_alert_status == 1) // If we're in alert 1, constant loop + if (!powerloop) // If the powerloop sound var is still null, it means we havent started playing it yet + occupant << "WARNING: [src] power levels below 30%. Please pilot to the nearest recharging station immediately." + create_sound(1) // We create it + occupant << powerloop // and start playing it to the occupant + last_power_warning = world.time // We set this var when we enter alert 1, to track how long we've been in it + + if ((world.time - last_power_warning) >= looptime) //If we've been in looping mode for long enough + occupant << "Alert: [src] power levels have remained in critical state for an unacceptably long period. Now switching to low-frequency warning mode to conserve power." + stop_sound(1) // We stop the soundloop + power_alert_status = 2 // And switch to alert 2 + last_power_warning = world.time + + else if (power_alert_status == 2) // If we're in alert 2 - infrequent vocal warnings + if ((world.time - last_power_warning) >= power_warning_delay) // IF its been long enough since the last warning + narrator_message(POWER) // We send a warning message to remind them + power_warning_delay *= 1.05 // We increase the delay between warnings by 5% multiplicatively each time + last_power_warning = world.time + //This causes the warnings to become less frequent and not be a constant annoyance + + + //The following block is basically a carbon copy of the above with minor alterations for damage + //-------------------------------------- + if (!damage_alert_status) + if (health < (initial(health)*0.3)) + damage_alert_status = 1 + narrator_message(DAMAGE) + log_append_to_last("Entered critical hull integrity alert.") + + + if (damage_alert_status) + if (health >= (initial(health)*0.3)) + damage_alert_status = 0 + damage_warning_delay = initial(damage_warning_delay) // Reset the delay + stop_sound(2) + occupant << "[src] hull integrity is now within safe operating parameters. Integrity alert status cancelled." + log_append_to_last("Hull integrity alert cleared.") return - if (!mecha.power_alert_status && mecha.cell)//If we're in the fine status - if (mecha.cell.charge < (mecha.cell.maxcharge*0.3))//but power is below 30% - mecha.power_alert_status = 1//Switch to the alert status - mecha.narrator_message(POWER)//And send a vocal warning - mecha.log_append_to_last("Entered critical power alert.") - - //No 'else' here, we want this to run in the same proc if the alert status was just enabled - - if (mecha.power_alert_status)//IF we're in either warning status - - if (mecha.cell.charge >= (mecha.cell.maxcharge*0.3))//But power has risen back above danger levels - mecha.power_alert_status = 0//cancel the alert status - power_warning_delay = initial(power_warning_delay)//Reset the delay - stop_sound(1, mecha) - mecha.occupant << "[mecha] power levels have returned to within safe operating parameters. Power alert status cancelled." - mecha.log_append_to_last("Power alert cleared") - return - - if (mecha.power_alert_status == 1)//If we're in alert 1, constant loop - if (!powerloop)//If the powerloop sound var is still null, it means we havent started playing it yet - mecha.occupant << "WARNING: [mecha] power levels below 30%. Please pilot to the nearest recharging station immediately." - create_sound(1)//We create it - mecha.occupant << powerloop//and start playing it to the occupant - last_power_warning = world.time//We set this var when we enter alert 1, to track how long we've been in it - - if ((world.time - last_power_warning) >= looptime) //If we've been in looping mode for long enough - mecha.occupant << "Alert: [mecha] power levels have remained in critical state for an unacceptably long period. Now switching to low-frequency warning mode to conserve power." - stop_sound(1, mecha)//We stop the soundloop - mecha.power_alert_status = 2//And switch to alert 2 - last_power_warning = world.time - - else if (mecha.power_alert_status == 2)//If we're in alert 2 - infrequent vocal warnings - if ((world.time - last_power_warning) >= power_warning_delay)//IF its been long enough since the last warning - mecha.narrator_message(POWER)//We send a warning message to remind them - power_warning_delay *= 1.05//We increase the delay between warnings by 5% multiplicatively each time - last_power_warning = world.time - //This causes the warnings to become less frequent and not be a constant annoyance - - - //The following block is basically a carbon copy of the above with minor alterations for damage - //-------------------------------------- - if (!mecha.damage_alert_status) - if (mecha.health < (initial(mecha.health)*0.3)) - mecha.damage_alert_status = 1 - mecha.narrator_message(DAMAGE) - mecha.log_append_to_last("Entered critical hull integrity alert.") - - - if (mecha.damage_alert_status) - if (mecha.health >= (initial(mecha.health)*0.3)) - mecha.damage_alert_status = 0 - damage_warning_delay = initial(damage_warning_delay)//Reset the delay - stop_sound(2, mecha) - mecha.occupant << "[mecha] hull integrity is now within safe operating parameters. Integrity alert status cancelled." - mecha.log_append_to_last("Hull integrity alert cleared.") - return - - if (mecha.damage_alert_status == 1) - if (!damageloop) - mecha.occupant << "WARNING: [mecha] hull integrity below 30%. Please report to the nearest Nanotrasen Certified Robotics Laboratory for urgent repairs." - create_sound(2) - mecha.occupant << damageloop - last_damage_warning = world.time - - if ((world.time - last_damage_warning) >= (looptime * 0.3)) //Looptime is shorter for the damage sound because its so horribly grating. - mecha.occupant << "Alert: [mecha] hull integrity has remained in critical state for a significant period of time. Now switching to low-frequency alert mode. Please seek repair as soon as possible." - stop_sound(2, mecha)//We stop the soundloop - mecha.damage_alert_status = 2//And switch to alert 2 - last_damage_warning = world.time - - else if (mecha.damage_alert_status == 2) - if ((world.time - last_damage_warning) >= damage_warning_delay) - mecha.narrator_message(DAMAGE) - damage_warning_delay *= 1.05 - last_damage_warning = world.time - - - //This creates the sound loop datums as necessary - //They are destroyed when the sound stops, and re-created when it starts looping. - proc/create_sound(var/type) - if (type == 1) - if (!powerloop) - powerloop = new /sound() - powerloop.file = 'sound/mecha/lowpower.ogg' - powerloop.repeat = 1 - powerloop.volume = 15 - var/done = 0 - while (!done)//This channel loop prevents both the looping sounds from sharing a channel - powerloop.channel = rand(1,100) - if (damageloop && damageloop.channel == powerloop.channel) - continue - - if (powerloop.channel) - done = 1 - - else if (type == 2) + if (damage_alert_status == 1) if (!damageloop) - damageloop = new /sound() - damageloop.file = 'sound/mecha/internaldmgalarm.ogg' - damageloop.repeat = 1 - damageloop.volume = 5//lower volume because the sound file is louder - var/done = 0 - while (!done) - damageloop.channel = rand(1,100) - if (powerloop && powerloop.channel == damageloop.channel) - continue + occupant << "WARNING: [src] hull integrity below 30%. Please report to the nearest Nanotrasen Certified Robotics Laboratory for urgent repairs." + create_sound(2) + occupant << damageloop + last_damage_warning = world.time - if (damageloop.channel) - done = 1 + if ((world.time - last_damage_warning) >= (looptime * 0.3)) //Looptime is shorter for the damage sound because its so horribly grating. + occupant << "Alert: [src] hull integrity has remained in critical state for a significant period of time. Now switching to low-frequency alert mode. Please seek repair as soon as possible." + stop_sound(2) // We stop the soundloop + damage_alert_status = 2 // And switch to alert 2 + last_damage_warning = world.time + + else if (damage_alert_status == 2) + if ((world.time - last_damage_warning) >= damage_warning_delay) + narrator_message(DAMAGE) + damage_warning_delay *= 1.05 + last_damage_warning = world.time - proc/stop_sound(var/type, var/obj/mecha/mecha) - if (type == 1 && powerloop) - mecha.occupant << sound(null,channel=powerloop.channel)//this stops the sound - powerloop = null +//This creates the sound loop datums as necessary +//They are destroyed when the sound stops, and re-created when it starts looping. +/obj/mecha/proc/create_sound(var/type) + if (type == 1) + if (!powerloop) + powerloop = new /sound() + powerloop.file = 'sound/mecha/lowpower.ogg' + powerloop.repeat = 1 + powerloop.volume = 15 + powerloop.channel = 50 // Only one mech can be heard at one time. So fuck the rand() deal. - else if (type == 2 && damageloop) - mecha.occupant << sound(null,channel=damageloop.channel)//this stops the sound - damageloop = null + else if (type == 2) + if (!damageloop) + damageloop = new /sound() + damageloop.file = 'sound/mecha/internaldmgalarm.ogg' + damageloop.repeat = 1 + damageloop.volume = 5 //lower volume because the sound file is louder + damageloop.channel = 51 - //This function exists for if someone enters the exosuit while its at alert stage 1 - //It starts playing the alert loops for the new occupant - proc/resume_sounds(var/obj/mecha/mecha) - if (mecha.power_alert_status == 1) - create_sound(1) - mecha.occupant << powerloop - if (mecha.damage_alert_status == 1) - create_sound(2) - mecha.occupant << damageloop +/obj/mecha/proc/stop_sound(var/type) + if (type == 1 && powerloop) + occupant << sound(null, channel=powerloop.channel) // this stops the sound + powerloop = null + else if (type == 2 && damageloop) + occupant << sound(null, channel=damageloop.channel) // this stops the sound + damageloop = null -/datum/global_iterator/mecha_preserve_temp //normalizing cabin air temperature to 20 degrees celsius - delay = 20 +//This function exists for if someone enters the exosuit while its at alert stage 1 +//It starts playing the alert loops for the new occupant +/obj/mecha/proc/resume_sounds() + if (power_alert_status == 1) + create_sound(1) + occupant << powerloop + if (damage_alert_status == 2) + create_sound(2) + occupant << damageloop - process(var/obj/mecha/mecha) - if(mecha.cabin_air && mecha.cabin_air.volume > 0) - var/delta = mecha.cabin_air.temperature - T20C - mecha.cabin_air.temperature -= max(-10, min(10, round(delta/4,0.1))) - return +// Normalizing cabin air temperature to 20 degrees celsius. +// Called every fourth process() tick (20 deciseconds). +/obj/mecha/proc/process_preserve_temp() + if (cabin_air && cabin_air.volume > 0) + var/delta = cabin_air.temperature - T20C + cabin_air.temperature -= max(-10, min(10, round(delta/4,0.1))) -/datum/global_iterator/mecha_tank_give_air - delay = 15 +// Handles internal air tank action. +// Called every third process() tick (15 deciseconds). +/obj/mecha/proc/process_tank_give_air() + if(internal_tank) + var/datum/gas_mixture/tank_air = internal_tank.return_air() - process(var/obj/mecha/mecha) - if(mecha.internal_tank) - var/datum/gas_mixture/tank_air = mecha.internal_tank.return_air() - var/datum/gas_mixture/cabin_air = mecha.cabin_air + var/release_pressure = internal_tank_valve + var/cabin_pressure = cabin_air.return_pressure() + var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) + var/transfer_moles = 0 - var/release_pressure = mecha.internal_tank_valve - var/cabin_pressure = cabin_air.return_pressure() - var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) - var/transfer_moles = 0 - if(pressure_delta > 0) //cabin pressure lower than release pressure - if(tank_air.temperature > 0) - transfer_moles = pressure_delta*cabin_air.volume/(cabin_air.temperature * R_IDEAL_GAS_EQUATION) - var/datum/gas_mixture/removed = tank_air.remove(transfer_moles) - cabin_air.merge(removed) - else if(pressure_delta < 0) //cabin pressure higher than release pressure - var/datum/gas_mixture/t_air = mecha.get_turf_air() - pressure_delta = cabin_pressure - release_pressure + if(pressure_delta > 0) //cabin pressure lower than release pressure + if(tank_air.temperature > 0) + transfer_moles = pressure_delta*cabin_air.volume/(cabin_air.temperature * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = tank_air.remove(transfer_moles) + cabin_air.merge(removed) + + else if(pressure_delta < 0) //cabin pressure higher than release pressure + var/datum/gas_mixture/t_air = get_turf_air() + pressure_delta = cabin_pressure - release_pressure + + if(t_air) + pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) + if(pressure_delta > 0) //if location pressure is lower than cabin pressure + transfer_moles = pressure_delta*cabin_air.volume/(cabin_air.temperature * R_IDEAL_GAS_EQUATION) + + var/datum/gas_mixture/removed = cabin_air.remove(transfer_moles) if(t_air) - pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) - if(pressure_delta > 0) //if location pressure is lower than cabin pressure - transfer_moles = pressure_delta*cabin_air.volume/(cabin_air.temperature * R_IDEAL_GAS_EQUATION) - var/datum/gas_mixture/removed = cabin_air.remove(transfer_moles) - if(t_air) - t_air.merge(removed) - else //just delete the cabin gas, we're in space or some shit - qdel(removed) - else - return stop() + t_air.merge(removed) + else //just delete the cabin gas, we're in space or some shit + qdel(removed) + +// Inertial movement in space. +// Called every process() tick (5 deciseconds). +/obj/mecha/proc/process_inertial_movement() + if(float_direction) + if(!step(src, float_direction) || check_for_support()) + stop_process(MECHA_PROC_MOVEMENT) + else + stop_process(MECHA_PROC_MOVEMENT) + return + +// Processes internal damage. +// Called every other process() tick (10 deciseconds). +/obj/mecha/proc/process_internal_damage() + if(!hasInternalDamage()) + stop_process(MECHA_PROC_DAMAGE) return -/datum/global_iterator/mecha_inertial_movement //inertial movement in space - delay = 7 + if(hasInternalDamage(MECHA_INT_FIRE)) + if(!hasInternalDamage(MECHA_INT_TEMP_CONTROL) && prob(5)) + clearInternalDamage(MECHA_INT_FIRE) + if(internal_tank) + if(internal_tank.return_pressure()>internal_tank.maximum_pressure && !(hasInternalDamage(MECHA_INT_TANK_BREACH))) + setInternalDamage(MECHA_INT_TANK_BREACH) + var/datum/gas_mixture/int_tank_air = internal_tank.return_air() + if(int_tank_air && int_tank_air.volume>0) //heat the air_contents + int_tank_air.temperature = min(6000+T0C, int_tank_air.temperature+rand(10,15)) + if(cabin_air && cabin_air.volume>0) + cabin_air.temperature = min(6000+T0C, cabin_air.temperature+rand(10,15)) + if(cabin_air.temperature>max_temperature/2) + take_damage(4/round(max_temperature/cabin_air.temperature,0.1),"fire") - process(var/obj/mecha/mecha as obj,direction) - if(direction) - if(!step(mecha, direction)||mecha.check_for_support()) - src.stop() - else - src.stop() - return + if(hasInternalDamage(MECHA_INT_TEMP_CONTROL)) + stop_process(MECHA_PROC_INT_TEMP) -/datum/global_iterator/mecha_internal_damage // processing internal damage + if(hasInternalDamage(MECHA_INT_TANK_BREACH)) //remove some air from internal tank + if(internal_tank) + var/datum/gas_mixture/int_tank_air = internal_tank.return_air() + var/datum/gas_mixture/leaked_gas = int_tank_air.remove_ratio(0.10) + if(istype(loc, /turf/simulated)) + loc.assume_air(leaked_gas) + else + qdel(leaked_gas) - process(var/obj/mecha/mecha) - if(!mecha.hasInternalDamage()) - return stop() - if(mecha.hasInternalDamage(MECHA_INT_FIRE)) - if(!mecha.hasInternalDamage(MECHA_INT_TEMP_CONTROL) && prob(5)) - mecha.clearInternalDamage(MECHA_INT_FIRE) - if(mecha.internal_tank) - if(mecha.internal_tank.return_pressure()>mecha.internal_tank.maximum_pressure && !(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH))) - mecha.setInternalDamage(MECHA_INT_TANK_BREACH) - var/datum/gas_mixture/int_tank_air = mecha.internal_tank.return_air() - if(int_tank_air && int_tank_air.volume>0) //heat the air_contents - int_tank_air.temperature = min(6000+T0C, int_tank_air.temperature+rand(10,15)) - if(mecha.cabin_air && mecha.cabin_air.volume>0) - mecha.cabin_air.temperature = min(6000+T0C, mecha.cabin_air.temperature+rand(10,15)) - if(mecha.cabin_air.temperature>mecha.max_temperature/2) - mecha.take_damage(4/round(mecha.max_temperature/mecha.cabin_air.temperature,0.1),"fire") - if(mecha.hasInternalDamage(MECHA_INT_TEMP_CONTROL)) //stop the mecha_preserve_temp loop datum - mecha.pr_int_temp_processor.stop() - if(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH)) //remove some air from internal tank - if(mecha.internal_tank) - var/datum/gas_mixture/int_tank_air = mecha.internal_tank.return_air() - var/datum/gas_mixture/leaked_gas = int_tank_air.remove_ratio(0.10) - if(mecha.loc && hascall(mecha.loc,"assume_air")) - mecha.loc.assume_air(leaked_gas) - else - qdel(leaked_gas) - if(mecha.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) - if(mecha.get_charge()) - mecha.spark_system.queue() - mecha.cell.charge -= min(20,mecha.cell.charge) - mecha.cell.maxcharge -= min(20,mecha.cell.maxcharge) - return + if(hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + if(get_charge()) + spark_system.queue() + cell.charge -= min(20,cell.charge) + cell.maxcharge -= min(20,cell.maxcharge) + return diff --git a/code/modules/cargo/randomstock.dm b/code/modules/cargo/randomstock.dm index 9262ba2ab41..78a45fe4d93 100644 --- a/code/modules/cargo/randomstock.dm +++ b/code/modules/cargo/randomstock.dm @@ -1821,21 +1821,19 @@ var/list/global/random_stock_large = list( exosuit.cell.charge = 0 - //Handle power or damage warnings - if (exosuit.pr_manage_warnings) - exosuit.pr_manage_warnings.process(exosuit)//Trigger them first, if they'll happen + exosuit.process_warnings()//Trigger them first, if they'll happen - if (exosuit.power_alert_status) - exosuit.pr_manage_warnings.last_power_warning = -99999999 - //Make it go into infrequent warning state instantly - exosuit.pr_manage_warnings.power_warning_delay = 99999999 - //and set the delay between warnings to a functionally infinite value - //so that it will shut up + if (exosuit.power_alert_status) + exosuit.last_power_warning = -99999999 + //Make it go into infrequent warning state instantly + exosuit.power_warning_delay = 99999999 + //and set the delay between warnings to a functionally infinite value + //so that it will shut up - if (exosuit.damage_alert_status) - exosuit.pr_manage_warnings.last_damage_warning = -99999999 - exosuit.pr_manage_warnings.damage_warning_delay = 99999999 + if (exosuit.damage_alert_status) + exosuit.last_damage_warning = -99999999 + exosuit.damage_warning_delay = 99999999 - exosuit.pr_manage_warnings.process(exosuit) + exosuit.process_warnings() else log_debug("ERROR: Random cargo spawn failed for [stock]")