diff --git a/aurorastation.dme b/aurorastation.dme
index 1df19864941..4abd60fd068 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -864,6 +864,7 @@
#include "code\game\objects\effects\spawners\gibspawner.dm"
#include "code\game\objects\effects\temporary_visuals\blaster_effect.dm"
#include "code\game\objects\effects\temporary_visuals\blood_splatter.dm"
+#include "code\game\objects\effects\temporary_visuals\incorporeal_mech.dm"
#include "code\game\objects\effects\temporary_visuals\nuke.dm"
#include "code\game\objects\effects\temporary_visuals\teleport_visuals.dm"
#include "code\game\objects\effects\temporary_visuals\temporary_visual.dm"
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 182de847687..d77e62978c4 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -23,6 +23,7 @@
#define INCORPOREAL_NINJA 2 // Pass through matter with a cool effect
#define INCORPOREAL_BSTECH 3 // Like ninja, but also go across Z-levels and move in space freely
#define INCORPOREAL_SHADE 4 // Shady
+#define INCORPOREAL_MECH 5 // stripped down bstech
// Grab levels.
#define GRAB_PASSIVE 1
diff --git a/code/game/objects/effects/temporary_visuals/incorporeal_mech.dm b/code/game/objects/effects/temporary_visuals/incorporeal_mech.dm
new file mode 100644
index 00000000000..e0718d4dde1
--- /dev/null
+++ b/code/game/objects/effects/temporary_visuals/incorporeal_mech.dm
@@ -0,0 +1,10 @@
+/obj/effect/temp_visual/incorporeal_mech
+ layer = BELOW_MOB_LAYER
+ randomdir = FALSE
+
+/obj/effect/temp_visual/incorporeal_mech/Initialize(mapload, new_dir, var/mob/living/heavy_vehicle/HV)
+ . = ..()
+ appearance = HV.appearance
+ mouse_opacity = 0
+ opacity = FALSE
+ animate(src, time = duration, alpha = 0)
\ No newline at end of file
diff --git a/code/modules/heavy_vehicle/equipment/combat.dm b/code/modules/heavy_vehicle/equipment/combat.dm
index 78b30d161ce..be450a971fb 100644
--- a/code/modules/heavy_vehicle/equipment/combat.dm
+++ b/code/modules/heavy_vehicle/equipment/combat.dm
@@ -318,11 +318,9 @@
return
if((world.time - last_recharge) < cooldown)
return
- var/obj/item/cell/cell = owner.get_cell()
var/actual_required_power = Clamp(max_charge - charge, 0, charging_rate)
- if(cell)
- charge += cell.use(actual_required_power)
+ owner.use_cell_power(actual_required_power)
/obj/item/mecha_equipment/shield/get_hardpoint_status_value()
return charge / max_charge
diff --git a/code/modules/heavy_vehicle/equipment/utility.dm b/code/modules/heavy_vehicle/equipment/utility.dm
index 163f4d2c6f5..c3aae9f5a1f 100644
--- a/code/modules/heavy_vehicle/equipment/utility.dm
+++ b/code/modules/heavy_vehicle/equipment/utility.dm
@@ -272,9 +272,7 @@
log_and_message_admins("used [src] to throw [locked] at [target].", user, owner.loc)
locked = null
- var/obj/item/cell/C = owner.get_cell()
- if(istype(C))
- C.use(active_power_use * CELLRATE)
+ owner.use_cell_power(active_power_use * CELLRATE)
else
locked = null
@@ -293,9 +291,8 @@
log_and_message_admins("used [src]'s area throw on [target].", user, owner.loc)
- var/obj/item/cell/C = owner.get_cell()
- if(istype(C))
- C.use(active_power_use * CELLRATE * 2) //bit more expensive to throw all
+
+ owner.use_cell_power(active_power_use * CELLRATE * 2) //bit more expensive to throw all
/obj/item/material/drill_head
var/durability = 0
@@ -374,9 +371,7 @@
to_chat(user, "Your drill doesn't have a head!")
return
- var/obj/item/cell/C = owner.get_cell()
- if(istype(C))
- C.use(active_power_use * CELLRATE)
+ owner.use_cell_power(active_power_use * CELLRATE)
owner.visible_message("\The [owner] starts to drill \the [target]", "You hear a large drill.")
var/T = target.loc
@@ -657,6 +652,70 @@
/obj/item/mecha_equipment/quick_enter/attack_self()
return
+/obj/item/mecha_equipment/phazon
+ name = "phazon bluespace transmission system"
+ desc = "A large back-mounted device that grants the exosuit it's mounted to the ability to semi-shift into bluespace, allowing it to pass through dense objects."
+ desc_info = "It needs an anomaly core to function. You can install some simply by using a core on it."
+ icon_state = "mecha_phazon"
+ restricted_hardpoints = list(HARDPOINT_BACK)
+ w_class = ITEMSIZE_HUGE
+ origin_tech = list(TECH_MATERIAL = 6, TECH_ENGINEERING = 6, TECH_BLUESPACE = 6)
+ active_power_use = 88 KILOWATTS
+
+ var/obj/item/anomaly_core/AC
+ var/image/anomaly_overlay
+
+/obj/item/mecha_equipment/phazon/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/anomaly_core))
+ if(AC)
+ to_chat(user, SPAN_WARNING("\The [src] already has an anomaly core installed!"))
+ return
+ user.drop_from_inventory(I, src)
+ AC = I
+ to_chat(user, SPAN_NOTICE("You insert \the [AC] into \the [src]."))
+ desc_info = "\The [src] has an anomaly core installed! You can use a wrench to remove it."
+ anomaly_overlay = image(AC.icon, null, AC.icon_state)
+ anomaly_overlay.pixel_y = 3
+ add_overlay(anomaly_overlay)
+ return
+ if(I.iswrench())
+ if(!AC)
+ to_chat(user, SPAN_WARNING("\The [src] doesn't have an anomaly core installed!"))
+ return
+ to_chat(user, SPAN_NOTICE("You remove \the [AC] from \the [src]."))
+ playsound(loc, I.usesound, 50, TRUE)
+ user.put_in_hands(AC)
+ cut_overlay(anomaly_overlay)
+ qdel(anomaly_overlay)
+ AC = null
+ if(owner)
+ deactivate()
+ return
+ return ..()
+
+/obj/item/mecha_equipment/phazon/attack_self(mob/user)
+ . = ..()
+ if(!.)
+ return
+
+ if(!AC)
+ to_chat(user, SPAN_WARNING("\The [src] needs an anomaly core to function!"))
+ return
+
+ if(!owner.incorporeal_move)
+ to_chat(user, SPAN_NOTICE("You fire up \the [src], semi-shifting into another plane of existence!"))
+ owner.set_mech_incorporeal(INCORPOREAL_MECH)
+ else
+ to_chat(user, SPAN_NOTICE("You disable \the [src], shifting back into your normal reality."))
+ owner.set_mech_incorporeal(INCORPOREAL_DISABLE)
+
+/obj/item/mecha_equipment/phazon/deactivate()
+ owner.set_mech_incorporeal(INCORPOREAL_DISABLE)
+ ..()
+
+/obj/item/mecha_equipment/phazon/uninstalled()
+ owner.set_mech_incorporeal(INCORPOREAL_DISABLE)
+ ..()
/obj/item/mecha_equipment/mounted_system/grenadecleaner
name = "cleaner grenade launcher"
diff --git a/code/modules/heavy_vehicle/mech_helpers.dm b/code/modules/heavy_vehicle/mech_helpers.dm
index 02956750f46..49fa2a9d6a3 100644
--- a/code/modules/heavy_vehicle/mech_helpers.dm
+++ b/code/modules/heavy_vehicle/mech_helpers.dm
@@ -18,7 +18,7 @@
next_mecha_move = world.time + 15
return
- next_mecha_move = world.time + legs.move_delay
+ next_mecha_move = world.time + (incorporeal_move ? legs.move_delay / 2 : legs.move_delay)
if(maintenance_protocols)
if(user)
@@ -74,4 +74,44 @@
text = replacemany(text, list("\"" = "", "." = "", "," = ""))
text = trim_left(text)
text = trim_right(text)
- return text
\ No newline at end of file
+ return text
+
+/mob/living/heavy_vehicle/proc/use_cell_power(var/power_to_use)
+ var/power_used = get_cell()?.use(power_to_use)
+ if(power_used <= 0)
+ for(var/hardpoint in hardpoints)
+ var/obj/item/mecha_equipment/ME = hardpoints[hardpoint]
+ if(ME)
+ ME.deactivate()
+ return power_used
+
+/mob/living/heavy_vehicle/proc/drain_cell_power(var/power_to_drain)
+ var/power_used = get_cell()?.drain_power(0, 0, power_to_drain)
+ if(power_used <= 0)
+ for(var/hardpoint in hardpoints)
+ var/obj/item/mecha_equipment/ME = hardpoints[hardpoint]
+ if(ME)
+ ME.deactivate()
+ return power_used
+
+/mob/living/heavy_vehicle/proc/checked_use_cell(var/power_to_drain)
+ var/can_use = get_cell()?.checked_use(0, 0, power_to_drain)
+ if(!get_cell()?.charge)
+ for(var/hardpoint in hardpoints)
+ var/obj/item/mecha_equipment/ME = hardpoints[hardpoint]
+ if(ME)
+ ME.deactivate()
+ return can_use
+
+/mob/living/heavy_vehicle/proc/set_mech_incorporeal(var/incorporeal_state)
+ var/old_corporeal_state = incorporeal_move
+ incorporeal_move = incorporeal_state
+ if(old_corporeal_state != incorporeal_move)
+ if(incorporeal_move)
+ add_filter("INCORPBLUR", 1, list("type" = "blur"))
+ animate(src, time = 1 SECOND, alpha = 150, flags = ANIMATION_PARALLEL)
+ animate(get_filter("INCORPBLUR"), time = 1 SECOND, size = 1.5, flags = ANIMATION_PARALLEL)
+ else
+ animate(get_filter("INCORPBLUR"), time = 1 SECOND, size = 1, flags = ANIMATION_PARALLEL)
+ animate(src, time = 1 SECOND, alpha = initial(alpha), flags = ANIMATION_PARALLEL)
+ remove_filter("INCORPBLUR")
\ No newline at end of file
diff --git a/code/modules/heavy_vehicle/mech_interaction.dm b/code/modules/heavy_vehicle/mech_interaction.dm
index a79151b8e87..a98875765e7 100644
--- a/code/modules/heavy_vehicle/mech_interaction.dm
+++ b/code/modules/heavy_vehicle/mech_interaction.dm
@@ -75,7 +75,7 @@
setClickCooldown(15)
return
- if(!(get_cell()?.checked_use(arms.power_use * CELLRATE)))
+ if(!checked_use_cell(arms.power_use * CELLRATE))
to_chat(user, power == MECH_POWER_ON ? SPAN_WARNING("Error: Power levels insufficient.") : SPAN_WARNING("\The [src] is powered off."))
return
@@ -286,9 +286,15 @@
var/turf/target_loc = get_step(src, direction)
if(!legs.can_move_on(loc, target_loc))
return
- Move(target_loc, direction)
+ if(incorporeal_move)
+ if(legs && legs.mech_step_sound)
+ playsound(src.loc,legs.mech_step_sound,40,1)
+ use_cell_power(legs.power_use * CELLRATE)
+ user.client.Process_Incorpmove(direction, src)
+ else
+ Move(target_loc, direction)
else
- get_cell()?.use(legs.power_use * CELLRATE)
+ use_cell_power(legs.power_use * CELLRATE)
if(legs && legs.mech_turn_sound)
playsound(src.loc,legs.mech_turn_sound,40,1)
next_mecha_move = world.time + legs.turn_delay
@@ -307,9 +313,15 @@
if(..() && !istype(loc, /turf/space))
if(legs && legs.mech_step_sound)
playsound(src.loc,legs.mech_step_sound,40,1)
- get_cell()?.use(legs.power_use * CELLRATE)
+ use_cell_power(legs.power_use * CELLRATE)
update_icon()
+/mob/living/heavy_vehicle/Post_Incorpmove()
+ if(istype(hardpoints[HARDPOINT_BACK], /obj/item/mecha_equipment/phazon))
+ var/obj/item/mecha_equipment/phazon/PZ = hardpoints[HARDPOINT_BACK]
+ use_cell_power(PZ.active_power_use * CELLRATE)
+ return ..()
+
/mob/living/heavy_vehicle/attackby(var/obj/item/thing, var/mob/user)
if(user.a_intent != I_HURT && istype(thing, /obj/item/mecha_equipment))
if(hardpoints_locked)
diff --git a/code/modules/heavy_vehicle/mech_life.dm b/code/modules/heavy_vehicle/mech_life.dm
index cfd6e07b10d..3a4ee7a07e4 100644
--- a/code/modules/heavy_vehicle/mech_life.dm
+++ b/code/modules/heavy_vehicle/mech_life.dm
@@ -30,7 +30,7 @@
var/powered = FALSE
if(get_cell())
- powered = get_cell().drain_power(0, 0, calc_power_draw()) > 0
+ powered = drain_cell_power(calc_power_draw()) > 0
if(!powered)
//Shut down all systems
diff --git a/code/modules/heavy_vehicle/mecha.dm b/code/modules/heavy_vehicle/mecha.dm
index 6b357750585..eaba2b963e8 100644
--- a/code/modules/heavy_vehicle/mecha.dm
+++ b/code/modules/heavy_vehicle/mecha.dm
@@ -10,6 +10,7 @@
mob_push_flags = ALLMOBS
can_be_buckled = FALSE
accent = ACCENT_TTS
+ appearance_flags = KEEP_TOGETHER
var/decal
var/emp_damage = 0
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index a59609b994c..fa9966809f8 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -191,7 +191,7 @@
Move_object(direct)
if(mob.incorporeal_move && isobserver(mob))
- Process_Incorpmove(direct)
+ Process_Incorpmove(direct, mob)
return
if(moving || world.time < move_delay)
@@ -219,8 +219,8 @@
if(isliving(mob))
var/mob/living/L = mob
- if(L.incorporeal_move)//Move though walls
- Process_Incorpmove(direct)
+ if(L.incorporeal_move && isturf(mob.loc))//Move though walls
+ Process_Incorpmove(direct, mob)
return
if(mob.client && ((mob.client.view != world.view) || (mob.client.pixel_x != 0) || (mob.client.pixel_y != 0))) // If mob moves while zoomed in with device, unzoom them.
for(var/obj/item/item in mob)
@@ -395,44 +395,49 @@
///Process_Incorpmove
///Called by client/Move()
///Allows mobs to run though walls
-/client/proc/Process_Incorpmove(direct)
- var/turf/mobloc = get_turf(mob)
- switch(mob.incorporeal_move)
+/client/proc/Process_Incorpmove(direct, var/mob/use_mob)
+ if(!use_mob)
+ use_mob = mob
+ var/turf/mobloc = get_turf(use_mob)
+ switch(use_mob.incorporeal_move)
if(INCORPOREAL_GHOST)
- var/turf/T = get_step(mob, direct)
- if(mob.check_holy(T))
- to_chat(mob, SPAN_WARNING("You cannot get past holy grounds while you are in this plane of existence!"))
+ var/turf/T = get_step(use_mob, direct)
+ if(use_mob.check_holy(T))
+ to_chat(src, SPAN_WARNING("You cannot get past holy grounds while you are in this plane of existence!"))
return
else
- mob.forceMove(get_step(mob, direct))
- mob.dir = direct
+ use_mob.forceMove(get_step(use_mob, direct))
+ use_mob.dir = direct
if(INCORPOREAL_NINJA, INCORPOREAL_BSTECH)
- anim(mobloc, mob, 'icons/mob/mob.dmi', null, "shadow", null, mob.dir)
- mob.forceMove(get_step(mob, direct))
- mob.dir = direct
+ anim(mobloc, use_mob, 'icons/mob/mob.dmi', null, "shadow", null, use_mob.dir)
+ use_mob.forceMove(get_step(use_mob, direct))
+ use_mob.dir = direct
+ if(INCORPOREAL_MECH)
+ new /obj/effect/temp_visual/incorporeal_mech(mobloc, use_mob.dir, use_mob)
+ use_mob.forceMove(get_step(use_mob, direct))
if(INCORPOREAL_SHADE)
- if(!mob.canmove || mob.anchored)
+ if(!use_mob.canmove || use_mob.anchored)
return
move_delay = 1 + world.time
- var/turf/T = get_step(mob, direct)
+ var/turf/T = get_step(use_mob, direct)
for(var/obj/structure/window/W in T)
if(istype(W, /obj/structure/window/phoronbasic) || istype(W, /obj/structure/window/phoronreinforced))
if(W.is_full_window())
- to_chat(mob, SPAN_WARNING("\The [W] obstructs your movement!"))
+ to_chat(src, SPAN_WARNING("\The [W] obstructs your movement!"))
return
if((direct & W.dir) && W.density)
- to_chat(mob, SPAN_WARNING("\The [W] obstructs your movement!"))
+ to_chat(src, SPAN_WARNING("\The [W] obstructs your movement!"))
return
if(istype(T, /turf/simulated/wall/phoron) || istype(T, /turf/simulated/wall/ironphoron))
- to_chat(mob, SPAN_WARNING("\The [T] obstructs your movement!"))
+ to_chat(src, SPAN_WARNING("\The [T] obstructs your movement!"))
return
for(var/mob/living/L in T)
if(L.is_diona() == DIONA_WORKER)
- to_chat(mob, SPAN_DANGER("You struggle briefly as you are photovored into \the [L], trapped within a nymphomatic husk!"))
+ to_chat(src, SPAN_DANGER("You struggle briefly as you are photovored into \the [L], trapped within a nymphomatic husk!"))
var/mob/living/carbon/alien/diona/D = new /mob/living/carbon/alien/diona(L)
- var/mob/living/simple_animal/shade/bluespace/BS = mob
+ var/mob/living/simple_animal/shade/bluespace/BS = use_mob
if (!(/mob/living/carbon/proc/echo_eject in L.verbs))
L.verbs.Add(/mob/living/carbon/proc/echo_eject)
BS.mind.transfer_to(D)
@@ -445,21 +450,21 @@
qdel(BS)
return
- mob.forceMove(get_step(mob, direct))
- mob.dir = direct
+ use_mob.forceMove(get_step(use_mob, direct))
+ use_mob.dir = direct
// Crossed is always a bit iffy
- for(var/obj/S in mob.loc)
+ for(var/obj/S in use_mob.loc)
if(istype(S,/obj/effect/step_trigger) || istype(S,/obj/effect/beam))
- S.Crossed(mob)
+ S.Crossed(use_mob)
- var/area/A = get_area_master(mob)
+ var/area/A = get_area_master(use_mob)
if(A)
- A.Entered(mob)
- if(isturf(mob.loc))
- var/turf/T = mob.loc
- T.Entered(mob)
- mob.Post_Incorpmove()
+ A.Entered(use_mob)
+ if(isturf(use_mob.loc))
+ var/turf/T = use_mob.loc
+ T.Entered(use_mob)
+ use_mob.Post_Incorpmove()
return 1
/mob/proc/Post_Incorpmove()
diff --git a/code/modules/research/designs/mechfab/mechs/designs_exosuit_equipment.dm b/code/modules/research/designs/mechfab/mechs/designs_exosuit_equipment.dm
index e37be761086..7b279a9fc56 100644
--- a/code/modules/research/designs/mechfab/mechs/designs_exosuit_equipment.dm
+++ b/code/modules/research/designs/mechfab/mechs/designs_exosuit_equipment.dm
@@ -131,4 +131,14 @@
/datum/design/item/mechfab/exosuit_equipment/drill_mover
name = "Mounted Drill Loader System"
materials = list(DEFAULT_WALL_MATERIAL = 15000)
- build_path = /obj/item/mecha_equipment/drill_mover
\ No newline at end of file
+ build_path = /obj/item/mecha_equipment/drill_mover
+
+/datum/design/item/mechfab/exosuit_equipment/phazon
+ name = "Phazon Bluespace Transmission System"
+ materials = list(MATERIAL_STEEL = 25000, MATERIAL_PHORON = 10000)
+ req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 5, TECH_BLUESPACE = 5)
+ build_path = /obj/item/mecha_equipment/phazon
+
+/datum/design/item/mechfab/exosuit_equipment/phazon/AssembleDesignDesc()
+ . = ..()
+ desc += " It needs an anomaly core to function, however."
\ No newline at end of file
diff --git a/html/changelogs/geeves-phazon_module.yml b/html/changelogs/geeves-phazon_module.yml
new file mode 100644
index 00000000000..c14a9065fa7
--- /dev/null
+++ b/html/changelogs/geeves-phazon_module.yml
@@ -0,0 +1,6 @@
+author: Geeves
+
+delete-after: True
+
+changes:
+ - rscadd: "Added the phazon bluespace transmission system to the mechfab. When built and supplied with an anomaly core, it'll allow exosuit to pass through solid objects, at a massive energy cost."
\ No newline at end of file
diff --git a/icons/mecha/mech_equipment.dmi b/icons/mecha/mech_equipment.dmi
index c9602e9cc91..90c3520826b 100644
Binary files a/icons/mecha/mech_equipment.dmi and b/icons/mecha/mech_equipment.dmi differ