mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-21 04:48:18 +01:00
Shielding Auras (#8760)
Ports Baystation12/Baystation12#19992 and Baystation12/Baystation12#27266. Added a personal shield device to the traitor tools uplink. Added a radiant shielding aura spell to Battlemage and Cleric. Added an exosuit shield drone to the mechfab. This works, but I'm not entirely happy with the sprites. The personal shield has no on-mob shimmer, it uses a mindbatterer grenade as an icon sprite. The wizard radiant spell uses a pretty big and janky sprite as an on-mob, and the exosuit's shield sprite doesn't follow the dir the mech faces, but that one I can maybe fix on my own. If anyone knows about that last one, lemme know, Bay had code for it that we do not.
This commit is contained in:
@@ -287,3 +287,157 @@
|
||||
if(istype(C))
|
||||
return C.charge/C.maxcharge
|
||||
return null
|
||||
|
||||
/obj/item/mecha_equipment/shield
|
||||
name = "exosuit shield droid"
|
||||
desc = "The Hephaestus Armature system is a well liked energy deflector system designed to stop any projectile before it has a chance to become a threat."
|
||||
icon_state = "shield_droid"
|
||||
var/obj/aura/mechshield/aura
|
||||
var/max_charge = 150
|
||||
var/charge = 150
|
||||
var/last_recharge = 0
|
||||
var/charging_rate = 7500 * CELLRATE
|
||||
var/cooldown = 3.5 SECONDS // Time until we can recharge again after a blocked impact
|
||||
restricted_hardpoints = list(HARDPOINT_BACK)
|
||||
restricted_software = list(MECH_SOFTWARE_WEAPONS)
|
||||
|
||||
/obj/item/mecha_equipment/shield/installed(mob/living/heavy_vehicle/_owner)
|
||||
. = ..()
|
||||
aura = new /obj/aura/mechshield(_owner)
|
||||
aura.added_to(_owner)
|
||||
aura.set_holder(src)
|
||||
|
||||
/obj/item/mecha_equipment/shield/uninstalled()
|
||||
QDEL_NULL(aura)
|
||||
. = ..()
|
||||
|
||||
/obj/item/mecha_equipment/shield/attack_self(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
toggle()
|
||||
|
||||
/obj/item/mecha_equipment/shield/proc/stop_damage(var/damage)
|
||||
var/difference = damage - charge
|
||||
charge = Clamp(charge - damage, 0, max_charge)
|
||||
|
||||
last_recharge = world.time
|
||||
|
||||
if(difference > 0)
|
||||
for(var/mob/pilot in owner.pilots)
|
||||
to_chat(pilot, FONT_LARGE(SPAN_WARNING("Warning: Deflector shield failure detected, shutting down.")))
|
||||
toggle()
|
||||
playsound(get_turf(owner),'sound/mecha/internaldmgalarm.ogg', 35, TRUE)
|
||||
return difference
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/item/mecha_equipment/shield/proc/toggle()
|
||||
if(!aura)
|
||||
return
|
||||
aura.toggle()
|
||||
aura.dir = owner.dir
|
||||
if(aura.dir == NORTH)
|
||||
aura.layer = MECH_UNDER_LAYER
|
||||
else
|
||||
aura.layer = ABOVE_MOB_LAYER
|
||||
playsound(owner,'sound/weapons/flash.ogg', 35, TRUE)
|
||||
update_icon()
|
||||
if(aura.active)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
else
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
owner.update_icon()
|
||||
|
||||
/obj/item/mecha_equipment/shield/update_icon()
|
||||
. = ..()
|
||||
if(!aura)
|
||||
return
|
||||
if(aura.active)
|
||||
icon_state = "shield_droid_a"
|
||||
else
|
||||
icon_state = "shield_droid"
|
||||
|
||||
/obj/item/mecha_equipment/shield/process()
|
||||
if(charge >= max_charge)
|
||||
return
|
||||
if((world.time - last_recharge) < cooldown)
|
||||
return
|
||||
var/obj/item/cell/cell = owner.get_cell()
|
||||
|
||||
var/actual_required_power = Clamp(max_charge - charge, 0, charging_rate)
|
||||
charge += cell.use(actual_required_power)
|
||||
|
||||
/obj/item/mecha_equipment/shield/get_hardpoint_status_value()
|
||||
return charge / max_charge
|
||||
|
||||
/obj/item/mecha_equipment/shield/get_hardpoint_maptext()
|
||||
return "[(aura && aura.active) ? "ONLINE" : "OFFLINE"]: [round((charge / max_charge) * 100)]%"
|
||||
|
||||
/obj/aura/mechshield
|
||||
icon = 'icons/mecha/shield.dmi'
|
||||
name = "mechshield"
|
||||
var/obj/item/mecha_equipment/shield/shields
|
||||
var/active = FALSE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
pixel_x = 8
|
||||
pixel_y = 4
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/aura/mechshield/added_to(mob/living/target)
|
||||
..()
|
||||
target.vis_contents += src
|
||||
dir = target.dir
|
||||
|
||||
/obj/aura/mechshield/proc/set_holder(var/obj/item/mecha_equipment/shield/holder)
|
||||
shields = holder
|
||||
|
||||
/obj/aura/mechshield/Destroy()
|
||||
if(user)
|
||||
user.vis_contents -= src
|
||||
shields = null
|
||||
. = ..()
|
||||
|
||||
/obj/aura/mechshield/proc/toggle()
|
||||
active = !active
|
||||
|
||||
update_icon()
|
||||
|
||||
if(active)
|
||||
flick("shield_raise", src)
|
||||
else
|
||||
flick("shield_drop", src)
|
||||
|
||||
|
||||
/obj/aura/mechshield/update_icon()
|
||||
. = ..()
|
||||
if(active)
|
||||
icon_state = "shield"
|
||||
else
|
||||
icon_state = "shield_null"
|
||||
|
||||
/obj/aura/mechshield/bullet_act(obj/item/projectile/P, var/def_zone)
|
||||
if(!active)
|
||||
return
|
||||
if(shields?.charge)
|
||||
P.damage = shields.stop_damage(P.damage)
|
||||
user.visible_message(SPAN_WARNING("\The [shields.owner]'s shields flash and crackle."))
|
||||
flick("shield_impact", src)
|
||||
playsound(user, 'sound/effects/basscannon.ogg', 35, TRUE)
|
||||
//light up the night.
|
||||
new /obj/effect/effect/smoke/illumination(get_turf(src), 5, 4, 1, "#ffffff")
|
||||
if(P.damage <= 0)
|
||||
return AURA_FALSE|AURA_CANCEL
|
||||
|
||||
spark(get_turf(src), 5, global.alldirs)
|
||||
playsound(get_turf(src), "sparks", 25, TRUE)
|
||||
|
||||
/obj/aura/mechshield/hitby(atom/movable/M, var/speed)
|
||||
. = ..()
|
||||
if(!active)
|
||||
return
|
||||
if(shields.charge && speed <= 5)
|
||||
user.visible_message(SPAN_WARNING("\The [shields.owner]'s shields flash briefly as they deflect \the [M]."))
|
||||
flick("shield_impact", src)
|
||||
playsound(user, 'sound/effects/basscannon.ogg', 10, TRUE)
|
||||
return AURA_FALSE|AURA_CANCEL
|
||||
//Too fast!
|
||||
@@ -307,6 +307,14 @@
|
||||
playsound(src.loc,legs.mech_turn_sound,40,1)
|
||||
next_move = world.time + legs.turn_delay
|
||||
set_dir(direction)
|
||||
if(istype(hardpoints[HARDPOINT_BACK], /obj/item/mecha_equipment/shield))
|
||||
var/obj/item/mecha_equipment/shield/S = hardpoints[HARDPOINT_BACK]
|
||||
if(S.aura)
|
||||
S.aura.dir = direction
|
||||
if(S.aura.dir == NORTH)
|
||||
S.aura.layer = MECH_UNDER_LAYER
|
||||
else
|
||||
S.aura.layer = ABOVE_MOB_LAYER
|
||||
update_icon()
|
||||
|
||||
/mob/living/heavy_vehicle/Move()
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/mob/living/exosuit
|
||||
movement_handlers = list(
|
||||
/datum/movement_handler/mob/space/exosuit,
|
||||
/datum/movement_handler/mob/exosuit
|
||||
)
|
||||
|
||||
/mob/living/exosuit/Move()
|
||||
. = ..()
|
||||
if(. && !istype(loc, /turf/space) && legs.mech_step_sound)
|
||||
playsound(src.loc, mech_step_sound, 40, 1)
|
||||
|
||||
//Override this and space move once a way to travel vertically is in
|
||||
///mob/living/exosuit/can_ztravel()
|
||||
// if(Allow_Spacemove()) //Handle here
|
||||
// return 1
|
||||
|
||||
// for(var/turf/simulated/T in trange(1,src))
|
||||
// if(T.density)
|
||||
// return 1
|
||||
|
||||
|
||||
/mob/living/exosuit/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = src.loc)
|
||||
//mechs are always anchored, so falling should always ignore it
|
||||
if(..(TRUE, location_override))
|
||||
return !(can_overcome_gravity())
|
||||
|
||||
|
||||
/datum/movement_handler/mob/exosuit
|
||||
expected_host_type = /mob/living/exosuit
|
||||
var/next_move
|
||||
|
||||
/datum/movement_handler/mob/exosuit/MayMove(var/mob/mover, var/is_external)
|
||||
var/mob/living/exosuit/exosuit = host
|
||||
if(world.time < next_move)
|
||||
return MOVEMENT_STOP
|
||||
if((!(mover in exosuit.pilots) && mover != exosuit) || exosuit.incapacitated() || mover.incapacitated())
|
||||
return MOVEMENT_STOP
|
||||
if(!exosuit.legs)
|
||||
to_chat(mover, "<span class='warning'>\The [exosuit] has no means of propulsion!</span>")
|
||||
next_move = world.time + 3 // Just to stop them from getting spammed with messages.
|
||||
return MOVEMENT_STOP
|
||||
if(!exosuit.legs.motivator || !exosuit.legs.motivator.is_functional())
|
||||
to_chat(mover, "<span class='warning'>Your motivators are damaged! You can't move!</span>")
|
||||
next_move = world.time + 15
|
||||
return MOVEMENT_STOP
|
||||
if(exosuit.maintenance_protocols)
|
||||
to_chat(mover, "<span class='warning'>Maintenance protocols are in effect.</span>")
|
||||
next_move = world.time + 3 // Just to stop them from getting spammed with messages.
|
||||
return MOVEMENT_STOP
|
||||
if(exosuit.lockdown)
|
||||
to_chat(mover, span("warning", "You cannot move while the exosuit's lockdown mode is active."))
|
||||
next_move = world.time + 3 // Just to stop them from getting spammed with messages.
|
||||
return MOVEMENT_STOP
|
||||
var/obj/item/cell/C = exosuit.get_cell()
|
||||
if(!C || !C.check_charge(exosuit.legs.power_use * CELLRATE))
|
||||
to_chat(mover, "<span class='warning'>The power indicator flashes briefly.</span>")
|
||||
next_move = world.time + 3 //On fast exosuits this got annoying fast
|
||||
return MOVEMENT_STOP
|
||||
|
||||
next_move = world.time + (exosuit.legs ? exosuit.legs.move_delay : 3)
|
||||
return MOVEMENT_PROCEED
|
||||
|
||||
/datum/movement_handler/mob/exosuit/DoMove(var/direction, var/mob/mover, var/is_external)
|
||||
var/mob/living/exosuit/exosuit = host
|
||||
var/moving_dir = direction
|
||||
|
||||
var/failed = FALSE
|
||||
if(exosuit.emp_damage >= EMP_MOVE_DISRUPT && prob(30))
|
||||
failed = TRUE
|
||||
if(failed)
|
||||
moving_dir = pick(cardinal - exosuit.dir)
|
||||
|
||||
exosuit.get_cell().use(exosuit.legs.power_use * CELLRATE)
|
||||
if(exosuit.dir != moving_dir)
|
||||
playsound(exosuit.loc, exosuit.mech_turn_sound, 40,1)
|
||||
exosuit.set_dir(moving_dir)
|
||||
next_move = world.time + exosuit.legs.turn_delay
|
||||
else
|
||||
var/turf/target_loc = get_step(exosuit, direction)
|
||||
if(target_loc && exosuit.legs && exosuit.legs.can_move_on(exosuit.loc, target_loc) && exosuit.MayEnterTurf(target_loc))
|
||||
exosuit.Move(target_loc)
|
||||
return MOVEMENT_HANDLED
|
||||
|
||||
|
||||
/datum/movement_handler/mob/space/exosuit
|
||||
expected_host_type = /mob/living/exosuit
|
||||
|
||||
// Space movement
|
||||
/datum/movement_handler/mob/space/exosuit/DoMove(var/direction, var/mob/mover)
|
||||
|
||||
if(!mob.check_solid_ground())
|
||||
mob.anchored = FALSE
|
||||
var/allowmove = mob.Allow_Spacemove(0)
|
||||
if(!allowmove)
|
||||
return MOVEMENT_HANDLED
|
||||
else if(allowmove == -1 && mob.handle_spaceslipping()) //Check to see if we slipped
|
||||
return MOVEMENT_HANDLED
|
||||
else
|
||||
mob.inertia_dir = 0 //If not then we can reset inertia and move
|
||||
else mob.anchored = TRUE
|
||||
|
||||
/datum/movement_handler/mob/space/exosuit/MayMove(var/mob/mover, var/is_external)
|
||||
if((mover != host) && is_external)
|
||||
return MOVEMENT_PROCEED
|
||||
|
||||
if(!mob.check_solid_ground())
|
||||
if(!mob.Allow_Spacemove(0))
|
||||
return MOVEMENT_STOP
|
||||
return MOVEMENT_PROCEED
|
||||
|
||||
/mob/living/exosuit/lost_in_space()
|
||||
for(var/atom/movable/AM in contents)
|
||||
if(!AM.lost_in_space())
|
||||
return FALSE
|
||||
return !pilots.len
|
||||
|
||||
/mob/living/exosuit/fall_damage()
|
||||
return 100 //Exosuits are big and heavy
|
||||
|
||||
/mob/living/exosuit/handle_fall_effect(var/turf/landing)
|
||||
// Return here if for any reason you shouldnt take damage
|
||||
..()
|
||||
var/damage = 30 //Enough to cause a malfunction if unlucky
|
||||
apply_damage(rand(0, damage), BRUTE, BP_R_LEG) //Any leg is good, will damage both
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
h_l_hand = /obj/item/mecha_equipment/mounted_system/taser/laser
|
||||
h_r_hand = /obj/item/mecha_equipment/mounted_system/taser/ion
|
||||
h_back = /obj/item/mecha_equipment/shield
|
||||
|
||||
/obj/item/mech_component/manipulators/heavy
|
||||
name = "heavy arms"
|
||||
|
||||
@@ -149,6 +149,11 @@ There are several things that need to be remembered:
|
||||
if(species.has_floating_eyes)
|
||||
ovr += species.get_eyes(src)
|
||||
|
||||
for(var/aura in auras)
|
||||
var/obj/aura/A = aura
|
||||
var/icon/aura_overlay = icon(A.icon, icon_state = A.icon_state)
|
||||
ovr += aura_overlay
|
||||
|
||||
add_overlay(ovr)
|
||||
|
||||
if (lying_prev != lying || size_multiplier != 1)
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
//Random events (vomiting etc)
|
||||
handle_random_events()
|
||||
|
||||
aura_check(AURA_TYPE_LIFE)
|
||||
|
||||
. = 1
|
||||
|
||||
//Handle temperature/pressure differences between body and environment
|
||||
|
||||
@@ -906,3 +906,25 @@ default behaviour is:
|
||||
Paralyse(rand(8,16))
|
||||
make_jittery(rand(150,200))
|
||||
adjustHalLoss(rand(50,60))
|
||||
|
||||
/mob/living/update_icons()
|
||||
for(var/aura in auras)
|
||||
var/obj/aura/A = aura
|
||||
var/icon/aura_overlay = icon(A.icon, icon_state = A.icon_state)
|
||||
add_overlay(aura_overlay)
|
||||
|
||||
/mob/living/proc/add_aura(var/obj/aura/aura)
|
||||
LAZYDISTINCTADD(auras, aura)
|
||||
update_icons()
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/remove_aura(var/obj/aura/aura)
|
||||
LAZYREMOVE(auras, aura)
|
||||
update_icons()
|
||||
return TRUE
|
||||
|
||||
/mob/living/Destroy()
|
||||
if(auras)
|
||||
for(var/a in auras)
|
||||
remove_aura(a)
|
||||
return ..()
|
||||
@@ -100,6 +100,28 @@
|
||||
P.on_hit(src, absorb, def_zone)
|
||||
return absorb
|
||||
|
||||
/mob/living/proc/aura_check(var/type)
|
||||
if(!auras)
|
||||
return TRUE
|
||||
. = TRUE
|
||||
var/list/newargs = args - args[1]
|
||||
for(var/a in auras)
|
||||
var/obj/aura/aura = a
|
||||
var/result = 0
|
||||
switch(type)
|
||||
if(AURA_TYPE_WEAPON)
|
||||
result = aura.attackby(arglist(newargs))
|
||||
if(AURA_TYPE_BULLET)
|
||||
result = aura.bullet_act(arglist(newargs))
|
||||
if(AURA_TYPE_THROWN)
|
||||
result = aura.hitby(arglist(newargs))
|
||||
if(AURA_TYPE_LIFE)
|
||||
result = aura.life_tick()
|
||||
if(result & AURA_FALSE)
|
||||
. = FALSE
|
||||
if(result & AURA_CANCEL)
|
||||
break
|
||||
|
||||
//For visuals, blood splatters and so on.
|
||||
/mob/living/proc/bullet_impact_visuals(var/obj/item/projectile/P, var/def_zone, var/damage)
|
||||
var/list/impact_sounds = LAZYACCESS(P.impact_sounds, get_bullet_impact_effect_type(def_zone))
|
||||
@@ -170,6 +192,8 @@
|
||||
|
||||
//this proc handles being hit by a thrown atom
|
||||
/mob/living/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve
|
||||
if(!aura_check(AURA_TYPE_THROWN, AM, speed))
|
||||
return
|
||||
if(istype(AM,/obj/))
|
||||
var/obj/O = AM
|
||||
var/dtype = O.damtype
|
||||
|
||||
@@ -69,4 +69,5 @@
|
||||
var/burn_mod = 1
|
||||
var/brute_mod = 1
|
||||
|
||||
var/limb_breaking = FALSE // used to limit people from queuing up limb-breaks
|
||||
var/limb_breaking = FALSE // used to limit people from queuing up limb-breaks
|
||||
var/list/obj/aura/auras //Basically a catch-all aura/force-field thing.
|
||||
@@ -174,6 +174,8 @@
|
||||
var/result = PROJECTILE_FORCE_MISS
|
||||
if(hit_zone)
|
||||
def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part
|
||||
if(!target_mob.aura_check(AURA_TYPE_BULLET, src, def_zone))
|
||||
return TRUE
|
||||
result = target_mob.bullet_act(src, def_zone)
|
||||
|
||||
if(result == PROJECTILE_FORCE_MISS && (can_miss == 0)) //if you're shooting at point blank you can't miss.
|
||||
|
||||
@@ -267,4 +267,11 @@
|
||||
/datum/design/item/mechfab/exosuit/passenger_compartment
|
||||
name = "Mounted Passenger Compartment"
|
||||
materials = list(DEFAULT_WALL_MATERIAL = 10000)
|
||||
build_path = /obj/item/mecha_equipment/sleeper/passenger_compartment
|
||||
build_path = /obj/item/mecha_equipment/sleeper/passenger_compartment
|
||||
|
||||
/datum/design/item/mechfab/exosuit/mechshields
|
||||
name = "Energy Shield Drone"
|
||||
time = 90
|
||||
materials = list(MATERIAL_STEEL = 20000, MATERIAL_SILVER = 12000, MATERIAL_GOLD = 12000)
|
||||
req_tech = list(TECH_MATERIAL = 4, TECH_MAGNET = 4, TECH_POWER = 4, TECH_COMBAT = 2)
|
||||
build_path = /obj/item/mecha_equipment/shield
|
||||
@@ -22,6 +22,7 @@
|
||||
/spell/aoe_turf/conjure/mirage = 1,
|
||||
/spell/targeted/shapeshift/corrupt_form = 1,
|
||||
/spell/targeted/flesh_to_stone = 1,
|
||||
/spell/radiant_aura = 1,
|
||||
/spell/noclothes = 1,
|
||||
/obj/structure/closet/wizard/armor = 1,
|
||||
/obj/item/gun/energy/staff/focus = 1,
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
/spell/aoe_turf/knock = 1,
|
||||
/spell/targeted/equip_item/holy_relic = 1,
|
||||
/spell/aoe_turf/conjure/grove/sanctuary = 1,
|
||||
/spell/radiant_aura = 1,
|
||||
/spell/targeted/projectile/dumbfire/fireball = 2,
|
||||
/spell/aoe_turf/conjure/forcewall = 1,
|
||||
/spell/targeted/subjugation = 1,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/spell/radiant_aura
|
||||
name = "Radiant Aura"
|
||||
desc = "Form a protective layer of light around you, making you immune to laser fire."
|
||||
school = "transmutation"
|
||||
feedback = "ra"
|
||||
invocation_type = SpI_EMOTE
|
||||
invocation = "conjures a sphere of fire around themselves."
|
||||
school = "conjuration"
|
||||
spell_flags = NEEDSCLOTHES
|
||||
charge_max = 300
|
||||
cooldown_min = 200
|
||||
level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 0)
|
||||
cast_sound = 'sound/effects/snap.ogg'
|
||||
duration = 250
|
||||
hud_state = "gen_immolate"
|
||||
|
||||
/spell/radiant_aura/choose_targets()
|
||||
return list(holder)
|
||||
|
||||
/spell/radiant_aura/cast(var/list/targets, mob/user)
|
||||
var/obj/aura/radiant_aura/A = new /obj/aura/radiant_aura(user)
|
||||
A.added_to(user)
|
||||
QDEL_IN(A, duration)
|
||||
|
||||
/spell/radiant_aura/starlight
|
||||
spell_flags = 0
|
||||
charge_max = 400
|
||||
Reference in New Issue
Block a user