From 524cd2e671d16d8683cbeccc0a5ed042de71aba9 Mon Sep 17 00:00:00 2001 From: Casey Date: Thu, 22 Sep 2022 20:52:28 -0400 Subject: [PATCH 1/3] Adds personal shield generators. [READY FOR MERGE] --- code/game/machinery/recharger.dm | 4 + .../devices/personal_shield_generator_vr.dm | 601 ++++++++++++++++++ code/modules/client/stored_item.dm | 5 + code/modules/examine/descriptions/devices.dm | 16 +- code/modules/mining/abandonedcrates.dm | 4 +- .../equipment_vendor.dm | 1 + code/modules/mob/_modifiers/modifiers_vr.dm | 304 ++++++++- .../mob/living/carbon/human/human_damage.dm | 71 +++ .../mob/living/carbon/human/human_defense.dm | 12 + .../mob/living/carbon/human/update_icons.dm | 10 +- code/modules/mob/living/damage_procs.dm | 48 ++ code/modules/mob/living/living.dm | 23 + icons/mob/modifier_effects_vr.dmi | Bin 0 -> 1128 bytes icons/obj/items_vr.dmi | Bin 5259 -> 18471 bytes vorestation.dme | 1 + 15 files changed, 1095 insertions(+), 5 deletions(-) create mode 100644 code/game/objects/items/devices/personal_shield_generator_vr.dm create mode 100644 icons/mob/modifier_effects_vr.dmi diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 115e5e710a..59813e615a 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -10,7 +10,11 @@ active_power_usage = 40000 //40 kW var/efficiency = 40000 //will provide the modified power rate when upgraded var/obj/item/charging = null +<<<<<<< HEAD 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/device/personal_shield_generator) //VOREStation Add - NSFW Batteries +>>>>>>> 95138e4672... Merge pull request #13696 from Cameron653/TEST 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..1c6eebb348 100644 --- a/code/modules/client/stored_item.dm +++ b/code/modules/client/stored_item.dm @@ -254,3 +254,8 @@ persist_storable = FALSE /obj/item/weapon/spacecasinocash persist_storable = FALSE +<<<<<<< HEAD +======= +/obj/item/device/personal_shield_generator + persist_storable = FALSE +>>>>>>> 95138e4672... Merge pull request #13696 from Cameron653/TEST 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 0000000000000000000000000000000000000000..108fff4f968d831fd6d52391211fe88de0627e0c GIT binary patch literal 1128 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 Bv=aaT literal 5259 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 diff --git a/vorestation.dme b/vorestation.dme index d26c936fc8..04b67e2ddd 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1259,6 +1259,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" From a09214745bde9e7d8f1c8863428111e45d206ed6 Mon Sep 17 00:00:00 2001 From: Razgriz Date: Thu, 22 Sep 2022 20:36:38 -0700 Subject: [PATCH 2/3] powder that makes you say yes --- code/game/machinery/recharger.dm | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 59813e615a..7914c8cfdf 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -10,11 +10,7 @@ active_power_usage = 40000 //40 kW var/efficiency = 40000 //will provide the modified power rate when upgraded var/obj/item/charging = null -<<<<<<< HEAD - 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/device/personal_shield_generator) //VOREStation Add - NSFW Batteries ->>>>>>> 95138e4672... Merge pull request #13696 from Cameron653/TEST + 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 From 1e0b390b53ac7152231844545b0f1bd52fe1379e Mon Sep 17 00:00:00 2001 From: Razgriz Date: Thu, 22 Sep 2022 20:37:15 -0700 Subject: [PATCH 3/3] powder that makes you say yes --- code/modules/client/stored_item.dm | 3 --- 1 file changed, 3 deletions(-) diff --git a/code/modules/client/stored_item.dm b/code/modules/client/stored_item.dm index 1c6eebb348..fda2dcc9c8 100644 --- a/code/modules/client/stored_item.dm +++ b/code/modules/client/stored_item.dm @@ -254,8 +254,5 @@ persist_storable = FALSE /obj/item/weapon/spacecasinocash persist_storable = FALSE -<<<<<<< HEAD -======= /obj/item/device/personal_shield_generator persist_storable = FALSE ->>>>>>> 95138e4672... Merge pull request #13696 from Cameron653/TEST