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 6ec3b13ea98..8f5ccf324c9 100644 Binary files a/icons/mob/clothing/modsuit/mod_modules.dmi and b/icons/mob/clothing/modsuit/mod_modules.dmi differ 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"