From 5227e3e333bc10d897da2276ea153f5c78bbc81f Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Mon, 29 Sep 2025 07:34:41 +0200 Subject: [PATCH] Reworks the mining MODsuit (#92948) ## About The Pull Request Slightly reworks the mining MODsuit to be more distinct from other mining gear and have its own designated role as an exploration and mining tool. - Base armor (when covered in ash) has been reduced to 50 from 60, being equal to that of an explorer suit with two goliath plates attached. However, entering the sphere mode will grant additional 20 armor, bumping it up to 70 (equal to that of a H.E.C.K. suit) - Integrated drill no longer mines instantly by default, instead having a delay of 0.25 seconds. However, when entering the sphere mode, the drill will overcharge and get back its instamine, as well as get halved power consumption. Currently, those two are mutually exclusive, and the drill cannot be used in the sphere mode. - Mining bomb cooldown has been reduced to 1s from 1.25s. They also now detonate much faster, and the detonation time matches their animation. The digging radius has been reduced back to 3x3 from 5x5, and their damage has been reduced to 28 from 48 to compensate increase in firing speed and reduced detonation delay making them much easier to use (functional DPS has been reduced from 36 to 28) - Rewrote ore bag a bit to try and make sure it doesn't break when depositing ores into the ORM. I only have faint suspicions of this being possibly being caused by ore getting deleted and leaving a null in the list, so removing it should hopefully? stop the bag from breaking. - The 0.25 slowdown is back, but it should be less of a problem considering that the sphere mode now is a much more viable traversal tool and not an utter joke aside from lava traversal. - The MODsuit now comes pre-equipped with a magnetic harness, which is now capable of stowing kinetic crushers in addition to guns. This should make using the sphere mode less of a pain in the ass, as you won't drop your weapon whenever you enter the sphere mode before you remember to put it in your suit storage slot. The delay on harnesses has also been reduced to 0.5 seconds, which should make them more comfortable to use, while still allowing someone to grab your gun if you're not careful. - The sphere mode can no longer traverse lava roundstart, instead requiring to be upgraded with two pieces of bileworm skin to get lava-resistant plating. This is meant to work together with #92877, being a part of ongoing effort to bring mining back in terms of speed and action level, reducing mining and exploration speeds in favor of higher ore spawns and more focus on gear and equipment progression. image Additionally, both the mining drill and green raptor bumpmining has been nerfed (technically fixed, practically nerfed) by removing the diagonal movement... thing which allowed you to mine thrice as quickly and ignore the one-tick movement delay due to how diagonal movement works. https://github.com/user-attachments/assets/711e895f-e7e7-4cd9-b484-d7d11ff597af Its still fast and comfortable to use, just not absurdly fast. ## Why It's Good For The Game The mining MODsuit is in a very weird place both balance and progression wise. Its very easy to get if you ignore vents, it has good armor stats, it allows you to partly ignore being set on fire (or fully if you get the regulator module, but that requires more effort). I don't think that the buff was very needed, it was very strong as-is when used properly (with a yellow or green raptor mount) which not a lot of people seem to have realized. However, its still in a pretty pitiful state as its core feature (sphere mode) is nigh useless as the drill only works outside of it, and mines themselves are extremely clunky and uncomfortable to use. This leaves it only being useful for its cheap armor (without needing to kill goliaths), free GPS and ore bag that don't occupy your pockets, and ability to ignore environmental hazards. The solution I've decided to go with is reworking the MODsuit to be focused on mining and exploration rather than combat, being a good equipment piece for newer players and miners less interested in hunting megafauna. This carves the MODsuit its own niche rather than being weirdly slotted between base suits and contending with drake armor in terms of stats/effects. Roundstart lava crossing capabilities removal alongside bumpmining nerf is somewhat unrelated to the rest of the changes, it is a part of the exploration rework alongside #92877, which is intended to force miners to engage in combat more. Without the nerf, the suit is as fast as a yellow raptor, which lets it go through lavaland at absurd speeds when moving diagonally. (Yes, diagonal zig-zag movement ignoring the bump delay allows you to outspeed someone moving cardinally) More details about the project can be found in this [design doc](https://hackmd.io/@smart-kar/HkUINgBtke). The instamine ability of the sphere will likely get slightly nerfed in the future with the main batch of ore spread buffs and mining speed nerfs, but I've left it as powerful as a green raptor to not make the suit useless when compared to other options in the meantime. ## Changelog :cl: add: Mining MODsuit has gained a magnetic harness for all of your crusher stowing needs. balance: Magnetic harnesses now take only 0.5 seconds to pick up your gun, and can pick up crushers. balance: Mining MODsuit has regained it small slowdown, and lost 10 melee armor. balance: Mining drill MODule is no longer instant (outside of the sphere mode of a mining MOD) balance: The mining sphere MODule now can break rocks when rolling into them, gives 20 melee and bomb armor when active, and has a shorter bomb cooldown, but bombs themselves have reduced damage and mining AOE. balance: Mining sphere MODule now requires an upgrade in form of two pieces of bileworm skin to be able to traverse lava, as opposed to being able to do so innately. fix: Fixed MODsuit ore bag sometimes breaking permanently when depositing ores into the ORM. /:cl: --- code/__DEFINES/dcs/signals/signals_mod.dm | 4 + code/__HELPERS/visual_effects.dm | 9 +- code/datums/components/proficient_miner.dm | 37 +++ code/datums/elements/proficient_miner.dm | 28 -- code/game/turfs/closed/minerals.dm | 15 +- .../mining/lavaland/mining_loot/clothing.dm | 11 +- .../living/basic/lavaland/raptor/_raptor.dm | 2 +- code/modules/mod/mod_types.dm | 2 + code/modules/mod/modules/_module.dm | 2 + code/modules/mod/modules/modules_antag.dm | 2 +- code/modules/mod/modules/modules_security.dm | 13 +- code/modules/mod/modules/modules_supply.dm | 278 ++++++++++++------ icons/mob/clothing/modsuit/mod_modules.dmi | Bin 15767 -> 14693 bytes tgstation.dme | 2 +- 14 files changed, 259 insertions(+), 146 deletions(-) create mode 100644 code/datums/components/proficient_miner.dm delete mode 100644 code/datums/elements/proficient_miner.dm diff --git a/code/__DEFINES/dcs/signals/signals_mod.dm b/code/__DEFINES/dcs/signals/signals_mod.dm index 6cc6832beb6..bc76dd3e87a 100644 --- a/code/__DEFINES/dcs/signals/signals_mod.dm +++ b/code/__DEFINES/dcs/signals/signals_mod.dm @@ -32,10 +32,14 @@ #define MOD_ABORT_USE (1<<0) /// Called when a module activates, after all checks have passed and cooldown started. #define COMSIG_MODULE_ACTIVATED "mod_module_activated" +/// Called when a module successfully activates on the MODsuit itself +#define COMSIG_MOD_MODULE_ACTIVATED "mod_core_module_activated" /// Called when a module starts a cooldown until its next activation. Passed the cooldown time. #define COMSIG_MODULE_COOLDOWN_STARTED "mod_module_cooldown_started" /// Called when a module deactivates, after all checks have passed. #define COMSIG_MODULE_DEACTIVATED "mod_module_deactivated" +/// Called when a module successfully deactivates on the mod itself +#define COMSIG_MOD_MODULE_DEACTIVATED "mod_core_module_deactivated" /// Called when a module is used, after all checks have passed and cooldown started. #define COMSIG_MODULE_USED "mod_module_used" /// Called when the MODsuit wearer is set. diff --git a/code/__HELPERS/visual_effects.dm b/code/__HELPERS/visual_effects.dm index 5e93920ac75..c8720ba46ee 100644 --- a/code/__HELPERS/visual_effects.dm +++ b/code/__HELPERS/visual_effects.dm @@ -32,7 +32,7 @@ #define UPDATE_TRANSFORM_ANIMATION_TIME (0.2 SECONDS) ///Animates source spinning around itself. For docmentation on the args, check atom/proc/SpinAnimation() -/atom/proc/do_spin_animation(speed = 1 SECONDS, loops = -1, segments = 3, angle = 120, parallel = TRUE) +/atom/proc/do_spin_animation(speed = 1 SECONDS, loops = -1, segments = 3, angle = 120, parallel = TRUE, tag = null) var/list/matrices = list() for(var/i in 1 to segments-1) var/matrix/segment_matrix = matrix(transform) @@ -44,7 +44,7 @@ speed /= segments if(parallel) - animate(src, transform = matrices[1], time = speed, loop = loops, flags = ANIMATION_PARALLEL) + animate(src, transform = matrices[1], time = speed, loop = loops, flags = ANIMATION_PARALLEL, tag = tag) else animate(src, transform = matrices[1], time = speed, loop = loops) for(var/i in 2 to segments) //2 because 1 is covered above @@ -78,15 +78,16 @@ * * clockwise: whether the atom ought to spin clockwise or counter-clockwise * * segments: in how many animate calls the rotation is split. Probably unnecessary, but you shouldn't set it lower than 3 anyway. * * parallel: whether the animation calls have the ANIMATION_PARALLEL flag, necessary for it to run alongside concurrent animations. + * * tag: animation tag to use, for parralel animations only */ -/atom/proc/SpinAnimation(speed = 1 SECONDS, loops = -1, clockwise = TRUE, segments = 3, parallel = TRUE) +/atom/proc/SpinAnimation(speed = 1 SECONDS, loops = -1, clockwise = TRUE, segments = 3, parallel = TRUE, tag = null) if(!segments) return var/segment = 360/segments if(!clockwise) segment = -segment SEND_SIGNAL(src, COMSIG_ATOM_SPIN_ANIMATION, speed, loops, segments, segment) - do_spin_animation(speed, loops, segments, segment, parallel) + do_spin_animation(speed, loops, segments, segment, parallel, tag) /// Makes this atom look like a "hologram" /// So transparent, blue, with a scanline and an emissive glow diff --git a/code/datums/components/proficient_miner.dm b/code/datums/components/proficient_miner.dm new file mode 100644 index 00000000000..cdc3b65871b --- /dev/null +++ b/code/datums/components/proficient_miner.dm @@ -0,0 +1,37 @@ +/// Component given to mobs that can mine when moving +/datum/component/proficient_miner + /// Last tick when we bumpmined. Prevents diagonal bumpnining being thrice as fast as normal + var/last_bumpmine_tick = -1 + +/datum/component/proficient_miner/Initialize() + if (!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + +/datum/component/proficient_miner/RegisterWithParent() + RegisterSignal(parent, COMSIG_MOVABLE_BUMP, PROC_REF(on_bump)) + +/datum/component/proficient_miner/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_MOVABLE_BUMP) + +/datum/component/proficient_miner/proc/on_bump(atom/movable/source, atom/target) + SIGNAL_HANDLER + + if(!ismineralturf(target) || last_bumpmine_tick == world.time) + return + + var/mob/living/user = null + if(isliving(parent)) + user = parent + if(user.stat != CONSCIOUS) + return + + var/turf/closed/mineral/mineral_wall = target + if(!istype(mineral_wall, /turf/closed/mineral/gibtonite)) + last_bumpmine_tick = world.time + mineral_wall.gets_drilled(source) + return + + var/turf/closed/mineral/gibtonite/gibtonite_wall = mineral_wall + if(gibtonite_wall.stage == GIBTONITE_UNSTRUCK) + last_bumpmine_tick = world.time + mineral_wall.gets_drilled(source) diff --git a/code/datums/elements/proficient_miner.dm b/code/datums/elements/proficient_miner.dm deleted file mode 100644 index a35b3951d44..00000000000 --- a/code/datums/elements/proficient_miner.dm +++ /dev/null @@ -1,28 +0,0 @@ -///element given to mobs that can mine when moving -/datum/element/proficient_miner - -/datum/element/proficient_miner/Attach(datum/target) - . = ..() - if(!ismovable(target)) - return - RegisterSignal(target, COMSIG_MOVABLE_BUMP, PROC_REF(on_bump)) - -/datum/element/proficient_miner/proc/on_bump(mob/living/source, atom/target) - SIGNAL_HANDLER - - if(!ismineralturf(target) || (istype(source) && source.stat != CONSCIOUS)) - return - - var/turf/closed/mineral/mineral_wall = target - - if(!istype(mineral_wall, /turf/closed/mineral/gibtonite)) - mineral_wall.gets_drilled(source) - return - - var/turf/closed/mineral/gibtonite/gibtonite_wall = mineral_wall - if(gibtonite_wall.stage == GIBTONITE_UNSTRUCK) - mineral_wall.gets_drilled(source) - -/datum/element/proficient_miner/Detach(datum/source, ...) - UnregisterSignal(source, COMSIG_MOVABLE_BUMP) - return ..() diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm index 9bcf1ef4a94..78fa1af160e 100644 --- a/code/game/turfs/closed/minerals.dm +++ b/code/game/turfs/closed/minerals.dm @@ -162,13 +162,14 @@ return ..() -/turf/closed/mineral/attackby(obj/item/I, mob/user, list/modifiers) +/turf/closed/mineral/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers, exp_multiplier = 1) if (!ISADVANCEDTOOLUSER(user)) to_chat(usr, span_warning("You don't have the dexterity to do this!")) return if(I.tool_behaviour != TOOL_MINING) return + var/turf/T = user.loc if (!isturf(T)) return @@ -177,14 +178,12 @@ return TIMER_COOLDOWN_START(src, REF(user), tool_mine_speed) - - balloon_alert(user, "picking...") - if(!I.use_tool(src, user, tool_mine_speed, volume=50)) TIMER_COOLDOWN_END(src, REF(user)) //if we fail we can start again immediately return + if(ismineralturf(src)) - gets_drilled(user, 1) + gets_drilled(user, exp_multiplier) SSblackbox.record_feedback("tally", "pick_used_mining", 1, I.type) /turf/closed/mineral/attack_hand(mob/user) @@ -784,7 +783,7 @@ det_time = rand(8,10) //So you don't know exactly when the hot potato will explode . = ..() -/turf/closed/mineral/gibtonite/attackby(obj/item/attacking_item, mob/living/user, list/modifiers) +/turf/closed/mineral/gibtonite/attackby(obj/item/attacking_item, mob/living/user, list/modifiers, list/attack_modifiers, exp_multiplier = 1) var/previous_stage = stage if(istype(attacking_item, /obj/item/goliath_infuser_hammer) && stage == GIBTONITE_ACTIVE) user.visible_message(span_notice("[user] digs [attacking_item] to [src]..."), span_notice("Your tendril hammer instictively digs and wraps around [src] to stop it...")) @@ -792,7 +791,7 @@ else if(istype(attacking_item, /obj/item/mining_scanner) || istype(attacking_item, /obj/item/t_scanner/adv_mining_scanner) && stage == GIBTONITE_ACTIVE) user.visible_message(span_notice("[user] holds [attacking_item] to [src]..."), span_notice("You use [attacking_item] to locate where to cut off the chain reaction and attempt to stop it...")) defuse(user) - ..() + . = ..() if(istype(attacking_item, /obj/item/clothing/gloves/gauntlets) && previous_stage == GIBTONITE_UNSTRUCK && stage == GIBTONITE_ACTIVE && istype(user)) user.Immobilize(0.5 SECONDS) user.throw_at(get_ranged_target_turf(src, get_dir(src, user), 5), range = 5, speed = 3, spin = FALSE) @@ -909,7 +908,7 @@ base_icon_state = "rock_wall" smoothing_flags = SMOOTH_BITMASK | SMOOTH_BORDER -/turf/closed/mineral/strong/attackby(obj/item/I, mob/user, list/modifiers) +/turf/closed/mineral/strong/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers, exp_multiplier = 1) if(!ishuman(user)) to_chat(usr, span_warning("Only a more advanced species could break a rock such as this one!")) return FALSE diff --git a/code/modules/mining/lavaland/mining_loot/clothing.dm b/code/modules/mining/lavaland/mining_loot/clothing.dm index 360388b61b6..8918e638688 100644 --- a/code/modules/mining/lavaland/mining_loot/clothing.dm +++ b/code/modules/mining/lavaland/mining_loot/clothing.dm @@ -116,12 +116,11 @@ /obj/item/clothing/gloves/gauntlets/equipped(mob/user, slot) . = ..() - if(slot & ITEM_SLOT_GLOVES) - tool_behaviour = TOOL_MINING - RegisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(rocksmash)) - RegisterSignal(user, COMSIG_MOVABLE_BUMP, PROC_REF(rocksmash)) - else - stopmining(user) + if(!(slot & ITEM_SLOT_GLOVES)) + return + tool_behaviour = TOOL_MINING + RegisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(rocksmash)) + RegisterSignal(user, COMSIG_MOVABLE_BUMP, PROC_REF(rocksmash)) /obj/item/clothing/gloves/gauntlets/dropped(mob/user) . = ..() diff --git a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm index 10dab01c8c7..576cc24cf82 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm @@ -271,7 +271,7 @@ GLOBAL_LIST_EMPTY(raptor_population) /mob/living/basic/raptor/green/Initialize(mapload) . = ..() - AddElement(/datum/element/proficient_miner) + AddComponent(/datum/component/proficient_miner) /mob/living/basic/raptor/white name = "white raptor" diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 26e06bb0bdd..65a7a75220d 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -132,11 +132,13 @@ /obj/item/mod/module/orebag, /obj/item/mod/module/clamp, /obj/item/mod/module/drill, + /obj/item/mod/module/magnetic_harness, /obj/item/mod/module/mouthhole, ) default_pins = list( /obj/item/mod/module/gps, /obj/item/mod/module/drill, + /obj/item/mod/module/orebag, /obj/item/mod/module/sphere_transform, ) diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm index ecf20ae2532..17d72f2e68f 100644 --- a/code/modules/mod/modules/_module.dm +++ b/code/modules/mod/modules/_module.dm @@ -171,6 +171,7 @@ balloon_alert(mod.wearer, "[src] activated, [used_button]-click to use") // As of now, only wearers can "use" mods active = TRUE SEND_SIGNAL(src, COMSIG_MODULE_ACTIVATED) + SEND_SIGNAL(mod, COMSIG_MOD_MODULE_ACTIVATED, src) on_activation(activator) update_clothing_slots() return TRUE @@ -190,6 +191,7 @@ UnregisterSignal(mod.wearer, used_signal) used_signal = null SEND_SIGNAL(src, COMSIG_MODULE_DEACTIVATED, mod.wearer) + SEND_SIGNAL(mod, COMSIG_MOD_MODULE_DEACTIVATED, src) on_deactivation(activator, display_message = TRUE, deleting = FALSE) update_clothing_slots() return TRUE diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index cd2e8ce06d4..7f6789affff 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -386,7 +386,7 @@ var/datum/storage/holding_storage = mod.loc.atom_storage if(!holding_storage || holding_storage.max_specific_storage >= mod.w_class) return - mod.forceMove(drop_location()) + mod.forceMove(mod.drop_location()) /obj/item/mod/module/demoralizer name = "MOD psi-echo demoralizer module" diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 2eaebddaf55..4cacbddb811 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -10,7 +10,7 @@ incompatible_modules = list(/obj/item/mod/module/magnetic_harness) required_slots = list(ITEM_SLOT_OCLOTHING) /// Time before we activate the magnet. - var/magnet_delay = 0.8 SECONDS + var/magnet_delay = 0.5 SECONDS /// The typecache of all guns we allow. var/static/list/guns_typecache /// The guns already allowed by the modsuit chestplate. @@ -19,7 +19,14 @@ /obj/item/mod/module/magnetic_harness/Initialize(mapload) . = ..() if(!guns_typecache) - guns_typecache = typecacheof(list(/obj/item/gun/ballistic, /obj/item/gun/energy, /obj/item/gun/grenadelauncher, /obj/item/gun/chem, /obj/item/gun/syringe)) + guns_typecache = typecacheof(list( + /obj/item/gun/ballistic, + /obj/item/gun/energy, + /obj/item/gun/grenadelauncher, + /obj/item/gun/chem, + /obj/item/gun/syringe, + /obj/item/kinetic_crusher, + )) /obj/item/mod/module/magnetic_harness/on_install() . = ..() @@ -139,7 +146,7 @@ /obj/item/mod/module/holster/on_uninstall(deleting = FALSE) . = ..() if(holstered) - holstered.forceMove(drop_location()) + holstered.forceMove(mod.drop_location()) /obj/item/mod/module/holster/Exited(atom/movable/gone, direction) if(gone == holstered) diff --git a/code/modules/mod/modules/modules_supply.dm b/code/modules/mod/modules/modules_supply.dm index 4ba54760aca..5fe7529f270 100644 --- a/code/modules/mod/modules/modules_supply.dm +++ b/code/modules/mod/modules/modules_supply.dm @@ -47,7 +47,6 @@ /// The crates stored in the module. var/list/stored_crates = list() - /obj/item/mod/module/clamp/Initialize(mapload) . = ..() accepted_items = typecacheof(list( @@ -125,55 +124,110 @@ ///Drill - Lets you dig through rock and basalt. /obj/item/mod/module/drill name = "MOD drill module" - desc = "An integrated drill, typically extending over the user's hand. While useful for drilling through rock, \ - your drill is surely the one that both pierces and creates the heavens." + desc = "An arm-mounted drill, typically extending over the user's hand. While useful for drilling through rock, \ + your drill is surely the one that both pierces and creates the heavens. Integrates with mining MODs' sphere \ + transformation module, changing it from a mere traversal tool to high-powered excavation unit." icon_state = "drill" module_type = MODULE_ACTIVE complexity = 1 use_energy_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/drill) - cooldown_time = 0.5 SECONDS + cooldown_time = 0.2 SECONDS overlay_state_active = "module_drill" required_slots = list(ITEM_SLOT_GLOVES) + toolspeed = 0.25 + /// Are we currently in passive sphere mode? + var/ballin = FALSE + /// Last tick when we bumpmined. Prevents diagonal bumpnining being thrice as fast as normal + var/last_bumpmine_tick = -1 + /// Mining skill experience multiplier for bumpmining + var/exp_multiplier = 1 + /// Cooldown on gibtonite detonation warnings + COOLDOWN_DECLARE(gibtonite_warning_cd) + +/obj/item/mod/module/drill/on_install() + . = ..() + RegisterSignal(mod, COMSIG_MOD_MODULE_ACTIVATED, PROC_REF(on_module_activated)) + RegisterSignal(mod, COMSIG_MOD_MODULE_DEACTIVATED, PROC_REF(on_module_deactivated)) + +/obj/item/mod/module/drill/on_uninstall(deleting) + . = ..() + UnregisterSignal(mod, list(COMSIG_MOD_MODULE_ACTIVATED, COMSIG_MOD_MODULE_DEACTIVATED)) + toolspeed = initial(toolspeed) + use_energy_cost = initial(use_energy_cost) + exp_multiplier = initial(exp_multiplier) + ballin = FALSE /obj/item/mod/module/drill/on_activation(mob/activator) + if (ballin) + return + tool_behaviour = TOOL_MINING RegisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP, PROC_REF(bump_mine)) /obj/item/mod/module/drill/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) + if (ballin) + return + tool_behaviour = NONE UnregisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP) /obj/item/mod/module/drill/on_select_use(atom/target) . = ..() - if(!.) + if(!. || !mod.wearer.Adjacent(target)) return - if(!mod.wearer.Adjacent(target)) + + if(!ismineralturf(target) || !isasteroidturf(target)) return - if(ismineralturf(target)) - var/turf/closed/mineral/mineral_turf = target - mineral_turf.gets_drilled(mod.wearer) - drain_power(use_energy_cost) - else if(isasteroidturf(target)) - var/turf/open/misc/asteroid/sand_turf = target - if(!sand_turf.can_dig(mod.wearer)) - return - sand_turf.getDug() - drain_power(use_energy_cost) + + if(drain_power(use_energy_cost)) + target.attackby(src, mod.wearer) /obj/item/mod/module/drill/proc/bump_mine(mob/living/carbon/human/bumper, atom/bumped_into, proximity) SIGNAL_HANDLER - if(!ismineralturf(bumped_into) || !drain_power(use_energy_cost)) - return - var/turf/closed/mineral/mineral_turf = bumped_into - var/turf/closed/mineral/gibtonite/giberal_turf = mineral_turf - if(istype(giberal_turf) && giberal_turf.stage != GIBTONITE_UNSTRUCK) - playsound(bumper, 'sound/machines/scanner/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) - to_chat(bumper, span_warning("[icon2html(src, bumper)] Unstable gibtonite ore deposit detected! Drills disabled.")) - on_deactivation() - return - mineral_turf.gets_drilled(mod.wearer) - return COMPONENT_CANCEL_ATTACK_CHAIN -///Ore Bag - Lets you pick up ores and drop them from the suit. + if (world.time == last_bumpmine_tick) + return + + if (!ismineralturf(bumped_into) || !drain_power(use_energy_cost)) + return + + var/turf/closed/mineral/gibtonite/giberal_turf = bumped_into + if (!istype(giberal_turf) || giberal_turf.stage != GIBTONITE_UNSTRUCK) + last_bumpmine_tick = world.time + var/turf/closed/mineral/rock = bumped_into + INVOKE_ASYNC(rock, TYPE_PROC_REF(/atom, attackby), src, bumper, null, null, exp_multiplier) + return + + if (!COOLDOWN_FINISHED(src, gibtonite_warning_cd)) + return + + COOLDOWN_START(src, gibtonite_warning_cd, 3 SECONDS) + playsound(bumper, 'sound/machines/scanner/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + to_chat(bumper, span_warning("[icon2html(src, bumper)] Unstable gibtonite ore deposit detected!")) + +/obj/item/mod/module/drill/proc/on_module_activated(datum/source, obj/item/mod/module/module) + SIGNAL_HANDLER + if (!istype(module, /obj/item/mod/module/sphere_transform)) + return + // In sphere mode we get instamine and halved power drain + toolspeed = 0 + use_energy_cost *= 0.5 + exp_multiplier *= 0.2 + if (!active) + on_activation() + ballin = TRUE + +/obj/item/mod/module/drill/proc/on_module_deactivated(datum/source, obj/item/mod/module/module) + SIGNAL_HANDLER + if (!istype(module, /obj/item/mod/module/sphere_transform)) + return + toolspeed = initial(toolspeed) + use_energy_cost *= 2 + exp_multiplier /= 2 + ballin = FALSE + if (!active) + on_deactivation() + +/// Ore Bag - Lets you pick up ores and drop them from the suit. /obj/item/mod/module/orebag name = "MOD ore bag module" desc = "An integrated ore storage system installed into the suit, \ @@ -187,8 +241,6 @@ cooldown_time = 0.5 SECONDS allow_flags = MODULE_ALLOW_INACTIVE required_slots = list(ITEM_SLOT_BACK) - /// The ores stored in the bag. - var/list/ores = list() /obj/item/mod/module/orebag/on_equip() RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, PROC_REF(ore_pickup)) @@ -204,20 +256,17 @@ playsound(src, SFX_RUSTLE, 50, TRUE) /obj/item/mod/module/orebag/proc/move_ore(obj/item/stack/ore) - for(var/obj/item/stack/stored_ore as anything in ores) + for(var/obj/item/stack/ore/stored_ore as anything in src) if(!ore.can_merge(stored_ore)) continue ore.merge(stored_ore) if(QDELETED(ore)) return - break ore.forceMove(src) - ores += ore /obj/item/mod/module/orebag/on_use(mob/activator) - for(var/obj/item/ore as anything in ores) - ore.forceMove(drop_location()) - ores -= ore + for(var/obj/item/ore as anything in src) + ore.forceMove(mod.drop_location()) drain_power(use_energy_cost) /obj/item/mod/module/hydraulic @@ -381,18 +430,18 @@ /// Armor values per tile. var/datum/armor/armor_mod = /datum/armor/mod_ash_accretion /// Speed added when you're fully covered in ash. - var/speed_added = -0.75 + var/speed_added = -0.5 /// Turfs that let us accrete ash. var/static/list/accretion_turfs /// Turfs that let us keep ash. var/static/list/keep_turfs /datum/armor/mod_ash_accretion - melee = 4 + melee = 3 // 50 armor when fully covered in ash, equal to two plates on an explorer suit bullet = 1 laser = 2 energy = 2 - bomb = 4 + bomb = 3 /obj/item/mod/module/ash_accretion/Initialize(mapload) . = ..() @@ -446,32 +495,44 @@ /obj/item/mod/module/ash_accretion/proc/on_move(atom/source, atom/oldloc, dir, forced) if(!isturf(mod.wearer.loc)) //dont lose ash from going in a locker return - if(traveled_tiles) //leave ash every tile - new /obj/effect/temp_visual/light_ash(get_turf(src)) + if(is_type_in_typecache(mod.wearer.loc, accretion_turfs)) if(traveled_tiles >= max_traveled_tiles) return + traveled_tiles++ for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().add_other_armor(armor_mod)) - if(traveled_tiles >= max_traveled_tiles) - balloon_alert(mod.wearer, "fully ash covered") - mod.wearer.color = list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,3) //make them super light - animate(mod.wearer, 1 SECONDS, color = null, flags = ANIMATION_PARALLEL) - playsound(src, 'sound/effects/sparks/sparks1.ogg', 100, TRUE) - mod.update_speed() - else if(is_type_in_typecache(mod.wearer.loc, keep_turfs)) - return - else - if(traveled_tiles <= 0) + + if(traveled_tiles < max_traveled_tiles) return - traveled_tiles-- - if(traveled_tiles == max_traveled_tiles - 1) // Just lost our speed buff - mod.update_speed() - for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) - part.set_armor(part.get_armor().subtract_other_armor(armor_mod)) - if(traveled_tiles <= 0) - balloon_alert(mod.wearer, "ran out of ash!") + + balloon_alert(mod.wearer, "fully ash covered") + var/cur_color = mod.wearer.color + mod.wearer.color = list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,3) // Make them super light + animate(mod.wearer, 1 SECONDS, color = cur_color, flags = ANIMATION_PARALLEL) + playsound(src, 'sound/effects/sparks/sparks1.ogg', 100, TRUE) + mod.update_speed() + return + + if(is_type_in_typecache(mod.wearer.loc, keep_turfs)) + return + + if(traveled_tiles) //leave ash every tile + new /obj/effect/temp_visual/light_ash(get_turf(src)) + + if(traveled_tiles <= 0) + return + + traveled_tiles-- + if(traveled_tiles == max_traveled_tiles - 1) // Just lost our speed buff + mod.update_speed() + + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) + part.set_armor(part.get_armor().subtract_other_armor(armor_mod)) + + if(traveled_tiles <= 0) + balloon_alert(mod.wearer, "ran out of ash!") /obj/item/mod/module/sphere_transform name = "MOD sphere transform module" @@ -483,17 +544,60 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.5 use_energy_cost = DEFAULT_CHARGE_DRAIN * 3 incompatible_modules = list(/obj/item/mod/module/sphere_transform) - cooldown_time = 1.25 SECONDS + cooldown_time = 1 SECONDS required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK, ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING, ITEM_SLOT_GLOVES, ITEM_SLOT_FEET) /// Time it takes us to complete the animation. var/animate_time = 0.25 SECONDS + /// Armor values when active + var/datum/armor/armor_mod = /datum/armor/mod_sphere_transform /// List of traits to add/remove from our subject as needed. - var/static/list/user_traits = list( + var/list/user_traits = list( TRAIT_FORCED_STANDING, TRAIT_HANDS_BLOCKED, - TRAIT_LAVA_IMMUNE, TRAIT_NO_SLIP_ALL, ) + /// Has the module been upgraded with bileworm hide plating? + var/hide_upgrade = FALSE + /// How much hide is required to reinforce the MOD + var/hide_amount = 2 // These are rather rare as of now, should be increased later once other methods of crossing lava are removed + +/datum/armor/mod_sphere_transform + melee = 20 // Can get up to 70 armor when ash covered and ballin, which is as good as a HECK suit... but you can't really attack anymore + bomb = 20 + +/obj/item/mod/module/sphere_transform/on_install() + . = ..() + RegisterSignal(mod, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(on_item_interaction)) + +// Isn't supposed to happen outside of deletion but just in case +/obj/item/mod/module/sphere_transform/on_uninstall(deleting) + . = ..() + // No need to drop the hide as we're supposed to be inbuilt and unremovable + UnregisterSignal(mod, COMSIG_ATOM_ITEM_INTERACTION) + +/obj/item/mod/module/sphere_transform/proc/on_item_interaction(atom/movable/source, mob/living/user, obj/item/item, modifiers) + SIGNAL_HANDLER + + if(!istype(item, /obj/item/stack/sheet/animalhide/bileworm)) + return NONE + + if (hide_upgrade) + to_chat(user, span_warning("[mod] is already reinforced with bileworm skin!")) + return ITEM_INTERACT_BLOCKING + + var/obj/item/stack/sheet/animalhide/bileworm/hide = item + if (!hide.use(hide_amount)) + to_chat(user, span_warning("You need more hide to fully reinforce [mod]!")) + return ITEM_INTERACT_BLOCKING + + hide_upgrade = TRUE + overlay_state_inactive = "module_bileworm_bracing" + user_traits += TRAIT_LAVA_IMMUNE + mod.balloon_alert(user, "plating reinforced!") + if (active) + ADD_TRAIT(mod.wearer, TRAIT_LAVA_IMMUNE, REF(src)) + update_clothing_slots() + return ITEM_INTERACT_SUCCESS /obj/item/mod/module/sphere_transform/activate(mob/activator) if(!mod.wearer.has_gravity()) @@ -507,13 +611,15 @@ mod.wearer.add_filter("mod_blur", 2, angular_blur_filter(size = 15)) mod.wearer.add_filter("mod_outline", 3, outline_filter(color = "#000000AA")) mod.wearer.add_offsets(REF(src), y_add = -4) - mod.wearer.SpinAnimation(1.5) + mod.wearer.SpinAnimation(1.5, tag = "sphere_transform") mod.wearer.add_traits(user_traits, REF(src)) mod.wearer.RemoveElement(/datum/element/footstep, FOOTSTEP_MOB_HUMAN, 1, -6) mod.wearer.AddElement(/datum/element/footstep, FOOTSTEP_OBJ_ROBOT, 1, -6, sound_vary = TRUE) mod.wearer.add_movespeed_mod_immunities(REF(src), /datum/movespeed_modifier/damage_slowdown) mod.wearer.add_movespeed_modifier(/datum/movespeed_modifier/sphere) RegisterSignal(mod.wearer, COMSIG_MOB_STATCHANGE, PROC_REF(on_statchange)) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) + part.set_armor(part.get_armor().add_other_armor(armor_mod)) /obj/item/mod/module/sphere_transform/on_deactivation(mob/activator, display_message = TRUE, deleting = FALSE) if(!deleting) @@ -522,11 +628,13 @@ addtimer(CALLBACK(mod.wearer, TYPE_PROC_REF(/datum, remove_filter), list("mod_ball", "mod_blur", "mod_outline")), animate_time) mod.wearer.remove_traits(user_traits, REF(src)) mod.wearer.remove_movespeed_mod_immunities(REF(src), /datum/movespeed_modifier/damage_slowdown) - animate(mod.wearer, time = 0) + animate(mod.wearer, tag = "sphere_transform") mod.wearer.RemoveElement(/datum/element/footstep, FOOTSTEP_OBJ_ROBOT, 1, -6, sound_vary = TRUE) mod.wearer.AddElement(/datum/element/footstep, FOOTSTEP_MOB_HUMAN, 1, -6) mod.wearer.remove_movespeed_modifier(/datum/movespeed_modifier/sphere) UnregisterSignal(mod.wearer, COMSIG_MOB_STATCHANGE) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) + part.set_armor(part.get_armor().subtract_other_armor(armor_mod)) /obj/item/mod/module/sphere_transform/used(mob/activator) if(!lavaland_equipment_pressure_check(get_turf(src))) @@ -539,7 +647,7 @@ . = ..() if(!.) return - var/obj/projectile/bomb = new /obj/projectile/bullet/mining_bomb(mod.wearer.loc) + var/obj/projectile/bullet/mining_bomb/bomb = new(mod.wearer.loc) bomb.aim_projectile(target, mod.wearer) bomb.firer = mod.wearer playsound(src, 'sound/items/weapons/gun/general/grenade_launch.ogg', 75, TRUE) @@ -547,17 +655,13 @@ drain_power(use_energy_cost) /obj/item/mod/module/sphere_transform/on_active_process(seconds_per_tick) - animate(mod.wearer) //stop the animation - mod.wearer.SpinAnimation(1.5) //start it back again if(!mod.wearer.has_gravity()) deactivate() //deactivate in no grav /obj/item/mod/module/sphere_transform/proc/on_statchange(datum/source) SIGNAL_HANDLER - - if(!mod.wearer.stat) - return - deactivate() + if(mod.wearer.stat) + deactivate() /obj/projectile/bullet/mining_bomb name = "mining bomb" @@ -596,46 +700,32 @@ light_power = 1 light_color = COLOR_LIGHT_ORANGE /// Time to prime the explosion - var/prime_time = 0.5 SECONDS + var/prime_time = 0.1 SECONDS /// Time to explode from the priming - var/explosion_time = 1 SECONDS + var/explosion_time = 0.9 SECONDS // Roughly this much until the blast part of the explosion animation /// Damage done on explosion. - var/damage = 12 + var/damage = 7 /// Damage multiplier on hostile fauna. var/fauna_boost = 4 - /// Image overlaid on explosion. - var/static/image/explosion_image - -/obj/structure/mining_bomb/Initialize(mapload, atom/movable/firer) - . = ..() - generate_image() - -/obj/structure/mining_bomb/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) - if(same_z_layer) - return ..() - explosion_image = null - generate_image() - return ..() - -/obj/structure/mining_bomb/proc/generate_image() - explosion_image = image('icons/effects/96x96.dmi', "judicial_explosion") - explosion_image.pixel_w = -32 - explosion_image.pixel_z = -32 - SET_PLANE_EXPLICIT(explosion_image, ABOVE_GAME_PLANE, src) /obj/structure/mining_bomb/proc/prime(atom/movable/firer) - add_overlay(explosion_image) + var/mutable_appearance/explosion_image = mutable_appearance('icons/effects/96x96.dmi', "judicial_explosion", FLOAT_LAYER, src, ABOVE_GAME_PLANE) + explosion_image.pixel_w = -32 + explosion_image.pixel_z = -32 + var/turf/our_loc = get_turf(src) + our_loc.flick_overlay_view(explosion_image, 1.35 SECONDS) addtimer(CALLBACK(src, PROC_REF(boom), firer), explosion_time) /obj/structure/mining_bomb/proc/boom(atom/movable/firer) visible_message(span_danger("[src] explodes!")) playsound(src, 'sound/effects/magic/magic_missile.ogg', 200, vary = TRUE) - for(var/turf/closed/mineral/rock in circle_range_turfs(src, 2)) + for(var/turf/closed/mineral/rock in circle_range_turfs(src, 1)) rock.gets_drilled() for(var/mob/living/victim in range(1, src)) if(HAS_TRAIT(victim, TRAIT_MINING_AOE_IMMUNE)) continue victim.apply_damage(damage * (ismining(victim) ? fauna_boost : 1), BRUTE, spread_damage = TRUE) + to_chat(victim, span_userdanger("You are hit by a mining bomb explosion!")) if(!firer) continue if(ishostile(victim)) diff --git a/icons/mob/clothing/modsuit/mod_modules.dmi b/icons/mob/clothing/modsuit/mod_modules.dmi index 6ec3b13ea98e23837e3116ca9eb07e97b536e3d1..8f5ccf324c98a32fdbc397c06406509ec2c552ae 100644 GIT binary patch literal 14693 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 P2t@aqp;pnAd(Zv{i5601 diff --git a/tgstation.dme b/tgstation.dme index 5cdcd23bd43..6464a108686 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1240,6 +1240,7 @@ #include "code\datums\components\pinnable_accessory.dm" #include "code\datums\components\plundering_attacks.dm" #include "code\datums\components\pricetag.dm" +#include "code\datums\components\proficient_miner.dm" #include "code\datums\components\profound_fisher.dm" #include "code\datums\components\prosthetic_item.dm" #include "code\datums\components\punchcooldown.dm" @@ -1607,7 +1608,6 @@ #include "code\datums\elements\point_of_interest.dm" #include "code\datums\elements\poster_tearer.dm" #include "code\datums\elements\prevent_attacking_of_types.dm" -#include "code\datums\elements\proficient_miner.dm" #include "code\datums\elements\projectile_drop.dm" #include "code\datums\elements\projectile_shield.dm" #include "code\datums\elements\prosthetic_icon.dm"