diff --git a/_maps/map_files/Blueshift/BlueShift_middle.dmm b/_maps/map_files/Blueshift/BlueShift_middle.dmm
index c146aaa34ff..d27d8911aa2 100644
--- a/_maps/map_files/Blueshift/BlueShift_middle.dmm
+++ b/_maps/map_files/Blueshift/BlueShift_middle.dmm
@@ -7337,7 +7337,7 @@
/obj/effect/turf_decal/delivery,
/obj/structure/rack/gunrack,
/obj/machinery/airalarm/directional/south,
-/obj/effect/spawner/armory_spawn/rifles,
+/obj/effect/spawner/armory_spawn/microfusion,
/turf/open/floor/iron,
/area/ai_monitored/security/armory)
"cev" = (
@@ -20604,7 +20604,7 @@
/obj/effect/turf_decal/delivery,
/obj/structure/rack/gunrack,
/obj/machinery/firealarm/directional/south,
-/obj/effect/spawner/armory_spawn/rifles,
+/obj/effect/spawner/armory_spawn/microfusion,
/turf/open/floor/iron/dark/corner{
dir = 8
},
diff --git a/_maps/map_files/Deltastation/DeltaStation2_skyrat.dmm b/_maps/map_files/Deltastation/DeltaStation2_skyrat.dmm
index 602c28bad32..cc3920cdb4a 100644
--- a/_maps/map_files/Deltastation/DeltaStation2_skyrat.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2_skyrat.dmm
@@ -9627,7 +9627,7 @@
dir = 8
},
/obj/structure/rack/gunrack,
-/obj/effect/spawner/armory_spawn/rifles,
+/obj/effect/spawner/armory_spawn/microfusion,
/turf/open/floor/iron/dark,
/area/ai_monitored/security/armory)
"bEx" = (
diff --git a/_maps/map_files/IceBoxStation/IceBoxStation_skyrat.dmm b/_maps/map_files/IceBoxStation/IceBoxStation_skyrat.dmm
index 8d7fc8d788c..db487957625 100644
--- a/_maps/map_files/IceBoxStation/IceBoxStation_skyrat.dmm
+++ b/_maps/map_files/IceBoxStation/IceBoxStation_skyrat.dmm
@@ -625,7 +625,7 @@
"agU" = (
/obj/structure/rack/gunrack,
/obj/effect/turf_decal/delivery/blue,
-/obj/effect/spawner/armory_spawn/rifles,
+/obj/effect/spawner/armory_spawn/microfusion,
/obj/machinery/light/directional/east,
/turf/open/floor/iron/dark,
/area/ai_monitored/security/armory)
diff --git a/_maps/map_files/MetaStation/MetaStation_skyrat.dmm b/_maps/map_files/MetaStation/MetaStation_skyrat.dmm
index c8da511af4c..0ee426f8753 100644
--- a/_maps/map_files/MetaStation/MetaStation_skyrat.dmm
+++ b/_maps/map_files/MetaStation/MetaStation_skyrat.dmm
@@ -62743,7 +62743,7 @@
"uom" = (
/obj/machinery/airalarm/directional/north,
/obj/structure/rack/gunrack,
-/obj/effect/spawner/armory_spawn/rifles,
+/obj/effect/spawner/armory_spawn/microfusion,
/obj/effect/turf_decal/delivery/red,
/turf/open/floor/iron/smooth,
/area/ai_monitored/security/armory)
diff --git a/_maps/map_files/NSSJourney/NSSJourney.dmm b/_maps/map_files/NSSJourney/NSSJourney.dmm
index 80817827c1e..ad8cd690b0b 100644
--- a/_maps/map_files/NSSJourney/NSSJourney.dmm
+++ b/_maps/map_files/NSSJourney/NSSJourney.dmm
@@ -37168,7 +37168,7 @@
"dZT" = (
/obj/machinery/airalarm/directional/north,
/obj/structure/rack/gunrack,
-/obj/effect/spawner/armory_spawn/rifles,
+/obj/effect/spawner/armory_spawn/microfusion,
/obj/effect/turf_decal/delivery/red,
/turf/open/floor/iron/smooth,
/area/ai_monitored/security/armory)
diff --git a/_maps/map_files/tramstation/tramstation_skyrat.dmm b/_maps/map_files/tramstation/tramstation_skyrat.dmm
index fcb47f5f04f..09459367deb 100644
--- a/_maps/map_files/tramstation/tramstation_skyrat.dmm
+++ b/_maps/map_files/tramstation/tramstation_skyrat.dmm
@@ -19863,7 +19863,7 @@
/area/security/detectives_office)
"eog" = (
/obj/structure/rack/gunrack,
-/obj/effect/spawner/armory_spawn/rifles,
+/obj/effect/spawner/armory_spawn/microfusion,
/turf/open/floor/iron/smooth,
/area/ai_monitored/security/armory)
"eoj" = (
diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index c2a8c0e2d5f..9c22227001f 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -191,6 +191,7 @@ GLOBAL_LIST_INIT(security_hardsuit_allowed, typecacheof(list(
/obj/item/reagent_containers/spray/pepper,
/obj/item/restraints/handcuffs,
/obj/item/tank/internals,
+ /obj/item/gun/microfusion, //SKYRAT EDIT ADDITION
)))
GLOBAL_LIST_INIT(detective_vest_allowed, typecacheof(list(
@@ -210,6 +211,7 @@ GLOBAL_LIST_INIT(detective_vest_allowed, typecacheof(list(
/obj/item/tank/internals/plasmaman,
/obj/item/storage/belt/holster/detective,
/obj/item/storage/belt/holster/nukie,
+ /obj/item/gun/microfusion, //SKYRAT EDIT ADDITION
)))
GLOBAL_LIST_INIT(security_vest_allowed, typecacheof(list(
@@ -226,6 +228,7 @@ GLOBAL_LIST_INIT(security_vest_allowed, typecacheof(list(
/obj/item/tank/internals/plasmaman,
/obj/item/storage/belt/holster/detective,
/obj/item/storage/belt/holster/nukie,
+ /obj/item/gun/microfusion, //SKYRAT EDIT ADDITION
)))
GLOBAL_LIST_INIT(security_wintercoat_allowed, typecacheof(list(
@@ -238,6 +241,7 @@ GLOBAL_LIST_INIT(security_wintercoat_allowed, typecacheof(list(
/obj/item/restraints/handcuffs,
/obj/item/storage/belt/holster/detective,
/obj/item/storage/belt/holster/nukie,
+ /obj/item/gun/microfusion, //SKYRAT EDIT ADDITION
)))
/// String for items placed into the left pocket.
diff --git a/code/__DEFINES/~skyrat_defines/traits.dm b/code/__DEFINES/~skyrat_defines/traits.dm
index 83957b6f28f..74b1f61949a 100644
--- a/code/__DEFINES/~skyrat_defines/traits.dm
+++ b/code/__DEFINES/~skyrat_defines/traits.dm
@@ -23,6 +23,9 @@
#define TRAIT_ASH_ASPECT "ash_aspect"
#define TRAIT_SPARKLE_ASPECT "sparkle_aspect"
+/// Allows the user to instantly reload.
+#define TRAIT_INSTANT_RELOAD "instant_reload"
+
// Trait sources
#define GHOSTROLE_TRAIT "ghostrole" // SKYRAT EDIT ADDITION -- Ghost Cafe Traits
diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm
index 889ef96cf81..df25285f12c 100644
--- a/code/game/machinery/cell_charger.dm
+++ b/code/game/machinery/cell_charger.dm
@@ -43,6 +43,12 @@
if(charging)
to_chat(user, span_warning("There is already a cell in the charger!"))
return
+ //SKYRAT EDIT ADDITION
+ var/obj/item/stock_parts/cell/inserting_cell = W
+ if(inserting_cell.chargerate <= 0)
+ to_chat(user, span_warning("[inserting_cell] cannot be recharged!"))
+ return
+ //SKYRAT EDIT END
else
var/area/a = loc.loc // Gets our locations location, like a dream within a dream
if(!isarea(a))
@@ -125,7 +131,6 @@
/obj/machinery/cell_charger/process(delta_time)
if(!charging || !anchored || (machine_stat & (BROKEN|NOPOWER)))
return
-
if(charging.percent() >= 100)
return
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index 7c72604a9b3..62bbc128081 100755
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -16,6 +16,8 @@
var/finished_recharging = FALSE
var/static/list/allowed_devices = typecacheof(list(
+ /obj/item/stock_parts/cell/microfusion, //SKYRAT EDIT ADDITION
+ /obj/item/gun/microfusion, // SKYRAT EDIT ADDITION
/obj/item/gun/energy,
/obj/item/melee/baton/security,
/obj/item/ammo_box/magazine/recharge,
@@ -86,6 +88,19 @@
to_chat(user, span_notice("Your gun has no external power connector."))
return 1
+ //SKYRAT EDIT ADDITION
+ if (istype(G, /obj/item/gun/microfusion))
+ var/obj/item/gun/microfusion/microfusion_gun = G
+ if(microfusion_gun.cell?.chargerate <= 0)
+ to_chat(user, span_notice("[microfusion_gun] cannot be recharged!"))
+ return TRUE
+
+ if(istype(G, /obj/item/stock_parts/cell/microfusion))
+ var/obj/item/stock_parts/cell/microfusion/inserting_cell = G
+ if(inserting_cell.chargerate <= 0)
+ to_chat(user, span_notice("[inserting_cell] cannot be recharged!"))
+ return TRUE
+ //SKYRAT EDIT END
if(!user.transferItemToLoc(G, src))
return 1
setCharging(G)
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 18eb44e8b9e..64458dbd2dc 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -254,7 +254,8 @@
/obj/item/radio,
/obj/item/clothing/gloves,
/obj/item/restraints/legcuffs/bola,
- /obj/item/holosign_creator/security
+ /obj/item/holosign_creator/security,
+ /obj/item/stock_parts/cell/microfusion, //SKYRAT EDIT ADDITION
))
/obj/item/storage/belt/security/full/PopulateContents()
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 933faa65b4f..7b122b3a1b7 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -46,8 +46,10 @@
if (override_maxcharge)
maxcharge = override_maxcharge
charge = maxcharge
+ /* SKYRAT EDIT REMOVAL
if(ratingdesc)
desc += " This one has a rating of [display_energy(maxcharge)], and you should not swallow it."
+ */ // SKYRAT EDIT END
update_appearance()
/obj/item/stock_parts/cell/create_reagents(max_vol, flags)
@@ -67,7 +69,7 @@
. += mutable_appearance('icons/obj/power.dmi', "grown_wires")
if(charge < 0.01)
return
- . += mutable_appearance('modular_skyrat/modules/aesthetics/cells/cell.dmi', "cell-o[((charge / maxcharge) >= 0.995) ? 2 : 1]") //SKYRAT EDIT CHANGE
+ . += mutable_appearance(charge_overlay_icon, "cell-o[((charge / maxcharge) >= 0.995) ? 2 : 1]") //SKYRAT EDIT CHANGE
/obj/item/stock_parts/cell/proc/percent() // return % charge of cell
return 100*charge/maxcharge
@@ -97,8 +99,16 @@
/obj/item/stock_parts/cell/examine(mob/user)
. = ..()
+ // SKYRAT EDIT ADDITION
+ if(ratingdesc && !microfusion_readout)
+ . += "This one has a rating of [display_energy(maxcharge)], and you should not swallow it."
+ // SKYRAT EDIT END
if(rigged)
. += span_danger("This power cell seems to be faulty!")
+ // SKYRAT EDIT ADDITION
+ else if(microfusion_readout)
+ . += "The charge meter reads [charge]/[maxcharge] MF."
+ // SKYRAT EDIT END
else
. += "The charge meter reads [round(src.percent() )]%."
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 4daa5efab60..521728ee8ee 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -33,8 +33,6 @@
var/use_cyborg_cell = FALSE
///set to true so the gun is given an empty cell
var/dead_cell = FALSE
- ///Does this gun support swapping energy cells?
- var/supports_swapping_cells = FALSE
/obj/item/gun/energy/emp_act(severity)
. = ..()
@@ -106,6 +104,7 @@
ammo_type[i] = shot
shot = ammo_type[select]
fire_sound = shot.fire_sound
+ fire_sound_volume = shot.fire_sound_volume //SKYRAT EDIT ADDITION
fire_delay = shot.delay
/obj/item/gun/energy/Destroy()
@@ -180,6 +179,7 @@
select = 1
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
fire_sound = shot.fire_sound
+ fire_sound_volume = shot.fire_sound_volume //SKYRAT EDIT ADDITION
fire_delay = shot.delay
if (shot.select_name && user)
balloon_alert(user, "set to [shot.select_name]")
@@ -208,29 +208,6 @@
worn_icon_state = temp_icon_to_use
return ..()
-// SKYRAT ADDITION START
-/obj/item/gun/energy/attackby(obj/item/A, mob/user, params)
- . = ..()
- if (.)
- return
- if(!supports_swapping_cells)
- return
- if(istype(A, /obj/item/stock_parts/cell))
- if(!cell)
- to_chat(user, span_notice("You insert [A] into [src]."))
- cell = A
- A.forceMove(src)
- cut_overlays()
- update_overlays()
- return
- to_chat(user, span_notice("You swap [cell] for [A] in [src]."))
- cell.forceMove(get_turf(src))
- cell = A
- A.forceMove(src)
- cut_overlays()
- update_overlays()
-// SKYRAT ADDITION END
-
/obj/item/gun/energy/update_overlays()
. = ..()
// SKYRAT EDIT START
diff --git a/modular_skyrat/master_files/code/modules/projectiles/guns/gun.dm b/modular_skyrat/master_files/code/modules/projectiles/guns/gun.dm
index 4c1de170dd4..0623ae88fcf 100644
--- a/modular_skyrat/master_files/code/modules/projectiles/guns/gun.dm
+++ b/modular_skyrat/master_files/code/modules/projectiles/guns/gun.dm
@@ -61,8 +61,11 @@
var/obj/item/flashlight/seclite/gun_light
var/datum/action/item_action/toggle_gunlight/alight
var/gunlight_state = "flight"
+ var/gunlight_icon = 'icons/obj/guns/flashlights.dmi'
var/can_bayonet = FALSE //if a bayonet can be added or removed if it already has one.
+ var/bayonet_state = "bayonet"
+ var/bayonet_icon = 'icons/obj/guns/bayonets.dmi'
var/obj/item/knife/bayonet
var/knife_x_offset = 0
var/knife_y_offset = 0
@@ -728,20 +731,19 @@
if(gun_light)
var/mutable_appearance/flashlight_overlay
var/state = "[gunlight_state][gun_light.on? "_on":""]" //Generic state.
- if(gun_light.icon_state in icon_states('icons/obj/guns/flashlights.dmi')) //Snowflake state?
+ if(gun_light.icon_state in icon_states(gunlight_icon)) //Snowflake state?
state = gun_light.icon_state
- flashlight_overlay = mutable_appearance('icons/obj/guns/flashlights.dmi', state)
+ flashlight_overlay = mutable_appearance(gunlight_icon, state)
flashlight_overlay.pixel_x = flight_x_offset
flashlight_overlay.pixel_y = flight_y_offset
. += flashlight_overlay
if(bayonet)
var/mutable_appearance/knife_overlay
- var/state = "bayonet" //Generic state.
- if(bayonet.icon_state in icon_states('icons/obj/guns/bayonets.dmi')) //Snowflake state?
+ var/state = bayonet_state
+ if(bayonet.icon_state in icon_states(bayonet_icon)) //Snowflake state?
state = bayonet.icon_state
- var/icon/bayonet_icons = 'icons/obj/guns/bayonets.dmi'
- knife_overlay = mutable_appearance(bayonet_icons, state)
+ knife_overlay = mutable_appearance(bayonet_icon, state)
knife_overlay.pixel_x = knife_x_offset
knife_overlay.pixel_y = knife_y_offset
. += knife_overlay
diff --git a/modular_skyrat/modules/aesthetics/cells/cell.dm b/modular_skyrat/modules/aesthetics/cells/cell.dm
index 671349579ed..bdc9214d810 100644
--- a/modular_skyrat/modules/aesthetics/cells/cell.dm
+++ b/modular_skyrat/modules/aesthetics/cells/cell.dm
@@ -1,5 +1,7 @@
/obj/item/stock_parts/cell
icon = 'modular_skyrat/modules/aesthetics/cells/cell.dmi'
+ /// The charge overlay icon file for the cell charge lights
+ var/charge_overlay_icon = 'modular_skyrat/modules/aesthetics/cells/cell.dmi'
/obj/machinery/cell_charger
icon = 'modular_skyrat/modules/aesthetics/cells/cell.dmi'
diff --git a/modular_skyrat/modules/goofsec/code/projectiles.dm b/modular_skyrat/modules/goofsec/code/projectiles.dm
index aaa3847501d..5c6ff37f26d 100644
--- a/modular_skyrat/modules/goofsec/code/projectiles.dm
+++ b/modular_skyrat/modules/goofsec/code/projectiles.dm
@@ -48,7 +48,6 @@
ammo_type = list(/obj/item/ammo_casing/energy/laser/hardlight_bullet/vintorez)
shaded_charge = TRUE
cell_type = /obj/item/stock_parts/cell/super
- supports_swapping_cells = TRUE
/obj/item/ammo_casing/energy/laser/hardlight_bullet/vintorez
name = "hardlight bullet vintorez casing"
@@ -85,7 +84,6 @@
fire_delay = 10
shaded_charge = TRUE
cell_type = /obj/item/stock_parts/cell/super
- supports_swapping_cells = TRUE
/obj/item/ammo_casing/energy/laser/hardlight_bullet/norwind
name = "hardlight bullet norwind casing"
@@ -114,8 +112,6 @@
can_bayonet = TRUE
ammo_type = list(/obj/item/ammo_casing/energy/laser/hardlight_bullet/ostwind)
cell_type = /obj/item/stock_parts/cell/super
- supports_swapping_cells = TRUE
-
/obj/item/ammo_casing/energy/laser/hardlight_bullet/ostwind
name = "hardlight bullet norostwindwind casing"
projectile_type = /obj/projectile/beam/laser/hardlight_bullet/ostwind
@@ -146,7 +142,6 @@
ammo_type = list(/obj/item/ammo_casing/energy/laser/hardlight_bullet/pitbull)
shaded_charge = TRUE
cell_type = /obj/item/stock_parts/cell/super
- supports_swapping_cells = TRUE
/obj/item/ammo_casing/energy/laser/hardlight_bullet/pitbull
name = "hardlight bullet pitbull casing"
@@ -175,7 +170,6 @@
ammo_type = list(/obj/item/ammo_casing/energy/laser/hardlight_bullet/pcr)
shaded_charge = TRUE
cell_type = /obj/item/stock_parts/cell/super
- supports_swapping_cells = TRUE
/obj/item/ammo_casing/energy/laser/hardlight_bullet/pcr
name = "hardlight bullet pcr casing"
@@ -196,7 +190,6 @@
fire_delay = 2 SECONDS
ammo_type = list(/obj/item/ammo_casing/energy/laser/hardlight_bullet/peacemaker)
shaded_charge = TRUE
- supports_swapping_cells = FALSE
/obj/item/ammo_casing/energy/laser/hardlight_bullet/peacemaker
name = "hardlight bullet peacemaker casing"
@@ -208,14 +201,3 @@
damage = 60
*/
-//////////////RIFLE SPAWNER
-/obj/effect/spawner/armory_spawn/rifles
- icon_state = "random_rifle"
- gun_count = 4
- guns = list(
- /obj/item/gun/energy/pcr,
- /obj/item/gun/energy/pitbull,
- /obj/item/gun/energy/ostwind,
- /obj/item/gun/energy/norwind,
- /obj/item/gun/energy/vintorez,
- )
diff --git a/modular_skyrat/modules/gunhud/code/gun_hud_component.dm b/modular_skyrat/modules/gunhud/code/gun_hud_component.dm
index 33c8a4e58df..4c6a0e87b7e 100644
--- a/modular_skyrat/modules/gunhud/code/gun_hud_component.dm
+++ b/modular_skyrat/modules/gunhud/code/gun_hud_component.dm
@@ -152,6 +152,44 @@
oth_h = "h9"
hud.set_hud(backing_color, oth_o, oth_t, oth_h, indicator)
+ else if(istype(parent, /obj/item/gun/microfusion))
+ var/obj/item/gun/microfusion/parent_gun = parent
+ if(!parent_gun.phase_emitter)
+ hud.icon_state = "microfusion_counter_no_emitter"
+ hud.maptext = null
+ return
+ if(parent_gun.phase_emitter.damaged)
+ hud.icon_state = "microfusion_counter_damaged"
+ hud.maptext = null
+ return
+ if(!parent_gun.cell)
+ hud.icon_state = "microfusion_counter_no_emitter"
+ hud.maptext = null
+ return
+ if(!parent_gun.cell.charge)
+ hud.icon_state = "microfusion_counter_no_emitter"
+ hud.maptext = null
+ return
+ var/phase_emitter_state = parent_gun.phase_emitter.get_heat_icon_state()
+ hud.icon_state = "microfusion_counter_[phase_emitter_state]"
+ hud.cut_overlays()
+ hud.maptext_x = -12
+ var/obj/item/ammo_casing/energy/shot = parent_gun.microfusion_lens
+ var/battery_percent = FLOOR(clamp(parent_gun.cell.charge / parent_gun.cell.maxcharge, 0, 1) * 100, 1)
+ var/shot_cost_percent = FLOOR(clamp(shot.e_cost / parent_gun.cell.maxcharge, 0, 1) * 100, 1)
+ if(battery_percent > 99 || shot_cost_percent > 99)
+ hud.maptext_x = -12
+ else
+ hud.maptext_x = -8
+ if(!parent_gun.can_shoot())
+ hud.icon_state = "microfusion_counter_no_emitter"
+ return
+ if(battery_percent <= 25)
+ hud.maptext = span_maptext("
[battery_percent]%
[shot_cost_percent]%
")
+ return
+ hud.maptext = span_maptext("[battery_percent]%
[shot_cost_percent]%
")
+
+
/obj/item/gun/ballistic/ComponentInitialize()
. = ..()
AddComponent(/datum/component/ammo_hud)
diff --git a/modular_skyrat/modules/gunhud/icons/gun_hud.dmi b/modular_skyrat/modules/gunhud/icons/gun_hud.dmi
index c412d504196..6bd861100e2 100644
Binary files a/modular_skyrat/modules/gunhud/icons/gun_hud.dmi and b/modular_skyrat/modules/gunhud/icons/gun_hud.dmi differ
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/master.dm b/modular_skyrat/modules/gunsgalore/code/guns/ballistic_master.dm
similarity index 85%
rename from modular_skyrat/modules/gunsgalore/code/guns/master.dm
rename to modular_skyrat/modules/gunsgalore/code/guns/ballistic_master.dm
index d9f5fdac274..d2437025350 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/master.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/ballistic_master.dm
@@ -1,15 +1,28 @@
/obj/item/gun/ballistic
- var/alt_icons = FALSE //Does this gun have mag and nomag on mob variance?
- var/alt_icon_state //What the icon state is for the on-back guns
- var/realistic = FALSE //realistic guns that use reliability and dirt
- var/jammed = FALSE //Is it jammed?
- var/dirt_level = 0 //how dirty a gun is.
- var/dirt_modifier = 0.1 //Tied in with how good a gun is, if firing it causes a lot of dirt to form, then change this accordingly.
- var/jam_chance = 0 //Used when calculating if a gun will jam or not.
- var/unjam_time = 0 //Used when calculating how long a gun takes to unjam.
+ /// Does this gun have mag and nomag on mob variance?
+ var/alt_icons = FALSE
+ /// What the icon state is for the on-back guns
+ var/alt_icon_state
+ /// Realistic guns that use reliability and dirt
+ var/realistic = FALSE
+ /// Is it jammed?
+ var/jammed = FALSE
+ /// How dirty a gun is.
+ var/dirt_level = 0
+ /// Tied in with how good a gun is, if firing it causes a lot of dirt to form, then change this accordingly.
+ var/dirt_modifier = 0.1
+ /// Used when calculating if a gun will jam or not.
+ var/jam_chance = 0
+ /// Used when calculating how long a gun takes to unjam.
+ var/unjam_time = 0
+ /// Tracking gun base spred.
var/base_spread = 0
- var/durability = 100 //How used this gun is.
- var/durability_factor = 0.1 //How quickly a gun will degrade. 0.1 = 1000 shots. Edit this to change a guns base reliability.
+ /// How used this gun is.
+ var/durability = 100
+ /// How quickly a gun will degrade. 0.1 = 1000 shots. Edit this to change a guns base reliability.
+ var/durability_factor = 0.1
+ /// How long it takes to reload a magazine.
+ var/reload_time = 2 SECONDS
/obj/item/gun/ballistic/Initialize()
@@ -40,6 +53,14 @@
inhand_icon_state = "[initial(icon_state)]"
worn_icon_state = "[initial(icon_state)]"
+/obj/item/gun/ballistic/insert_magazine(mob/user, obj/item/ammo_box/magazine/AM, display_message)
+ if(reload_time && !HAS_TRAIT(user, TRAIT_INSTANT_RELOAD) && magazine) //This only happens when you're attempting a tactical reload, e.g. there's a mag already inserted.
+ to_chat(user, span_notice("You start to insert the magazine into [src]!"))
+ if(!do_after(user, reload_time, src))
+ to_chat(user, span_danger("You fail to insert the magazine into [src]!"))
+ return
+ . = ..()
+
/obj/item/gun/ballistic/assault_rifle
rack_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_cock.ogg'
load_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_magin.ogg'
@@ -134,6 +155,8 @@
if(jammed)
jam(TRUE, user)
return
+ if(!internal_magazine && magazine && user.Adjacent(src))
+ eject_magazine(user)
. = ..()
/obj/item/gun/ballistic/examine(mob/user)
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/skillchip.dm b/modular_skyrat/modules/gunsgalore/code/guns/skillchip.dm
new file mode 100644
index 00000000000..542114b5c3c
--- /dev/null
+++ b/modular_skyrat/modules/gunsgalore/code/guns/skillchip.dm
@@ -0,0 +1,9 @@
+/obj/item/skillchip/chameleon/reload
+ name = "T.A.C.T.I.C00L skillchip"
+ desc = "If used, allows the user to perform tactical and instant reloads on all weapons with a magazine."
+ auto_traits = list(TRAIT_INSTANT_RELOAD)
+ skill_name = "Tactical Reloading"
+ skill_description = "Fine tune motor skills when performing reloads on weapons to reduce time taken."
+ skill_icon = "sitemap"
+ activate_message = span_notice("You suddenly learn the art of tactical reloading.")
+ deactivate_message = span_danger("You suddenly lose the ability to tactically reload.")
diff --git a/modular_skyrat/modules/microfusion/code/_microfusion_defines.dm b/modular_skyrat/modules/microfusion/code/_microfusion_defines.dm
new file mode 100644
index 00000000000..2abc005ea7e
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/_microfusion_defines.dm
@@ -0,0 +1,52 @@
+/// The amount of cell charge drained during a drain failure.
+#define MICROFUSION_CELL_DRAIN_FAILURE 500
+/// The heavy EMP range for when a cell suffers an EMP failure.
+#define MICROFUSION_CELL_EMP_HEAVY_FAILURE 2
+/// The light EMP range for when a cell suffers an EMP failure.
+#define MICROFUSION_CELL_EMP_LIGHT_FAILURE 4
+/// The radiation range for when a cell suffers a radiation failure.
+#define MICROFUSION_CELL_RADIATION_RANGE_FAILURE 1
+
+/// The lower most time for a microfusion cell meltdown.
+#define MICROFUSION_CELL_FAILURE_LOWER 10 SECONDS
+/// The upper most time for a microfusion cell meltdown.
+#define MICROFUSION_CELL_FAILURE_UPPER 15 SECONDS
+
+/// A charge drain failure.
+#define MICROFUSION_CELL_FAILURE_TYPE_CHARGE_DRAIN 1
+/// A small explosion failure.
+#define MICROFUSION_CELL_FAILURE_TYPE_EXPLOSION 2
+/// EMP failure.
+#define MICROFUSION_CELL_FAILURE_TYPE_EMP 3
+/// Radiation failure.
+#define MICROFUSION_CELL_FAILURE_TYPE_RADIATION 4
+
+/// Returned when the phase emtiter process is successful.
+#define SHOT_SUCCESS "success"
+/// Returned when a gun is fired but there is no phase emitter.
+#define SHOT_FAILURE_NO_EMITTER "No phase emitter installed!"
+
+/// The error message returned when the phase emitter is processed but damaged.
+#define PHASE_FAILURE_DAMAGED "PHASE EMITTER: Emitter damaged!"
+/// The error message returned when the phase emitter has reached it's htermal throttle.
+#define PHASE_FAILURE_THROTTLE "PHASE EMITTER: Thermal throttle active!"
+
+/// The heat dissipation bonus of an emitter being in space!
+#define PHASE_HEAT_DISSIPATION_BONUS_SPACE 30
+/// The heat dissipation bonus of an emitter being in air!
+#define PHASE_HEAT_DISSIPATION_BONUS_AIR 10
+
+// Slot defines for the gun.
+/// The gun barrel slot.
+#define GUN_SLOT_BARREL "barrel"
+/// The gun underbarrel slot.
+#define GUN_SLOT_UNDERBARREL "underbarrel"
+/// The gun rail slot.
+#define GUN_SLOT_RAIL "rail"
+/// Unique slots, can hold as many as you want.
+#define GUN_SLOT_UNIQUE "unique"
+
+/// Max name size for changing names
+#define GUN_MAX_NAME_CHARS 20
+/// Min name size for changing names
+#define GUN_MIN_NAME_CHARS 3
diff --git a/modular_skyrat/modules/microfusion/code/cargo_stuff.dm b/modular_skyrat/modules/microfusion/code/cargo_stuff.dm
new file mode 100644
index 00000000000..b29213fa232
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/cargo_stuff.dm
@@ -0,0 +1,51 @@
+/datum/supply_pack/security/armory/mcr01
+ name = "MCR-01 Microfusion Crate"
+ desc = "Micron Control Systems Incorporated supplied MCR-01 Microfusion weapons platform. Comes with 4 guns and 4 advanced cells!"
+ cost = CARGO_CRATE_VALUE * 20
+ contains = list(
+ /obj/item/gun/microfusion/mcr01/advanced,
+ /obj/item/gun/microfusion/mcr01/advanced,
+ /obj/item/gun/microfusion/mcr01/advanced,
+ /obj/item/gun/microfusion/mcr01/advanced,
+ /obj/item/storage/box/ammo_box/microfusion/advanced,
+ /obj/item/storage/box/ammo_box/microfusion/advanced,
+ /obj/item/storage/box/ammo_box/microfusion/advanced,
+ /obj/item/storage/box/ammo_box/microfusion/advanced,
+ )
+ crate_name = "MCR-01 Microfusion Crate"
+
+/datum/supply_pack/security/microfusion
+ name = "Assorted Microfusion Cell Crate"
+ desc = "Micron Control Systems Incorporated supplied Microfusion cells and attachments!"
+ cost = CARGO_CRATE_VALUE * 5
+ contains = list(
+ /obj/item/stock_parts/cell/microfusion/advanced,
+ /obj/item/stock_parts/cell/microfusion/advanced,
+ /obj/item/stock_parts/cell/microfusion/advanced,
+ /obj/item/stock_parts/cell/microfusion/advanced,
+ /obj/item/stock_parts/cell/microfusion/advanced,
+ /obj/item/stock_parts/cell/microfusion/advanced,
+ /obj/item/microfusion_cell_attachment/rechargeable,
+ /obj/item/microfusion_cell_attachment/rechargeable,
+ /obj/item/microfusion_cell_attachment/rechargeable,
+ /obj/item/microfusion_cell_attachment/rechargeable,
+ /obj/item/microfusion_cell_attachment/rechargeable,
+ /obj/item/microfusion_cell_attachment/rechargeable,
+ )
+ crate_name = "Microfusion Cell Crate"
+
+/datum/supply_pack/security/mcr01_attachments
+ name = "MCR-01 Military Attachments Crate"
+ desc = "Micron Control Systems Incorporated supplied MCR-01 Military spec attachments!"
+ cost = CARGO_CRATE_VALUE * 15
+ contains = list(
+ /obj/item/microfusion_gun_attachment/scope,
+ /obj/item/microfusion_gun_attachment/scope,
+ /obj/item/microfusion_gun_attachment/grip,
+ /obj/item/microfusion_gun_attachment/grip,
+ /obj/item/microfusion_gun_attachment/rail,
+ /obj/item/microfusion_gun_attachment/rail,
+ /obj/item/microfusion_gun_attachment/repeater,
+ /obj/item/microfusion_gun_attachment/repeater,
+ )
+ crate_name = "MCR-01 Military Attachments Crate"
diff --git a/modular_skyrat/modules/microfusion/code/gun_types.dm b/modular_skyrat/modules/microfusion/code/gun_types.dm
new file mode 100644
index 00000000000..4745258a564
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/gun_types.dm
@@ -0,0 +1,41 @@
+/obj/item/gun/microfusion/mcr01
+ name = "MCR-01"
+ desc = "An advanced, modular energy weapon produced by Allstar Lasers Incorporated. These cutting edge weapons differ from traditional beam weaponry in producing individual bolts, as well as utilizing hotswapped cells rather than being tied to immobile power sources."
+ icon_state = "mcr01"
+ inhand_icon_state = "mcr01"
+ shaded_charge = TRUE
+
+/// Gun for cargo crates.
+/obj/item/gun/microfusion/mcr01/advanced
+ name = "Advanced MCR-01"
+ cell_type = /obj/item/stock_parts/cell/microfusion/advanced
+ phase_emitter_type = /obj/item/microfusion_phase_emitter/advanced
+
+/obj/item/gun/microfusion/mcr01/nanocarbon
+ name = "Nanocarbon Destroyer"
+ desc = "The pinnacle of the Nanocarbon weapon line. This weapon is the ultimate in power and performance. It is capable of firing a wide variety of beams, including a wide range of energy types, and is capable of firing a wide variety of frequencies."
+ icon_state = "mcr01"
+ inhand_icon_state = "mcr01"
+ shaded_charge = TRUE
+
+/obj/item/storage/box/ammo_box/microfusion/advanced
+ name = "advanced microfusion cell container"
+ desc = "A box filled with microfusion cells."
+
+/obj/item/storage/box/ammo_box/microfusion/advanced/PopulateContents()
+ new /obj/item/storage/bag/ammo(src)
+ new /obj/item/stock_parts/cell/microfusion/advanced(src)
+ new /obj/item/stock_parts/cell/microfusion/advanced(src)
+ new /obj/item/stock_parts/cell/microfusion/advanced(src)
+
+//////////////MICROFUSION SPAWNERS
+/obj/effect/spawner/armory_spawn/microfusion
+ icon_state = "random_rifle"
+ gun_count = 4
+ guns = list(
+ /obj/item/gun/microfusion/mcr01,
+ /obj/item/gun/microfusion/mcr01,
+ /obj/item/gun/microfusion/mcr01,
+ /obj/item/gun/microfusion/mcr01,
+ )
+
diff --git a/modular_skyrat/modules/microfusion/code/microfusion_cell.dm b/modular_skyrat/modules/microfusion/code/microfusion_cell.dm
new file mode 100644
index 00000000000..f0953d7d959
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/microfusion_cell.dm
@@ -0,0 +1,189 @@
+/*
+MICROFUSION CELL SYSTEM
+
+Microfusion cells are small battery units that house controlled nuclear fusion within, and that fusion is converted into useable energy.
+
+They cannot be charged as standard, and require upgrades to do so.
+
+These are basically advanced cells.
+*/
+
+/obj/item/stock_parts/cell/microfusion //Just a standard cell.
+ name = "microfusion cell"
+ desc = "A standard-issue microfusion cell, produced by Micron Control Systems. Smaller than a can of soda, these fulfill the need for a power source where plugging into a recharger is inconvenient or unavailable; although they will eventually run dry due to being shipped without a fuel source."
+ icon = 'modular_skyrat/modules/microfusion/icons/microfusion_cells.dmi'
+ charge_overlay_icon = 'modular_skyrat/modules/microfusion/icons/microfusion_cells.dmi'
+ icon_state = "microfusion"
+ w_class = WEIGHT_CLASS_NORMAL
+ maxcharge = 1200 //12 shots
+ chargerate = 0 //Standard microfusion cells can't be recharged, they're single use.
+ microfusion_readout = TRUE
+
+ /// A hard referenced list of upgrades currently attached to the weapon.
+ var/list/attachments = list()
+ /// Are we melting down? For icon stuffs.
+ var/meltdown = FALSE
+ /// How many upgrades can you have on this cell?
+ var/max_attachments = 1
+ /// Hard ref to the parent gun.
+ var/obj/item/gun/microfusion/parent_gun
+ /// Do we play an alarm when empty?
+ var/empty_alarm = TRUE
+ /// What sound do we play when empty?
+ var/empty_alarm_sound = 'sound/weapons/gun/general/empty_alarm.ogg'
+ /// Do we have the self charging upgrade?
+ var/self_charging = FALSE
+
+/obj/item/stock_parts/cell
+ /// Is this cell stabilised? (used in microfusion guns)
+ var/stabilised = FALSE
+ /// Do we show the microfusion readout instead of KJ?
+ var/microfusion_readout = FALSE
+
+/obj/item/stock_parts/cell/microfusion/Destroy()
+ if(attachments.len)
+ for(var/obj/item/iterating_item as anything in attachments)
+ iterating_item.forceMove(get_turf(src))
+ attachments = null
+ parent_gun = null
+ return ..()
+
+/obj/item/stock_parts/cell/microfusion/attackby(obj/item/attacking_item, mob/living/user, params)
+ if(istype(attacking_item, /obj/item/microfusion_cell_attachment))
+ add_attachment(attacking_item, user)
+ return
+ return ..()
+
+/obj/item/stock_parts/cell/microfusion/emp_act(severity)
+ var/prob_percent = charge / 100 * severity
+ if(prob(prob_percent) && !meltdown && !stabilised && parent_gun)
+ process_instability()
+
+/obj/item/stock_parts/cell/microfusion/use(amount)
+ if(charge >= amount)
+ var/check_if_empty = charge - amount
+ if(check_if_empty < amount && empty_alarm && !self_charging)
+ playsound(src, empty_alarm_sound, 50)
+ return ..()
+
+/obj/item/stock_parts/cell/microfusion/proc/process_instability()
+ var/seconds_to_explode = rand(MICROFUSION_CELL_FAILURE_LOWER, MICROFUSION_CELL_FAILURE_UPPER)
+ meltdown = TRUE
+ say("Malfunction in [seconds_to_explode] seconds!")
+ playsound(src, 'sound/machines/warning-buzzer.ogg', 30, FALSE, FALSE)
+ add_filter("rad_glow", 2, list("type" = "outline", "color" = "#ff5e0049", "size" = 2))
+ addtimer(CALLBACK(src, .proc/process_failure), seconds_to_explode)
+
+/obj/item/stock_parts/cell/microfusion/proc/process_failure()
+ var/fuckup_type = rand(1, 4)
+ remove_filter("rad_glow")
+ playsound(src, 'sound/effects/spray.ogg', 70)
+ switch(fuckup_type)
+ if(MICROFUSION_CELL_FAILURE_TYPE_CHARGE_DRAIN)
+ charge = clamp(charge - MICROFUSION_CELL_DRAIN_FAILURE, 0, maxcharge)
+ if(MICROFUSION_CELL_FAILURE_TYPE_EXPLOSION)
+ explode()
+ if(MICROFUSION_CELL_FAILURE_TYPE_EMP)
+ empulse(get_turf(src), MICROFUSION_CELL_EMP_HEAVY_FAILURE, MICROFUSION_CELL_EMP_LIGHT_FAILURE, FALSE)
+ if(MICROFUSION_CELL_FAILURE_TYPE_RADIATION)
+ radiation_pulse(src, MICROFUSION_CELL_RADIATION_RANGE_FAILURE, RAD_MEDIUM_INSULATION)
+ meltdown = FALSE
+
+/obj/item/stock_parts/cell/microfusion/update_overlays()
+ . = ..()
+ for(var/obj/item/microfusion_cell_attachment/microfusion_cell_attachment as anything in attachments)
+ . += microfusion_cell_attachment.attachment_overlay_icon_state
+
+/obj/item/stock_parts/cell/microfusion/screwdriver_act(mob/living/user, obj/item/tool)
+ if(!attachments.len)
+ to_chat(user, span_danger("There are no attachments to remove!"))
+ return
+ remove_attachments()
+ playsound(src, 'sound/items/screwdriver.ogg', 70, TRUE)
+ to_chat(user, span_notice("You remove the upgrades from [src]."))
+
+/obj/item/stock_parts/cell/microfusion/process(delta_time)
+ for(var/obj/item/microfusion_cell_attachment/microfusion_cell_attachment as anything in attachments)
+ microfusion_cell_attachment.process_attachment(src, delta_time)
+
+/obj/item/stock_parts/cell/microfusion/examine(mob/user)
+ . = ..()
+ . += span_notice("It can hold [max_attachments] attachment(s).")
+ if(attachments.len)
+ for(var/obj/item/microfusion_cell_attachment/microfusion_cell_attachment as anything in attachments)
+ . += span_notice("It has a [microfusion_cell_attachment.name] installed.")
+ . += span_notice("Use a screwdriver to remove the attachments.")
+
+/obj/item/stock_parts/cell/microfusion/proc/add_attachment(obj/item/microfusion_cell_attachment/microfusion_cell_attachment, mob/living/user)
+ if(attachments.len >= max_attachments)
+ to_chat(user, span_warning("[src] cannot fit any more attachments!"))
+ return FALSE
+ if(is_type_in_list(microfusion_cell_attachment, attachments))
+ to_chat(user, span_warning("[src] already has [microfusion_cell_attachment] installed!"))
+ return FALSE
+ attachments += microfusion_cell_attachment
+ microfusion_cell_attachment.forceMove(src)
+ microfusion_cell_attachment.add_attachment(src)
+ to_chat(user, span_notice("You successfully install [microfusion_cell_attachment] onto [src]!"))
+ playsound(src, 'sound/effects/structure_stress/pop2.ogg', 70, TRUE)
+ update_appearance()
+ return TRUE
+
+/obj/item/stock_parts/cell/microfusion/proc/remove_attachments()
+ for(var/obj/item/microfusion_cell_attachment/microfusion_cell_attachment in attachments)
+ microfusion_cell_attachment.remove_attachment(src)
+ microfusion_cell_attachment.forceMove(get_turf(src))
+ attachments -= microfusion_cell_attachment
+ update_appearance()
+
+/datum/crafting_recipe/makeshift/microfusion_cell
+ name = "Makeshift Microfusion Cell"
+ tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER, TOOL_WELDER)
+ result = /obj/item/stock_parts/cell/microfusion/makeshift
+ reqs = list(/obj/item/trash/can = 1,
+ /obj/item/stack/sheet/iron = 1,
+ /obj/item/stack/cable_coil = 1)
+ time = 12 SECONDS
+ category = CAT_MISC
+
+//WHY WOULD YOU MAKE THIS?
+/obj/item/stock_parts/cell/microfusion/makeshift
+ name = "makeshift microfusion cell"
+ desc = "An... Apparatus, comprised of an everyday aluminum can with several civilian-grade batteries tightly packed together and plugged in. This vaguely resembles a microfusion cell, if you tilt your head to a precise fifty degree angle. While the effects on enemy combatants may be dubious, it will certainly do incredible damage to the gun's warranty. What the hell were you thinking when you came up with this?"
+ icon_state = "microfusion_makeshift"
+ maxcharge = 600
+ max_attachments = 0
+ /// The probability of the cell failing
+ var/fail_prob = 10
+
+/obj/item/stock_parts/cell/microfusion/makeshift/use(amount)
+ if(prob(fail_prob))
+ process_instability()
+ return ..()
+
+/obj/item/stock_parts/cell/microfusion/enhanced
+ name = "enhanced microfusion cell"
+ desc = "A second generation microfusion cell, weighing about the same as the standard-issue cell and having the same space for attachments; however, it has a higher capacity."
+ icon_state = "microfusion_enhanced"
+ maxcharge = 1500
+
+/obj/item/stock_parts/cell/microfusion/advanced
+ name = "advanced microfusion cell"
+ desc = "A third generation microfusion cell, boasting a much higher shot count. Additionally, these come with support for up to three modifications to the cell itself."
+ icon_state = "microfusion_advanced"
+ maxcharge = 1700
+ max_attachments = 3
+
+/obj/item/stock_parts/cell/microfusion/bluespace
+ name = "bluespace microfusion cell"
+ desc = "A fourth generation microfusion cell, employing bluespace technology to store power in a medium that's bigger on the inside. This has the highest capacity of any man-portable cell, and has flexibility for four different attachments to the cell itself."
+ icon_state = "microfusion_bluespace"
+ maxcharge = 2000
+ max_attachments = 4
+
+/obj/item/stock_parts/cell/microfusion/nanocarbon
+ name = "nanocarbon fusion cell"
+ desc = "This cell combines both top-of-the-line nanotech and advanced microfusion power to brute force the most common issue of Nanotrasen Asset Protection operatives, ammunition, through sheer volume. Intended for use with Nanotrasen-brand capacitor arrays only. Warranty void if dropped in toilet."
+ icon_state = "microfusion_nanocarbon"
+ maxcharge = 30000
+ max_attachments = 420
diff --git a/modular_skyrat/modules/microfusion/code/microfusion_cell_attachments.dm b/modular_skyrat/modules/microfusion/code/microfusion_cell_attachments.dm
new file mode 100644
index 00000000000..711d1db57aa
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/microfusion_cell_attachments.dm
@@ -0,0 +1,132 @@
+/*
+MICROFUSION CELL UPGRADE ATTACHMENTS
+
+For adding unique abilities to microfusion cells. These cannot directly interact with the gun.
+*/
+
+/obj/item/microfusion_cell_attachment
+ name = "microfusion cell attachment"
+ desc = "broken"
+ icon = 'modular_skyrat/modules/microfusion/icons/microfusion_cells.dmi'
+ w_class = WEIGHT_CLASS_NORMAL
+ /// The overlay that will be automatically added, must be in the cells icon.
+ var/attachment_overlay_icon_state
+ /// Does this attachment process with the cell?
+ var/processing_attachment = FALSE
+
+
+/obj/item/microfusion_cell_attachment/proc/add_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ SHOULD_CALL_PARENT(TRUE)
+ START_PROCESSING(SSobj, microfusion_cell)
+ return
+
+/obj/item/microfusion_cell_attachment/proc/process_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell, delta_time)
+ return PROCESS_KILL
+
+/obj/item/microfusion_cell_attachment/proc/remove_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ SHOULD_CALL_PARENT(TRUE)
+ STOP_PROCESSING(SSobj, microfusion_cell)
+ return
+
+/*
+rechargeable ATTACHMENT
+
+Allows the cell to be recharged at a gun recharger OR cell recharger.
+*/
+/obj/item/microfusion_cell_attachment/rechargeable
+ name = "rechargeable microfusion cell attachment"
+ desc = "An adapter meant to be plugged into a microfusion cell, allowing the cell to be recharged at recharge stations for both weapons and civilian-grade batteries. Neither Allstar Lasers Incorporated or Micron Control Systems Incorporated suggest licking the prongs."
+ icon_state = "attachment_rechargeable"
+ attachment_overlay_icon_state = "microfusion_rechargeable"
+ /// The bonus charge rate by adding this attachment.
+ var/bonus_charge_rate = 300
+
+/obj/item/microfusion_cell_attachment/rechargeable/add_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ . = ..()
+ microfusion_cell.chargerate += bonus_charge_rate
+
+/obj/item/microfusion_cell_attachment/rechargeable/remove_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ . = ..()
+ microfusion_cell.chargerate -= bonus_charge_rate
+
+/*
+OVERCAPACITY ATTACHMENT
+
+Increases the cell capacity by a set percentage.
+*/
+/obj/item/microfusion_cell_attachment/overcapacity
+ name = "overcapacity microfusion cell attachment"
+ desc = "An attachment which increases the capacity of the microfusion cell it's attached to. These are an additional, smaller capacitor, using a system to automatically switch from the cell to the capacitor as it's depleted, maximizing the weapon's charge."
+ icon_state = "attachment_overcapacity"
+ attachment_overlay_icon_state = "microfusion_overcapacity"
+ /// How much the attachment increases the cell's capacity by, as a percentage
+ var/capacity_increase = 20
+ /// The initial capacity of the cell before this upgrade is added!
+ var/initial_charge_capacity = 0
+
+/obj/item/microfusion_cell_attachment/overcapacity/add_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ . = ..()
+ initial_charge_capacity = microfusion_cell.maxcharge
+ var/capacity_to_add = microfusion_cell.maxcharge / 100 * capacity_increase
+ microfusion_cell.maxcharge += capacity_to_add
+
+/obj/item/microfusion_cell_attachment/overcapacity/remove_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ . = ..()
+ microfusion_cell.charge = min(microfusion_cell.charge, initial_charge_capacity)
+ microfusion_cell.maxcharge = initial_charge_capacity
+ initial_charge_capacity = 0
+
+/*
+STABILISER ATTACHMENT
+
+The cell is stable and will not emit sparks when firing.
+*/
+
+/obj/item/microfusion_cell_attachment/stabiliser
+ name = "stabilising microfusion cell attachment"
+ desc = "A stabilizer system attachment combining a grounding system with additional containment coils for self-charging purposes, this gives additional safety to the cell it's attached to; preventing both sparks and leakage."
+ icon_state = "attachment_stabiliser"
+ attachment_overlay_icon_state = "microfusion_stabiliser"
+
+/obj/item/microfusion_cell_attachment/stabiliser/add_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ . = ..()
+ microfusion_cell.stabilised = TRUE
+
+/obj/item/microfusion_cell_attachment/stabiliser/remove_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ . = ..()
+ microfusion_cell.stabilised = FALSE
+
+/*
+SELFCHARGE ATTACHMENT
+
+The cell will charge itself.
+If the cell isn't stabilised by a stabiliser, it may emit a radiation pulse.
+*/
+/obj/item/microfusion_cell_attachment/selfcharging
+ name = "self-charging microfusion cell attachment"
+ desc = "While microfusion cells are normally shipped without their fuel source, this attachment comes with fifteen grams of hydrogen fuel; allowing the cell to sustain a small, yet active reaction to self-charge. These can keep going for weeks to months in ideal conditions, making them more than enough for most campaigns."
+ icon_state = "attachment_selfcharge"
+ attachment_overlay_icon_state = "microfusion_selfcharge"
+ /// The amount of charge this cell will passively gain!
+ var/self_charge_amount = 20
+
+/obj/item/microfusion_cell_attachment/selfcharging/examine(mob/user)
+ . = ..()
+ . += span_warning("WARNING: May cause radiation burns and weapon instability if not stabilized with recommended attachment!")
+
+/obj/item/microfusion_cell_attachment/selfcharging/add_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ . = ..()
+ microfusion_cell.self_charging = TRUE
+
+/obj/item/microfusion_cell_attachment/selfcharging/remove_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell)
+ . = ..()
+ microfusion_cell.self_charging = FALSE
+
+/obj/item/microfusion_cell_attachment/selfcharging/process_attachment(obj/item/stock_parts/cell/microfusion/microfusion_cell, delta_time)
+ if(microfusion_cell.charge < microfusion_cell.maxcharge)
+ microfusion_cell.charge = clamp(microfusion_cell.charge + (self_charge_amount * delta_time), 0, microfusion_cell.maxcharge)
+ if(microfusion_cell.parent_gun)
+ microfusion_cell.parent_gun.update_appearance()
+ if(!microfusion_cell.stabilised && DT_PROB(1, delta_time))
+ radiation_pulse(src, 1, RAD_MEDIUM_INSULATION)
+
diff --git a/modular_skyrat/modules/microfusion/code/microfusion_designs.dm b/modular_skyrat/modules/microfusion/code/microfusion_designs.dm
new file mode 100644
index 00000000000..77377719943
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/microfusion_designs.dm
@@ -0,0 +1,218 @@
+// CELLS AND EMITTERS
+/datum/design/basic_microfusion_cell
+ name = "Basic Microfusion Cell"
+ desc = "A basic microfusion cell with a capacity of 1200 MF and and 1 attachment points."
+ id = "basic_microfusion_cell"
+ build_type = PROTOLATHE | AWAY_LATHE | AUTOLATHE
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 200)
+ construction_time = 10 SECONDS
+ build_path = /obj/item/stock_parts/cell/microfusion
+ category = list("Misc", "Power Designs", "Machinery", "initial")
+
+/datum/design/microfusion_phase_emitter_undercharger
+ name = "Microfusion Phase Emitter Undercharger"
+ desc = "Inverts the output beam of the phase emitter, popular amongst law enforcement as a non-lethal upgrade."
+ id = "microfusion_phase_emitter_undercharger"
+ build_type = PROTOLATHE | AWAY_LATHE | AUTOLATHE
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 200)
+ construction_time = 10 SECONDS
+ build_path = /obj/item/microfusion_gun_attachment/undercharger
+ category = list("Misc", "Power Designs", "Machinery", "initial")
+
+/datum/design/enhanced_microfusion_cell
+ name = "Enhanced Microfusion Cell"
+ desc = "An enhanced microfusion cell with a capacity of 1500 MF and 2 attachment points."
+ id = "enhanced_microfusion_cell"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 200, /datum/material/uranium = 200)
+ construction_time = 10 SECONDS
+ build_path = /obj/item/stock_parts/cell/microfusion/enhanced
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/enhanced_microfusion_phase_emitter
+ name = "Enhanced Microfusion Phase Emitter"
+ desc = "The core of a microfusion projection weapon, produces the laser."
+ id = "enhanced_microfusion_phase_emitter"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/silver = 500)
+ construction_time = 10 SECONDS
+ build_path = /obj/item/microfusion_phase_emitter/enhanced
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/advanced_microfusion_cell
+ name = "Advanced Microfusion Cell"
+ desc = "An advanced microfusion cell with a capacity of 1700 MF and 3 attachment points."
+ id = "advanced_microfusion_cell"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/gold = 300, /datum/material/silver = 300, /datum/material/glass = 300, /datum/material/uranium = 300)
+ construction_time = 10 SECONDS
+ build_path = /obj/item/stock_parts/cell/microfusion/advanced
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/advanced_microfusion_phase_emitter
+ name = "Advanced Microfusion Phase Emitter"
+ desc = "The core of a microfusion projection weapon, produces the laser."
+ id = "advanced_microfusion_phase_emitter"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/silver = 500, /datum/material/gold = 500)
+ construction_time = 10 SECONDS
+ build_path = /obj/item/microfusion_phase_emitter/advanced
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/bluespace_microfusion_cell
+ name = "Bluespace Microfusion Cell"
+ desc = "A bluespace microfusion cell with a capacity of 2000 MF and 4 attachment points."
+ id = "bluespace_microfusion_cell"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/gold = 300, /datum/material/glass = 300, /datum/material/diamond = 300, /datum/material/uranium = 300, /datum/material/titanium = 300, /datum/material/bluespace = 300)
+ construction_time = 10 SECONDS
+ build_path = /obj/item/stock_parts/cell/microfusion/bluespace
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/bluespace_microfusion_phase_emitter
+ name = "Bluespace Microfusion Phase Emitter"
+ desc = "The core of a microfusion projection weapon, produces the laser."
+ id = "bluespace_microfusion_phase_emitter"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/silver = 500, /datum/material/gold = 500, /datum/material/diamond = 500)
+ construction_time = 10 SECONDS
+ build_path = /obj/item/microfusion_phase_emitter/bluespace
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+// CELL UPGRADES
+/datum/design/microfusion_cell_attachment_rechargeable
+ name = "Rechargeable Microfusion Cell Attachment"
+ desc = "An attachment for microfusion cells that allows conversion of KJ to MF in standard chargers."
+ id = "microfusion_cell_attachment_rechargeable"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/gold = 1000)
+ build_path = /obj/item/microfusion_cell_attachment/rechargeable
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_cell_attachment_stabiliser
+ name = "Stabilising Microfusion Cell Attachment"
+ desc = "Stabilises the internal fusion reaction of microfusion cells."
+ id = "microfusion_cell_attachment_stabiliser"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/plasma = 1000)
+ build_path = /obj/item/microfusion_cell_attachment/stabiliser
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_cell_attachment_overcapacity
+ name = "Overcapacity Microfusion Cell Attachment"
+ desc = "An attachment for microfusion cells that increases MF capacity."
+ id = "microfusion_cell_attachment_overcapacity"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/plasma = 500, /datum/material/gold = 500)
+ build_path = /obj/item/microfusion_cell_attachment/overcapacity
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_cell_attachment_selfcharging
+ name = "Self-Charging Microfusion Cell Attachment"
+ desc = "Contains a small amount of infinitely decaying nuclear material, causing the fusion reaction to be self sustaining. WARNING: May cause radiation burns if not stabilised."
+ id = "microfusion_cell_attachment_selfcharging"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/diamond = 500, /datum/material/uranium = 1000)
+ build_path = /obj/item/microfusion_cell_attachment/selfcharging
+ category = list("Misc", "Power Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+// GUN UPGRADES
+/datum/design/microfusion_gun_attachment_grip
+ name = "Microfusion Weapon Grip"
+ desc = "A grip... for microfusion weapon platforms."
+ id = "microfusion_gun_attachment_grip"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/silver = 500)
+ build_path = /obj/item/microfusion_gun_attachment/grip
+ category = list("Weapons")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_gun_attachment_scope
+ name = "Microfusion Weapon Scope"
+ desc = "A scope... for microfusion weapon platforms."
+ id = "microfusion_gun_attachment_scope"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/silver = 500)
+ build_path = /obj/item/microfusion_gun_attachment/scope
+ category = list("Weapons")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_gun_attachment_black_camo
+ name = "Black Camo Microfusion Frame"
+ desc = "A frame modification for the MCR-10, changing the color of the gun to black."
+ id = "microfusion_gun_attachment_black_camo"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/gold = 500)
+ build_path = /obj/item/microfusion_gun_attachment/black_camo
+ category = list("Weapons")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_gun_attachment_rail
+ name = "Microfusion Weapon Rail"
+ desc = "A rail system for any additional attachments, such as a torch."
+ id = "microfusion_gun_attachment_rail"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/silver = 500, /datum/material/gold = 500)
+ build_path = /obj/item/microfusion_gun_attachment/rail
+ category = list("Weapons")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_gun_attachment_heatsink
+ name = "Phase Emitter Heatsink"
+ desc = "A heatsink attachment for your microfusion weapon. Massively increases cooling potential."
+ id = "microfusion_gun_attachment_heatsink"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/silver = 500, /datum/material/bronze = 500)
+ build_path = /obj/item/microfusion_gun_attachment/heatsink
+ category = list("Weapons")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_gun_attachment_scatter
+ name = "Diffuser Microfusion Lens Attachment"
+ desc = "Splits the microfusion laser beam entering the lens!"
+ id = "microfusion_gun_attachment_scatter"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/diamond = 500, /datum/material/silver = 500)
+ build_path = /obj/item/microfusion_gun_attachment/scatter
+ category = list("Weapons")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_gun_attachment_superheat
+ name = "Superheating Phase Emitter Upgrade"
+ desc = "Superheats the beam, causing targets to ignite!"
+ id = "microfusion_gun_attachment_superheat"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/diamond = 500, /datum/material/plasma = 500)
+ build_path = /obj/item/microfusion_gun_attachment/superheat
+ category = list("Weapons")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_gun_attachment_repeater
+ name = "Repeating Phase Emitter Upgrade"
+ desc = "Upgrades the central phase emitter to repeat twice."
+ id = "microfusion_gun_attachment_repeater"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/diamond = 500, /datum/material/bluespace = 500)
+ build_path = /obj/item/microfusion_gun_attachment/repeater
+ category = list("Weapons")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/microfusion_gun_attachment_xray
+ name = "Phase Inverter Emitter Array"
+ desc = "Experimental technology that inverts the central phase emitter causing the wave frequency to shift into X-ray. CAUTION: Phase emitter heats up very quickly."
+ id = "microfusion_gun_attachment_xray"
+ build_type = PROTOLATHE | AWAY_LATHE | MECHFAB
+ materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000, /datum/material/diamond = 1000, /datum/material/uranium = 500, /datum/material/bluespace = 500)
+ build_path = /obj/item/microfusion_gun_attachment/xray
+ category = list("Weapons")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_SCIENCE
diff --git a/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm b/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm
new file mode 100644
index 00000000000..836459c4cc4
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm
@@ -0,0 +1,806 @@
+#define DUALWIELD_PENALTY_EXTRA_MULTIPLIER 1.4
+
+// Master file for cell loadable energy guns. PROCS ONLY YOU MONKEYS!
+// This file is a copy/paste of _energy.dm with extensive modification.
+
+/obj/item/gun/microfusion
+ name = "prototype detatchable cell energy projection aparatus"
+ desc = "The coders have obviously failed to realise this is broken."
+ icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi'
+ icon_state = "mcr01"
+ bayonet_icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi'
+ gunlight_icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi'
+ lefthand_file = 'modular_skyrat/modules/microfusion/icons/guns_lefthand.dmi'
+ righthand_file = 'modular_skyrat/modules/microfusion/icons/guns_lefthand.dmi'
+ has_gun_safety = TRUE
+ can_flashlight = FALSE
+ can_bayonet = FALSE
+ w_class = WEIGHT_CLASS_BULKY
+
+ /// What type of power cell this uses
+ var/obj/item/stock_parts/cell/microfusion/cell
+ /// The cell we will spawn with
+ var/cell_type = /obj/item/stock_parts/cell/microfusion
+ /// The cell type we check when inserting a cell
+ var/base_cell_type = /obj/item/stock_parts/cell/microfusion
+ /// If the weapon has custom icons for individual ammo types it can switch between. ie disabler beams, taser, laser/lethals, ect.
+ var/modifystate = FALSE
+ /// Can it be charged in a recharger?
+ var/can_charge = TRUE
+ /// How many charge sections do we have?
+ var/charge_sections = 4
+ ammo_x_offset = 2
+ /// if this gun uses a stateful charge bar for more detail
+ var/shaded_charge = FALSE
+ /// If this gun has a "this is loaded with X" overlay alongside chargebars and such
+ var/single_shot_type_overlay = TRUE
+ /// Should we give an overlay to empty guns?
+ var/display_empty = TRUE
+ /// whether the gun's cell drains the cyborg user's cell to recharge
+ var/dead_cell = FALSE
+
+ // MICROFUSION SPECIFIC VARS
+
+ /// The microfusion lens used for generating the beams.
+ var/obj/item/ammo_casing/energy/laser/microfusion/microfusion_lens
+ /// The time it takes for someone to (tactically) reload this gun. In deciseconds.
+ var/reload_time = 2 SECONDS
+ /// The sound played when you insert a cell.
+ var/sound_cell_insert = 'modular_skyrat/modules/microfusion/sound/mag_insert.ogg'
+ /// Should the insertion sound played vary?
+ var/sound_cell_insert_vary = TRUE
+ /// The volume at which we will play the insertion sound.
+ var/sound_cell_insert_volume = 50
+ /// The sound played when you remove a cell.
+ var/sound_cell_remove = 'modular_skyrat/modules/microfusion/sound/mag_insert.ogg'
+ /// Should the removal sound played vary?
+ var/sound_cell_remove_vary = TRUE
+ /// The volume at which we will play the removal sound.
+ var/sound_cell_remove_volume = 50
+ /// A list of attached upgrades
+ var/list/attachments = list()
+ /// The starting phase emitter in this weapon.
+ var/phase_emitter_type = /obj/item/microfusion_phase_emitter
+ /// The base emitter type that we check when putting a new emitter in.
+ var/base_phase_emitter_type = /obj/item/microfusion_phase_emitter
+ /// The phase emitter that this gun currently has.
+ var/obj/item/microfusion_phase_emitter/phase_emitter
+ /// The amount of heat produced per shot
+ var/heat_per_shot = 100
+ /// The heat dissipation bonus granted by the weapon.
+ var/heat_dissipation_bonus = 0
+ /// What slots does this gun have?
+ var/attachment_slots = list(GUN_SLOT_BARREL, GUN_SLOT_UNDERBARREL, GUN_SLOT_RAIL, GUN_SLOT_UNIQUE)
+ /// Our base firedelay.
+ var/base_fire_delay = 0
+ /// Do we use more power because of attachments?
+ var/extra_power_usage = 0
+
+/obj/item/gun/microfusion/emp_act(severity)
+ . = ..()
+ if(!(. & EMP_PROTECT_CONTENTS))
+ cell.use(round(cell.charge / severity))
+ chambered = null //we empty the chamber
+ recharge_newshot() //and try to charge a new shot
+ update_appearance()
+
+/obj/item/gun/microfusion/Initialize(mapload)
+ . = ..()
+ if(cell_type)
+ cell = new cell_type(src)
+ else
+ cell = new(src)
+ cell.parent_gun = src
+ if(!dead_cell)
+ cell.give(cell.maxcharge)
+ if(phase_emitter_type)
+ phase_emitter = new phase_emitter_type(src)
+ else
+ phase_emitter = new(src)
+ phase_emitter.parent_gun = src
+ update_microfusion_lens()
+ recharge_newshot(TRUE)
+ update_appearance()
+ AddComponent(/datum/component/ammo_hud)
+ RegisterSignal(src, COMSIG_ITEM_RECHARGED, .proc/instant_recharge)
+ base_fire_delay = fire_delay
+
+/obj/item/gun/microfusion/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/update_icon_updates_onmob)
+
+/obj/item/gun/microfusion/add_weapon_description()
+ AddElement(/datum/element/weapon_description, attached_proc = .proc/add_notes_energy)
+
+/obj/item/gun/microfusion/Destroy()
+ if(microfusion_lens)
+ QDEL_NULL(microfusion_lens)
+ if(cell)
+ cell.parent_gun = null
+ QDEL_NULL(cell)
+ if(attachments.len)
+ for(var/obj/item/iterating_item in attachments)
+ qdel(iterating_item)
+ attachments = null
+ if(phase_emitter)
+ QDEL_NULL(phase_emitter)
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/item/gun/microfusion/handle_atom_del(atom/to_handle)
+ if(to_handle == cell)
+ cell = null
+ update_appearance()
+ if(to_handle == phase_emitter)
+ phase_emitter = null
+ update_appearance()
+ return ..()
+
+/obj/item/gun/microfusion/can_shoot()
+ return !QDELETED(cell) ? (cell.charge >= microfusion_lens.e_cost) : FALSE
+
+/obj/item/gun/microfusion/recharge_newshot()
+ if (!microfusion_lens || !cell || !phase_emitter)
+ return
+ chambered = microfusion_lens
+ if(!chambered.loaded_projectile)
+ chambered.newshot()
+
+/obj/item/gun/microfusion/handle_chamber()
+ if(chambered && !chambered.loaded_projectile && cell) //if loaded_projectile is null, i.e the shot has been fired...
+ var/obj/item/ammo_casing/energy/shot = chambered
+ cell.use(shot.e_cost + extra_power_usage)//... drain the cell
+ chambered = null //either way, released the prepared shot
+ recharge_newshot() //try to charge a new shot
+
+/obj/item/gun/microfusion/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+ if(!chambered && can_shoot())
+ process_chamber() // If the gun was drained and then recharged, load a new shot.
+ return ..()
+
+/obj/item/gun/microfusion/update_icon_state()
+ var/skip_inhand = initial(inhand_icon_state) //only build if we aren't using a preset inhand icon
+ var/skip_worn_icon = initial(worn_icon_state) //only build if we aren't using a preset worn icon
+
+ if(skip_inhand && skip_worn_icon) //if we don't have either, don't do the math.
+ return ..()
+
+ var/ratio = get_charge_ratio()
+ var/temp_icon_to_use = initial(icon_state)
+ if(modifystate)
+ temp_icon_to_use += "[microfusion_lens.select_name]"
+
+ temp_icon_to_use += "[ratio]"
+ if(!skip_inhand)
+ inhand_icon_state = temp_icon_to_use
+ if(!skip_worn_icon)
+ worn_icon_state = temp_icon_to_use
+ return ..()
+
+/obj/item/gun/microfusion/update_overlays()
+ . = ..()
+ SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD) //update the ammo hud since it's heavily dependent on the gun's state
+ if(!phase_emitter)
+ . += "[icon_state]_phase_emitter_missing"
+ else if(phase_emitter.damaged)
+ . += "[icon_state]_phase_emitter_damaged"
+ else if(cell)
+ var/ratio = get_charge_ratio()
+ if(ratio == 0 && display_empty)
+ . += "[icon_state]_empty"
+ else if(shaded_charge)
+ . += "[icon_state]_charge[ratio]_[phase_emitter.icon_state]"
+ else
+ . += "[icon_state]_phase_emitter_missing"
+
+
+ for(var/obj/item/microfusion_gun_attachment/microfusion_gun_attachment in attachments)
+ . += "[icon_state]_[microfusion_gun_attachment.attachment_overlay_icon_state]"
+
+
+/obj/item/gun/microfusion/ignition_effect(atom/to_ignite, mob/living/user)
+ if(!can_shoot() || !microfusion_lens)
+ shoot_with_empty_chamber()
+ . = ""
+ else
+ var/obj/projectile/energy/loaded_projectile = microfusion_lens.loaded_projectile
+ if(!loaded_projectile)
+ . = ""
+ else if(loaded_projectile.nodamage || !loaded_projectile.damage || loaded_projectile.damage_type == STAMINA)
+ user.visible_message(span_danger("[user] tries to light [to_ignite.loc == user ? "[user.p_their()] [to_ignite.name]" : to_ignite] with [src], but it doesn't do anything. Dumbass."))
+ playsound(user, microfusion_lens.fire_sound, 50, TRUE)
+ playsound(user, loaded_projectile.hitsound, 50, TRUE)
+ cell.use(microfusion_lens.e_cost)
+ . = ""
+ else if(loaded_projectile.damage_type != BURN)
+ user.visible_message(span_danger("[user] tries to light [to_ignite.loc == user ? "[user.p_their()] [to_ignite.name]" : to_ignite] with [src], but only succeeds in utterly destroying it. Dumbass."))
+ playsound(user, microfusion_lens.fire_sound, 50, TRUE)
+ playsound(user, loaded_projectile.hitsound, 50, TRUE)
+ cell.use(microfusion_lens.e_cost)
+ qdel(to_ignite)
+ . = ""
+ else
+ playsound(user, microfusion_lens.fire_sound, 50, TRUE)
+ playsound(user, loaded_projectile.hitsound, 50, TRUE)
+ cell.use(microfusion_lens.e_cost)
+ . = span_danger("[user] casually lights [to_ignite.loc == user ? "[user.p_their()] [to_ignite.name]" : to_ignite] with [src]. Damn.")
+
+/obj/item/gun/microfusion/attackby(obj/item/attacking_item, mob/user, params)
+ . = ..()
+ if (.)
+ return
+ if(istype(attacking_item, base_cell_type))
+ insert_cell(user, attacking_item)
+ if(istype(attacking_item, /obj/item/microfusion_gun_attachment))
+ add_attachment(attacking_item, user)
+ if(istype(attacking_item, base_phase_emitter_type))
+ insert_emitter(attacking_item, user)
+
+/obj/item/gun/microfusion/process_chamber(empty_chamber, from_firing, chamber_next_round)
+ . = ..()
+ if(!cell?.stabilised && prob(40))
+ do_sparks(2, FALSE, src) //Microfusion guns create sparks!
+
+/obj/item/gun/microfusion/attack_hand(mob/user, list/modifiers)
+ if(loc == user && user.is_holding(src) && cell)
+ eject_cell(user)
+ return
+ return ..()
+
+/obj/item/gun/microfusion/crowbar_act(mob/living/user, obj/item/tool)
+ if(!phase_emitter)
+ to_chat(user, span_danger("There is no phase emitter for you to remove!"))
+ return
+ playsound(src, 'sound/items/crowbar.ogg', 70, TRUE)
+ remove_emitter()
+
+/obj/item/gun/microfusion/AltClick(mob/user)
+ . = ..()
+ if(can_interact(user))
+ var/obj/item/microfusion_gun_attachment/to_remove = input(user, "Please select what part you'd like to remove.", "Remove attachment") as null|obj in sort_names(attachments)
+ if(!to_remove)
+ return
+ remove_attachment(to_remove, user)
+
+/obj/item/gun/microfusion/proc/remove_all_attachments()
+ if(attachments.len)
+ for(var/obj/item/microfusion_gun_attachment/attachment in attachments)
+ attachment.remove_attachment(src)
+ attachment.forceMove(get_turf(src))
+ attachments -= attachment
+ update_appearance()
+
+/obj/item/gun/microfusion/examine(mob/user)
+ . = ..()
+ if(attachments.len)
+ for(var/obj/item/microfusion_gun_attachment/microfusion_gun_attachment in attachments)
+ . += span_notice("It has a [microfusion_gun_attachment.name] installed.")
+ . += span_notice("Alt+click it to remove an upgrade.")
+ if(phase_emitter)
+ . += span_notice("It has a [phase_emitter.name] installed, at [phase_emitter.get_heat_percent()]% heat capacity.")
+ . += span_notice("The [phase_emitter.name] is at [phase_emitter.integrity]% integrity.")
+ . += span_notice("The [phase_emitter.name] will thermal throttle at [phase_emitter.throttle_percentage]% heat capacity.")
+ . += span_notice("Use a crowbar to remove the phase emitter.")
+ else
+ . += span_danger("It does not have a phase emitter installed!")
+
+ if(cell)
+ . += span_notice("It has a [cell.name] installed, with a capacity of [cell.charge]/[cell.maxcharge] MF.")
+
+/obj/item/gun/microfusion/suicide_act(mob/living/user)
+ if (istype(user) && can_shoot() && can_trigger_gun(user) && user.get_bodypart(BODY_ZONE_HEAD))
+ user.visible_message(span_suicide("[user] is putting the barrel of [src] in [user.p_their()] mouth. It looks like [user.p_theyre()] trying to commit suicide!"))
+ sleep(25)
+ if(user.is_holding(src))
+ user.visible_message(span_suicide("[user] melts [user.p_their()] face off with [src]!"))
+ playsound(loc, fire_sound, 50, TRUE, -1)
+ cell.use(microfusion_lens.e_cost)
+ update_appearance()
+ return(FIRELOSS)
+ else
+ user.visible_message(span_suicide("[user] panics and starts choking to death!"))
+ return(OXYLOSS)
+ else
+ user.visible_message(span_suicide("[user] is pretending to melt [user.p_their()] face off with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
+ playsound(src, dry_fire_sound, 30, TRUE)
+ return (OXYLOSS)
+
+// To maintain modularity, I am moving this proc override here.
+/obj/item/gun/microfusion/fire_gun(atom/target, mob/living/user, flag, params)
+ if(QDELETED(target))
+ return
+ if(firing_burst)
+ return
+ if(flag) //It's adjacent, is the user, or is on the user's person
+ if(target in user.contents) //can't shoot stuff inside us.
+ return
+ if(!ismob(target) || user.combat_mode) //melee attack
+ return
+ if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected)
+ return
+ if(iscarbon(target))
+ var/mob/living/carbon/carbon = target
+ for(var/i in carbon.all_wounds)
+ var/datum/wound/W = i
+ if(W.try_treating(src, user))
+ return // another coward cured!
+
+ if(istype(user))//Check if the user can use the gun, if the user isn't alive(turrets) assume it can.
+ var/mob/living/living = user
+ if(!can_trigger_gun(living))
+ return
+ if(flag)
+ if(user.zone_selected == BODY_ZONE_PRECISE_MOUTH)
+ handle_suicide(user, target, params)
+ return
+
+ if(!can_shoot()) //Just because you can pull the trigger doesn't mean it can shoot.
+ shoot_with_empty_chamber(user)
+ return
+
+ if(check_botched(user))
+ return
+
+ var/obj/item/bodypart/other_hand = user.has_hand_for_held_index(user.get_inactive_hand_index()) //returns non-disabled inactive hands
+ if(weapon_weight == WEAPON_HEAVY && (user.get_inactive_held_item() || !other_hand))
+ to_chat(user, span_warning("You need two hands to fire [src]!"))
+ return
+
+ var/attempted_shot = process_emitter()
+ if(attempted_shot != SHOT_SUCCESS)
+ if(attempted_shot)
+ to_chat(user, span_danger(attempted_shot))
+ return
+
+ //DUAL (or more!) WIELDING
+ var/bonus_spread = 0
+ var/loop_counter = 0
+ if(ishuman(user) && user.combat_mode)
+ var/mob/living/carbon/human/H = user
+ for(var/obj/item/gun/gun in H.held_items)
+ if(gun == src || gun.weapon_weight >= WEAPON_MEDIUM)
+ continue
+ else if(gun.can_trigger_gun(user))
+ bonus_spread += dual_wield_spread
+ loop_counter++
+ addtimer(CALLBACK(gun, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread), loop_counter)
+
+ return process_fire(target, user, TRUE, params, null, bonus_spread)
+
+// To maintain modularity, I am moving this proc override here.
+/obj/item/gun/microfusion/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+ if(user)
+ SEND_SIGNAL(user, COMSIG_MOB_FIRED_GUN, user, target, params, zone_override)
+
+ SEND_SIGNAL(src, COMSIG_GUN_FIRED, user, target, params, zone_override)
+
+ add_fingerprint(user)
+
+ if(semicd)
+ return
+
+ //Vary by at least this much
+ var/base_bonus_spread = 0
+ var/calculated_spread = 0
+ var/randomized_gun_spread = 0
+ var/random_spread = rand()
+ if(user && HAS_TRAIT(user, TRAIT_POOR_AIM)) //Nice job hotshot
+ bonus_spread += 35
+ base_bonus_spread += 10
+
+ if(spread)
+ randomized_gun_spread = rand(0,spread)
+ var/randomized_bonus_spread = rand(base_bonus_spread, bonus_spread)
+
+ if(burst_size > 1)
+ firing_burst = TRUE
+ var/fire_delay_to_add = 0
+ if(phase_emitter)
+ fire_delay_to_add = phase_emitter.fire_delay
+ for(var/i = 1 to burst_size)
+ addtimer(CALLBACK(src, .proc/process_burst, user, target, message, params, zone_override, calculated_spread, randomized_gun_spread, randomized_bonus_spread, random_spread, i), (fire_delay + fire_delay_to_add) * (i - 1))
+ else
+ if(chambered)
+ if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
+ if(chambered.harmful) // Is the bullet chambered harmful?
+ to_chat(user, span_warning("[src] is lethally chambered! You don't want to risk harming anyone..."))
+ return
+ calculated_spread = round((rand(0, 1) - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
+ before_firing(target,user)
+ process_microfusion()
+ if(!chambered.fire_casing(target, user, params, , suppressed, zone_override, calculated_spread, src))
+ shoot_with_empty_chamber(user)
+ return
+ else
+ if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
+ shoot_live_shot(user, 1, target, message)
+ else
+ shoot_live_shot(user, 0, target, message)
+ else
+ shoot_with_empty_chamber(user)
+ return
+ process_chamber()
+ update_appearance()
+ semicd = TRUE
+ var/fire_delay_to_add = 0
+ if(phase_emitter)
+ fire_delay_to_add = phase_emitter.fire_delay
+ addtimer(CALLBACK(src, .proc/reset_semicd), fire_delay + fire_delay_to_add)
+
+ if(user)
+ user.update_inv_hands()
+ SSblackbox.record_feedback("tally", "gun_fired", 1, type)
+
+ SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD)
+
+ return TRUE
+
+// Same goes for this!
+/obj/item/gun/microfusion/process_burst(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", calculated_spread = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, random_spread= 0, iteration = 0)
+ if(!user || !firing_burst)
+ firing_burst = FALSE
+ return FALSE
+ if(!can_shoot())
+ firing_burst = FALSE
+ return FALSE
+ if(!chambered)
+ process_chamber() // Ditto.
+ if(!issilicon(user))
+ if(iteration > 1 && !(user.is_holding(src))) //for burst firing
+ firing_burst = FALSE
+ return FALSE
+ if(chambered?.loaded_projectile)
+ if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
+ if(chambered.harmful) // Is the bullet chambered harmful?
+ to_chat(user, span_warning("[src] is lethally chambered! You don't want to risk harming anyone..."))
+ return
+ if(randomspread)
+ calculated_spread = round((rand(0, 1) - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
+ else //Smart spread
+ calculated_spread = round((((random_spread/burst_size) * iteration) - (0.5 + (random_spread * 0.25))) * (randomized_gun_spread + randomized_bonus_spread))
+ before_firing(target,user)
+ process_microfusion()
+ if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, calculated_spread, src))
+ shoot_with_empty_chamber(user)
+ firing_burst = FALSE
+ return FALSE
+ else
+ if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
+ shoot_live_shot(user, 1, target, message)
+ else
+ shoot_live_shot(user, 0, target, message)
+ if (iteration >= burst_size)
+ firing_burst = FALSE
+ else
+ shoot_with_empty_chamber(user)
+ firing_burst = FALSE
+ return FALSE
+ process_chamber()
+ update_appearance()
+ SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD)
+ return TRUE
+
+/obj/item/gun/microfusion/shoot_live_shot(mob/living/user, pointblank, atom/pbtarget, message)
+ if(recoil)
+ shake_camera(user, recoil + 1, recoil)
+
+ var/sound_freq_to_add = 0
+
+ if(phase_emitter && phase_emitter.sound_freq > 1)
+ sound_freq_to_add = phase_emitter.sound_freq
+
+ if(suppressed)
+ playsound(user, suppressed_sound, suppressed_volume, vary_fire_sound, ignore_walls = FALSE, extrarange = SILENCED_SOUND_EXTRARANGE, frequency = sound_freq_to_add, falloff_distance = 0)
+ else
+ playsound(user, fire_sound, fire_sound_volume, vary_fire_sound, frequency = sound_freq_to_add)
+ if(message)
+ if(pointblank)
+ user.visible_message(span_danger("[user] fires [src] point blank at [pbtarget]!"), \
+ span_danger("You fire [src] point blank at [pbtarget]!"), \
+ span_hear("You hear a gunshot!"), COMBAT_MESSAGE_RANGE, pbtarget)
+ to_chat(pbtarget, span_userdanger("[user] fires [src] point blank at you!"))
+ if(pb_knockback > 0 && ismob(pbtarget))
+ var/mob/PBT = pbtarget
+ var/atom/throw_target = get_edge_target_turf(PBT, user.dir)
+ PBT.throw_at(throw_target, pb_knockback, 2)
+ else
+ user.visible_message(span_danger("[user] fires [src]!"), \
+ span_danger("You fire [src]!"), \
+ span_hear("You hear a gunshot!"), COMBAT_MESSAGE_RANGE)
+ if(user.resting)
+ user.Immobilize(20, TRUE)
+
+ phase_emitter.add_heat(heat_per_shot)
+
+ if(phase_emitter.current_heat > phase_emitter.max_heat)
+ if(ishuman(user))
+ var/mob/living/carbon/human/human = user
+ var/obj/item/bodypart/affecting = human.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm")
+ if(affecting?.receive_damage( 0, 5 )) // 1 burn damage
+ to_chat(user, span_warning("[src] burns your hand, it's too hot!"))
+
+/obj/item/gun/microfusion/proc/process_microfusion()
+ if(attachments.len)
+ for(var/obj/item/microfusion_gun_attachment/attachment in attachments)
+ attachment.process_fire(src, chambered)
+ return TRUE
+
+/obj/item/gun/microfusion/proc/process_emitter()
+ if(!phase_emitter)
+ return SHOT_FAILURE_NO_EMITTER
+ var/phase_emitter_process = phase_emitter.check_emitter()
+ if(phase_emitter_process != SHOT_SUCCESS)
+ return phase_emitter_process
+ return SHOT_SUCCESS
+
+/obj/item/gun/microfusion/proc/instant_recharge()
+ SIGNAL_HANDLER
+ if(!cell)
+ return
+ cell.charge = cell.maxcharge
+ recharge_newshot()
+ update_appearance()
+
+///Used by update_icon_state() and update_overlays()
+/obj/item/gun/microfusion/proc/get_charge_ratio()
+ return can_shoot() ? CEILING(clamp(cell.charge / cell.maxcharge, 0, 1) * charge_sections, 1) : 0
+ // Sets the ratio to 0 if the gun doesn't have enough charge to fire, or if its power cell is removed.
+
+/**
+ *
+ * Outputs type-specific weapon stats for energy-based firearms based on its firing modes
+ * and the stats of those firing modes. Esoteric firing modes like ion are currently not supported
+ * but can be added easily
+ *
+ */
+/obj/item/gun/microfusion/proc/add_notes_energy()
+ var/list/readout = list()
+ // Make sure there is something to actually retrieve
+ if(!microfusion_lens)
+ return
+ var/obj/projectile/exam_proj
+ readout += "Our heroic interns have shown that one can theoretically stay standing after..."
+ exam_proj = GLOB.proj_by_path_key[microfusion_lens?.projectile_type]
+
+ if(!istype(exam_proj))
+ return readout.Join("\n")
+
+ if(exam_proj.damage > 0) // Don't divide by 0!!!!!
+ readout += "[span_warning("[HITS_TO_CRIT(exam_proj.damage * microfusion_lens.pellets)] shot\s")] on [span_warning("[microfusion_lens.select_name]")] mode before collapsing from [exam_proj.damage_type == STAMINA ? "immense pain" : "their wounds"]."
+ if(exam_proj.stamina > 0) // In case a projectile does damage AND stamina damage (Energy Crossbow)
+ readout += "[span_warning("[HITS_TO_CRIT(exam_proj.stamina * microfusion_lens.pellets)] shot\s")] on [span_warning("[microfusion_lens.select_name]")] mode before collapsing from immense pain."
+ else
+ readout += "a theoretically infinite number of shots on [span_warning("[microfusion_lens.select_name]")] mode."
+
+ return readout.Join("\n") // Sending over the singular string, rather than the whole list
+
+/obj/item/gun/microfusion/proc/update_microfusion_lens()
+ if(!microfusion_lens)
+ microfusion_lens = new(src)
+ fire_sound = microfusion_lens.fire_sound
+ fire_sound_volume = microfusion_lens.fire_sound_volume
+ fire_delay = microfusion_lens.delay
+
+// Cell, emitter and upgrade interactions
+
+/obj/item/gun/microfusion/proc/remove_emitter(mob/user)
+ playsound(src, sound_cell_insert, 50, TRUE)
+ phase_emitter.forceMove(get_turf(src))
+ if(user)
+ user.put_in_hands(phase_emitter)
+ to_chat(user, span_notice("You remove [phase_emitter] from [src]!"))
+ phase_emitter.parent_gun = null
+ phase_emitter = null
+ update_appearance()
+
+/obj/item/gun/microfusion/proc/insert_emitter(obj/item/microfusion_phase_emitter/inserting_phase_emitter, mob/living/user)
+ if(phase_emitter)
+ to_chat(user, span_danger("There is already a phase emitter installed!"))
+ return FALSE
+ to_chat(user, span_notice("You carefully insert [inserting_phase_emitter] into the slot."))
+ playsound(src, sound_cell_remove, 50, TRUE)
+ inserting_phase_emitter.forceMove(src)
+ phase_emitter = inserting_phase_emitter
+ phase_emitter.parent_gun = src
+ update_appearance()
+
+
+/// Try to insert the cell into the gun, if successful, return TRUE
+/obj/item/gun/microfusion/proc/insert_cell(mob/user, obj/item/stock_parts/cell/microfusion/inserting_cell, display_message = TRUE)
+ var/tactical_reload = FALSE //We need to do this so that cells don't fall on the ground.
+ var/obj/item/stock_parts/cell/old_cell = cell
+ if(cell)
+ if(reload_time && !HAS_TRAIT(user, TRAIT_INSTANT_RELOAD)) //This only happens when you're attempting a tactical reload, e.g. there's a mag already inserted.
+ if(display_message)
+ to_chat(user, span_notice("You start to insert [inserting_cell] into [src]!"))
+ if(!do_after(user, reload_time, src))
+ if(display_message)
+ to_chat(user, span_warning("You fail to insert [inserting_cell] into [src]!"))
+ return FALSE
+ if(display_message)
+ to_chat(user, span_notice("You tactically reload [src], replacing [cell] inside!"))
+ tactical_reload = TRUE
+ eject_cell(user, FALSE, FALSE)
+ else if(display_message)
+ to_chat(user, span_notice("You insert [inserting_cell] into [src]!"))
+ if(sound_cell_insert)
+ playsound(src, sound_cell_insert, sound_cell_insert_volume, sound_cell_insert_vary)
+ cell = inserting_cell
+ inserting_cell.forceMove(src)
+ cell.parent_gun = src
+ if(tactical_reload)
+ user.put_in_hands(old_cell)
+ recharge_newshot()
+ update_appearance()
+ return TRUE
+
+/// Ejecting a cell.
+/obj/item/gun/microfusion/proc/eject_cell(mob/user, display_message = TRUE, put_in_hands = TRUE)
+ var/obj/item/stock_parts/cell/microfusion/old_cell = cell
+ old_cell.forceMove(get_turf(src))
+ if(user)
+ if(put_in_hands)
+ user.put_in_hands(old_cell)
+ if(display_message)
+ to_chat(user, span_notice("You remove [old_cell] from [src]!"))
+ if(sound_cell_remove)
+ playsound(src, sound_cell_remove, sound_cell_remove_volume, sound_cell_remove_vary)
+ old_cell.update_appearance()
+ cell.parent_gun = null
+ cell = null
+ update_appearance()
+
+/// Attatching an upgrade.
+/obj/item/gun/microfusion/proc/add_attachment(obj/item/microfusion_gun_attachment/microfusion_gun_attachment, mob/living/user)
+ if(is_type_in_list(microfusion_gun_attachment, attachments))
+ to_chat(user, span_warning("[src] already has [microfusion_gun_attachment] installed!"))
+ return FALSE
+ if(!(microfusion_gun_attachment.slot in attachment_slots))
+ to_chat(user, span_warning("[src] cannot install [microfusion_gun_attachment]!"))
+ return FALSE
+ for(var/obj/item/microfusion_gun_attachment/iterating_attachment in attachments)
+ if(is_type_in_list(microfusion_gun_attachment, iterating_attachment.incompatable_attachments))
+ to_chat(user, span_warning("[microfusion_gun_attachment] is not compatible with [iterating_attachment]!"))
+ return FALSE
+ if(iterating_attachment.slot != GUN_SLOT_UNIQUE && iterating_attachment.slot == microfusion_gun_attachment.slot)
+ to_chat(user, span_warning("[microfusion_gun_attachment] cannot be installed in the same slot as [iterating_attachment]!"))
+ return FALSE
+ attachments += microfusion_gun_attachment
+ microfusion_gun_attachment.forceMove(src)
+ microfusion_gun_attachment.run_attachment(src)
+ to_chat(user, span_notice("You successfully install [microfusion_gun_attachment] onto [src]!"))
+ playsound(src, 'sound/effects/structure_stress/pop2.ogg', 70, TRUE)
+ return TRUE
+
+/obj/item/gun/microfusion/proc/remove_attachment(obj/item/microfusion_gun_attachment/microfusion_gun_attachment, mob/living/user)
+ to_chat(user, span_notice("You remove [microfusion_gun_attachment] from [src]!"))
+ playsound(src, 'sound/items/screwdriver.ogg', 70)
+ microfusion_gun_attachment.forceMove(get_turf(src))
+ attachments -= microfusion_gun_attachment
+ microfusion_gun_attachment.remove_attachment(src)
+ user?.put_in_hands(microfusion_gun_attachment)
+ update_appearance()
+
+/obj/item/gun/microfusion/proc/change_name(mob/user)
+ var/new_name = input(user, "Enter new name:", "Change gun name") as null|text
+ if(!new_name)
+ return
+ var/name_length = length(new_name)
+ if(name_length > GUN_MAX_NAME_CHARS && name_length < GUN_MIN_NAME_CHARS)
+ to_chat(user, span_warning("New name cannot be longer than 20 or shorter than 5 characters!"))
+ return
+
+ name = sanitize(new_name)
+ update_appearance()
+
+// UI CONTROL
+
+/obj/item/gun/microfusion/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "MicrofusionGunControl")
+ ui.open()
+
+/obj/item/gun/microfusion/ui_data(mob/user)
+ var/list/data = list()
+
+ data["gun_name"] = name
+ data["gun_desc"] = desc
+ data["gun_heat_dissipation"] = heat_dissipation_bonus
+
+ if(phase_emitter)
+ data["has_emitter"] = TRUE
+ data["phase_emitter_data"] = list(
+ "type" = capitalize(phase_emitter.name),
+ "integrity" = phase_emitter.integrity,
+ "current_heat" = phase_emitter.current_heat,
+ "throttle_percentage" = phase_emitter.throttle_percentage,
+ "heat_dissipation_per_tick" = phase_emitter.heat_dissipation_per_tick,
+ "max_heat" = phase_emitter.max_heat,
+ "damaged" = phase_emitter.damaged,
+ "hacked" = phase_emitter.hacked,
+ "heat_percent" = phase_emitter.get_heat_percent(),
+ "process_time" = phase_emitter.fire_delay,
+ "cooling_system" = phase_emitter.cooling_system,
+ "cooling_system_rate" = phase_emitter.cooling_system_rate,
+ )
+ else
+ data["has_emitter"] = FALSE
+
+ if(cell)
+ var/list/attachments = list()
+ for(var/obj/item/microfusion_cell_attachment/attachment in cell.attachments)
+ attachments += attachment.name
+ data["has_cell"] = TRUE
+ data["cell_data"] = list(
+ "type" = capitalize(cell.name),
+ "charge" = cell.charge,
+ "max_charge" = cell.maxcharge,
+ "status" = cell.meltdown,
+ "attachments" = attachments,
+ )
+ else
+ data["has_cell"] = FALSE
+
+
+
+ if(attachments.len)
+ data["has_attachments"] = TRUE
+ data["attachments"] = list()
+ for(var/obj/item/microfusion_gun_attachment/attachment in attachments)
+ var/list/attachment_functions = attachment.get_modify_data()
+ var/has_modifications = FALSE
+ if(attachment_functions?.len > 0)
+ has_modifications = TRUE
+ data["attachments"] += list(list(
+ "name" = uppertext(attachment.name),
+ "desc" = attachment.desc,
+ "slot" = capitalize(attachment.slot),
+ "information" = attachment.get_information_data(),
+ "has_modifications" = has_modifications,
+ "modify" = attachment_functions,
+ "ref" = REF(attachment),
+ ))
+
+ else
+ data["has_attachments"] = FALSE
+
+ return data
+
+/obj/item/gun/microfusion/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return
+
+ switch(action)
+ if("eject_cell")
+ if(!cell)
+ return
+ eject_cell(usr)
+ if("change_gun_name")
+ change_name(usr)
+ if("overclock_emitter")
+ if(!phase_emitter)
+ return
+ if(!phase_emitter.hacked)
+ return
+ phase_emitter.set_overclock(usr)
+ if("eject_emitter")
+ if(!phase_emitter)
+ return
+ remove_emitter(usr)
+ if("remove_attachment")
+ var/obj/item/microfusion_gun_attachment/to_remove = locate(params["attachment_ref"]) in src
+ if(!to_remove)
+ return
+ remove_attachment(to_remove, usr)
+ if("modify_attachment")
+ var/obj/item/microfusion_gun_attachment/to_modify = locate(params["attachment_ref"]) in src
+ if(!to_modify)
+ return
+ to_modify.run_modify_data(params["modify_ref"], usr, src)
+ if("toggle_cooling_system")
+ if(!phase_emitter)
+ return
+ phase_emitter.toggle_cooling_system(usr)
+
diff --git a/modular_skyrat/modules/microfusion/code/microfusion_gun_attachments.dm b/modular_skyrat/modules/microfusion/code/microfusion_gun_attachments.dm
new file mode 100644
index 00000000000..b7f3e85967c
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/microfusion_gun_attachments.dm
@@ -0,0 +1,447 @@
+/**
+*MICROFUSION GUN UPGRADE ATTACHMENTS
+*For adding unique abilities to microfusion guns, these can directly interact with the gun!
+*/
+
+/obj/item/microfusion_gun_attachment
+ name = "microfusion gun attachment"
+ desc = "broken"
+ icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun_attachments.dmi'
+ w_class = WEIGHT_CLASS_NORMAL
+ /// The attachment overlay icon state.
+ var/attachment_overlay_icon_state
+ /// Any incompatable upgrade types.
+ var/list/incompatable_attachments = list()
+ /// The added heat produced by having this module installed.
+ var/heat_addition = 0
+ /// The slot this attachment is installed in.
+ var/slot = GUN_SLOT_UNIQUE
+ /// How much extra power do we use?
+ var/power_usage = 0
+
+/obj/item/microfusion_gun_attachment/examine(mob/user)
+ . = ..()
+ . += "Compatible slot: [slot]."
+
+/obj/item/microfusion_gun_attachment/proc/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ SHOULD_CALL_PARENT(TRUE)
+ microfusion_gun.heat_per_shot += heat_addition
+ microfusion_gun.update_appearance()
+ microfusion_gun.extra_power_usage += power_usage
+ return
+
+/obj/item/microfusion_gun_attachment/proc/process_attachment(obj/item/gun/microfusion/microfusion_gun)
+ return
+
+//Firing the gun right before we let go of it, tis is called.
+/obj/item/microfusion_gun_attachment/proc/process_fire(obj/item/gun/microfusion/microfusion_gun, obj/item/ammo_casing/chambered)
+ return
+
+/obj/item/microfusion_gun_attachment/proc/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ SHOULD_CALL_PARENT(TRUE)
+ microfusion_gun.heat_per_shot -= heat_addition
+ microfusion_gun.update_appearance()
+ microfusion_gun.extra_power_usage -= power_usage
+ return
+
+/*
+Returns a list of modifications of this attachment, it must return a list within a list list(list()).
+All of the following must be returned.
+list(list("title" = "Toggle [toggle ? "OFF" : "ON"]", "icon" = "power-off", "color" = "blue" "reference" = "toggle_on_off"))
+title - The title of the modification button
+icon - The icon of the modification button
+color - The color of the modification button
+reference - The reference of the modification button, this is used to call the proc when the run modify data proc is called.
+*/
+/obj/item/microfusion_gun_attachment/proc/get_modify_data()
+ return
+
+/obj/item/microfusion_gun_attachment/proc/run_modify_data(params, mob/living/user, obj/item/gun/microfusion/microfusion_gun)
+ return
+
+/obj/item/microfusion_gun_attachment/proc/get_information_data()
+ return
+
+/*
+SCATTER ATTACHMENT
+
+The cell is stable and will not emit sparks when firing.
+*/
+/obj/item/microfusion_gun_attachment/scatter
+ name = "diffuser microfusion lens upgrade"
+ desc = "A diffusing lens system capable of splitting one beam into three. However, the additional ionizing of the air will cause higher recoil."
+ icon_state = "attachment_scatter"
+ attachment_overlay_icon_state = "attachment_scatter"
+ slot = GUN_SLOT_BARREL
+ /// How many pellets are we going to add to the existing amount on the gun?
+ var/pellets_to_add = 2
+ /// The variation in pellet scatter.
+ var/variance_to_add = 20
+ /// How much recoil are we adding?
+ var/recoil_to_add = 1
+ /// The spread to add.
+ var/spread_to_add = 10
+
+/obj/item/microfusion_gun_attachment/scatter/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.recoil += recoil_to_add
+ microfusion_gun.spread += spread_to_add
+ microfusion_gun.microfusion_lens.pellets += pellets_to_add
+ microfusion_gun.microfusion_lens.variance += variance_to_add
+
+/obj/item/microfusion_gun_attachment/scatter/process_fire(obj/item/gun/microfusion/microfusion_gun, obj/item/ammo_casing/chambered)
+ . = ..()
+ chambered.loaded_projectile?.damage = chambered.loaded_projectile.damage / chambered.pellets
+
+/obj/item/microfusion_gun_attachment/scatter/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.recoil -= recoil_to_add
+ microfusion_gun.spread -= spread_to_add
+ microfusion_gun.microfusion_lens.pellets -= microfusion_gun.microfusion_lens.pellets
+ microfusion_gun.microfusion_lens.variance -= microfusion_gun.microfusion_lens.variance
+
+/*
+REPEATER ATTACHMENT
+
+The gun can fire volleys of shots.
+*/
+/obj/item/microfusion_gun_attachment/superheat
+ name = "superheating phase emitter upgrade"
+ desc = "A barrel attachment hooked to the phase emitter, this adjusts the beam's wavelength to carry an intense wave of heat; causing targets to ignite."
+ icon_state = "attachment_superheat"
+ attachment_overlay_icon_state = "attachment_superheat"
+ incompatable_attachments = list(/obj/item/microfusion_gun_attachment/scatter)
+ heat_addition = 70
+ slot = GUN_SLOT_BARREL
+ var/projectile_override =/obj/projectile/beam/laser/microfusion/superheated
+
+/obj/item/microfusion_gun_attachment/superheat/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.fire_sound = 'modular_skyrat/modules/microfusion/sound/vaporize.ogg'
+
+/obj/item/microfusion_gun_attachment/superheat/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.fire_sound = microfusion_gun.chambered?.fire_sound
+
+
+/obj/item/microfusion_gun_attachment/superheat/process_fire(obj/item/gun/microfusion/microfusion_gun, obj/item/ammo_casing/chambered)
+ . = ..()
+ chambered.loaded_projectile = new projectile_override
+
+/*
+REPEATER ATTACHMENT
+
+The gun can fire volleys of shots.
+*/
+/obj/item/microfusion_gun_attachment/repeater
+ name = "repeating phase emitter upgrade"
+ desc = "This barrel attachment upgrades the central phase emitter to fire off two beams in quick succession. While offering an increased rate of fire, the heat output and recoil rises too."
+ icon_state = "attachment_repeater"
+ attachment_overlay_icon_state = "attachment_repeater"
+ heat_addition = 40
+ slot = GUN_SLOT_BARREL
+ /// The spread to add to the gun.
+ var/spread_to_add = 15
+ /// The recoil to add to the gun.
+ var/recoil_to_add = 1
+ /// The burst to add to the gun.
+ var/burst_to_add = 1
+ /// The delay to add to the firing.
+ var/delay_to_add = 2
+
+/obj/item/microfusion_gun_attachment/repeater/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.recoil += recoil_to_add
+ microfusion_gun.burst_size += burst_to_add
+ microfusion_gun.fire_delay += delay_to_add
+ microfusion_gun.spread += spread_to_add
+
+/obj/item/microfusion_gun_attachment/repeater/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.recoil -= recoil_to_add
+ microfusion_gun.burst_size -= burst_to_add
+ microfusion_gun.fire_delay -= delay_to_add
+ microfusion_gun.spread -= spread_to_add
+
+/*
+X-RAY ATTACHMENT
+
+The gun can fire X-RAY shots.
+*/
+/obj/item/microfusion_gun_attachment/xray
+ name = "quantum phase inverter array" //Yes quantum makes things sound cooler.
+ desc = "An experimental barrel attachment that modifies the central phase emitter, causing the wave frequency to shift into X-ray. Capable of penetrating both glass and solid matter with ease, though the bolts don't carry a greater effect against armor, due to going through the target and doing more minimal internal damage. These attachments are power-hungry and overheat easily, though engineers have deemed the costs necessary drawbacks."
+ icon_state = "attachment_xray"
+ slot = GUN_SLOT_BARREL
+ attachment_overlay_icon_state = "attachment_xray"
+ heat_addition = 90
+ power_usage = 50
+
+/obj/item/microfusion_gun_attachment/xray/examine(mob/user)
+ . = ..()
+ . += span_warning("CAUTION: Phase emitter heats up extremely quickly, sustained fire not recommended!")
+
+/obj/item/microfusion_gun_attachment/xray/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.fire_sound = 'modular_skyrat/modules/microfusion/sound/incinerate.ogg'
+
+/obj/item/microfusion_gun_attachment/xray/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.fire_sound = microfusion_gun.chambered?.fire_sound
+
+/obj/item/microfusion_gun_attachment/xray/process_fire(obj/item/gun/microfusion/microfusion_gun, obj/item/ammo_casing/chambered)
+ . = ..()
+ chambered.loaded_projectile.icon_state = "laser_greyscale"
+ chambered.loaded_projectile.color = COLOR_GREEN
+ chambered.loaded_projectile.light_color = COLOR_GREEN
+ chambered.loaded_projectile.projectile_piercing = PASSCLOSEDTURF|PASSGRILLE|PASSGLASS
+
+/*
+GRIP ATTACHMENT
+
+Greatly reduces recoil and spread.
+*/
+/obj/item/microfusion_gun_attachment/grip
+ name = "grip attachment"
+ desc = "A simple grip that increases accuracy."
+ icon_state = "attachment_grip"
+ attachment_overlay_icon_state = "attachment_grip"
+ slot = GUN_SLOT_UNDERBARREL
+ /// How much recoil are we removing?
+ var/recoil_to_remove = 1
+ /// How much spread are we removing?
+ var/spread_to_remove = 10
+
+/obj/item/microfusion_gun_attachment/grip/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.recoil -= recoil_to_remove
+ microfusion_gun.spread -= spread_to_remove
+
+/obj/item/microfusion_gun_attachment/grip/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.recoil += recoil_to_remove
+ microfusion_gun.spread += spread_to_remove
+
+/*
+HEATSINK ATTACHMENT
+
+"Greatly increases the phase emitter cooling rate."
+*/
+/obj/item/microfusion_gun_attachment/heatsink
+ name = "phase emitter heatsink"
+ desc = "Greatly increases the phase emitter cooling rate."
+ icon_state = "attachment_heatsink"
+ attachment_overlay_icon_state = "attachment_heatsink"
+ slot = GUN_SLOT_UNDERBARREL
+ /// Coolant bonus
+ var/cooling_rate_increase = 50
+
+/obj/item/microfusion_gun_attachment/heatsink/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.heat_dissipation_bonus += cooling_rate_increase
+
+/obj/item/microfusion_gun_attachment/heatsink/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.heat_dissipation_bonus -= cooling_rate_increase
+
+/*
+UNDERCHARGER ATTACHMENT
+
+Massively decreases the output beam of the phase emitter.
+Converts shots to STAMNINA damage.
+*/
+/obj/item/microfusion_gun_attachment/undercharger
+ name = "phase emitter undercharger"
+ desc = "An underbarrel system hooked to the phase emitter, this allows the weapon to also fire an electron bolt, producing a short-lived underpowered electric charge capable of stunning targets. These shots are less demanding on the weapon, leading to an increase in cooling rate."
+ icon_state = "attachment_undercharger"
+ attachment_overlay_icon_state = "attachment_undercharger"
+ slot = GUN_SLOT_UNDERBARREL
+ var/toggle = FALSE
+ var/cooling_rate_increase = 10
+ /// The projectile we override
+ var/projectile_override = /obj/projectile/beam/microfusion_disabler
+ /// How much recoil are we removing?
+ var/recoil_to_remove = 1
+ /// How much spread are we removing?
+ var/spread_to_remove = 10
+
+/obj/item/microfusion_gun_attachment/undercharger/get_modify_data()
+ return list(list("title" = "Turn [toggle ? "OFF" : "ON"]", "icon" = "power-off", "color" = "[toggle ? "red" : "green"]", "reference" = "toggle_on_off"))
+
+/obj/item/microfusion_gun_attachment/undercharger/run_modify_data(params, mob/living/user, obj/item/gun/microfusion/microfusion_gun)
+ if(params == "toggle_on_off")
+ toggle(microfusion_gun, user)
+
+/obj/item/microfusion_gun_attachment/undercharger/proc/toggle(obj/item/gun/microfusion/microfusion_gun, mob/user)
+ if(toggle)
+ toggle = FALSE
+ microfusion_gun.heat_dissipation_bonus -= cooling_rate_increase
+ microfusion_gun.recoil -= recoil_to_remove
+ microfusion_gun.spread -= spread_to_remove
+ else
+ toggle = TRUE
+ microfusion_gun.heat_dissipation_bonus += cooling_rate_increase
+ microfusion_gun.recoil += recoil_to_remove
+ microfusion_gun.spread += spread_to_remove
+
+ if(user)
+ to_chat(user, span_notice("You toggle [src] [toggle ? "ON" : "OFF"]."))
+
+/obj/item/microfusion_gun_attachment/undercharger/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.fire_sound = 'modular_skyrat/modules/microfusion/sound/burn.ogg'
+
+/obj/item/microfusion_gun_attachment/undercharger/process_fire(obj/item/gun/microfusion/microfusion_gun, obj/item/ammo_casing/chambered)
+ . = ..()
+ if(toggle)
+ chambered.loaded_projectile = new projectile_override
+
+/obj/item/microfusion_gun_attachment/undercharger/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ if(toggle)
+ microfusion_gun.heat_dissipation_bonus -= cooling_rate_increase
+ microfusion_gun.recoil -= recoil_to_remove
+ microfusion_gun.spread -= spread_to_remove
+ microfusion_gun.fire_sound = microfusion_gun.chambered?.fire_sound
+
+/*
+RGB ATTACHMENT
+
+Enables you to change the light color of the laser.
+*/
+/obj/item/microfusion_gun_attachment/rgb
+ name = "phase emitter spectrograph"
+ desc = "An attachment hooked up to the phase emitter, allowing the user to adjust the color of the beam outputted. This has seen widespread use by various factions capable of getting their hands on microfusion weapons, whether as a calling card or simply for entertainment."
+ icon_state = "attachment_rgb"
+ attachment_overlay_icon_state = "attachment_rgb"
+ /// What color are we changing the sprite to?
+ var/color_to_apply = COLOR_MOSTLY_PURE_RED
+
+/obj/item/microfusion_gun_attachment/rgb/process_fire(obj/item/gun/microfusion/microfusion_gun, obj/item/ammo_casing/chambered)
+ . = ..()
+ chambered?.loaded_projectile.icon_state = "laser_greyscale"
+ chambered?.loaded_projectile.color = color_to_apply
+ chambered?.loaded_projectile.light_color = color_to_apply
+
+/obj/item/microfusion_gun_attachment/rgb/proc/select_color(mob/living/user)
+ var/new_color = input(user, "Please select your new projectile color", "Laser color", color_to_apply) as null|color
+
+ if(!new_color)
+ return
+
+ color_to_apply = new_color
+
+/obj/item/microfusion_gun_attachment/rgb/attack_self(mob/user, modifiers)
+ . = ..()
+ select_color(user)
+
+/obj/item/microfusion_gun_attachment/rgb/get_modify_data()
+ return list(list("title" = "Change Color", "icon" = "wrench", "reference" = "color", "color" = "blue"))
+
+/obj/item/microfusion_gun_attachment/rgb/run_modify_data(params, mob/living/user)
+ if(params == "color")
+ select_color(user)
+
+/*
+RAIL ATTACHMENT
+
+Allows for flashlights bayonets and adds 1 slot to equipment.
+*/
+/obj/item/microfusion_gun_attachment/rail
+ name = "gun rail attachment"
+ desc = "A simple set of rails that attaches to weapon hardpoints. Allows for 3 more attachment slots and the instillation of a flashlight or bayonet."
+ icon_state = "attachment_rail"
+ attachment_overlay_icon_state = "attachment_rail"
+ slot = GUN_SLOT_RAIL
+
+/obj/item/microfusion_gun_attachment/rail/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.can_flashlight = TRUE
+ microfusion_gun.can_bayonet = TRUE
+
+/obj/item/microfusion_gun_attachment/rail/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.gun_light = initial(microfusion_gun.can_flashlight)
+ if(microfusion_gun.gun_light)
+ microfusion_gun.gun_light.forceMove(get_turf(microfusion_gun))
+ microfusion_gun.clear_gunlight()
+ microfusion_gun.can_bayonet = initial(microfusion_gun.can_bayonet)
+ if(microfusion_gun.bayonet)
+ microfusion_gun.bayonet.forceMove(get_turf(microfusion_gun))
+ microfusion_gun.clear_bayonet()
+ microfusion_gun.remove_all_attachments()
+
+/*
+SCOPE ATTACHMENT
+
+Allows for a scope to be attached to the gun.
+DANGER: SNOWFLAKE ZONE
+*/
+/obj/item/microfusion_gun_attachment/scope
+ name = "scope attachment"
+ desc = "A simple telescopic scope, allowing for long-ranged use of the weapon. However, these do not provide any night vision."
+ icon_state = "attachment_scope"
+ attachment_overlay_icon_state = "attachment_scope"
+ slot = GUN_SLOT_RAIL
+
+/obj/item/microfusion_gun_attachment/scope/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ if(microfusion_gun.azoom)
+ return
+
+ microfusion_gun.azoom = new()
+ microfusion_gun.azoom.gun = microfusion_gun
+ microfusion_gun.update_action_buttons()
+
+/obj/item/microfusion_gun_attachment/scope/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ if(microfusion_gun.azoom)
+ microfusion_gun.azoom.Remove(microfusion_gun.azoom.owner)
+ QDEL_NULL(microfusion_gun.azoom)
+ microfusion_gun.update_action_buttons()
+
+/*
+BLACK CAMO ATTACHMENT
+
+Allows for a black camo to be applied to the gun.
+All tactical, all the time.
+*/
+/obj/item/microfusion_gun_attachment/black_camo
+ name = "black camo microfusion frame"
+ desc = "A frame modification for the MCR-10, changing the color of the gun to black."
+ icon_state = "attachment_black"
+ attachment_overlay_icon_state = "attachment_black"
+
+/*
+PULSE ATTACHMENT
+
+The gun can fire PULSE shots.
+*/
+/obj/item/microfusion_gun_attachment/pulse
+ name = "pulse induction carriage"
+ desc = "A cutting-edge bluespace capacitor array and distributing lens overhaul produced in laboratories by Nanotrasen scientists that allow microfusion rifles to fire military-grade pulse rounds. Comes equipped with cyclic cooling to ensure maximum combat efficiency, a munitions counter, and an extra-secure drop cage for the power source. May shorten trigger lifetime."
+ icon_state = "attachment_pulse"
+ slot = GUN_SLOT_BARREL
+ attachment_overlay_icon_state = "attachment_pulse"
+ heat_addition = 150
+ power_usage = 50
+ var/added_burst_size = 2
+ var/added_fire_delay = 2
+
+/obj/item/microfusion_gun_attachment/pulse/examine(mob/user)
+ . = ..()
+ . += span_warning("CAUTION: Phase emitter heats up extremely quickly, sustained fire not recommended!")
+
+/obj/item/microfusion_gun_attachment/pulse/run_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.burst_size += added_burst_size
+ microfusion_gun.fire_delay += added_fire_delay
+
+/obj/item/microfusion_gun_attachment/pulse/remove_attachment(obj/item/gun/microfusion/microfusion_gun)
+ . = ..()
+ microfusion_gun.burst_size -= added_burst_size
+ microfusion_gun.fire_delay -= added_fire_delay
+
+/obj/item/microfusion_gun_attachment/pulse/process_fire(obj/item/gun/microfusion/microfusion_gun, obj/item/ammo_casing/chambered)
+ . = ..()
+ chambered.loaded_projectile = new /obj/projectile/beam/pulse
diff --git a/modular_skyrat/modules/microfusion/code/microfusion_techweb.dm b/modular_skyrat/modules/microfusion/code/microfusion_techweb.dm
new file mode 100644
index 00000000000..a673f7fce65
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/microfusion_techweb.dm
@@ -0,0 +1,87 @@
+/datum/techweb_node/basic_microfusion
+ id = "basic_microfusion"
+ starting_node = TRUE
+ display_name = "Basic Microfusion Technology"
+ description = "Basic microfusion technology allowing for basic microfusion designs."
+ design_ids = list(
+ "basic_microfusion_cell",
+ "microfusion_phase_emitter_undercharger",
+ )
+
+//Enhanced microfusion
+/datum/techweb_node/enhanced_microfusion
+ id = "enhanced_microfusion"
+ display_name = "Enhanced Microfusion Technology"
+ description = "Enhanced microfusion technology allowing for upgraded basic microfusion!"
+ prereq_ids = list(
+ "basic_microfusion",
+ "engineering",
+ "weaponry",
+ "high_efficiency",
+ )
+ design_ids = list(
+ "enhanced_microfusion_cell",
+ "microfusion_cell_attachment_rechargeable",
+ "enhanced_microfusion_phase_emitter",
+ "microfusion_gun_attachment_black_camo",
+ )
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500)
+
+//Advanced microfusion
+/datum/techweb_node/advanced_microfusion
+ id = "advanced_microfusion"
+ display_name = "Advanced Microfusion Technology"
+ description = "Advanced microfusion technology allowing for advanced microfusion!"
+ prereq_ids = list(
+ "enhanced_microfusion",
+ "adv_engi",
+ "adv_weaponry",
+ "adv_power",
+ "adv_plasma",
+ )
+ design_ids = list(
+ "advanced_microfusion_cell",
+ "microfusion_cell_attachment_overcapacity",
+ "microfusion_cell_attachment_stabiliser",
+ "microfusion_gun_attachment_scatter",
+ "microfusion_gun_attachment_superheat",
+ "advanced_microfusion_phase_emitter",
+ "microfusion_gun_attachment_grip",
+ "microfusion_gun_attachment_rail",
+ "microfusion_gun_attachment_scope",
+ )
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
+
+
+// Bluespace microfusion
+/datum/techweb_node/bluespace_microfusion
+ id = "bluespace_microfusion"
+ display_name = "Bluespace Microfusion Technology"
+ description = "Bluespace tinkering plus microfusion technology!"
+ prereq_ids = list(
+ "advanced_microfusion",
+ "bluespace_power",
+ "beam_weapons",
+ "explosive_weapons",
+ )
+ design_ids = list(
+ "bluespace_microfusion_cell",
+ "microfusion_gun_attachment_repeater",
+ "bluespace_microfusion_phase_emitter",
+ "microfusion_cell_attachment_selfcharging",
+ )
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
+
+// Bluespace microfusion
+/datum/techweb_node/quantum_microfusion
+ id = "quantum_microfusion"
+ display_name = "Quantum Microfusion Technology"
+ description = "Bleeding edge microfusion tech, making use of the latest in materials and components, bluespace or otherwise."
+ prereq_ids = list(
+ "bluespace_microfusion",
+ "alientech",
+ )
+ design_ids = list(
+ "microfusion_gun_attachment_xray",
+ )
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 15000)
diff --git a/modular_skyrat/modules/microfusion/code/phase_emitter.dm b/modular_skyrat/modules/microfusion/code/phase_emitter.dm
new file mode 100644
index 00000000000..99a72ec27f0
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/phase_emitter.dm
@@ -0,0 +1,211 @@
+////////////////////////////////////////////////////////////// PHASE EMITTERS
+/*
+Basically the heart of the gun, can be upgraded.
+*/
+/obj/item/microfusion_phase_emitter
+ name = "basic microfusion phase emitter"
+ desc = "A first-generation phase emitter, this is the core of the weapon and the source of the beam."
+ icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun_attachments.dmi'
+ icon_state = "phase_emitter"
+ base_icon_state = "phase_emitter"
+ w_class = WEIGHT_CLASS_NORMAL
+ /// Max heat before it breaks
+ var/max_heat = 2000
+ /// Current heat level
+ var/current_heat = 0
+ /// Thermal throttle percentage
+ var/throttle_percentage = 80
+ /// How much heat it dissipates passively
+ var/heat_dissipation_per_tick = 30
+ /// Active cooling system
+ var/cooling_system = FALSE
+ /// How quickly does the active cooling system cool - 1/1 ratio of cell charge to cooling point
+ var/cooling_system_rate = 30
+ /// What is our dynamic integrity?
+ var/integrity = 100
+ /// Are we fucked?
+ var/damaged = FALSE
+ /// Hard ref to the gun.
+ var/obj/item/gun/microfusion/parent_gun
+ /// Are we "hacked" thus allowing overclocking?
+ var/hacked = FALSE
+ /// The fire delay this emitter adds to the gun.
+ var/fire_delay = 0
+ /// The sound playback speed, used for overheating sound effects on fire.
+ var/sound_freq = 0
+
+
+/obj/item/microfusion_phase_emitter/Initialize(mapload)
+ . = ..()
+ START_PROCESSING(SSobj, src)
+
+/obj/item/microfusion_phase_emitter/Destroy()
+ parent_gun = null
+ return ..()
+
+/obj/item/microfusion_phase_emitter/process(delta_time)
+ if(current_heat == 0)
+ return
+ var/calculated_heat_dissipation_per_tick = heat_dissipation_per_tick
+ if(isspaceturf(get_turf(src)))
+ calculated_heat_dissipation_per_tick += PHASE_HEAT_DISSIPATION_BONUS_SPACE // Passive cooling in space boost!
+ if(parent_gun)
+ calculated_heat_dissipation_per_tick += parent_gun.heat_dissipation_bonus
+ else
+ calculated_heat_dissipation_per_tick += PHASE_HEAT_DISSIPATION_BONUS_AIR //We get some passive cooling from being out of the gun.
+ if(cooling_system && parent_gun && parent_gun.cell && parent_gun.cell.use(cooling_system_rate))
+ calculated_heat_dissipation_per_tick += cooling_system_rate
+
+ current_heat = clamp(current_heat - (calculated_heat_dissipation_per_tick * delta_time) * 0.5, 0, INFINITY)
+ if(current_heat > max_heat)
+ integrity = integrity - current_heat / 1000 * delta_time * 0.5
+
+ process_fire_delay_and_sound()
+
+ if(integrity <= 0)
+ kill()
+ update_appearance()
+ parent_gun?.update_appearance()
+
+/obj/item/microfusion_phase_emitter/proc/toggle_cooling_system(mob/user)
+ if(!parent_gun)
+ return
+ if(!cooling_system && !parent_gun.cell)
+ if(user)
+ to_chat(user, span_warning("You need a cell to turn on the cooling system."))
+ return
+
+ if(cooling_system)
+ cooling_system = FALSE
+ else
+ cooling_system = TRUE
+
+ if(user)
+ to_chat(user, span_notice("You toggle the cooling system [cooling_system ? "ON" : "OFF"]."))
+
+/obj/item/microfusion_phase_emitter/multitool_act(mob/living/user, obj/item/tool)
+ if(hacked)
+ to_chat(user, span_warning("[src] is already unlocked!"))
+ return
+ to_chat(user, span_notice("You begin to override the thermal overclock safety..."))
+ if(do_after(user, 5 SECONDS, src))
+ hacked = TRUE
+ to_chat(user, span_notice("You override the thermal overclock safety."))
+
+/obj/item/microfusion_phase_emitter/proc/set_overclock(mob/living/user)
+ if(!hacked)
+ return
+ var/new_throttle = clamp(input(user, "Please input a new thermal throttle percentage(0-300):", "Phase Emitter Overclock") as null|num, 1, 300)
+
+ to_chat(user, span_notice("Thermal throttle percent set to: [new_throttle]."))
+
+ if(new_throttle > 100)
+ to_chat(user, span_danger("WARNING: You have input a throttle percentage of more than 100, this may cause emitter damage."))
+
+ throttle_percentage = new_throttle
+
+/obj/item/microfusion_phase_emitter/update_icon_state()
+ . = ..()
+
+ if(damaged)
+ icon_state = "[base_icon_state]_damaged"
+ else
+ switch(get_heat_percent())
+ if(40 to 69)
+ icon_state = "[base_icon_state]_hot"
+ if(70 to INFINITY)
+ icon_state = "[base_icon_state]_critical"
+ else
+ icon_state = base_icon_state
+
+/obj/item/microfusion_phase_emitter/proc/process_fire_delay_and_sound()
+ var/fire_delay_to_add = 0
+ if(integrity < 100)
+ fire_delay_to_add = fire_delay_to_add + (100 - integrity) / 10
+
+ if(current_heat > max_heat)
+ fire_delay_to_add = fire_delay_to_add + (current_heat - max_heat) / 100 //Holy shit this emitter is tanking
+
+ fire_delay = round(fire_delay_to_add, 1.45)
+
+/obj/item/microfusion_phase_emitter/proc/get_heat_icon_state()
+ switch(get_heat_percent())
+ if(40 to 69)
+ return "hot"
+ if(70 to INFINITY)
+ return "critical"
+ else
+ return "normal"
+
+/obj/item/microfusion_phase_emitter/examine(mob/user)
+ . = ..()
+ if(damaged)
+ . += span_danger("It is damaged beyond repair.")
+ else
+ . += span_notice("It has a thermal rating of: [max_heat] C")
+ . += span_notice("It dissipates heat at: [heat_dissipation_per_tick] C")
+ . += span_notice("Heat capacity: [get_heat_percent()]%")
+ . += span_notice("Integrity: [integrity]%")
+ . += span_notice("Thermal throttle: [throttle_percentage]%")
+ . += span_notice("Cooling system: [cooling_system ? "enabled, cooling at [cooling_system_rate] C/s" : "disabled"].")
+
+/obj/item/microfusion_phase_emitter/proc/get_heat_percent()
+ return round(current_heat / max_heat * 100)
+
+/obj/item/microfusion_phase_emitter/proc/check_emitter()
+ if(damaged)
+ return PHASE_FAILURE_DAMAGED
+ if(get_heat_percent() >= throttle_percentage)
+ return PHASE_FAILURE_THROTTLE
+ return SHOT_SUCCESS
+
+/obj/item/microfusion_phase_emitter/proc/add_heat(heat_to_add)
+ current_heat += heat_to_add
+ update_appearance()
+
+/obj/item/microfusion_phase_emitter/proc/kill()
+ damaged = TRUE
+ name = "damaged [name]"
+ playsound(src, 'modular_skyrat/modules/microfusion/sound/overheat.ogg', 70)
+ say("ERROR: Integrity failure!")
+ STOP_PROCESSING(SSobj, src)
+
+/obj/item/microfusion_phase_emitter/enhanced
+ name = "enhanced microfusion phase emitter"
+ desc = "A second-generation phase emitter, this one is made of more robust materials which allow for a higher capacity for heat, a faster dissipation and cooling of it, and more capacity for thermal throttling."
+ max_heat = 3000
+ throttle_percentage = 85
+ heat_dissipation_per_tick = 40
+ cooling_system_rate = 40
+ integrity = 120
+ color = "#ffffcc"
+
+/obj/item/microfusion_phase_emitter/advanced
+ name = "advanced microfusion phase emitter"
+ desc = "A third-generation phase emitter, boasting a high capacity for heat, greater dissipation and cooling, and is built using higher-grade materials for more durability."
+ max_heat = 4000
+ throttle_percentage = 90
+ heat_dissipation_per_tick = 50
+ cooling_system_rate = 50
+ integrity = 150
+ color = "#99ffcc"
+
+/obj/item/microfusion_phase_emitter/bluespace
+ name = "bluespace microfusion phase emitter"
+ desc = "A fourth-generation phase emitter, utilizing a bluespace medium to store and manage heat, allowing for much cooler temperatures than realspace would allow. This is made of nothing but the latest materials, leading to the highest durability of any phase emitter on the market."
+ max_heat = 5000
+ throttle_percentage = 95
+ heat_dissipation_per_tick = 60
+ cooling_system_rate = 60
+ integrity = 200
+ color = "#66ccff"
+
+/obj/item/microfusion_phase_emitter/nanocarbon
+ name = "nanocarbon microfusion phase emitter"
+ desc = "An experimental phase emitter, made of nanocarbon, which is the most durable material on the market. It is capable of storing and managing heat, and is capable of cooling at a much higher rate than the other phase emitters."
+ max_heat = 15000
+ throttle_percentage = 95
+ heat_dissipation_per_tick = 130
+ cooling_system_rate = 60
+ integrity = 500
+ color = "#6966ff"
diff --git a/modular_skyrat/modules/microfusion/code/projectiles.dm b/modular_skyrat/modules/microfusion/code/projectiles.dm
new file mode 100644
index 00000000000..b11e1446f25
--- /dev/null
+++ b/modular_skyrat/modules/microfusion/code/projectiles.dm
@@ -0,0 +1,44 @@
+/obj/item/ammo_casing
+ ///What volume should the sound play at?
+ var/fire_sound_volume = 50
+
+/obj/item/ammo_casing/energy/laser/microfusion
+ name = "microfusion energy lens"
+ projectile_type = /obj/projectile/beam/laser/microfusion
+ e_cost = 100 // 10 shots with a normal cell.
+ select_name = "laser"
+ fire_sound = 'modular_skyrat/modules/microfusion/sound/laser_1.ogg'
+ fire_sound_volume = 100
+
+/obj/projectile/beam/laser/microfusion
+ name = "microfusion laser"
+ icon = 'modular_skyrat/modules/microfusion/icons/projectiles.dmi'
+
+/obj/projectile/beam/microfusion_disabler
+ name = "microfusion disabler laser"
+ icon = 'modular_skyrat/modules/microfusion/icons/projectiles.dmi'
+ icon_state = "disabler"
+ damage = 41
+ damage_type = STAMINA
+ flag = ENERGY
+ hitsound = 'sound/weapons/tap.ogg'
+ eyeblur = 0
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
+ light_color = LIGHT_COLOR_BLUE
+ tracer_type = /obj/effect/projectile/tracer/disabler
+ muzzle_type = /obj/effect/projectile/muzzle/disabler
+ impact_type = /obj/effect/projectile/impact/disabler
+
+/obj/projectile/beam/laser/microfusion/superheated
+ name = "superheated microfusion laser"
+ icon_state = "laser_greyscale"
+ color = LIGHT_COLOR_FIRE
+ light_color = LIGHT_COLOR_FIRE
+
+
+/obj/projectile/beam/laser/microfusion/superheated/on_hit(atom/target, blocked)
+ . = ..()
+ if(isliving(target))
+ var/mob/living/living = target
+ living.fire_stacks += 2
+ living.IgniteMob()
diff --git a/modular_skyrat/modules/microfusion/icons/guns_lefthand.dmi b/modular_skyrat/modules/microfusion/icons/guns_lefthand.dmi
new file mode 100644
index 00000000000..6690df96ac0
Binary files /dev/null and b/modular_skyrat/modules/microfusion/icons/guns_lefthand.dmi differ
diff --git a/modular_skyrat/modules/microfusion/icons/guns_righthand.dmi b/modular_skyrat/modules/microfusion/icons/guns_righthand.dmi
new file mode 100644
index 00000000000..47f36b05d48
Binary files /dev/null and b/modular_skyrat/modules/microfusion/icons/guns_righthand.dmi differ
diff --git a/modular_skyrat/modules/microfusion/icons/microfusion_cells.dmi b/modular_skyrat/modules/microfusion/icons/microfusion_cells.dmi
new file mode 100644
index 00000000000..12afc1a7183
Binary files /dev/null and b/modular_skyrat/modules/microfusion/icons/microfusion_cells.dmi differ
diff --git a/modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi b/modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi
new file mode 100644
index 00000000000..02c1091fcd8
Binary files /dev/null and b/modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi differ
diff --git a/modular_skyrat/modules/microfusion/icons/microfusion_gun_attachments.dmi b/modular_skyrat/modules/microfusion/icons/microfusion_gun_attachments.dmi
new file mode 100644
index 00000000000..2c90ae846c4
Binary files /dev/null and b/modular_skyrat/modules/microfusion/icons/microfusion_gun_attachments.dmi differ
diff --git a/modular_skyrat/modules/microfusion/icons/projectiles.dmi b/modular_skyrat/modules/microfusion/icons/projectiles.dmi
new file mode 100644
index 00000000000..c3ee49a1e79
Binary files /dev/null and b/modular_skyrat/modules/microfusion/icons/projectiles.dmi differ
diff --git a/modular_skyrat/modules/microfusion/sound/burn.ogg b/modular_skyrat/modules/microfusion/sound/burn.ogg
new file mode 100644
index 00000000000..ea37d14ccc1
Binary files /dev/null and b/modular_skyrat/modules/microfusion/sound/burn.ogg differ
diff --git a/modular_skyrat/modules/microfusion/sound/incinerate.ogg b/modular_skyrat/modules/microfusion/sound/incinerate.ogg
new file mode 100644
index 00000000000..38f7846d7ab
Binary files /dev/null and b/modular_skyrat/modules/microfusion/sound/incinerate.ogg differ
diff --git a/modular_skyrat/modules/microfusion/sound/laser_1.ogg b/modular_skyrat/modules/microfusion/sound/laser_1.ogg
new file mode 100644
index 00000000000..285f74416d9
Binary files /dev/null and b/modular_skyrat/modules/microfusion/sound/laser_1.ogg differ
diff --git a/modular_skyrat/modules/microfusion/sound/mag_insert.ogg b/modular_skyrat/modules/microfusion/sound/mag_insert.ogg
new file mode 100644
index 00000000000..53460ebf14d
Binary files /dev/null and b/modular_skyrat/modules/microfusion/sound/mag_insert.ogg differ
diff --git a/modular_skyrat/modules/microfusion/sound/melt.ogg b/modular_skyrat/modules/microfusion/sound/melt.ogg
new file mode 100644
index 00000000000..45a847ad35f
Binary files /dev/null and b/modular_skyrat/modules/microfusion/sound/melt.ogg differ
diff --git a/modular_skyrat/modules/microfusion/sound/overheat.ogg b/modular_skyrat/modules/microfusion/sound/overheat.ogg
new file mode 100644
index 00000000000..3585471bf9b
Binary files /dev/null and b/modular_skyrat/modules/microfusion/sound/overheat.ogg differ
diff --git a/modular_skyrat/modules/microfusion/sound/vaporize.ogg b/modular_skyrat/modules/microfusion/sound/vaporize.ogg
new file mode 100644
index 00000000000..0ba30857973
Binary files /dev/null and b/modular_skyrat/modules/microfusion/sound/vaporize.ogg differ
diff --git a/modular_skyrat/modules/modular_items/code/bags.dm b/modular_skyrat/modules/modular_items/code/bags.dm
index 646eba97fca..8274c296c03 100644
--- a/modular_skyrat/modules/modular_items/code/bags.dm
+++ b/modular_skyrat/modules/modular_items/code/bags.dm
@@ -15,7 +15,7 @@
STR.max_combined_w_class = 30
STR.max_items = 3
STR.display_numerical_stacking = FALSE
- STR.can_hold = typecacheof(list(/obj/item/ammo_box/magazine, /obj/item/ammo_casing, /obj/item/ammo_box/revolver))
+ STR.can_hold = typecacheof(list(/obj/item/ammo_box/magazine, /obj/item/ammo_casing, /obj/item/ammo_box/revolver, /obj/item/stock_parts/cell/microfusion))
/obj/item/storage/bag/material
name = "material pouch"
diff --git a/modular_skyrat/modules/multicellcharger/code/multi_cell_charger.dm b/modular_skyrat/modules/multicellcharger/code/multi_cell_charger.dm
index 843acbab28b..12561e684cc 100644
--- a/modular_skyrat/modules/multicellcharger/code/multi_cell_charger.dm
+++ b/modular_skyrat/modules/multicellcharger/code/multi_cell_charger.dm
@@ -59,6 +59,10 @@
if(!anchored)
to_chat(user, span_warning("[src] isn't attached to the ground!"))
return
+ var/obj/item/stock_parts/cell/inserting_cell = tool
+ if(inserting_cell.chargerate <= 0)
+ to_chat(user, span_warning("[inserting_cell] cannot be recharged!"))
+ return
if(charging_batteries.len >= 4)
to_chat(user, span_warning("[src] is full, and cannot hold anymore cells!"))
return
diff --git a/modular_skyrat/modules/robohand/code/robohand.dm b/modular_skyrat/modules/robohand/code/robohand.dm
index c18343fade6..60cc7d43464 100644
--- a/modular_skyrat/modules/robohand/code/robohand.dm
+++ b/modular_skyrat/modules/robohand/code/robohand.dm
@@ -23,6 +23,7 @@
rack_sound = 'modular_skyrat/modules/robohand/sound/slide.ogg'
fire_sound_volume = 100
bolt_wording = "fuckin' slide"
+ reload_time = 0 //FAST AS FUCK BOIS!
//Gun actions
diff --git a/modular_skyrat/modules/sec_haul/code/guns/gun_spawns.dm b/modular_skyrat/modules/sec_haul/code/guns/gun_spawns.dm
index fc568e8ba99..4af51d2c4fa 100644
--- a/modular_skyrat/modules/sec_haul/code/guns/gun_spawns.dm
+++ b/modular_skyrat/modules/sec_haul/code/guns/gun_spawns.dm
@@ -15,24 +15,33 @@
/// Do we want to angle it so that it is horizontal?
var/vertical_guns = TRUE
-/obj/structure/rack/shelf
/obj/effect/spawner/armory_spawn/Initialize(mapload)
..()
- for(var/gun in guns) // 11/20/21: Gun spawners now spawn 1 of each gun in it's list no matter what, so as to reduce the RNG of the armory stock.
- var/obj/item/gun/spawned_gun = new gun(loc)
+ if(guns)
+ var/current_offset = -10
+ var/offset_percent = 20 / guns.len
+ for(var/gun in guns) // 11/20/21: Gun spawners now spawn 1 of each gun in it's list no matter what, so as to reduce the RNG of the armory stock.
+ var/obj/item/gun/spawned_gun = new gun(loc)
- if(vertical_guns)
- spawned_gun.place_on_rack()
- spawned_gun.pixel_x = rand(-10, 10)
+ if(vertical_guns)
+ spawned_gun.place_on_rack()
+ spawned_gun.pixel_x = current_offset
+ current_offset += offset_percent
- if(istype(spawned_gun, /obj/item/gun/ballistic))
- var/obj/item/gun/ballistic/spawned_ballistic_gun = spawned_gun
- if(spawned_ballistic_gun.magazine && !istype(spawned_ballistic_gun.magazine, /obj/item/ammo_box/magazine/internal))
- var/obj/item/storage/box/ammo_box/spawned_box = new(loc)
- spawned_box.name = "ammo box - [spawned_ballistic_gun.name]"
+ if(istype(spawned_gun, /obj/item/gun/ballistic))
+ var/obj/item/gun/ballistic/spawned_ballistic_gun = spawned_gun
+ if(spawned_ballistic_gun.magazine && !istype(spawned_ballistic_gun.magazine, /obj/item/ammo_box/magazine/internal))
+ var/obj/item/storage/box/ammo_box/spawned_box = new(loc)
+ spawned_box.name = "ammo box - [spawned_ballistic_gun.name]"
+ for(var/i in 1 to mags_to_spawn)
+ new spawned_ballistic_gun.mag_type (spawned_box)
+
+ if(istype(spawned_gun, /obj/item/gun/microfusion))
+ var/obj/item/gun/microfusion/spawned_microfusion_gun = spawned_gun
+ var/obj/item/storage/box/ammo_box/microfusion/spawned_box = new(loc)
for(var/i in 1 to mags_to_spawn)
- new spawned_ballistic_gun.mag_type (spawned_box)
+ new spawned_microfusion_gun.cell_type (spawned_box)
return INITIALIZE_HINT_QDEL
@@ -60,9 +69,12 @@
illustration = null
layer = 2.9
-/obj/item/storage/box/ammo_box/PopulateContents()
+/obj/item/storage/box/ammo_box/microfusion
+ name = "microfusion cell container"
+ desc = "A box filled with microfusion cells."
+
+/obj/item/storage/box/ammo_box/microfusion/PopulateContents()
new /obj/item/storage/bag/ammo(src)
- new /obj/item/gun_maintenance_supplies(src)
/obj/effect/spawner/armory_spawn/centcom_rifles
diff --git a/tgstation.dme b/tgstation.dme
index 7f19c13abcf..b43519921fe 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -4633,8 +4633,9 @@
#include "modular_skyrat\modules\gunpoint\code\gunpoint_radial.dm"
#include "modular_skyrat\modules\gunsafety\code\gun_safety.dm"
#include "modular_skyrat\modules\gunsgalore\code\ammo\ammo.dm"
+#include "modular_skyrat\modules\gunsgalore\code\guns\ballistic_master.dm"
#include "modular_skyrat\modules\gunsgalore\code\guns\energy.dm"
-#include "modular_skyrat\modules\gunsgalore\code\guns\master.dm"
+#include "modular_skyrat\modules\gunsgalore\code\guns\skillchip.dm"
#include "modular_skyrat\modules\gunsgalore\code\guns\akm\akm.dm"
#include "modular_skyrat\modules\gunsgalore\code\guns\fg42\fg42.dm"
#include "modular_skyrat\modules\gunsgalore\code\guns\m16\m16.dm"
@@ -4782,6 +4783,17 @@
#include "modular_skyrat\modules\mentor\code\mentorpm.dm"
#include "modular_skyrat\modules\mentor\code\mentorsay.dm"
#include "modular_skyrat\modules\mentor\code\mentorwho.dm"
+#include "modular_skyrat\modules\microfusion\code\_microfusion_defines.dm"
+#include "modular_skyrat\modules\microfusion\code\cargo_stuff.dm"
+#include "modular_skyrat\modules\microfusion\code\gun_types.dm"
+#include "modular_skyrat\modules\microfusion\code\microfusion_cell.dm"
+#include "modular_skyrat\modules\microfusion\code\microfusion_cell_attachments.dm"
+#include "modular_skyrat\modules\microfusion\code\microfusion_designs.dm"
+#include "modular_skyrat\modules\microfusion\code\microfusion_energy_master.dm"
+#include "modular_skyrat\modules\microfusion\code\microfusion_gun_attachments.dm"
+#include "modular_skyrat\modules\microfusion\code\microfusion_techweb.dm"
+#include "modular_skyrat\modules\microfusion\code\phase_emitter.dm"
+#include "modular_skyrat\modules\microfusion\code\projectiles.dm"
#include "modular_skyrat\modules\Midroundtraitor\code\datum_traitor.dm"
#include "modular_skyrat\modules\Midroundtraitor\code\event.dm"
#include "modular_skyrat\modules\modular_ert\code\engineer\engineer.dm"
diff --git a/tgui/packages/tgui/interfaces/MicrofusionGunControl.js b/tgui/packages/tgui/interfaces/MicrofusionGunControl.js
new file mode 100644
index 00000000000..106ab778a32
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/MicrofusionGunControl.js
@@ -0,0 +1,269 @@
+import { toFixed } from 'common/math';
+import { useBackend } from '../backend';
+import { NoticeBox, Section, Stack, Button, LabeledList, ProgressBar } from '../components';
+import { Window } from '../layouts';
+
+export const MicrofusionGunControl = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { cell_data } = data;
+ const { phase_emitter_data } = data;
+ const {
+ gun_name,
+ gun_desc,
+ gun_heat_dissipation,
+ has_cell,
+ has_emitter,
+ has_attachments,
+ attachments = [],
+ } = data;
+ return (
+
+
+
+
+ act('change_gun_name')} />
+ )}>
+
+
+ {gun_name}
+
+
+ {gun_desc}
+
+
+ {gun_heat_dissipation + ' C/s'}
+
+
+
+
+
+ act('eject_cell')} />
+ )}>
+ {has_cell ? (
+
+
+ {cell_data.type}
+
+
+ {cell_data.status ? 'ERROR' : 'Nominal'}
+
+
+
+ {cell_data.charge + '/' + cell_data.max_charge + 'MF'}
+
+
+ {!!cell_data.charge <= 0 && (
+
+
+
+ )}
+
+ ) : (
+
+ No cell installed!
+
+ )}
+
+
+
+ act('eject_emitter')} />
+ )}>
+ {has_emitter ? (
+ phase_emitter_data.damaged ? (
+
+ Phase emitter is damaged!
+
+ ) : (
+
+
+ {phase_emitter_data.type}
+
+
+
+ {toFixed(phase_emitter_data.current_heat) + ' C' + ' (' + phase_emitter_data.heat_percent + '%)'}
+
+
+
+ {phase_emitter_data.max_heat + ' C'}
+
+
+ {phase_emitter_data.throttle_percentage + '% '}
+
+
+ {phase_emitter_data.heat_dissipation_per_tick + ' C/s'}
+
+
+
+
+ {phase_emitter_data.cooling_system ? (
+ phase_emitter_data.heat_dissipation_per_tick + gun_heat_dissipation + phase_emitter_data.cooling_system_rate + ' C/s'
+ ) : (
+ phase_emitter_data.heat_dissipation_per_tick + gun_heat_dissipation + ' C/s'
+ )}
+
+
+
+ {phase_emitter_data.integrity + '%'}
+
+
+
+
+ {phase_emitter_data.process_time / 10 + 's'}
+
+
+ {phase_emitter_data.heat_percent
+ >= phase_emitter_data.throttle_percentage && (
+
+
+ Thermal throttle active!
+
+
+ )}
+ {phase_emitter_data.current_heat
+ >= phase_emitter_data.max_heat && (
+
+
+ Overheating!
+
+
+ )}
+
+ )
+ ) : (
+
+ No phase emitter installed!
+
+ )}
+
+
+
+
+ {has_attachments ? (
+ attachments.map((attachment, index) => (
+ act('remove_attachment', {
+ attachment_ref: attachment.ref,
+ })} />
+ )}>
+
+
+ {attachment.desc}
+
+
+ {attachment.slot}
+
+ {attachment.information && (
+
+ {attachment.information}
+
+ )}
+ {!!attachment.has_modifications && (
+ attachment.modify.map((mod, index) => (
+ act('modify_attachment', {
+ attachment_ref: attachment.ref,
+ modify_ref: mod.reference,
+ })} />
+ )} />
+ ))
+ )}
+
+
+ ))
+ ) : (
+
+ No attachments installed!
+
+ )}
+
+
+
+
+
+ );
+};