mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-25 16:45:42 +00:00
tweaks the colors on the security modsuit to be lighter, i think i did that on the original pr but it got reverted due to merge conflicts makes the standard quick carry module have nitrile level carrying instead of latex level environmental bodybags are now always pressurized adds medical and security hardlight bags, which are environmental bags you can use to move people through space, security ones can be sinched to prevent escape adds a medical version of the prisoner capture module, for patient transport, prisoner capture and patient transport now use the medical/security holobags, medical one deploying them faster. when you move too far out of range the holobag dissipates adds a defibrillator module, extends shock paddles adds a thread ripper module, this module temporarily rips away the matter of clothing, to allow stuff like injections, surgery, defibrillation etc through it adds a surgery processor module, essentially a portable surgery computer like borgs have fixes a bug where you can unwield defibrillator paddles just after starting the do_after to defib onehanded fixes a bug where the modsuit gps would have a broken name when renamed
626 lines
23 KiB
Plaintext
626 lines
23 KiB
Plaintext
//Supply modules for MODsuits
|
|
|
|
///Internal GPS - Extends a GPS you can use.
|
|
/obj/item/mod/module/gps
|
|
name = "MOD internal GPS module"
|
|
desc = "This module uses common Nanotrasen technology to calculate the user's position anywhere in space, \
|
|
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_USABLE
|
|
complexity = 1
|
|
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
|
|
incompatible_modules = list(/obj/item/mod/module/gps)
|
|
cooldown_time = 0.5 SECONDS
|
|
allowed_inactive = TRUE
|
|
|
|
/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
|
|
name = "MOD hydraulic clamp module"
|
|
desc = "A series of actuators installed into both arms of the suit, boasting a lifting capacity of almost a ton. \
|
|
However, this design has been locked by Nanotrasen to be primarily utilized for lifting various crates. \
|
|
A lot of people would say that loading cargo is a dull job, but you could not disagree more."
|
|
icon_state = "clamp"
|
|
module_type = MODULE_ACTIVE
|
|
complexity = 3
|
|
use_power_cost = DEFAULT_CHARGE_DRAIN
|
|
incompatible_modules = list(/obj/item/mod/module/clamp)
|
|
cooldown_time = 0.5 SECONDS
|
|
overlay_state_inactive = "module_clamp"
|
|
overlay_state_active = "module_clamp_on"
|
|
/// Time it takes to load a crate.
|
|
var/load_time = 3 SECONDS
|
|
/// The max amount of crates you can carry.
|
|
var/max_crates = 3
|
|
/// The crates stored in the module.
|
|
var/list/stored_crates = list()
|
|
|
|
/obj/item/mod/module/clamp/on_select_use(atom/target)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(!mod.wearer.Adjacent(target))
|
|
return
|
|
if(istype(target, /obj/structure/closet/crate) || istype(target, /obj/item/delivery/big))
|
|
var/atom/movable/picked_crate = target
|
|
if(!check_crate_pickup(picked_crate))
|
|
return
|
|
playsound(src, 'sound/mecha/hydraulic.ogg', 25, TRUE)
|
|
if(!do_after(mod.wearer, load_time, target = target))
|
|
balloon_alert(mod.wearer, "interrupted!")
|
|
return
|
|
if(!check_crate_pickup(picked_crate))
|
|
return
|
|
stored_crates += picked_crate
|
|
picked_crate.forceMove(src)
|
|
balloon_alert(mod.wearer, "picked up [picked_crate]")
|
|
drain_power(use_power_cost)
|
|
else if(length(stored_crates))
|
|
var/turf/target_turf = get_turf(target)
|
|
if(target_turf.is_blocked_turf())
|
|
return
|
|
playsound(src, 'sound/mecha/hydraulic.ogg', 25, TRUE)
|
|
if(!do_after(mod.wearer, load_time, target = target))
|
|
balloon_alert(mod.wearer, "interrupted!")
|
|
return
|
|
if(target_turf.is_blocked_turf())
|
|
return
|
|
var/atom/movable/dropped_crate = pop(stored_crates)
|
|
dropped_crate.forceMove(target_turf)
|
|
balloon_alert(mod.wearer, "dropped [dropped_crate]")
|
|
drain_power(use_power_cost)
|
|
else
|
|
balloon_alert(mod.wearer, "invalid target!")
|
|
|
|
/obj/item/mod/module/clamp/on_suit_deactivation(deleting = FALSE)
|
|
if(deleting)
|
|
return
|
|
for(var/atom/movable/crate as anything in stored_crates)
|
|
crate.forceMove(drop_location())
|
|
stored_crates -= crate
|
|
|
|
/obj/item/mod/module/clamp/proc/check_crate_pickup(atom/movable/target)
|
|
if(length(stored_crates) >= max_crates)
|
|
balloon_alert(mod.wearer, "too many crates!")
|
|
return FALSE
|
|
for(var/mob/living/mob in target.get_all_contents())
|
|
if(mob.mob_size < MOB_SIZE_HUMAN)
|
|
continue
|
|
balloon_alert(mod.wearer, "crate too heavy!")
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/item/mod/module/clamp/loader
|
|
name = "MOD loader hydraulic clamp module"
|
|
icon_state = "clamp_loader"
|
|
complexity = 0
|
|
removable = FALSE
|
|
overlay_state_inactive = null
|
|
overlay_state_active = "module_clamp_loader"
|
|
load_time = 1 SECONDS
|
|
max_crates = 5
|
|
use_mod_colors = TRUE
|
|
|
|
///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."
|
|
icon_state = "drill"
|
|
module_type = MODULE_ACTIVE
|
|
complexity = 2
|
|
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()
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
RegisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP, .proc/bump_mine)
|
|
|
|
/obj/item/mod/module/drill/on_deactivation(display_message = TRUE, deleting = FALSE)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
UnregisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP)
|
|
|
|
/obj/item/mod/module/drill/on_select_use(atom/target)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(!mod.wearer.Adjacent(target))
|
|
return
|
|
if(ismineralturf(target))
|
|
var/turf/closed/mineral/mineral_turf = target
|
|
mineral_turf.gets_drilled(mod.wearer)
|
|
drain_power(use_power_cost)
|
|
else if(istype(target, /turf/open/misc/asteroid))
|
|
var/turf/open/misc/asteroid/sand_turf = target
|
|
if(!sand_turf.can_dig(mod.wearer))
|
|
return
|
|
sand_turf.getDug()
|
|
drain_power(use_power_cost)
|
|
|
|
/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_power_cost))
|
|
return
|
|
var/turf/closed/mineral/mineral_turf = bumped_into
|
|
mineral_turf.gets_drilled(mod.wearer)
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
///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, \
|
|
this utilizes precise electromagnets and storage compartments to automatically collect and deposit ore. \
|
|
It's recommended by Nakamura Engineering to actually deposit that ore at local refineries."
|
|
icon_state = "ore"
|
|
module_type = MODULE_USABLE
|
|
complexity = 1
|
|
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.2
|
|
incompatible_modules = list(/obj/item/mod/module/orebag)
|
|
cooldown_time = 0.5 SECONDS
|
|
allowed_inactive = TRUE
|
|
/// The ores stored in the bag.
|
|
var/list/ores = list()
|
|
|
|
/obj/item/mod/module/orebag/on_equip()
|
|
RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, .proc/ore_pickup)
|
|
|
|
/obj/item/mod/module/orebag/on_unequip()
|
|
UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED)
|
|
|
|
/obj/item/mod/module/orebag/proc/ore_pickup(atom/movable/source, atom/old_loc, dir, forced)
|
|
SIGNAL_HANDLER
|
|
|
|
for(var/obj/item/stack/ore/ore in get_turf(mod.wearer))
|
|
INVOKE_ASYNC(src, .proc/move_ore, ore)
|
|
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)
|
|
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()
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
for(var/obj/item/ore as anything in ores)
|
|
ore.forceMove(drop_location())
|
|
ores -= ore
|
|
drain_power(use_power_cost)
|
|
|
|
/obj/item/mod/module/hydraulic
|
|
name = "MOD loader hydraulic arms module"
|
|
desc = "A pair of powerful hydraulic arms installed in a MODsuit."
|
|
icon_state = "launch_loader"
|
|
module_type = MODULE_ACTIVE
|
|
removable = FALSE
|
|
use_power_cost = DEFAULT_CHARGE_DRAIN*10
|
|
incompatible_modules = list(/obj/item/mod/module/hydraulic)
|
|
cooldown_time = 4 SECONDS
|
|
overlay_state_inactive = "module_hydraulic"
|
|
overlay_state_active = "module_hydraulic_active"
|
|
use_mod_colors = TRUE
|
|
/// Time it takes to launch
|
|
var/launch_time = 2 SECONDS
|
|
/// User overlay
|
|
var/mutable_appearance/lightning
|
|
|
|
/obj/item/mod/module/hydraulic/on_select_use(atom/target)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
var/atom/game_renderer = mod.wearer.hud_used.plane_masters["[RENDER_PLANE_GAME]"]
|
|
var/matrix/render_matrix = matrix(game_renderer.transform)
|
|
render_matrix.Scale(1.25, 1.25)
|
|
animate(game_renderer, launch_time, flags = SINE_EASING|EASE_IN, transform = render_matrix)
|
|
var/current_time = world.time
|
|
mod.wearer.visible_message(span_warning("[mod.wearer] starts whirring!"), \
|
|
blind_message = span_hear("You hear a whirring sound."))
|
|
playsound(src, 'sound/items/modsuit/loader_charge.ogg', 75, TRUE)
|
|
lightning = mutable_appearance('icons/effects/effects.dmi', "electricity3", plane = GAME_PLANE_FOV_HIDDEN)
|
|
mod.wearer.add_overlay(lightning)
|
|
balloon_alert(mod.wearer, "you start charging...")
|
|
var/power = launch_time
|
|
if(!do_after(mod.wearer, launch_time, target = mod))
|
|
power = world.time - current_time
|
|
animate(game_renderer)
|
|
drain_power(use_power_cost)
|
|
new /obj/effect/temp_visual/mook_dust(get_turf(src))
|
|
playsound(src, 'sound/items/modsuit/loader_launch.ogg', 75, TRUE)
|
|
game_renderer.transform = game_renderer.transform.Scale(0.8, 0.8)
|
|
mod.wearer.cut_overlay(lightning)
|
|
var/angle = get_angle(mod.wearer, target)
|
|
mod.wearer.transform = mod.wearer.transform.Turn(angle)
|
|
mod.wearer.throw_at(get_ranged_target_turf_direct(mod.wearer, target, power), \
|
|
range = power, speed = max(round(0.2*power), 1), thrower = mod.wearer, spin = FALSE, \
|
|
callback = CALLBACK(src, .proc/on_throw_end, mod.wearer, -angle))
|
|
|
|
/obj/item/mod/module/hydraulic/proc/on_throw_end(mob/user, angle)
|
|
if(!user)
|
|
return
|
|
user.transform = user.transform.Turn(angle)
|
|
|
|
/obj/item/mod/module/disposal_connector
|
|
name = "MOD disposal selector module"
|
|
desc = "A module that connects to the disposal pipeline, causing the user to go into their config selected disposal. \
|
|
Only seems to work when the suit is on."
|
|
icon_state = "disposal"
|
|
complexity = 2
|
|
idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3
|
|
incompatible_modules = list(/obj/item/mod/module/disposal_connector)
|
|
var/disposal_tag = NONE
|
|
|
|
/obj/item/mod/module/disposal_connector/Initialize(mapload)
|
|
. = ..()
|
|
disposal_tag = pick(GLOB.TAGGERLOCATIONS)
|
|
|
|
/obj/item/mod/module/disposal_connector/on_suit_activation()
|
|
RegisterSignal(mod.wearer, COMSIG_MOVABLE_DISPOSING, .proc/disposal_handling)
|
|
|
|
/obj/item/mod/module/disposal_connector/on_suit_deactivation(deleting = FALSE)
|
|
UnregisterSignal(mod.wearer, COMSIG_MOVABLE_DISPOSING)
|
|
|
|
/obj/item/mod/module/disposal_connector/get_configuration()
|
|
. = ..()
|
|
.["disposal_tag"] = add_ui_configuration("Disposal Tag", "list", GLOB.TAGGERLOCATIONS[disposal_tag], GLOB.TAGGERLOCATIONS)
|
|
|
|
/obj/item/mod/module/disposal_connector/configure_edit(key, value)
|
|
switch(key)
|
|
if("disposal_tag")
|
|
for(var/tag in 1 to length(GLOB.TAGGERLOCATIONS))
|
|
if(GLOB.TAGGERLOCATIONS[tag] == value)
|
|
disposal_tag = tag
|
|
break
|
|
|
|
/obj/item/mod/module/disposal_connector/proc/disposal_handling(datum/disposal_source, obj/structure/disposalholder/disposal_holder, obj/machinery/disposal/disposal_machine, hasmob)
|
|
SIGNAL_HANDLER
|
|
|
|
disposal_holder.destinationTag = disposal_tag
|
|
|
|
/obj/item/mod/module/magnet
|
|
name = "MOD loader hydraulic magnet module"
|
|
desc = "A powerful hydraulic electromagnet able to launch crates and lockers towards the user, and keep 'em attached."
|
|
icon_state = "magnet_loader"
|
|
module_type = MODULE_ACTIVE
|
|
removable = FALSE
|
|
use_power_cost = DEFAULT_CHARGE_DRAIN * 3
|
|
incompatible_modules = list(/obj/item/mod/module/magnet)
|
|
cooldown_time = 1.5 SECONDS
|
|
overlay_state_active = "module_magnet"
|
|
use_mod_colors = TRUE
|
|
|
|
/obj/item/mod/module/magnet/on_select_use(atom/target)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(istype(mod.wearer.pulling, /obj/structure/closet))
|
|
var/obj/structure/closet/locker = mod.wearer.pulling
|
|
playsound(locker, 'sound/effects/gravhit.ogg', 75, TRUE)
|
|
locker.forceMove(mod.wearer.loc)
|
|
locker.throw_at(target, range = 7, speed = 4, thrower = mod.wearer)
|
|
return
|
|
if(!istype(target, /obj/structure/closet) || !(target in view(mod.wearer)))
|
|
balloon_alert(mod.wearer, "invalid target!")
|
|
return
|
|
var/obj/structure/closet/locker = target
|
|
if(locker.anchored || locker.move_resist >= MOVE_FORCE_OVERPOWERING)
|
|
balloon_alert(mod.wearer, "target anchored!")
|
|
return
|
|
new /obj/effect/temp_visual/mook_dust(get_turf(locker))
|
|
playsound(locker, 'sound/effects/gravhit.ogg', 75, TRUE)
|
|
locker.throw_at(mod.wearer, range = 7, speed = 3, force = MOVE_FORCE_WEAK, \
|
|
callback = CALLBACK(src, .proc/check_locker, locker))
|
|
|
|
/obj/item/mod/module/magnet/on_deactivation(display_message = TRUE, deleting = FALSE)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(istype(mod.wearer.pulling, /obj/structure/closet))
|
|
mod.wearer.stop_pulling()
|
|
|
|
/obj/item/mod/module/magnet/proc/check_locker(obj/structure/closet/locker)
|
|
if(!mod?.wearer)
|
|
return
|
|
if(!locker.Adjacent(mod.wearer) || !isturf(locker.loc) || !isturf(mod.wearer.loc))
|
|
return
|
|
mod.wearer.start_pulling(locker)
|
|
locker.strong_grab = TRUE
|
|
RegisterSignal(locker, COMSIG_ATOM_NO_LONGER_PULLED, .proc/on_stop_pull)
|
|
|
|
/obj/item/mod/module/magnet/proc/on_stop_pull(obj/structure/closet/locker, atom/movable/last_puller)
|
|
SIGNAL_HANDLER
|
|
|
|
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"
|
|
use_mod_colors = TRUE
|
|
/// 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 = 4, BULLET = 1, LASER = 2, ENERGY = 2, BOMB = 4)
|
|
/// Speed added when you're fully covered in ash.
|
|
var/speed_added = 0.5
|
|
/// Speed that we actually added.
|
|
var/actual_speed_added = 0
|
|
/// 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/misc/asteroid,
|
|
/turf/open/misc/ashplanet,
|
|
/turf/open/misc/dirt,
|
|
))
|
|
if(!keep_turfs)
|
|
keep_turfs = typecacheof(list(
|
|
/turf/open/misc/grass,
|
|
/turf/open/floor/plating/snowed,
|
|
/turf/open/misc/sandy_dirt,
|
|
/turf/open/misc/ironsand,
|
|
/turf/open/misc/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(deleting = FALSE)
|
|
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)
|
|
actual_speed_added = max(0, min(mod.slowdown_active, speed_added))
|
|
mod.slowdown -= actual_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 += actual_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(!mod.wearer.has_gravity())
|
|
balloon_alert(mod.wearer, "no gravity!")
|
|
return FALSE
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
playsound(src, 'sound/items/modsuit/ballin.ogg', 100, TRUE)
|
|
mod.wearer.add_filter("mod_ball", 1, alpha_mask_filter(icon = icon('icons/mob/clothing/modsuit/mod_modules.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.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, deleting = FALSE)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(!deleting)
|
|
playsound(src, 'sound/items/modsuit/ballin.ogg', 100, TRUE, frequency = -1)
|
|
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
|
|
armor_flag = BOMB
|
|
light_system = MOVABLE_LIGHT
|
|
light_range = 1
|
|
light_power = 1
|
|
light_color = COLOR_LIGHT_ORANGE
|
|
ammo_type = /obj/structure/mining_bomb
|
|
|
|
/obj/projectile/bullet/reusable/mining_bomb/handle_drop()
|
|
if(dropped)
|
|
return
|
|
dropped = TRUE
|
|
new ammo_type(get_turf(src), firer)
|
|
|
|
/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
|
|
/// Image overlaid on explosion.
|
|
var/static/image/explosion_image
|
|
|
|
/obj/structure/mining_bomb/Initialize(mapload, atom/movable/firer)
|
|
. = ..()
|
|
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, firer), prime_time)
|
|
|
|
/obj/structure/mining_bomb/proc/prime(atom/movable/firer)
|
|
add_overlay(explosion_image)
|
|
addtimer(CALLBACK(src, .proc/boom, firer), explosion_time)
|
|
|
|
/obj/structure/mining_bomb/proc/boom(atom/movable/firer)
|
|
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)
|
|
if(!ishostile(mob) || !firer)
|
|
continue
|
|
var/mob/living/simple_animal/hostile/hostile_mob = mob
|
|
hostile_mob.GiveTarget(firer)
|
|
for(var/obj/object in range(1, src))
|
|
object.take_damage(damage, BRUTE, BOMB)
|
|
qdel(src)
|