mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2025-12-26 10:03:45 +00:00
* Creating new objects is cheap, in fact comparable to the cost of getting it out of the pool, so it doesn't help there. * Placing items in the pool is far more expensive than letting them garbage collect due to the resetting of vars and such.
226 lines
8.3 KiB
Plaintext
226 lines
8.3 KiB
Plaintext
//** Shield Helpers
|
|
//These are shared by various items that have shield-like behaviour
|
|
|
|
//bad_arc is the ABSOLUTE arc of directions from which we cannot block. If you want to fix it to e.g. the user's facing you will need to rotate the dirs yourself.
|
|
/proc/check_shield_arc(mob/user, var/bad_arc, atom/damage_source = null, mob/attacker = null)
|
|
//check attack direction
|
|
var/attack_dir = 0 //direction from the user to the source of the attack
|
|
if(istype(damage_source, /obj/item/projectile))
|
|
var/obj/item/projectile/P = damage_source
|
|
attack_dir = get_dir(get_turf(user), P.starting)
|
|
else if(attacker)
|
|
attack_dir = get_dir(get_turf(user), get_turf(attacker))
|
|
else if(damage_source)
|
|
attack_dir = get_dir(get_turf(user), get_turf(damage_source))
|
|
|
|
if(!(attack_dir && (attack_dir & bad_arc)))
|
|
return 1
|
|
return 0
|
|
|
|
/proc/default_parry_check(mob/user, mob/attacker, atom/damage_source)
|
|
//parry only melee attacks
|
|
if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated())
|
|
return 0
|
|
|
|
//block as long as they are not directly behind us
|
|
var/bad_arc = reverse_direction(user.dir) //arc of directions from which we cannot block
|
|
if(!check_shield_arc(user, bad_arc, damage_source, attacker))
|
|
return 0
|
|
|
|
return 1
|
|
|
|
/obj/item/weapon/shield
|
|
name = "shield"
|
|
var/base_block_chance = 50
|
|
item_icons = list(
|
|
slot_l_hand_str = 'icons/mob/items/lefthand_melee.dmi',
|
|
slot_r_hand_str = 'icons/mob/items/righthand_melee.dmi',
|
|
)
|
|
|
|
/obj/item/weapon/shield/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
|
|
if(user.incapacitated())
|
|
return 0
|
|
|
|
//block as long as they are not directly behind us
|
|
var/bad_arc = reverse_direction(user.dir) //arc of directions from which we cannot block
|
|
if(check_shield_arc(user, bad_arc, damage_source, attacker))
|
|
if(prob(get_block_chance(user, damage, damage_source, attacker)))
|
|
user.visible_message("<span class='danger'>\The [user] blocks [attack_text] with \the [src]!</span>")
|
|
return 1
|
|
return 0
|
|
|
|
/obj/item/weapon/shield/proc/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null)
|
|
return base_block_chance
|
|
|
|
/obj/item/weapon/shield/riot
|
|
name = "riot shield"
|
|
desc = "A shield adept for close quarters engagement. It's also capable of protecting from less powerful projectiles."
|
|
icon = 'icons/obj/weapons.dmi'
|
|
icon_state = "riot"
|
|
flags = CONDUCT
|
|
slot_flags = SLOT_BACK
|
|
force = 5.0
|
|
throwforce = 5.0
|
|
throw_speed = 1
|
|
throw_range = 4
|
|
w_class = ITEMSIZE_LARGE
|
|
origin_tech = list(TECH_MATERIAL = 2)
|
|
matter = list("glass" = 7500, DEFAULT_WALL_MATERIAL = 1000)
|
|
attack_verb = list("shoved", "bashed")
|
|
var/cooldown = 0 //shield bash cooldown. based on world.time
|
|
|
|
/obj/item/weapon/shield/riot/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
|
|
if(user.incapacitated())
|
|
return 0
|
|
|
|
//block as long as they are not directly behind us
|
|
var/bad_arc = reverse_direction(user.dir) //arc of directions from which we cannot block
|
|
if(check_shield_arc(user, bad_arc, damage_source, attacker))
|
|
if(prob(get_block_chance(user, damage, damage_source, attacker)))
|
|
//At this point, we succeeded in our roll for a block attempt, however these kinds of shields struggle to stand up
|
|
//to strong bullets and lasers. They still do fine to pistol rounds of all kinds, however.
|
|
if(istype(damage_source, /obj/item/projectile))
|
|
var/obj/item/projectile/P = damage_source
|
|
if((is_sharp(P) && P.armor_penetration >= 10) || istype(P, /obj/item/projectile/beam))
|
|
//If we're at this point, the bullet/beam is going to go through the shield, however it will hit for less damage.
|
|
//Bullets get slowed down, while beams are diffused as they hit the shield, so these shields are not /completely/
|
|
//useless. Extremely penetrating projectiles will go through the shield without less damage.
|
|
user.visible_message("<span class='danger'>\The [user]'s [src.name] is pierced by [attack_text]!</span>")
|
|
if(P.armor_penetration < 30) //PTR bullets and x-rays will bypass this entirely.
|
|
P.damage = P.damage / 2
|
|
return 0
|
|
//Otherwise, if we're here, we're gonna stop the attack entirely.
|
|
user.visible_message("<span class='danger'>\The [user] blocks [attack_text] with \the [src]!</span>")
|
|
playsound(user.loc, 'sound/weapons/Genhit.ogg', 50, 1)
|
|
return 1
|
|
return 0
|
|
|
|
/obj/item/weapon/shield/riot/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
|
if(istype(W, /obj/item/weapon/melee/baton))
|
|
if(cooldown < world.time - 25)
|
|
user.visible_message("<span class='warning'>[user] bashes [src] with [W]!</span>")
|
|
playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1)
|
|
cooldown = world.time
|
|
else
|
|
..()
|
|
|
|
/*
|
|
* Energy Shield
|
|
*/
|
|
|
|
/obj/item/weapon/shield/energy
|
|
name = "energy combat shield"
|
|
desc = "A shield capable of stopping most projectile and melee attacks. It can be retracted, expanded, and stored anywhere."
|
|
icon = 'icons/obj/weapons.dmi'
|
|
icon_state = "eshield0" // eshield1 for expanded
|
|
slot_flags = SLOT_EARS
|
|
flags = CONDUCT
|
|
force = 3.0
|
|
throwforce = 5.0
|
|
throw_speed = 1
|
|
throw_range = 4
|
|
w_class = ITEMSIZE_SMALL
|
|
origin_tech = list(TECH_MATERIAL = 4, TECH_MAGNET = 3, TECH_ILLEGAL = 4)
|
|
attack_verb = list("shoved", "bashed")
|
|
var/active = 0
|
|
|
|
/obj/item/weapon/shield/energy/handle_shield(mob/user)
|
|
if(!active)
|
|
return 0 //turn it on first!
|
|
. = ..()
|
|
|
|
if(.)
|
|
var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
|
|
spark_system.set_up(5, 0, user.loc)
|
|
spark_system.start()
|
|
playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1)
|
|
|
|
/obj/item/weapon/shield/energy/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null)
|
|
if(istype(damage_source, /obj/item/projectile))
|
|
var/obj/item/projectile/P = damage_source
|
|
if((is_sharp(P) && damage > 10) || istype(P, /obj/item/projectile/beam))
|
|
return (base_block_chance - round(damage / 3)) //block bullets and beams using the old block chance
|
|
return base_block_chance
|
|
|
|
/obj/item/weapon/shield/energy/attack_self(mob/living/user as mob)
|
|
if ((CLUMSY in user.mutations) && prob(50))
|
|
user << "<span class='warning'>You beat yourself in the head with [src].</span>"
|
|
user.take_organ_damage(5)
|
|
active = !active
|
|
if (active)
|
|
force = 10
|
|
update_icon()
|
|
w_class = ITEMSIZE_LARGE
|
|
slot_flags = null
|
|
playsound(user, 'sound/weapons/saberon.ogg', 50, 1)
|
|
user << "<span class='notice'>\The [src] is now active.</span>"
|
|
|
|
else
|
|
force = 3
|
|
update_icon()
|
|
w_class = ITEMSIZE_TINY
|
|
slot_flags = SLOT_EARS
|
|
playsound(user, 'sound/weapons/saberoff.ogg', 50, 1)
|
|
user << "<span class='notice'>\The [src] can now be concealed.</span>"
|
|
|
|
if(istype(user,/mob/living/carbon/human))
|
|
var/mob/living/carbon/human/H = user
|
|
H.update_inv_l_hand()
|
|
H.update_inv_r_hand()
|
|
|
|
add_fingerprint(user)
|
|
return
|
|
|
|
/obj/item/weapon/shield/energy/update_icon()
|
|
icon_state = "eshield[active]"
|
|
if(active)
|
|
set_light(1.5, 1.5, "#006AFF")
|
|
else
|
|
set_light(0)
|
|
|
|
/obj/item/weapon/shield/riot/tele
|
|
name = "telescopic shield"
|
|
desc = "An advanced riot shield made of lightweight materials that collapses for easy storage."
|
|
icon = 'icons/obj/weapons.dmi'
|
|
icon_state = "teleriot0"
|
|
slot_flags = null
|
|
force = 3
|
|
throwforce = 3
|
|
throw_speed = 3
|
|
throw_range = 4
|
|
w_class = ITEMSIZE_NORMAL
|
|
var/active = 0
|
|
/*
|
|
/obj/item/weapon/shield/energy/IsShield()
|
|
if(active)
|
|
return 1
|
|
else
|
|
return 0
|
|
*/
|
|
/obj/item/weapon/shield/riot/tele/attack_self(mob/living/user)
|
|
active = !active
|
|
icon_state = "teleriot[active]"
|
|
playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
|
|
|
|
if(active)
|
|
force = 8
|
|
throwforce = 5
|
|
throw_speed = 2
|
|
w_class = ITEMSIZE_LARGE
|
|
slot_flags = SLOT_BACK
|
|
user << "<span class='notice'>You extend \the [src].</span>"
|
|
else
|
|
force = 3
|
|
throwforce = 3
|
|
throw_speed = 3
|
|
w_class = ITEMSIZE_NORMAL
|
|
slot_flags = null
|
|
user << "<span class='notice'>[src] can now be concealed.</span>"
|
|
|
|
if(istype(user,/mob/living/carbon/human))
|
|
var/mob/living/carbon/human/H = user
|
|
H.update_inv_l_hand()
|
|
H.update_inv_r_hand()
|
|
|
|
add_fingerprint(user)
|
|
return |