[MIRROR] Mining MODsuit Rework [MDB IGNORE] (#11328)

* Mining MODsuit Rework (#64688)

makes dropkey deactivate device modules
fixes speed potion being fucky
fixes doubled up balloon alerts
makes some cell code better i think
makes the gps module open the gps tgui for you, instead of putting a gps in your hand
the loader suit can now hold mailbags

Reworks the mining modsuit.
The suit is no longer cold-proof (this can be mitigated by using module space for thermal regulators)
The suit fits less modules than standard suits, but cant burn in lava.
In suit storage it can carry ore bags, resonators and kinetic crushers.
It features a storage, gps, ore bag, drill, clamp and by default comes with a plasma core, being recharged with plasma ore rather than by power cell.
Features two new modules:

Ash Accretion, it gathers dust from basalt (or snow) you walk on to create a layer of ash around the suit, acting as armor and a speed up that quickly drains when you walk on other terrain.
Sphere Transform, turns you into a fast moving ball that can travel past lava, you cannot use your hands when in this form, but you can launch aoe mining bombs to attack or mine

* Mining MODsuit Rework

Co-authored-by: Fikou <23585223+Fikou@users.noreply.github.com>
This commit is contained in:
SkyratBot
2022-02-08 01:46:15 +01:00
committed by GitHub
parent 0742a055f9
commit 3a8459a5f8
25 changed files with 453 additions and 74 deletions
+1 -1
View File
@@ -84,4 +84,4 @@
name = "Shaft Miner (Equipment + MODsuit)"
back = /obj/item/mod/control/pre_equipped/mining
suit = null
mask = /obj/item/clothing/mask/breath
mask = /obj/item/clothing/mask/gas/explorer
+1 -1
View File
@@ -29,7 +29,6 @@
new /datum/data/mining_equipment("Explorer's Webbing", /obj/item/storage/belt/mining, 500),
new /datum/data/mining_equipment("Point Transfer Card", /obj/item/card/mining_point_card, 500),
new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 500),
new /datum/data/mining_equipment("Mining MOD Plating", /obj/item/mod/construction/armor/mining, 500),
new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 600),
new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600),
new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750),
@@ -47,6 +46,7 @@
new /datum/data/mining_equipment("Super Resonator", /obj/item/resonator/upgraded, 2500),
new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 2500),
new /datum/data/mining_equipment("Ice Hiking Boots", /obj/item/clothing/shoes/winterboots/ice_boots, 2500),
new /datum/data/mining_equipment("Mining MODsuit", /obj/item/mod/control/pre_equipped/mining, 2500),
new /datum/data/mining_equipment("Luxury Shelter Capsule", /obj/item/survivalcapsule/luxury, 3000),
new /datum/data/mining_equipment("Luxury Bar Capsule", /obj/item/survivalcapsule/luxuryelite, 10000),
new /datum/data/mining_equipment("Nanotrasen Minebot", /mob/living/simple_animal/hostile/mining_drone, 800),
-3
View File
@@ -160,9 +160,6 @@
. = ..()
if(!.)
return
var/obj/item/mod/control/mod = target
if(!mod.active)
mod.balloon_alert(usr, "suit not on!")
module.on_select()
/datum/action/item_action/mod/pinned_module/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force)
+1 -4
View File
@@ -70,9 +70,6 @@
/obj/item/mod/construction/armor/atmospheric
theme = /datum/mod_theme/atmospheric
/obj/item/mod/construction/armor/mining
theme = /datum/mod_theme/mining
/obj/item/mod/construction/armor/medical
theme = /datum/mod_theme/medical
@@ -85,7 +82,7 @@
/obj/item/mod/paint
name = "MOD paint kit"
desc = "This kit will repaint your MODsuit to something unique."
icon = 'icons/obj/clothing/modsuit/mod_modules.dmi'
icon = 'icons/obj/clothing/modsuit/mod_construction.dmi'
icon_state = "paintkit"
#define START_STEP "start"
+8 -9
View File
@@ -3,7 +3,6 @@
name = "Base MOD"
desc = "You should not see this, yell at a coder!"
icon = 'icons/obj/clothing/modsuit/mod_clothing.dmi'
icon_state = "standard-control"
worn_icon = 'icons/mob/clothing/mod.dmi'
/obj/item/mod/control
@@ -30,7 +29,7 @@
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
permeability_coefficient = 0.01
siemens_coefficient = 0.5
alternate_worn_layer = BODY_FRONT_LAYER
alternate_worn_layer = HANDS_LAYER+0.1 //we want it to go above generally everything, but not hands
/// The MOD's theme, decides on some stuff like armor and statistics.
var/datum/mod_theme/theme = /datum/mod_theme
/// Looks of the MOD.
@@ -114,7 +113,7 @@
mod_parts += helmet
chestplate = new /obj/item/clothing/suit/mod(src)
chestplate.mod = src
chestplate.allowed = theme.allowed.Copy()
chestplate.allowed = theme.allowed_suit_storage.Copy()
mod_parts += chestplate
gauntlets = new /obj/item/clothing/gloves/mod(src)
gauntlets.mod = src
@@ -537,7 +536,7 @@
return FALSE
do_sparks(5, TRUE, src)
var/check_range = TRUE
return electrocute_mob(user, get_charge_source(), src, 0.7, check_range)
return electrocute_mob(user, get_cell(), src, 0.7, check_range)
/obj/item/mod/control/proc/install(module, mob/user)
var/obj/item/mod/module/new_module = module
@@ -657,8 +656,8 @@
SIGNAL_HANDLER
update_charge_alert()
var/obj/item/stock_parts/cell/cell = get_charge_source()
if(!istype(cell))
var/obj/item/stock_parts/cell/cell = get_cell()
if(!cell)
return
cell.give(amount)
@@ -667,10 +666,10 @@
if(slowdown_inactive <= 0)
to_chat(user, span_warning("[src] has already been coated with red, that's as fast as it'll go!"))
return
return SPEED_POTION_STOP
if(wearer)
to_chat(user, span_warning("It's too dangerous to smear [speed_potion] on [src] while it's on someone!"))
return
return SPEED_POTION_STOP
to_chat(user, span_notice("You slather the red gunk over [src], making it faster."))
var/list/all_parts = mod_parts.Copy() + src
for(var/obj/item/part as anything in all_parts)
@@ -680,4 +679,4 @@
slowdown_active = 0
update_speed()
qdel(speed_potion)
return SPEED_POTION_SUCCESSFUL
return SPEED_POTION_STOP
+84 -13
View File
@@ -41,6 +41,27 @@
/obj/item/mod/core/proc/update_charge_alert()
mod.wearer.clear_alert("mod_charge")
/obj/item/mod/core/infinite
name = "MOD infinite core"
icon_state = "mod-core-infinite"
desc = "A fusion core using the rare Fixium to sustain enough energy for the lifetime of the MOD's user. \
This might be because of the slowly killing poison inside, but those are just rumors."
/obj/item/mod/core/infinite/charge_source()
return src
/obj/item/mod/core/infinite/charge_amount()
return INFINITY
/obj/item/mod/core/infinite/max_charge_amount()
return INFINITY
/obj/item/mod/core/infinite/add_charge(amount)
return TRUE
/obj/item/mod/core/infinite/subtract_charge(amount)
return TRUE
/obj/item/mod/core/standard
name = "MOD standard core"
icon_state = "mod-core-standard"
@@ -68,7 +89,6 @@
/obj/item/mod/core/standard/uninstall()
if(!QDELETED(cell))
cell.forceMove(drop_location())
uninstall_cell()
UnregisterSignal(mod, list(COMSIG_PARENT_EXAMINE, COMSIG_ATOM_ATTACK_HAND, COMSIG_PARENT_ATTACKBY))
return ..()
@@ -224,23 +244,74 @@
return
mod.wearer.throw_alert("mod_charge", /atom/movable/screen/alert/nocell)
/obj/item/mod/core/infinite
name = "MOD infinite core"
icon_state = "mod-core-infinite"
desc = "A fusion core using the rare palladium to sustain enough energy for the lifetime of the MOD's user. \
This might be because of the slowly killing poison inside, but those are just rumors."
/obj/item/mod/core/plasma
name = "MOD plasma core"
icon_state = "mod-core-plasma"
desc = "Nanotrasen's attempt at capitalizing on their plasma research. These plasma cores are refueled \
through plasma ore, allowing for easy continued use by their mining squads."
/// How much charge we can store.
var/maxcharge = 10000
/// How much charge we are currently storing.
var/charge = 10000
/// Charge per plasma ore.
var/charge_given = 1500
/obj/item/mod/core/infinite/charge_source()
/obj/item/mod/core/plasma/install(obj/item/mod/control/mod_unit)
. = ..()
RegisterSignal(mod, COMSIG_PARENT_ATTACKBY, .proc/on_attackby)
/obj/item/mod/core/plasma/uninstall()
UnregisterSignal(mod, COMSIG_PARENT_ATTACKBY)
return ..()
/obj/item/mod/core/plasma/attackby(obj/item/attacking_item, mob/user, params)
if(charge_plasma(attacking_item, user))
return TRUE
return ..()
/obj/item/mod/core/plasma/charge_source()
return src
/obj/item/mod/core/infinite/charge_amount()
return INFINITY
/obj/item/mod/core/plasma/charge_amount()
return charge
/obj/item/mod/core/infinite/max_charge_amount()
return INFINITY
/obj/item/mod/core/plasma/max_charge_amount()
return maxcharge
/obj/item/mod/core/infinite/add_charge(amount)
/obj/item/mod/core/plasma/add_charge(amount)
charge = min(maxcharge, charge + amount)
return TRUE
/obj/item/mod/core/infinite/subtract_charge(amount)
/obj/item/mod/core/plasma/subtract_charge(amount)
charge = max(0, charge - amount)
return TRUE
/obj/item/mod/core/plasma/update_charge_alert()
var/remaining_plasma = charge_amount() / max_charge_amount()
switch(remaining_plasma)
if(0.75 to INFINITY)
mod.wearer.clear_alert("mod_charge")
if(0.5 to 0.75)
mod.wearer.throw_alert("mod_charge", /atom/movable/screen/alert/lowcell/plasma, 1)
if(0.25 to 0.5)
mod.wearer.throw_alert("mod_charge", /atom/movable/screen/alert/lowcell/plasma, 2)
if(0.01 to 0.25)
mod.wearer.throw_alert("mod_charge", /atom/movable/screen/alert/lowcell/plasma, 3)
else
mod.wearer.throw_alert("mod_charge", /atom/movable/screen/alert/emptycell/plasma)
/obj/item/mod/core/plasma/proc/on_attackby(datum/source, obj/item/attacking_item, mob/user)
SIGNAL_HANDLER
if(charge_plasma(attacking_item, user))
return COMPONENT_NO_AFTERATTACK
return NONE
/obj/item/mod/core/plasma/proc/charge_plasma(obj/item/attacking_item, mob/user)
if(!istype(attacking_item, /obj/item/stack/ore/plasma))
return FALSE
if(!attacking_item.use(1))
return FALSE
add_charge(charge_given)
balloon_alert(user, "core refueled")
return TRUE
+46 -9
View File
@@ -44,7 +44,7 @@
/// Theme used by the MOD TGUI.
var/ui_theme = "ntos"
/// Allowed items in the chestplate's suit storage.
var/list/allowed = list(/obj/item/flashlight, /obj/item/tank/internals)
var/list/allowed_suit_storage = list(/obj/item/flashlight, /obj/item/tank/internals)
/// List of inbuilt modules. These are different from the pre-equipped suits, you should mainly use these for unremovable modules with 0 complexity.
var/list/inbuilt_modules = list()
/// Modules blacklisted from the MOD.
@@ -224,22 +224,58 @@
/datum/mod_theme/mining
name = "mining"
desc = "A high-power Nanotrasen mining suit, supporting more complexity at a bigger drain."
desc = "A Nanotrasen mining suit for on-site operations, fit with accreting ash armor and a sphere form."
extended_desc = "A high-powered Nanotrasen-designed suit, based off the work of Nakamura Engineering. \
While initial designs were built for the rigors of asteroid mining, given blast resistance through inbuilt ceramics, \
mining teams have since heavily tweaked the suit themselves. Aftermarket armor plating has been added, \
giving way to incredible protection against corrosives and thermal protection good enough for volcanic environments. \
The systems have been upgraded as well, giving space for further modification down the line. \
However, all of this has proven to be straining on the power and the actuators of the suit, \
making it demand more power in exchange."
mining teams have since heavily tweaked the suit themselves with assistance from devices crafted by \
destructive analysis of unknown technologies discovered on the Indecipheres mining sites, patterned off \
their typical non-EVA exploration suits. The visor has been expanded to a system of seven arachnid-like cameras, \
offering full view of the land and its soon-to-be-dead inhabitants. The armor plating has been trimmed down to \
the bare essentials, geared far more for environmental hazards than combat against fauna; however, \
this gives way to incredible protection against corrosives and thermal protection good enough for \
both casual backstroking through molten magma and romantic walks through arctic terrain. \
Instead, the suit is capable of using its' anomalous properties to attract and \
carefully distribute layers of ash or ice across the surface; these layers are ablative, but incredibly strong. \
Lastly, the suit is capable of compressing and shrinking the mass of the wearer, as well as \
rearranging its own constitution, to allow them to fit upright in a sphere form that can \
roll around at half their original size; leaving high-powered mining ordinance in its wake. \
However, all of this has proven to be straining on all Nanotrasen-approved cells, \
so much so that it comes default fueled by equally-enigmatic plasma fuel rather than a simple recharge. \
Additionally, the systems have been put to near their maximum load, allowing for far less customization than others."
default_skin = "mining"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, FIRE = 100, ACID = 75, WOUND = 15)
resistance_flags = FIRE_PROOF
resistance_flags = FIRE_PROOF|LAVA_PROOF
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
complexity_max = DEFAULT_MAX_COMPLEXITY + 5
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
complexity_max = DEFAULT_MAX_COMPLEXITY - 5
charge_drain = DEFAULT_CHARGE_DRAIN * 2
allowed_suit_storage = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/storage/bag/ore, /obj/item/kinetic_crusher, /obj/item/resonator)
inbuilt_modules = list(/obj/item/mod/module/ash_accretion, /obj/item/mod/module/sphere_transform)
skins = list(
"mining" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT,
SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE,
UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR,
SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT,
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
),
CHESTPLATE_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
SEALED_INVISIBILITY = HIDEJUMPSUIT,
),
GAUNTLETS_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
),
BOOTS_FLAGS = list(
UNSEALED_CLOTHING = THICKMATERIAL,
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
),
),
"asteroid" = list(
HELMET_LAYER = null,
HELMET_FLAGS = list(
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
@@ -285,6 +321,7 @@
complexity_max = DEFAULT_MAX_COMPLEXITY - 5
slowdown_inactive = 0.5
slowdown_active = 0
allowed_suit_storage = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/storage/bag/mail)
inbuilt_modules = list(/obj/item/mod/module/hydraulic, /obj/item/mod/module/clamp/loader, /obj/item/mod/module/magnet)
skins = list(
"loader" = list(
+4 -5
View File
@@ -64,13 +64,12 @@
/obj/item/mod/control/pre_equipped/mining
theme = /datum/mod_theme/mining
applied_cell = /obj/item/stock_parts/cell/high/plus
applied_core = /obj/item/mod/core/plasma
initial_modules = list(
/obj/item/mod/module/storage/large_capacity,
/obj/item/mod/module/welding,
/obj/item/mod/module/storage,
/obj/item/mod/module/gps,
/obj/item/mod/module/orebag,
/obj/item/mod/module/flashlight,
/obj/item/mod/module/magboot,
/obj/item/mod/module/clamp,
/obj/item/mod/module/drill,
)
+13 -3
View File
@@ -96,7 +96,7 @@
return
if(module_type != MODULE_USABLE)
if(active)
on_deactivation(display_message = TRUE)
on_deactivation()
else
on_activation()
else
@@ -125,6 +125,7 @@
if(mod.wearer.put_in_hands(device))
balloon_alert(mod.wearer, "[device] extended")
RegisterSignal(mod.wearer, COMSIG_ATOM_EXITED, .proc/on_exit)
RegisterSignal(mod.wearer, COMSIG_KB_MOB_DROPITEM_DOWN, .proc/dropkey)
else
balloon_alert(mod.wearer, "can't extend [device]!")
mod.wearer.transferItemToLoc(device, src, force = TRUE)
@@ -149,6 +150,7 @@
if(device)
mod.wearer.transferItemToLoc(device, src, force = TRUE)
UnregisterSignal(mod.wearer, COMSIG_ATOM_EXITED)
UnregisterSignal(mod.wearer, COMSIG_KB_MOB_DROPITEM_DOWN)
else
UnregisterSignal(mod.wearer, used_signal)
used_signal = null
@@ -195,7 +197,7 @@
/obj/item/mod/module/proc/on_process(delta_time)
if(active)
if(!drain_power(active_power_cost * delta_time))
on_deactivation(display_message = TRUE)
on_deactivation()
return FALSE
on_active_process(delta_time)
else
@@ -247,7 +249,7 @@
if(part.loc == mod.wearer)
return
if(part == device)
on_deactivation(display_message = TRUE)
on_deactivation(display_message = FALSE)
/// Called when the device gets deleted on active modules
/obj/item/mod/module/proc/on_device_deletion(datum/source)
@@ -296,6 +298,14 @@
action = new(mod, src, user)
action.Grant(user)
/// On drop key, concels a device item.
/obj/item/mod/module/proc/dropkey(mob/living/user)
SIGNAL_HANDLER
if(user.get_active_held_item() != device)
return
on_deactivation()
///Anomaly Locked - Causes the module to not function without an anomaly.
/obj/item/mod/module/anomaly_locked
name = "MOD anomaly locked module"
@@ -112,7 +112,6 @@
name = "tether"
icon_state = "tether_projectile"
icon = 'icons/obj/clothing/modsuit/mod_modules.dmi'
pass_flags = PASSTABLE
damage = 0
nodamage = TRUE
range = 10
+267 -9
View File
@@ -7,18 +7,21 @@
down to the exact coordinates. This information is fed to a central database viewable from the device itself, \
though using it to help people is up to you."
icon_state = "gps"
module_type = MODULE_ACTIVE
module_type = MODULE_USABLE
complexity = 1
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
device = /obj/item/gps/mod
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
incompatible_modules = list(/obj/item/mod/module/gps)
cooldown_time = 0.5 SECONDS
/obj/item/gps/mod
name = "MOD internal GPS"
desc = "Common Nanotrasen technology that calcaulates the user's position from anywhere in space, down to their coordinates."
icon_state = "gps-b"
gpstag = "MOD0"
/obj/item/mod/module/gps/Initialize(mapload)
. = ..()
AddComponent(/datum/component/gps/item, "MOD0", state = GLOB.deep_inventory_state, overlay_state = FALSE)
/obj/item/mod/module/gps/on_use()
. = ..()
if(!.)
return
attack_self(mod.wearer)
///Hydraulic Clamp - Lets you pick up and drop crates.
/obj/item/mod/module/clamp
@@ -103,6 +106,7 @@
use_power_cost = DEFAULT_CHARGE_DRAIN
incompatible_modules = list(/obj/item/mod/module/drill)
cooldown_time = 0.5 SECONDS
overlay_state_active = "module_drill"
/obj/item/mod/module/drill/on_activation()
. = ..()
@@ -149,7 +153,7 @@
It's recommended by Nakamura Engineering to actually deposit that ore at local refineries."
icon_state = "ore"
module_type = MODULE_USABLE
complexity = 2
complexity = 1
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
incompatible_modules = list(/obj/item/mod/module/orebag)
cooldown_time = 0.5 SECONDS
@@ -337,3 +341,257 @@
locker.strong_grab = FALSE
UnregisterSignal(locker, COMSIG_ATOM_NO_LONGER_PULLED)
/obj/item/mod/module/ash_accretion
name = "MOD ash accretion module"
desc = "A module that collects ash from the terrain, covering the suit in a protective layer, this layer is \
lost when moving across standard terrain."
icon_state = "ash_accretion"
removable = FALSE
incompatible_modules = list(/obj/item/mod/module/ash_accretion)
overlay_state_inactive = "module_ash"
/// How many tiles we can travel to max out the armor.
var/max_traveled_tiles = 10
/// How many tiles we traveled through.
var/traveled_tiles = 0
/// Armor values per tile.
var/list/armor_values = list(MELEE = 5.5, BULLET = 1.5, LASER = 2, ENERGY = 2.5, BOMB = 2.5)
/// Speed added when you're fully covered in ash.
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
/obj/item/mod/module/ash_accretion/Initialize(mapload)
. = ..()
if(!accretion_turfs)
accretion_turfs = typecacheof(list(
/turf/open/floor/plating/asteroid,
/turf/open/floor/plating/ashplanet,
/turf/open/floor/plating/dirt,
))
if(!keep_turfs)
keep_turfs = typecacheof(list(
/turf/open/floor/plating/grass,
/turf/open/floor/plating/snowed,
/turf/open/floor/plating/sandy_dirt,
/turf/open/floor/plating/ironsand,
/turf/open/floor/plating/ice,
/turf/open/indestructible/hierophant,
/turf/open/indestructible/boss,
/turf/open/indestructible/necropolis,
/turf/open/lava,
/turf/open/water,
))
/obj/item/mod/module/ash_accretion/on_suit_activation()
ADD_TRAIT(mod.wearer, TRAIT_ASHSTORM_IMMUNE, MOD_TRAIT)
ADD_TRAIT(mod.wearer, TRAIT_SNOWSTORM_IMMUNE, MOD_TRAIT)
RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, .proc/on_move)
/obj/item/mod/module/ash_accretion/on_suit_deactivation()
REMOVE_TRAIT(mod.wearer, TRAIT_ASHSTORM_IMMUNE, MOD_TRAIT)
REMOVE_TRAIT(mod.wearer, TRAIT_SNOWSTORM_IMMUNE, MOD_TRAIT)
UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED)
if(!traveled_tiles)
return
var/list/parts = mod.mod_parts + mod
var/list/removed_armor = armor_values.Copy()
for(var/armor_type in removed_armor)
removed_armor[armor_type] = -removed_armor[armor_type] * traveled_tiles
for(var/obj/item/part as anything in parts)
part.armor = part.armor.modifyRating(arglist(removed_armor))
if(traveled_tiles == max_traveled_tiles)
mod.slowdown += speed_added
mod.wearer.update_equipment_speed_mods()
traveled_tiles = 0
/obj/item/mod/module/ash_accretion/generate_worn_overlay(mutable_appearance/standing)
overlay_state_inactive = "[initial(overlay_state_inactive)]-[mod.skin]"
return ..()
/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++
var/list/parts = mod.mod_parts + mod
for(var/obj/item/part as anything in parts)
part.armor = part.armor.modifyRating(arglist(armor_values))
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/sparks1.ogg', 100, TRUE)
mod.slowdown -= speed_added
mod.wearer.update_equipment_speed_mods()
else if(is_type_in_typecache(mod.wearer.loc, keep_turfs))
return
else
if(traveled_tiles <= 0)
return
if(traveled_tiles == max_traveled_tiles)
mod.slowdown += speed_added
mod.wearer.update_equipment_speed_mods()
traveled_tiles--
var/list/parts = mod.mod_parts + mod
var/list/removed_armor = armor_values.Copy()
for(var/armor_type in removed_armor)
removed_armor[armor_type] = -removed_armor[armor_type]
for(var/obj/item/part as anything in parts)
part.armor = part.armor.modifyRating(arglist(removed_armor))
if(traveled_tiles <= 0)
balloon_alert(mod.wearer, "ran out of ash!")
/obj/item/mod/module/sphere_transform
name = "MOD sphere transform module"
desc = "A module able to move the suit's parts around, turning it and the user into a sphere. \
The sphere can move quickly, even through lava, and launch mining bombs to decimate terrain."
icon_state = "sphere"
module_type = MODULE_ACTIVE
removable = FALSE
active_power_cost = DEFAULT_CHARGE_DRAIN*0.5
use_power_cost = DEFAULT_CHARGE_DRAIN*3
incompatible_modules = list(/obj/item/mod/module/sphere_transform)
cooldown_time = 1.25 SECONDS
/// Time it takes us to complete the animation.
var/animate_time = 0.25 SECONDS
/obj/item/mod/module/sphere_transform/on_activation()
. = ..()
if(!.)
return
playsound(src, 'sound/items/modsuit/ballin.ogg', 100)
mod.wearer.add_filter("mod_ball", 1, alpha_mask_filter(icon = icon('icons/mob/clothing/mod.dmi', "ball_mask"), flags = MASK_INVERSE))
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.base_pixel_y -= 4
animate(mod.wearer, animate_time, pixel_y = mod.wearer.base_pixel_y, flags = ANIMATION_PARALLEL)
mod.wearer.SpinAnimation(1.5)
ADD_TRAIT(mod.wearer, TRAIT_LAVA_IMMUNE, MOD_TRAIT)
ADD_TRAIT(mod.wearer, TRAIT_HANDS_BLOCKED, MOD_TRAIT)
ADD_TRAIT(mod.wearer, TRAIT_FORCED_STANDING, MOD_TRAIT)
ADD_TRAIT(mod.wearer, TRAIT_NOSLIPALL, MOD_TRAIT)
mod.wearer.add_movespeed_mod_immunities(MOD_TRAIT, /datum/movespeed_modifier/turf_slowdown)
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_modifier(/datum/movespeed_modifier/sphere)
RegisterSignal(mod.wearer, COMSIG_MOB_STATCHANGE, .proc/on_statchange)
/obj/item/mod/module/sphere_transform/on_deactivation(display_message = TRUE)
. = ..()
if(!.)
return
playsound(src, 'sound/items/modsuit/ballout.ogg', 100)
mod.wearer.base_pixel_y = 0
animate(mod.wearer, animate_time, pixel_y = mod.wearer.base_pixel_y)
addtimer(CALLBACK(mod.wearer, /atom.proc/remove_filter, list("mod_ball", "mod_blur", "mod_outline")), animate_time)
REMOVE_TRAIT(mod.wearer, TRAIT_LAVA_IMMUNE, MOD_TRAIT)
REMOVE_TRAIT(mod.wearer, TRAIT_HANDS_BLOCKED, MOD_TRAIT)
REMOVE_TRAIT(mod.wearer, TRAIT_FORCED_STANDING, MOD_TRAIT)
REMOVE_TRAIT(mod.wearer, TRAIT_NOSLIPALL, MOD_TRAIT)
mod.wearer.remove_movespeed_mod_immunities(MOD_TRAIT, /datum/movespeed_modifier/damage_slowdown)
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)
/obj/item/mod/module/sphere_transform/on_use()
if(!lavaland_equipment_pressure_check(get_turf(src)))
balloon_alert(mod.wearer, "too much pressure!")
playsound(src, 'sound/weapons/gun/general/dry_fire.ogg', 25, TRUE)
return FALSE
return ..()
/obj/item/mod/module/sphere_transform/on_select_use(atom/target)
. = ..()
if(!.)
return
var/obj/projectile/bomb = new /obj/projectile/bullet/reusable/mining_bomb(mod.wearer.loc)
bomb.preparePixelProjectile(target, mod.wearer)
bomb.firer = mod.wearer
playsound(src, 'sound/weapons/gun/general/grenade_launch.ogg', 75, TRUE)
INVOKE_ASYNC(bomb, /obj/projectile.proc/fire)
drain_power(use_power_cost)
/obj/item/mod/module/sphere_transform/on_active_process(delta_time)
animate(mod.wearer) //stop the animation
mod.wearer.SpinAnimation(1.5) //start it back again
if(!mod.wearer.has_gravity())
on_deactivation() //deactivate in no grav
/obj/item/mod/module/sphere_transform/proc/on_statchange(datum/source)
SIGNAL_HANDLER
if(!mod.wearer.stat)
return
on_deactivation()
/obj/projectile/bullet/reusable/mining_bomb
name = "mining bomb"
desc = "A bomb. Why are you examining this?"
icon_state = "mine_bomb"
icon = 'icons/obj/clothing/modsuit/mod_modules.dmi'
damage = 0
nodamage = TRUE
range = 6
suppressed = SUPPRESSED_VERY
flag = BOMB
light_system = MOVABLE_LIGHT
light_range = 1
light_power = 1
light_color = COLOR_LIGHT_ORANGE
ammo_type = /obj/structure/mining_bomb
/obj/structure/mining_bomb
name = "mining bomb"
desc = "A bomb. Why are you examining this?"
icon_state = "mine_bomb"
icon = 'icons/obj/clothing/modsuit/mod_modules.dmi'
anchored = TRUE
resistance_flags = FIRE_PROOF|LAVA_PROOF
light_system = MOVABLE_LIGHT
light_range = 1
light_power = 1
light_color = COLOR_LIGHT_ORANGE
/// Time to prime the explosion
var/prime_time = 0.5 SECONDS
/// Time to explode from the priming
var/explosion_time = 1 SECONDS
/// Damage done on explosion.
var/damage = 15
/// Damage multiplier on hostile fauna.
var/fauna_boost = 4
/// Damage multiplier on objects
var/object_boost = 2
/// Image overlaid on explosion.
var/static/image/explosion_image
/obj/structure/mining_bomb/Initialize(mapload)
. = ..()
if(!explosion_image)
explosion_image = image('icons/effects/96x96.dmi', "judicial_explosion")
explosion_image.pixel_x = -32
explosion_image.pixel_y = -32
explosion_image.plane = ABOVE_GAME_PLANE
addtimer(CALLBACK(src, .proc/prime), prime_time)
/obj/structure/mining_bomb/proc/prime()
add_overlay(explosion_image)
addtimer(CALLBACK(src, .proc/boom), explosion_time)
/obj/structure/mining_bomb/proc/boom()
visible_message(span_danger("[src] explodes!"))
playsound(src, 'sound/magic/magic_missile.ogg', 200, vary = TRUE)
for(var/turf/closed/mineral/rock in circle_range_turfs(src, 2))
rock.gets_drilled()
for(var/mob/living/mob in range(1, src))
mob.apply_damage(12 * (ishostile(mob) ? fauna_boost : 1), BRUTE, spread_damage = TRUE)
for(var/obj/object in range(1, src))
object.take_damage(damage * object_boost, BRUTE, BOMB)
qdel(src)
@@ -13,3 +13,6 @@
/datum/movespeed_modifier/berserk
multiplicative_slowdown = -0.2
/datum/movespeed_modifier/sphere
multiplicative_slowdown = -0.5
@@ -888,7 +888,7 @@
if(!istype(C))
to_chat(user, span_warning("The potion can only be used on objects!"))
return
if(SEND_SIGNAL(C, COMSIG_SPEED_POTION_APPLIED, src, user) & SPEED_POTION_SUCCESSFUL)
if(SEND_SIGNAL(C, COMSIG_SPEED_POTION_APPLIED, src, user) & SPEED_POTION_STOP)
return
if(isitem(C))
var/obj/item/I = C