diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index 115e5e710a..7914c8cfdf 100644
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -10,7 +10,7 @@
active_power_usage = 40000 //40 kW
var/efficiency = 40000 //will provide the modified power rate when upgraded
var/obj/item/charging = null
- var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/modular_computer, /obj/item/weapon/computer_hardware/battery_module, /obj/item/weapon/cell, /obj/item/device/suit_cooling_unit/emergency, /obj/item/device/flashlight, /obj/item/device/electronic_assembly, /obj/item/weapon/weldingtool/electric, /obj/item/ammo_magazine/smart, /obj/item/device/flash, /obj/item/device/defib_kit, /obj/item/ammo_casing/microbattery, /obj/item/device/paicard, /obj/item/ammo_magazine/cell_mag, /obj/item/weapon/gun/projectile/cell_loaded) // CHOMPedit: medigun stuff
+ var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/modular_computer, /obj/item/weapon/computer_hardware/battery_module, /obj/item/weapon/cell, /obj/item/device/suit_cooling_unit/emergency, /obj/item/device/flashlight, /obj/item/device/electronic_assembly, /obj/item/weapon/weldingtool/electric, /obj/item/ammo_magazine/smart, /obj/item/device/flash, /obj/item/device/defib_kit, /obj/item/ammo_casing/microbattery, /obj/item/device/paicard, /obj/item/ammo_magazine/cell_mag, /obj/item/weapon/gun/projectile/cell_loaded, /obj/item/device/personal_shield_generator) // CHOMPedit: medigun stuff
var/icon_state_charged = "recharger2"
var/icon_state_charging = "recharger1"
var/icon_state_idle = "recharger0" //also when unpowered
diff --git a/code/game/objects/items/devices/personal_shield_generator_vr.dm b/code/game/objects/items/devices/personal_shield_generator_vr.dm
new file mode 100644
index 0000000000..c09d7ae8c5
--- /dev/null
+++ b/code/game/objects/items/devices/personal_shield_generator_vr.dm
@@ -0,0 +1,601 @@
+// TO ANYBODY LOOKING AT THIS FILE:
+// Everything is mostly commented on to give as much detailed information as possible.
+// Some things may be difficult to understand, but every variable in here has a comment explaining what it is/does.
+// The base unit, the 'personal_shield_generator' is a backpack, comes with a gun, and has normal numbers for everything.
+// The belt units do NOT come with a gun and have a cell that is half the capacity of backpack units.
+// These can be VERY, VERY, VERY strong if too many are handed out, the cell is too strong, or the modifier is too strong.
+// Additionally, if you are mapping any of these in, ensure you map in the /loaded versions or else they won't have a battery.
+// I have also made it so you can modify everything about them, including the modifier they give and the cell, which can be changed via mapping.
+
+// In essence, these can be viewed as an extra layer of armor that has upsides and downsides with more extensive features.
+// Shield generators apply PRE armor. Ultimately this shouldn't matter too much, but it makes more sense this way.
+// There are a good amount of variants in here, ranging from mining to security to misc ones.
+// If you want to make a variant, you need to only change modifier_type and make the modifier desired.
+
+
+/obj/item/device/personal_shield_generator
+ name = "personal shield generator"
+ desc = "A personal shield generator."
+ icon = 'icons/obj/items_vr.dmi'
+ icon_state = "shield_pack"
+ item_state = "defibunit" //Placeholder
+ slot_flags = SLOT_BACK
+ force = 5
+ throwforce = 6
+ preserve_item = 1
+ w_class = ITEMSIZE_HUGE //It's a giant shield generator!!!
+ unacidable = TRUE
+ origin_tech = list(TECH_MATERIAL = 6, TECH_COMBAT = 8, TECH_POWER = 6, TECH_DATA = 4) //These are limited AND high tech. Breaking one of them down is massive.
+ action_button_name = "Toggle Shield"
+ var/obj/item/weapon/gun/energy/gun/generator/active_weapon
+ var/obj/item/weapon/cell/device/bcell = null
+
+
+ var/generator_hit_cost = 100 // Power used when a special effect (such as a bullet being blocked) is performed! Could also be expanded to other things.
+ var/generator_active_cost = 10 // Power used when turned on.
+ var/damage_cost = 25 // 40 damage absorbed per 1000 charge.
+ var/modifier_type = /datum/modifier/shield_projection // What type of modifier will it add? Used for variant modifiers!
+
+ var/has_weapon = 1 // Backpack units generally have weapons.
+ var/shield_active = 0 // If the shield gen is active.
+ var/effect_color = "#99FFFF" // Allows for changing shield colors. Default cyan.
+
+/obj/item/device/personal_shield_generator/get_cell()
+ return bcell
+
+/obj/item/device/personal_shield_generator/New()
+ ..()
+ if(ispath(bcell))
+ bcell = new bcell(src)
+
+ if(has_weapon)
+ if(ispath(active_weapon))
+ active_weapon = new active_weapon(src, src)
+ active_weapon.power_supply = bcell
+ else
+ active_weapon = new(src, src)
+ active_weapon.power_supply = bcell
+ else
+ verbs -= /obj/item/device/personal_shield_generator/verb/weapon_toggle
+ STOP_PROCESSING(SSobj, src) //We do this so it doesn't start processing until it's first used.
+ update_icon()
+
+/obj/item/device/personal_shield_generator/Destroy()
+ . = ..()
+ QDEL_NULL(active_weapon)
+ QDEL_NULL(bcell)
+
+/obj/item/device/personal_shield_generator/loaded //starts with a cell
+ bcell = /obj/item/weapon/cell/device/shield_generator/backpack
+
+
+/obj/item/device/personal_shield_generator/update_icon()
+ if(shield_active)
+ icon_state = "shieldpack_basic_on"
+ else
+ icon_state = "shieldpack_basic"
+
+/obj/item/device/personal_shield_generator/examine(mob/user)
+ . = ..()
+ if(Adjacent(user))
+ if(bcell)
+ . += "The internal cell is [round(bcell.percent() )]% charged."
+ else
+ . += "The device has no cell installed."
+ return
+ if(damage_cost) //Prevention of dividing by 0 errors.
+ . += "It reads that it can take [bcell.charge/damage_cost] more damage before the shield goes down."
+ if(bcell.self_recharge && bcell.charge_amount)
+ . += "This model is self charging and will take [bcell.maxcharge/bcell.charge_amount] seconds to fully charge from empty."
+ if(bcell.rigged)
+ . += "A red flashing 'WARNING' is visible on the display, noting that the cell is unstable and requires replacement."
+
+
+/* //This would be cool, but we need sprites.
+ cut_overlays()
+
+ if(has_weapon && active_weapon && active_weapon.loc == src) //in case gun gets destroyed somehow.
+ add_overlay("[initial(icon_state)]-paddles")
+ if(bcell)
+ if(bcell.check_charge(generator_hit_cost)) //Can we take a blow?
+ add_overlay("[initial(icon_state)]-powered")
+ else if(has_weapon && active_weapon)
+ if(bcell.check_charge(active_weapon.charge_cost)) //We got enough to go pew pew?
+ add_overlay("[initial(icon_state)]-powered")
+
+ var/ratio = CEILING(bcell.percent()/25, 1) * 25
+ add_overlay("[initial(icon_state)]-charge[ratio]")
+ else
+ add_overlay("[initial(icon_state)]-nocell")
+*/
+
+/obj/item/device/personal_shield_generator/emp_act(severity)
+ if(bcell && shield_active)
+ switch(severity)
+ if(1) //Point blank EMP shots have a good chance of burning the cell charge.
+ if(prob(50))
+ bcell.emp_act(severity)
+ if(prob(5)) //1 in 20% chance to fry the battery completly, which has a 1/10 chance of making the battery explode on next use.
+ bcell.corrupt() //Not too bad if you slotted a battery in. Disasterous if it has a self-charging battery.
+ if(bcell.rigged) //Did the above just rig the cell? Turn it off. Don't immediately have it go boom. Instead have the cell blow soon-ish.
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ shield_active = 0
+ if(bcell.charge_delay) //It WILL blow up soon. Downside of self-charging cells.
+ to_chat(src.loc, "Your shield generator sparks and suddenly goes down! A warning message pops up on screen: \
+ 'WARNING, INTERNAL CELL MELTDOWN IMMINENT. TIME TILL EXPLOSION: [bcell.charge_delay/10] SECONDS. DISCARD UNIT IMMEDIATELY!'")
+ else //It won't blow up unless you turn it back on again. Upside of using non-charging cells.
+ to_chat(src.loc, "Your shield generator sparks and suddenly goes down! A warning message pops up on screen: \
+ 'WARNING, INTERNAL CELL CRITICALLY DAMAGED. REPLACE CELL IMMEDIATELY.'")
+ STOP_PROCESSING(SSobj, src)
+ update_icon()
+ else
+ if(prob(25))
+ bcell.emp_act(severity)
+ ..()
+
+/obj/item/device/personal_shield_generator/ui_action_click()
+ toggle_shield()
+
+/obj/item/device/personal_shield_generator/attack_hand(mob/user)
+ if(loc == user)
+ toggle_shield()
+ else
+ ..()
+
+/obj/item/device/personal_shield_generator/AltClick(mob/living/user)
+ weapon_toggle()
+
+/obj/item/device/personal_shield_generator/MouseDrop()
+ if(ismob(src.loc))
+ if(!CanMouseDrop(src))
+ return
+ var/mob/M = src.loc
+ if(!M.unEquip(src))
+ return
+ src.add_fingerprint(usr)
+ M.put_in_any_hand_if_possible(src)
+
+
+/obj/item/device/personal_shield_generator/attackby(obj/item/weapon/W, mob/user, params)
+ if(W == active_weapon)
+ reattach_gun(user)
+ else if(istype(W, /obj/item/weapon/cell))
+ if(bcell)
+ to_chat(user, "\The [src] already has a cell.")
+ else if(!istype(W, /obj/item/weapon/cell/device/weapon)) //Weapon cells only!
+ to_chat(user, "This cell will not fit in the device.")
+ else
+ if(!user.unEquip(W))
+ return
+ W.forceMove(src)
+ bcell = W
+ if(active_weapon)
+ active_weapon.power_supply = bcell
+ to_chat(user, "You install a cell in \the [src].")
+ update_icon()
+
+ else if(W.is_screwdriver())
+ if(bcell)
+ if(istype(bcell, /obj/item/weapon/cell/device/shield_generator)) //No stealing self charging batteries!
+ var/choice = tgui_alert(user, "A popup appears on the device 'REMOVING THE INTERNAL CELL WILL DESTROY THE BATTERY. DO YOU WISH TO CONTINUE?'...Well, do you?", "Selection List", list("Cancel", "Remove"))
+ if(choice == "Remove") //Warned you...
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ bcell.forceMove(get_turf(src.loc))
+ qdel(bcell)
+ bcell = null //Sanity.
+ if(active_weapon)
+ reattach_gun() //Put the gun back if it's out. No shooting if we don't have a cell!
+ active_weapon.power_supply = null //No power cell anymore!
+ to_chat(user, "You remove the cell from \the [src], destroying the battery.")
+ update_icon()
+ return
+ else
+ return
+ else
+ bcell.update_icon()
+ bcell.forceMove(get_turf(src.loc))
+ bcell = null
+ if(active_weapon)
+ reattach_gun() //Put the gun back if it's out. No shooting if we don't have a cell!
+ active_weapon.power_supply = null //No power cell anymore!
+ to_chat(user, "You remove the cell from \the [src].")
+ update_icon()
+ else if(istype(W,/obj/item/device/multitool))
+ var/new_color = input(usr, "Choose a color to set the shield to!", "", effect_color) as color|null
+ if(new_color)
+ effect_color = new_color
+ else
+ return ..()
+
+// TODO: EMAG ACT
+// Perhaps make it so emagging the generator gives two options: One to rig the cell (stealthily) and one to disable the safeties (supercharge it)
+// Disabling the safeties would make it a stronger variant but boost the 'damage_cost' perhaps. Dunno.
+// We're an RP server so emags don't come into play except for random trash finds. Meaning it'd be RNG if you could 'supercharge' your shield genrator.
+// This would kind of be like people being able to emag the NIFSoft for bloodletters & all the buffs that come with an emagged NIFSoft.
+// Making it so emagging the weapon it comes with would also be a good idea. Different modes, perhaps?
+
+/*
+/obj/item/device/personal_shield_generator/emag_act(var/remaining_charges, var/mob/user)
+ if(active_weapon)
+ . = active_weapon.emag_act(user)
+ update_icon()
+ return
+*/
+
+//Gun stuff
+
+
+/obj/item/device/personal_shield_generator/verb/toggle_shield()
+ set name = "Toggle Shield"
+ set category = "Object"
+
+ var/mob/living/carbon/human/user = usr
+
+ if(user.last_special > world.time)
+ return
+ user.last_special = world.time + 10 //No spamming!
+
+ if(!bcell || !bcell.check_charge(generator_hit_cost) || !bcell.check_charge(generator_active_cost))
+ to_chat(user, "You require a charged cell to do this!")
+ return
+
+ if(!slot_check())
+ to_chat(user, "You need to equip [src] before starting the shield up!")
+ return
+ else
+ if(shield_active)
+ shield_active = !shield_active //Deactivate the shield!
+ to_chat(user, "You deactive the shield!")
+ user.remove_modifiers_of_type(/datum/modifier/shield_projection)
+ STOP_PROCESSING(SSobj, src)
+ playsound(src, 'sound/weapons/saberoff.ogg', 50, 1) //Shield turning off! PLACEHOLDER
+ else
+ shield_active = !shield_active
+ to_chat(user, "You activate the shield!")
+ user.remove_modifiers_of_type(/datum/modifier/shield_projection) //Just to make sure they aren't using two at once!
+ user.add_modifier(modifier_type)
+ user.update_modifier_visuals() //Forces coloration to WORK.
+ START_PROCESSING(SSobj, src) //Let's only bother draining power when we're being used!
+ playsound(src, 'sound/weapons/saberon.ogg', 50, 1) //Shield turning off! PLACEHOLDER
+ update_icon()
+
+/obj/item/device/personal_shield_generator/verb/weapon_toggle() //Make this work on Alt-Click
+ set name = "Toggle Gun"
+ set category = "Object"
+
+ var/mob/living/carbon/human/user = usr
+
+ if(user.last_special > world.time)
+ return
+ user.last_special = world.time + 10 //No spamming!
+
+ if(!active_weapon)
+ to_chat(user, "The gun is missing!")
+ return
+
+ if(!bcell)
+ to_chat(user, "The gun requires a power supply!")
+ return
+
+ if(active_weapon.loc != src)
+ reattach_gun(user) //Remove from their hands and back onto the defib unit
+ return
+
+ if(!slot_check())
+ to_chat(user, "You need to equip [src] before taking out [active_weapon].")
+ else
+ if(!usr.put_in_hands(active_weapon)) //Detach the gun into the user's hands
+ to_chat(user, "You need a free hand to hold the gun!")
+ update_icon() //success
+
+/obj/item/device/personal_shield_generator/process()
+ if(!bcell) //They removed the battery midway.
+ if(istype(loc, /mob/living/carbon/human)) //We on someone? Tell them it turned off.
+ var/mob/living/carbon/human/user = loc
+ to_chat(user, "The shield deactivates! An error message pops up on screen: 'Cell missing. Cell replacement required.'")
+ user.remove_modifiers_of_type(/datum/modifier/shield_projection)
+ shield_active = 0
+ STOP_PROCESSING(SSobj, src)
+ update_icon()
+ playsound(src, 'sound/weapons/saberoff.ogg', 50, 1) //Shield turning off! PLACEHOLDER
+ return
+
+ if(shield_active)
+ if(bcell.rigged) //They turned it back on after it was rigged to go boom.
+ if(istype(loc, /mob/living/carbon/human)) //Deactivate the shield, first. You're not getting reduced damage...
+ var/mob/living/carbon/human/user = loc
+ to_chat(user, "The shield deactivates, an error message popping up on screen: 'Cell Reactor Critically damaged. Cell replacement required.'")
+ user.remove_modifiers_of_type(/datum/modifier/shield_projection)
+
+ if(active_weapon) //Retract the gun. There's about to be no cell anymore.
+ reattach_gun()
+ active_weapon.power_supply = null
+
+ bcell.use(generator_active_cost) //Causes it to go boom.
+ bcell = null
+ shield_active = 0
+ STOP_PROCESSING(SSobj, src)
+ update_icon()
+ return
+
+ else //Normal operation.
+ bcell.use(generator_active_cost)
+
+ if(bcell.charge < generator_hit_cost || bcell.charge < generator_active_cost) //Out of charge...
+ shield_active = 0
+ if(istype(loc, /mob/living/carbon/human)) //We on someone? Tell them it turned off.
+ var/mob/living/carbon/human/user = loc
+ to_chat(user, "The shield deactivates, an error message popping up on screen: 'Cell out of charge.'")
+ user.remove_modifiers_of_type(/datum/modifier/shield_projection)
+ STOP_PROCESSING(SSobj, src)
+ update_icon()
+ playsound(src, 'sound/weapons/saberoff.ogg', 50, 1) //Shield turning off! PLACEHOLDER
+ return
+
+
+
+//checks that the base unit is in the correct slot to be used
+/obj/item/device/personal_shield_generator/proc/slot_check()
+ var/mob/M = loc
+ if(!istype(M))
+ return 0 //not equipped
+
+ if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back) == src)
+ return 1
+ if((slot_flags & SLOT_BELT) && M.get_equipped_item(slot_belt) == src)
+ return 1
+ //RIGSuit compatability. This shouldn't be possible, however, except for select RIGs.
+ if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_s_store) == src)
+ return 1
+ if((slot_flags & SLOT_BELT) && M.get_equipped_item(slot_s_store) == src)
+ return 1
+
+ return 0
+
+/obj/item/device/personal_shield_generator/dropped(mob/user)
+ ..()
+ reattach_gun(user) //A gun attached to a base unit should never exist outside of their base unit or the mob equipping the base unit
+
+/obj/item/device/personal_shield_generator/proc/reattach_gun(mob/user)
+ if(!active_weapon) return
+
+ if(ismob(active_weapon.loc))
+ var/mob/M = active_weapon.loc
+ if(M.drop_from_inventory(active_weapon, src))
+ to_chat(user, "\The [active_weapon] snaps back into the main unit.")
+ else
+ active_weapon.forceMove(src)
+
+ update_icon()
+
+//The gun
+
+/obj/item/weapon/gun/energy/gun/generator //The gun attached to the personal shield generator.
+ name = "generator gun"
+ desc = "A gun that is attached to the battery of the personal shield generator."
+ icon_state = "egunstun"
+ item_state = null //so the human update icon uses the icon_state instead.
+ fire_delay = 8
+ use_external_power = TRUE
+ cell_type = null //No cell! It runs off the cell in the shield_gen!
+
+ projectile_type = /obj/item/projectile/beam/stun/med
+ modifystate = "egunstun"
+
+ firemodes = list(
+ list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun/med, modifystate="egunstun", fire_sound='sound/weapons/Taser.ogg', charge_cost = 240),
+ list(mode_name="lethal", projectile_type=/obj/item/projectile/beam, modifystate="egunkill", fire_sound='sound/weapons/Laser.ogg', charge_cost = 480),
+ )
+
+ var/obj/item/device/personal_shield_generator/shield_generator //The generator we are linked to!
+ var/wielded = 0
+ var/cooldown = 0
+ var/busy = 0
+
+/obj/item/weapon/gun/energy/gun/generator/New(newloc, obj/item/device/personal_shield_generator/shield_gen)
+ ..(newloc)
+ shield_generator = shield_gen
+ power_supply = shield_generator.bcell
+
+/* //Unused. Use for large guns.
+/obj/item/weapon/gun/energy/gun/generator/update_held_icon()
+ var/mob/living/M = loc
+ if(istype(M) && M.item_is_in_hands(src) && !M.hands_are_full())
+ wielded = 1
+ name = "[initial(name)] (wielded)"
+ else
+ wielded = 0
+ name = initial(name)
+ update_icon()
+ ..()
+*/
+
+/obj/item/weapon/gun/energy/gun/generator/proc/can_use(mob/user, mob/M)
+ if(busy)
+ return 0
+ if(!check_charge(charge_cost))
+ to_chat(user, "\The [src] doesn't have enough charge left to do that.")
+ return 0
+ if(!wielded && !isrobot(user))
+ to_chat(user, "You need to wield the gun with both hands before you can use it on someone!")
+ return 0
+ if(cooldown)
+ to_chat(user, "\The [src] are re-energizing!")
+ return 0
+ return 1
+
+// TODO: EMP ACT
+// The cell already gets hit and can have some nasty effects when EMP'd, so this isn't too much of a concern.
+
+/*
+/obj/item/weapon/gun/energy/gun/generator/emp_act(severity)
+ ..()
+*/
+
+/obj/item/weapon/gun/energy/gun/generator/dropped(mob/user)
+ ..() //update twohanding
+ if(shield_generator)
+ shield_generator.reattach_gun(user)
+
+/obj/item/weapon/gun/energy/proc/check_charge(var/charge_amt) //In case using any other guns.
+ return 0
+
+/obj/item/weapon/gun/energy/proc/checked_use(var/charge_amt) //In case using any other guns.
+ return 0
+
+/obj/item/weapon/gun/energy/gun/generator/check_charge(var/charge_amt)
+ return (shield_generator.bcell && shield_generator.bcell.check_charge(charge_amt))
+
+/obj/item/weapon/gun/energy/gun/generator/checked_use(var/charge_amt)
+ return (shield_generator.bcell && shield_generator.bcell.checked_use(charge_amt))
+
+
+
+//VARIANTS.
+
+/obj/item/device/personal_shield_generator/belt
+ name = "personal shield generator"
+ desc = "A personal shield generator."
+ icon_state = "shield_back_active"
+ item_state = "shield_pack"
+ w_class = ITEMSIZE_LARGE //No putting these in backpacks!
+ slot_flags = SLOT_BELT
+ has_weapon = 0 //No gun with the belt!
+
+/obj/item/device/personal_shield_generator/belt/loaded
+ bcell = /obj/item/weapon/cell/device/shield_generator
+
+/obj/item/device/personal_shield_generator/belt/update_icon()
+ if(shield_active)
+ icon_state = "shieldpack_basic_on"
+ else
+ icon_state = "shieldpack_basic"
+
+/obj/item/device/personal_shield_generator/belt/bruteburn //Example of a modified generator.
+ modifier_type = /datum/modifier/shield_projection/bruteburn
+/obj/item/device/personal_shield_generator/belt/bruteburn/loaded //If mapped in, ONLY put loaded ones down.
+ bcell = /obj/item/weapon/cell/device/shield_generator
+
+// Mining belts
+/obj/item/device/personal_shield_generator/belt/mining
+ name = "mining PSG"
+ desc = "A personal shield generator designed for mining. It has a warning on the back: 'Do NOT expose the shield to stun-based weaponry.'"
+ modifier_type = /datum/modifier/shield_projection/mining
+
+/obj/item/device/personal_shield_generator/belt/mining/loaded
+ bcell = /obj/item/weapon/cell/device/shield_generator
+
+/obj/item/device/personal_shield_generator/belt/mining/update_icon()
+ if(shield_active)
+ icon_state = "shieldpack_mining_on"
+ else
+ icon_state = "shieldpack_mining"
+
+/obj/item/borg/upgrade/shield_upgrade
+ name = "mining PSG upgrade disk."
+ desc = "A upgrade disk that, when slotted into a mining shield generator, upgrades the efficiency of the internal software, providing a stronger shield \
+ in exchange for being weaker to stun-based weaponry."
+ icon = 'icons/obj/objects_vr.dmi'
+ icon_state = "modkit"
+ w_class = ITEMSIZE_SMALL
+
+/obj/item/device/personal_shield_generator/belt/mining/attackby(obj/item/weapon/W, mob/user, params)
+ if(modifier_type == /datum/modifier/shield_projection/mining/strong)
+ to_chat(user, "This shield generator is already upgraded!")
+ return
+ if(istype(W, /obj/item/borg/upgrade/shield_upgrade))
+ modifier_type = /datum/modifier/shield_projection/mining/strong
+ to_chat(user, "You upgrade the [src] with the [W]!")
+ user.drop_from_inventory(W)
+ qdel(W)
+ else
+ ..()
+
+
+//Security belts
+
+/obj/item/device/personal_shield_generator/belt/security
+ name = "security PSG"
+ desc = "A personal shield generator designed for security."
+ modifier_type = /datum/modifier/shield_projection/security/weak
+
+/obj/item/device/personal_shield_generator/belt/security/loaded
+ bcell = /obj/item/weapon/cell/device/shield_generator
+
+/obj/item/device/personal_shield_generator/belt/security/update_icon()
+ if(shield_active)
+ icon_state = "shieldpack_security_on"
+ else
+ icon_state = "shieldpack_security"
+
+//Misc belts. Admin-spawn only atm.
+
+/obj/item/device/personal_shield_generator/belt/adminbus
+ desc = "You should not see this. You REALLY should not see this. If you do, you have either been blessed or are about to be the target of some sick prank."
+ modifier_type = /datum/modifier/shield_projection/admin
+ generator_hit_cost = 0
+ generator_active_cost = 0
+ shield_active = 0
+ damage_cost = 0
+ bcell = /obj/item/weapon/cell/device/shield_generator
+
+/obj/item/device/personal_shield_generator/belt/parry //The 'provides one second of pure immunity to brute/burn/halloss' belt.
+ name = "PSG variant-P" //Not meant to be used in any serious capacity.
+ desc = "A personal shield generator that sacrifices long-term usability in exchange for a strong, short-lived shield projection, enabling the user to be nigh \
+ impervious for a second."
+ modifier_type = /datum/modifier/shield_projection/parry
+ generator_hit_cost = 0 //No cost for being hit.
+ damage_cost = 0//No cost for blocking effects.
+ generator_active_cost = 100 //However, it disables the tick immediately after being turned on.
+ shield_active = 0
+ bcell = /obj/item/weapon/cell/device/shield_generator/parry
+
+// Backpacks. These are meant to be MUCH stronger in exchange for the fact that you are giving up a backpack slot.
+// HOWEVER, be careful with these. They come loaded with a gun in them, so they shouldn't be handed out willy-nilly.
+
+/obj/item/device/personal_shield_generator/security
+ name = "security PSG"
+ desc = "A personal shield generator designed for security. Comes with a built in defense pistol."
+ modifier_type = /datum/modifier/shield_projection/security
+
+/obj/item/device/personal_shield_generator/security/loaded
+ bcell = /obj/item/weapon/cell/device/shield_generator/backpack
+
+/obj/item/device/personal_shield_generator/security/strong
+ modifier_type = /datum/modifier/shield_projection/security/strong
+
+/obj/item/device/personal_shield_generator/security/strong/loaded
+ bcell = /obj/item/weapon/cell/device/shield_generator/backpack
+
+/obj/item/device/personal_shield_generator/security/update_icon()
+ if(shield_active)
+ icon_state = "shieldpack_security_on"
+ else
+ icon_state = "shieldpack_security"
+
+//Power cells.
+/obj/item/weapon/cell/device/shield_generator //The base power cell the shield gen comes with.
+ name = "shield generator battery"
+ desc = "A self charging battery which houses a micro-nuclear reactor. Takes a while to start charging."
+ maxcharge = 2400
+ self_recharge = TRUE
+ charge_amount = 80 //After the charge_delay is over, charges the cell over 30 seconds.
+ charge_delay = 600 //Takes a minute before it starts to recharge.
+
+/obj/item/weapon/cell/device/shield_generator/backpack //The base power cell the backpack units come with. Double the charge vs the belt.
+ maxcharge = 4800
+ charge_amount = 160
+
+/obj/item/weapon/cell/device/shield_generator/upgraded //A stronger version of the normal cell. Double the maxcharge, halved charge time.
+ maxcharge = 4800
+ charge_amount = 320
+ charge_delay = 300
+
+/obj/item/weapon/cell/device/shield_generator/parry //The cell for the 'parry' shield gen.
+ maxcharge = 100
+ charge_amount = 100
+ charge_delay = 20 //Starts charging two seconds after it's discharged.
\ No newline at end of file
diff --git a/code/modules/client/stored_item.dm b/code/modules/client/stored_item.dm
index 88dbbe2ee8..fda2dcc9c8 100644
--- a/code/modules/client/stored_item.dm
+++ b/code/modules/client/stored_item.dm
@@ -254,3 +254,5 @@
persist_storable = FALSE
/obj/item/weapon/spacecasinocash
persist_storable = FALSE
+/obj/item/device/personal_shield_generator
+ persist_storable = FALSE
diff --git a/code/modules/examine/descriptions/devices.dm b/code/modules/examine/descriptions/devices.dm
index 7b5c0019a4..a929873e0f 100644
--- a/code/modules/examine/descriptions/devices.dm
+++ b/code/modules/examine/descriptions/devices.dm
@@ -29,4 +29,18 @@
/obj/item/device/assembly/electronic_assembly
description_info = "This is the casing for the 'device' type of electronic assembly. It behaves like any other 'assembly' type device such as an igniter or signaler \
- and can be attached to others in the same way. Use the 'toggle-open' verb (right click) or a crowbar to pop the electronic device open to add components and close when finished."
\ No newline at end of file
+ and can be attached to others in the same way. Use the 'toggle-open' verb (right click) or a crowbar to pop the electronic device open to add components and close when finished."
+
+/obj/item/device/personal_shield_generator
+ description_info = "This is a personal shield generator. Depending on the type, it can either be worn on your backpack slot, your belt slot, or in a rigsuit \
+ storage slot. It runs on an internal battery, which is usually self-charging. Some versions come with a gun. To active the shield, click the button in the upper \
+ right of the screen, use the 'Toggle Shield' command under your objects tab, or click the device itself while it is on you. Some units come with an active weapon \
+ which can be taken out at any time by Alt-clicking the device. If the device requires a cell, a screwdriver can be used. The shield slowly drains charge while \
+ active and becomes weaker with each individual strike taken. Additonally, the device can be colored via use of a multitool."
+
+ description_fluff = "A relatively new invention, made in a collaboration between Hephaestus Industries and a startup known as Kuznetsova Enterprise in the year \
+ 2322. Numerous variants of the device have been made for specific tasks, ranging from riot control, mining, biohazard containment, and search and rescue, among \
+ others. Most of the devices share the flaw that electrical attacks can easily overload the device and cause a shield failure, encouraging combatants to swap to \
+ the use of stun-based electric weaponry when shield generators are in use. Most shield devices are self-charging, running off a micro-nuclear reactor built into \
+ the chassis itself, although some variants exist without this capability and can have normal cells inserted into them. Larger units boast the capability of \
+ storing a weapon, although without upgraded batteries the usage of said weapon is ill-advised."
\ No newline at end of file
diff --git a/code/modules/mining/abandonedcrates.dm b/code/modules/mining/abandonedcrates.dm
index d6e72e4e33..cf595a0821 100644
--- a/code/modules/mining/abandonedcrates.dm
+++ b/code/modules/mining/abandonedcrates.dm
@@ -19,7 +19,7 @@
generate_loot()
/obj/structure/closet/crate/secure/loot/proc/generate_loot()
- var/loot = rand(1, 99)
+ var/loot = rand(1, 100)
switch(loot)
if(1 to 5) // Common things go, 5%
new/obj/item/weapon/reagent_containers/food/drinks/bottle/rum(src)
@@ -140,6 +140,8 @@
if(99)
new/obj/item/weapon/storage/belt/champion(src)
new/obj/item/clothing/mask/luchador(src)
+ if(100)
+ new/obj/item/device/personal_shield_generator/belt/mining/loaded(src)
/obj/structure/closet/crate/secure/loot/togglelock(mob/user as mob)
if(!locked)
diff --git a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm
index 2f8ab107ed..6dd1f84f37 100644
--- a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm
+++ b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm
@@ -126,6 +126,7 @@
EQUIPMENT("Thalers - 1000", /obj/item/weapon/spacecash/c1000, 10000),
EQUIPMENT("Umbrella", /obj/item/weapon/melee/umbrella/random, 200),
EQUIPMENT("Whiskey", /obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey, 125),
+ EQUIPMENT("Mining PSG Upgrade Disk", /obj/item/borg/upgrade/shield_upgrade, 2500),
)
prize_list["Extra"] = list() // Used in child vendors
//VOREStation Edit End
diff --git a/code/modules/mob/_modifiers/modifiers_vr.dm b/code/modules/mob/_modifiers/modifiers_vr.dm
index a56bc5d2e0..2de03120d4 100644
--- a/code/modules/mob/_modifiers/modifiers_vr.dm
+++ b/code/modules/mob/_modifiers/modifiers_vr.dm
@@ -1,3 +1,51 @@
+/datum/modifier
+ var/effect_color // Allows for coloring of modifiers.
+ var/coloration_applied = 0 // Tells the game is coloration has been applied already or not.
+ var/icon_override = 0 // Tells the game if it should use modifer_effects_vr.dmi or not.
+ // ENERGY CODE. Variables to allow for energy based modifiers.
+ var/energy_based // Sees if the modifier is based on something electronic based.
+ var/energy_cost // How much the modifier uses per action/special effect blocked. For base values.
+ var/damage_cost // How much energy is used when numbers are involed. For values, such as taking damage. Ex: (Damage*damage_cost)
+ var/obj/item/weapon/cell/energy_source = null // The source of the above.
+
+ // RESISTANCES CODE. Variable to enable external damage resistance modifiers. This is not unlike armor.
+ // 0 = immune || < 0 = heals || 1 = full damage || >1 = increased damage.
+ // It should never be below zero as it is not intended to do such, but you are free to experiment!
+ // Ex: Max_brute_resistance = 0. Min_brute resistance = 1. When started, provides 100% resistance to brute. When cell is dying, goes down to 0% resistance.
+ // Max is the MAXIMUM % multiplier that will be taken at a MAX charge. Min is the MINIMUM % multiplier that will be taken at a MINIMUM charge.
+ // Think of it like this: Minimum = what happens at minimum charge. Max = what happens at maximum charge.
+ // Why do I mention this so much? Because even /I/ got confused, and I wrote this thing!
+ var/min_damage_resistance
+ var/max_damage_resistance
+ var/effective_damage_resistance
+
+ var/min_brute_resistance
+ var/max_brute_resistance
+ var/effective_brute_resistance
+
+ var/min_fire_resistance
+ var/max_fire_resistance
+ var/effective_fire_resistance
+
+ var/min_tox_resistance
+ var/max_tox_resistance
+ var/effective_tox_resistance
+
+ var/min_oxy_resistance
+ var/max_oxy_resistance
+ var/effective_oxy_resistance
+
+ var/min_clone_resistance
+ var/max_clone_resistance
+ var/effective_clone_resistance
+
+ var/min_hal_resistance
+ var/max_hal_resistance
+ var/effective_hal_resistance
+ // Resistances end
+
+
+
/datum/modifier/underwater_stealth
name = "underwater stealth"
desc = "You are currently underwater, rendering it more difficult to see you and enabling you to move quicker, thanks to your aquatic nature."
@@ -30,4 +78,258 @@
if(water_floor.depth < 1) //You're not in deep enough water anymore.
expire(silent = FALSE)
else
- expire(silent = FALSE)
\ No newline at end of file
+ expire(silent = FALSE)
+
+
+
+
+
+
+
+
+
+/datum/modifier/shield_projection
+ name = "Shield Projection"
+ desc = "You are currently protected by a shield, rendering nigh impossible to hit you through conventional means."
+
+ on_created_text = "Your shield generator buzzes on."
+ on_expired_text = "Your shield generator buzzes off."
+ stacks = MODIFIER_STACK_FORBID //No stacking shields. If you put one one your belt and backpack it won't work.
+
+ icon_override = 1
+ mob_overlay_state = "deflect"
+ siemens_coefficient = 2 //Stun weapons drain 100% charge per point of damage. They're good at blocking lasers and bullets but not good at blocking stun beams!
+ energy_based = 1
+ energy_cost = 99999 //This is changed to the shield_generator's energy_cost.
+ damage_cost = 50 //This is how much battery is used per damage unit absorbed. Higher damage means higher charge use per damage absorbed. Changed below!
+
+ //Not actually in use until effective resistances are set. Just here so it doesn't have to be placed down for all the variants. Less lines.
+ max_damage_resistance = 1
+ max_brute_resistance = 1
+ max_fire_resistance = 1
+ max_tox_resistance = 1
+ max_oxy_resistance = 1
+ max_clone_resistance = 1
+ max_hal_resistance = 1
+ min_damage_resistance = 1
+ min_brute_resistance = 1
+ min_fire_resistance = 1
+ min_tox_resistance = 1
+ min_oxy_resistance = 1
+ min_clone_resistance = 1
+ min_hal_resistance = 1
+
+/* // These are not set, but left here as an example. All three (min,max,effective) must be set or BAD THINGS will happen.
+ min_brute_resistance = 1 // Min = WHAT HAPPENS AT MINIMUM CHARGE
+ max_brute_resistance = 0 // MAX = WHAT HAPPENS AT MAXIMUM CHARGE
+ effective_brute_resistance = 1 //Just tells the game that it has vars. Done to use less checks.
+
+ min_fire_resistance = 1
+ max_fire_resistance = 0
+ effective_fire_resistance = 1
+ disable_duration_percent = 1 //THIS CAN ALSO BE USED! Don't be too afraid to use this one, but use it sparingly!
+*/
+ var/obj/item/device/personal_shield_generator/shield_generator //This is the shield generator you're wearing!
+
+
+/datum/modifier/shield_projection/on_applied()
+ return
+
+/datum/modifier/shield_projection/on_expire() //Don't need to modify this!
+ return
+
+/datum/modifier/shield_projection/check_if_valid() //Let's check to make sure you got the stuff and set the vars. Don't need to modify this for any subtypes!
+ if(ishuman(holder)) //Only humans can use this! Other things later down the line might use the same stuff this does, but the shield generator is human only!
+ var/mob/living/carbon/human/H = holder
+ if(istype(H.get_equipped_item(slot_back), /obj/item/device/personal_shield_generator))
+ shield_generator = H.get_equipped_item(slot_back) //Sets the var on the modifier that the shield gen is their back shield gen.
+ else if(istype(H.get_equipped_item(slot_belt), /obj/item/device/personal_shield_generator))
+ shield_generator = H.get_equipped_item(slot_belt) //No need for other checks. If they got hit by this, they just turned it on.
+ else if(istype(H.get_equipped_item(slot_s_store), /obj/item/device/personal_shield_generator) ) //Rigsuits.
+ shield_generator = H.get_equipped_item(slot_s_store)
+ else
+ expire(silent = TRUE)
+ if(shield_generator) //Sanity.
+ energy_source = shield_generator.bcell
+ energy_cost = shield_generator.generator_hit_cost
+ damage_cost = shield_generator.damage_cost
+ effect_color = shield_generator.effect_color
+ if(!coloration_applied) //Does a check if colors have been applied. If not, updates the color.
+ H.update_modifier_visuals() //This can only happen on the next tick, unfortunately, not the same tick the modifier is applied. Thus, must be done here.
+ coloration_applied = 1
+ else
+ expire(silent = TRUE)
+
+
+/datum/modifier/shield_projection/tick() //When the shield generator runs out of charge, it'll remove this naturally.
+ if(holder.stat == DEAD)
+ expire(silent = TRUE) //If you're dead the generator stops protecting you but keeps running.
+ if(!shield_generator || !shield_generator.slot_check()) //No shield to begin with/shield is not on them any longer.
+ expire(silent = FALSE)
+
+ var/shield_efficiency = (energy_source.charge/energy_source.maxcharge) //1 = complete resistance. 0 = no resistance. Must be adjusted for subtypes!
+ if(!isnull(effective_damage_resistance))
+ effective_damage_resistance = min_damage_resistance + (max_damage_resistance - min_damage_resistance) * shield_efficiency
+
+ if(!isnull(effective_brute_resistance))
+ effective_brute_resistance = min_brute_resistance + (max_brute_resistance - min_brute_resistance) * shield_efficiency
+
+ if(!isnull(effective_fire_resistance))
+ effective_fire_resistance = min_fire_resistance + (max_fire_resistance - min_fire_resistance) * shield_efficiency
+
+ if(!isnull(effective_tox_resistance))
+ effective_tox_resistance = min_tox_resistance + (max_tox_resistance - min_tox_resistance) * shield_efficiency
+
+ if(!isnull(effective_oxy_resistance))
+ effective_oxy_resistance = min_oxy_resistance + (max_oxy_resistance - min_oxy_resistance) * shield_efficiency
+
+ if(!isnull(effective_clone_resistance))
+ effective_clone_resistance = min_clone_resistance + (max_clone_resistance - min_clone_resistance) * shield_efficiency
+
+ if(!isnull(effective_hal_resistance))
+ effective_hal_resistance = min_hal_resistance + (max_hal_resistance - min_hal_resistance) * shield_efficiency
+
+//Shield variants.
+
+//Simple. Goes from 100% resistance to 0% resistance depending on charge. This is mostly an example of a shield variant.
+/datum/modifier/shield_projection/bruteburn
+ max_brute_resistance = 0
+ effective_brute_resistance = 1
+
+ max_fire_resistance = 0
+ effective_fire_resistance = 1
+
+/datum/modifier/shield_projection/bruteburn/weak
+ max_brute_resistance = 0.5
+ max_fire_resistance = 0.5
+
+//SECURITY VARIANTS
+/datum/modifier/shield_projection/security // Security backpack. 50% resistance at full charge. 10% resistance for the last shot taken.
+ max_brute_resistance = 0.50
+ min_brute_resistance = 0.9
+ effective_brute_resistance = 1
+
+ max_fire_resistance = 0.5
+ min_fire_resistance = 0.9
+ effective_fire_resistance = 1
+
+ max_hal_resistance = 0.5
+ min_hal_resistance = 0.9
+ effective_hal_resistance = 1
+
+ disable_duration_percent = 0.75
+
+/datum/modifier/shield_projection/security/weak // Security belt.
+ max_brute_resistance = 0.75
+ min_brute_resistance = 0.95
+ max_fire_resistance = 0.75
+ min_fire_resistance = 0.95
+ max_hal_resistance = 0.75
+ min_hal_resistance = 0.95
+
+/datum/modifier/shield_projection/security/strong // Dunno. Upgraded variant of security backpack?
+ max_brute_resistance = 0.25
+ max_fire_resistance = 0.25
+ max_hal_resistance = 0.25
+ siemens_coefficient = 1.5 //Not as weak as normal, but still weak.
+ disable_duration_percent = 0.5
+
+
+//MINING VARIANTS
+/datum/modifier/shield_projection/mining //Base mining belt. 30% resistance that fades to 15% resistance
+ max_brute_resistance = 0.70
+ min_brute_resistance = 0.85
+ effective_brute_resistance = 1
+
+ max_fire_resistance = 0.70
+ min_brute_resistance = 0.85
+ effective_fire_resistance = 1
+
+ max_hal_resistance = 1.5 // No mobs should be shooting you with halloss. If this happens, it means you're using it wrong!!!
+ min_hal_resistance = 1.5
+ effective_hal_resistance = 1
+
+ disable_duration_percent = 0.75 //Miners often come into contact with things that can stun them.
+
+/datum/modifier/shield_projection/mining/strong // Mining belt, but upgraded. Even weaker to halloss!
+ max_brute_resistance = 0.55
+ min_brute_resistance = 0.75
+ max_fire_resistance = 0.55
+ min_fire_resistance = 0.75
+ disable_duration_percent = 0.5
+
+ max_hal_resistance = 2
+ min_hal_resistance = 2
+
+//MISC VARIANTS
+
+/datum/modifier/shield_projection/biohazard //The odd-ball damage types. Provides near-complete immunity while it's up.
+ min_tox_resistance = 0.25
+ max_tox_resistance = 0
+ effective_tox_resistance = 1
+
+ min_oxy_resistance = 0.25
+ max_oxy_resistance = 0
+ effective_oxy_resistance = 1
+
+ min_clone_resistance = 0.25
+ max_clone_resistance = 0
+ effective_clone_resistance = 1
+
+/datum/modifier/shield_projection/admin // Adminbus.
+ on_created_text = "Your shield generator activates and you feel the power of the tesla buzzing around you."
+ on_expired_text = "Your shield generator deactivates, leaving you feeling weak and vulnerable."
+ siemens_coefficient = 0
+ disable_duration_percent = 0
+ min_damage_resistance = 0
+ max_damage_resistance = 0
+ effective_damage_resistance = 0
+ min_brute_resistance = 0
+ max_brute_resistance = 0
+ effective_brute_resistance = 0
+ min_fire_resistance = 0
+ max_fire_resistance = 0
+ effective_fire_resistance = 0
+ min_tox_resistance = 0
+ max_tox_resistance = 0
+ effective_tox_resistance = 0
+ min_oxy_resistance = 0
+ max_oxy_resistance = 0
+ effective_oxy_resistance = 0
+ min_clone_resistance = 0
+ max_clone_resistance = 0
+ effective_clone_resistance = 0
+ min_hal_resistance = 0
+ max_hal_resistance = 0
+ effective_hal_resistance = 0
+
+/datum/modifier/shield_projection/broken //For broken variants. Good if possible randomization is included for packs spawned on PoIs.
+ max_brute_resistance = 2
+ min_brute_resistance = 2
+ effective_brute_resistance = 1
+
+ max_fire_resistance = 2
+ min_fire_resistance = 2
+ effective_fire_resistance = 1
+
+/datum/modifier/shield_projection/inverted //Becomes stronger the weaker the cell is. Means the last shot taken will be the weakest. Example just to show it can be done.
+ max_brute_resistance = 1
+ min_brute_resistance = 0
+ effective_brute_resistance = 1
+
+ max_fire_resistance = 1
+ min_fire_resistance = 0
+ effective_fire_resistance = 1
+
+/datum/modifier/shield_projection/parry //Intended for 'parry' shields, which only last for a single second before running out of charge
+ max_brute_resistance = 0
+ min_brute_resistance = 0
+ effective_brute_resistance = 1
+
+ max_fire_resistance = 0
+ min_fire_resistance = 0
+ effective_fire_resistance = 1
+
+ max_hal_resistance = 0
+ min_hal_resistance = 0
+ effective_hal_resistance = 1
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 645d563ad0..d8dda93705 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -115,8 +115,12 @@
if(amount > 0)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_brute_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_brute_damage_percent
if(nif && nif.flag_check(NIF_C_BRUTEARMOR,NIF_FLAGS_COMBAT)){amount *= 0.7} //VOREStation Edit - NIF mod for damage resistance for this type of damage
take_overall_damage(amount, 0)
@@ -133,8 +137,12 @@
if(amount > 0)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_fire_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_fire_damage_percent
if(nif && nif.flag_check(NIF_C_BURNARMOR,NIF_FLAGS_COMBAT)){amount *= 0.7} //VOREStation Edit - NIF mod for damage resistance for this type of damage
take_overall_damage(0, amount)
@@ -153,8 +161,12 @@
if(amount > 0)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_brute_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_brute_damage_percent
if(nif && nif.flag_check(NIF_C_BRUTEARMOR,NIF_FLAGS_COMBAT)){amount *= 0.7} //VOREStation Edit - NIF mod for damage resistance for this type of damage
O.take_damage(amount, 0, sharp=is_sharp(damage_source), edge=has_edge(damage_source), used_weapon=damage_source)
@@ -175,8 +187,12 @@
if(amount > 0)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_fire_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_fire_damage_percent
if(nif && nif.flag_check(NIF_C_BURNARMOR,NIF_FLAGS_COMBAT)){amount *= 0.7} //VOREStation Edit - NIF mod for damage resistance for this type of damage
O.take_damage(0, amount, sharp=is_sharp(damage_source), edge=has_edge(damage_source), used_weapon=damage_source)
@@ -485,6 +501,53 @@ This function restores all organs.
if(!def_zone) def_zone = ran_zone(def_zone)
organ = get_organ(check_zone(def_zone))
+ for(var/datum/modifier/M in modifiers) //MODIFIER STUFF. It's best to do this RIGHT before armor is calculated, so it's done here! This is the 'forcefield' defence.
+ if(damagetype == BRUTE && (!isnull(M.effective_brute_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_brute_resistance
+ continue
+ if((damagetype == BURN || damagetype == ELECTROCUTE) && (!isnull(M.effective_fire_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_fire_resistance
+ continue
+ if(damagetype == TOX && (!isnull(M.effective_tox_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_tox_resistance
+ continue
+ if(damagetype == OXY && (!isnull(M.effective_oxy_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_oxy_resistance
+ continue
+ if(damagetype == CLONE && (!isnull(M.effective_clone_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_clone_resistance
+ continue
+ if(damagetype == HALLOSS && (!isnull(M.effective_hal_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_hal_resistance
+ continue
+ if(damagetype == SEARING && (!isnull(M.effective_fire_resistance) || !isnull(M.effective_brute_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ var/damage_mitigation = 0//Used for dual calculations.
+ if(!isnull(M.effective_fire_resistance))
+ damage_mitigation += round((1/3)*damage * M.effective_fire_resistance)
+ if(!isnull(M.effective_brute_resistance))
+ damage_mitigation += round((2/3)*damage * M.effective_brute_resistance)
+ damage -= damage_mitigation
+ continue
+ if(damagetype == BIOACID && (isSynthetic() && (!isnull(M.effective_fire_resistance))) || (!isSynthetic() && M.effective_tox_resistance))
+ if(isSynthetic())
+ damage = damage * M.effective_fire_resistance
+ else
+ damage = damage * M.effective_tox_resistance
+ continue
//Handle other types of damage
if((damagetype != BRUTE) && (damagetype != BURN))
if(damagetype == HALLOSS)
@@ -523,8 +586,12 @@ This function restores all organs.
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*damage)
damage *= M.incoming_damage_percent
if(!isnull(M.incoming_brute_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*damage)
damage *= M.incoming_brute_damage_percent
if(organ.take_damage(damage, 0, sharp, edge, used_weapon))
@@ -536,8 +603,12 @@ This function restores all organs.
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*damage)
damage *= M.incoming_damage_percent
if(!isnull(M.incoming_brute_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*damage)
damage *= M.incoming_fire_damage_percent
if(organ.take_damage(0, damage, sharp, edge, used_weapon))
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index f8c266a95b..4c883807c8 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -37,6 +37,18 @@ emp_act
var/armor = getarmor_organ(organ, "bullet")
if(!prob(armor/2)) //Even if the armor doesn't stop the bullet from hurting you, it might stop it from embedding.
var/hit_embed_chance = P.embed_chance + (P.damage - armor) //More damage equals more chance to embed
+
+ //Modifiers can make bullets less likely to embed! These are the normal modifiers and shouldn't be related to energy stuff, but they can be anyways!
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.energy_cost) //We use energy_cost here for special effects, such as embedding.
+ hit_embed_chance = hit_embed_chance*M.incoming_damage_percent
+ if(P.damage_type == BRUTE && (!isnull(M.incoming_brute_damage_percent)))
+ if(M.energy_based)
+ M.energy_source.use(M.energy_cost)
+ hit_embed_chance = hit_embed_chance*M.incoming_brute_damage_percent
+
if(prob(max(hit_embed_chance, 0)))
var/obj/item/weapon/material/shard/shrapnel/SP = new()
SP.name = (P.name != "shrapnel")? "[P.name] shrapnel" : "shrapnel"
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index c94959a13a..e0c9397f0e 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -1137,8 +1137,14 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon()
var/image/effects = new()
for(var/datum/modifier/M in modifiers)
if(M.mob_overlay_state)
- var/image/I = image(icon = 'icons/mob/modifier_effects.dmi', icon_state = M.mob_overlay_state)
- effects.overlays += I // Leaving this as overlays +=
+ if(M.icon_override) //VOREStation Edit. Override for the modifer icon.
+ var/image/I = image(icon = 'icons/mob/modifier_effects_vr.dmi', icon_state = M.mob_overlay_state)
+ I.color = M.effect_color
+ effects.overlays += I // Leaving this as overlays +=
+ else
+ var/image/I = image(icon = 'icons/mob/modifier_effects.dmi', icon_state = M.mob_overlay_state)
+ I.color = M.effect_color
+ effects.overlays += I // Leaving this as overlays +=
overlays_standing[MODIFIER_EFFECTS_LAYER] = effects
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index 4eaab77926..a865a6b05d 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -13,6 +13,53 @@
to_world_log("## DEBUG: apply_damage() was called on [src], with [damage] damage, and an armor value of [blocked].")
if(!damage || (blocked >= 100))
return 0
+ for(var/datum/modifier/M in modifiers) //MODIFIER STUFF. It's best to do this RIGHT before armor is calculated, so it's done here! This is the 'forcefield' defence.
+ if(damagetype == BRUTE && (!isnull(M.effective_brute_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_brute_resistance
+ continue
+ if((damagetype == BURN || damagetype == ELECTROCUTE)&& (!isnull(M.effective_fire_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_fire_resistance
+ continue
+ if(damagetype == TOX && (!isnull(M.effective_tox_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_tox_resistance
+ continue
+ if(damagetype == OXY && (!isnull(M.effective_oxy_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_oxy_resistance
+ continue
+ if(damagetype == CLONE && (!isnull(M.effective_clone_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_clone_resistance
+ continue
+ if(damagetype == HALLOSS && (!isnull(M.effective_hal_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ damage = damage * M.effective_hal_resistance
+ continue
+ if(damagetype == SEARING && (!isnull(M.effective_fire_resistance) || !isnull(M.effective_brute_resistance)))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost * damage)
+ var/damage_mitigation = 0//Used for dual calculations.
+ if(!isnull(M.effective_fire_resistance))
+ damage_mitigation += round((1/3)*damage * M.effective_fire_resistance)
+ if(!isnull(M.effective_brute_resistance))
+ damage_mitigation += round((2/3)*damage * M.effective_brute_resistance)
+ damage -= damage_mitigation
+ continue
+ if(damagetype == BIOACID && (isSynthetic() && (!isnull(M.effective_fire_resistance))) || (!isSynthetic() && M.effective_tox_resistance))
+ if(isSynthetic())
+ damage = damage * M.effective_fire_resistance
+ else
+ damage = damage * M.effective_tox_resistance
+ continue
if(soaked)
if(soaked >= round(damage*0.8))
damage -= round(damage*0.8)
@@ -55,6 +102,7 @@
/mob/living/proc/apply_damages(var/brute = 0, var/burn = 0, var/tox = 0, var/oxy = 0, var/clone = 0, var/halloss = 0, var/def_zone = null, var/blocked = 0)
if(blocked >= 100)
return 0
+ // INSERT MODIFIER CODE HERE... But no, really, only two things in the game use it, quad and viruses. The former is admin-only and the latter wouldn't be affected logically, but would if shield code was inerted here. If you really want, you can copy&paste the above and modify it to adjust brute/burn/etc. I do not advise this however.
if(brute) apply_damage(brute, BRUTE, def_zone, blocked)
if(burn) apply_damage(burn, BURN, def_zone, blocked)
if(tox) apply_damage(tox, TOX, def_zone, blocked)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index e0f7d9a14b..2c24fd1482 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -192,8 +192,12 @@
if(amount > 0)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_brute_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_brute_damage_percent
else if(amount < 0)
for(var/datum/modifier/M in modifiers)
@@ -219,8 +223,12 @@
if(amount > 0)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_oxy_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_oxy_damage_percent
else if(amount < 0)
for(var/datum/modifier/M in modifiers)
@@ -243,8 +251,12 @@
if(amount > 0)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_tox_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_tox_damage_percent
else if(amount < 0)
for(var/datum/modifier/M in modifiers)
@@ -273,8 +285,12 @@
if(amount > 0)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_fire_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_fire_damage_percent
else if(amount < 0)
for(var/datum/modifier/M in modifiers)
@@ -298,8 +314,12 @@
if(amount > 0)
for(var/datum/modifier/M in modifiers)
if(!isnull(M.incoming_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_clone_damage_percent))
+ if(M.energy_based)
+ M.energy_source.use(M.damage_cost*amount)
amount *= M.incoming_clone_damage_percent
else if(amount < 0)
for(var/datum/modifier/M in modifiers)
@@ -331,6 +351,9 @@
if(status_flags & GODMODE) return 0 //godmode
if(amount > 0)
for(var/datum/modifier/M in modifiers)
+ if(M.energy_based && (!isnull(M.incoming_hal_damage_percent) || !isnull(M.disable_duration_percent)))
+ M.energy_source.use(M.damage_cost*amount) // Cost of the Damage absorbed.
+ M.energy_source.use(M.energy_cost) // Cost of the Effect absorbed.
if(!isnull(M.incoming_damage_percent))
amount *= M.incoming_damage_percent
if(!isnull(M.incoming_hal_damage_percent))
diff --git a/icons/mob/modifier_effects_vr.dmi b/icons/mob/modifier_effects_vr.dmi
new file mode 100644
index 0000000000..108fff4f96
Binary files /dev/null and b/icons/mob/modifier_effects_vr.dmi differ
diff --git a/icons/obj/items_vr.dmi b/icons/obj/items_vr.dmi
index ca82649d88..1833ff1514 100644
Binary files a/icons/obj/items_vr.dmi and b/icons/obj/items_vr.dmi differ
diff --git a/vorestation.dme b/vorestation.dme
index 905965c35b..5520bb526b 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -1261,6 +1261,7 @@
#include "code\game\objects\items\devices\paicard.dm"
#include "code\game\objects\items\devices\paicard_ch.dm"
#include "code\game\objects\items\devices\paicard_vr.dm"
+#include "code\game\objects\items\devices\personal_shield_generator_vr.dm"
#include "code\game\objects\items\devices\pipe_painter.dm"
#include "code\game\objects\items\devices\powersink.dm"
#include "code\game\objects\items\devices\spy_bug.dm"