mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-13 17:07:53 +01:00
eebb8b971c
Soft-ish port of https://github.com/NebulaSS13/Nebula/pull/540. Except we call them singletons. Repaths all materials as singletons instead of datums, and replaces material defines from strings to paths so that we can just run GET_SINGLETON instead of needing to use SSMaterials. This is Step One. This PR has no player-facing changes. changes: - refactor: "Repaths /material to /singleton/material." - refactor: "Replaces all material string defines to path defines, replacing SSmaterials procs w/ GET_SINGLETON instead." - refactor: "Removes all material var edited objects from all maps, adding new presets where necessary." - refactor: "Updates recipes unit test to run all recipes against all material singletons." --------- Signed-off-by: Batrachophreno <Batrochophreno@gmail.com> Co-authored-by: kano-dot <bhutanlikanoxy@gmail.com>
366 lines
16 KiB
Plaintext
366 lines
16 KiB
Plaintext
/obj/item/ship_ammunition
|
|
name = "artillery shell"
|
|
desc = "A shell of some sort."
|
|
icon = 'icons/obj/projectiles.dmi'
|
|
icon_state = "nuke"
|
|
w_class = WEIGHT_CLASS_HUGE
|
|
slowdown = 1
|
|
drop_sound = 'sound/items/drop/shell_drop.ogg'
|
|
var/projectile_type_override //Override projectile type fired by the gun. This is because certain guns don't use ammo (the Leviathan) but with some we want the ammo to matter.
|
|
var/overmap_projectile_type_override //Override projectile type on the overmap, fired by the gun. Like the Grauwolf Probe.
|
|
var/name_override //If set, this will override the ammunition name for the overmap effect.
|
|
var/written_message
|
|
var/wielded = FALSE
|
|
var/caliber = SHIP_CALIBER_NONE
|
|
var/burst = 0 //If set to a number, this many projectiles will spawn to the side of the main projectile.
|
|
var/impact_type = SHIP_AMMO_IMPACT_HE //This decides what happens when the ammo hits. Is it a bunkerbuster? HE? AP?
|
|
var/ammunition_status = SHIP_AMMO_STATUS_GOOD //Currently unused, but will be relevant for chemical ammo.
|
|
var/ammunition_flags = SHIP_AMMO_FLAG_INFLAMMABLE|SHIP_AMMO_FLAG_VERY_HEAVY
|
|
var/ammunition_behaviour = SHIP_AMMO_BEHAVIOUR_DUMBFIRE //Not a bitfield!
|
|
var/overmap_behaviour = SHIP_AMMO_CAN_HIT_HAZARDS|SHIP_AMMO_CAN_HIT_VISITABLES|SHIP_AMMO_CAN_HIT_PLANETS //Whether or not the ammo can hit hazards or ships, and so on.
|
|
var/overmap_icon_state = "cannon"
|
|
var/obj/effect/overmap/origin
|
|
var/atom/overmap_target
|
|
var/obj/entry_point
|
|
var/obj/projectile/original_projectile
|
|
var/heading = SOUTH
|
|
var/range = OVERMAP_PROJECTILE_RANGE_MEDIUM
|
|
var/mob_carry_size = 12 //How large a mob has to be to carry the shell
|
|
//Cookoff variables.
|
|
var/cookoff_devastation = 0
|
|
var/cookoff_heavy = 2
|
|
var/cookoff_light = 3
|
|
|
|
/obj/item/ship_ammunition/mechanics_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
. += "Using a pen on \the [src] will let you write a lovely message on it for your intended target; this message is detectable on the overmap by ship sensors."
|
|
. += "Some types of ammunition are especially flammable, fragile, etc. They can cook off if not stored and handled very carefully."
|
|
|
|
/obj/item/ship_ammunition/feedback_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
if(written_message)
|
|
if(distance > 3)
|
|
. += "It has something written on it, but you'd need to get closer to tell what the writing says."
|
|
else
|
|
. += "It has a message written on the casing: <span class='notice'><i>[written_message]</i></span>."
|
|
|
|
/obj/item/ship_ammunition/antagonist_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
if(ammunition_flags & SHIP_AMMO_FLAG_INFLAMMABLE)
|
|
. += "This ammunition is flammable, and will cook off and explode when exposed to fire."
|
|
if(ammunition_flags & SHIP_AMMO_FLAG_VULNERABLE)
|
|
. += "This ammunition is vulnerable, and will cook off and explode on impact if shot at or attacked."
|
|
if(ammunition_flags & SHIP_AMMO_FLAG_VERY_FRAGILE)
|
|
. += "This ammunition is very fragile, and will cook off and explode on impact if thrown, or even just dropped with the Harm intent!"
|
|
|
|
/obj/item/ship_ammunition/Initialize()
|
|
. = ..()
|
|
update_status()
|
|
|
|
/obj/item/ship_ammunition/Destroy()
|
|
origin = null
|
|
overmap_target = null
|
|
entry_point = null
|
|
original_projectile = null
|
|
return ..()
|
|
|
|
/obj/item/ship_ammunition/attackby(obj/item/attacking_item, mob/user)
|
|
if(attacking_item.force > 10 && (ammunition_flags & SHIP_AMMO_FLAG_VERY_FRAGILE))
|
|
if(istype(attacking_item, /obj/item/mecha_equipment/clamp))
|
|
return ..()
|
|
else
|
|
log_and_message_admins("[user] has caused the cookoff of [src] by attacking it with [attacking_item]!", user)
|
|
cookoff(FALSE)
|
|
|
|
else if(attacking_item.tool_behaviour == TOOL_PEN)
|
|
var/obj/item/pen/P = attacking_item
|
|
if(!use_check_and_message(user))
|
|
var/friendly_message = sanitizeSafe( tgui_input_text(user, "What do you want to write on \the [src]?", "Personal Message", "", 32), 32 )
|
|
if(friendly_message)
|
|
written_message = friendly_message
|
|
visible_message(SPAN_NOTICE("[user] writes something on \the [src] with \the [P]."), SPAN_NOTICE("You leave a nice message on \the [src]!"))
|
|
return
|
|
return ..()
|
|
|
|
/obj/item/ship_ammunition/do_additional_pickup_checks(var/mob/user)
|
|
if(ammunition_flags & SHIP_AMMO_FLAG_VERY_HEAVY)
|
|
if(ishuman(user))
|
|
var/mob/living/carbon/human/H = user
|
|
var/datum/species/S = H.species
|
|
if(S.mob_size >= mob_carry_size || S.resist_mod >= 10 || user.status_flags & GODMODE)
|
|
visible_message(SPAN_NOTICE("[user] tightens their grip on [src] and starts heaving..."))
|
|
if(do_after(user, 1 SECONDS, src, DO_UNIQUE))
|
|
visible_message(SPAN_NOTICE("[user] heaves \the [src] up!"))
|
|
wield(user)
|
|
return TRUE
|
|
else return FALSE
|
|
if(istype(H.back, /obj/item/rig))
|
|
var/obj/item/rig/R = H.back
|
|
if(R.suit_is_deployed())
|
|
visible_message(SPAN_NOTICE("[user] tightens their grip on [src] and starts heaving with some difficulty..."))
|
|
if(do_after(user, 5 SECONDS, src, DO_UNIQUE))
|
|
visible_message(SPAN_NOTICE("[user] heaves \the [src] up!"))
|
|
wield(user)
|
|
return TRUE
|
|
else return FALSE
|
|
to_chat(user, SPAN_WARNING("\The [src] is way too heavy for you to pick up without some assistance!"))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/item/ship_ammunition/too_heavy_to_throw()
|
|
if(ammunition_flags & SHIP_AMMO_FLAG_VERY_HEAVY)
|
|
return TRUE
|
|
else
|
|
return FALSE
|
|
|
|
/obj/item/ship_ammunition/throw_impact(atom/hit_atom)
|
|
. = ..()
|
|
if(prob(50) && ((ammunition_flags & SHIP_AMMO_FLAG_VERY_FRAGILE) || (ammunition_flags & SHIP_AMMO_FLAG_VULNERABLE)))
|
|
cookoff(FALSE)
|
|
|
|
/obj/item/ship_ammunition/ex_act(severity)
|
|
if(ammunition_flags & SHIP_AMMO_FLAG_INFLAMMABLE)
|
|
cookoff(TRUE)
|
|
|
|
/obj/item/ship_ammunition/fire_act(exposed_temperature, exposed_volume)
|
|
. = ..()
|
|
|
|
if(ammunition_flags & SHIP_AMMO_FLAG_INFLAMMABLE)
|
|
if(exposed_temperature >= T0C+200)
|
|
cookoff(TRUE)
|
|
|
|
/obj/item/ship_ammunition/proc/cookoff(var/caused_by_heat = TRUE)
|
|
if(ammunition_flags & SHIP_AMMO_FLAG_INFLAMMABLE)
|
|
visible_message(SPAN_DANGER("\The [src] [caused_by_heat ? "cooks" : "goes"] off and explodes!"))
|
|
explosion(get_turf(src), cookoff_devastation, cookoff_heavy, cookoff_light)
|
|
qdel(src)
|
|
|
|
/obj/item/ship_ammunition/proc/can_be_loaded()
|
|
return TRUE
|
|
|
|
/obj/item/ship_ammunition/proc/update_status()
|
|
return
|
|
|
|
/obj/item/ship_ammunition/proc/eject_shell(var/obj/structure/machinery/ship_weapon/SW) //do cool casing ejection effects here
|
|
return
|
|
|
|
/obj/item/ship_ammunition/proc/wield(var/mob/living/carbon/human/user)
|
|
var/obj/A = user.get_inactive_hand()
|
|
if(A)
|
|
to_chat(user, SPAN_WARNING("Your other hand is occupied!"))
|
|
return
|
|
wielded = TRUE
|
|
var/obj/item/offhand/O = new(user)
|
|
O.name = "[initial(name)] - offhand"
|
|
O.desc = "Your second grip on \the [initial(name)]."
|
|
user.put_in_inactive_hand(O)
|
|
|
|
/obj/item/ship_ammunition/proc/unwield()
|
|
wielded = FALSE
|
|
|
|
/obj/item/ship_ammunition/dropped(mob/user)
|
|
..()
|
|
if(user)
|
|
var/obj/item/offhand/O = user.get_inactive_hand()
|
|
if(istype(O))
|
|
O.unwield()
|
|
return unwield()
|
|
|
|
/obj/item/ship_ammunition/can_swap_hands(var/mob/user)
|
|
if(wielded)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/item/ship_ammunition/proc/get_additional_info()
|
|
. += SPAN_DANGER("[name_override ? name_override : name]<br>")
|
|
. += "[desc]<br>"
|
|
. += "Caliber: [caliber]<br>"
|
|
. += "Ammunition Type: [capitalize_first_letters(impact_type)]<br>"
|
|
if(written_message)
|
|
. += "Sensor readings indicate the presence of a message written on the shell: <b>[written_message]</b>"
|
|
|
|
/obj/item/ship_ammunition/proc/get_speed() //Lag variable used for step_towards(). Lower is better.
|
|
return 4
|
|
|
|
/obj/item/ship_ammunition/touch_map_edge(var/new_z)
|
|
if(isprojectile(loc))
|
|
transfer_to_overmap(new_z)
|
|
origin = GLOB.map_sectors["[new_z]"]
|
|
return TRUE
|
|
else
|
|
. = ..()
|
|
|
|
/obj/item/ship_ammunition/proc/transfer_to_overmap(var/new_z)
|
|
var/obj/effect/overmap/start_object = GLOB.map_sectors["[new_z]"]
|
|
if(!start_object)
|
|
return FALSE
|
|
|
|
var/obj/effect/overmap/projectile/P = null
|
|
if(overmap_projectile_type_override)
|
|
P = new overmap_projectile_type_override(null, start_object.x, start_object.y, origin)
|
|
else
|
|
P = new(null, start_object.x, start_object.y, origin)
|
|
|
|
P.name = name_override ? name_override : name
|
|
P.desc = desc
|
|
P.ammunition = src
|
|
P.target = overmap_target
|
|
P.range = range
|
|
if(istype(origin, /obj/effect/overmap/visitable/ship))
|
|
var/obj/effect/overmap/visitable/ship/S = origin
|
|
P.dir = S.dir
|
|
P.icon_state = overmap_icon_state
|
|
P.speed = get_speed()
|
|
P.submap_target = entry_point
|
|
forceMove(P)
|
|
log_and_message_admins("A projectile ([name]) has entered the Overmap! (<A href='byond://?_src_=holder;adminplayerobservecoodjump=1;X=[P.x];Y=[P.y];Z=[P.z]'>JMP</a>)")
|
|
return TRUE
|
|
|
|
//SNOWFLAKE CODE: ACTIVATE
|
|
//The problem is getting the projectile from the gun to the map edge. We want to do this naturally, but using process() and BYOND's walk procs makes it look very... unnatural. And also slow!
|
|
//The solution? Let's co-opt projectile code!
|
|
/obj/projectile/ship_ammo
|
|
name = "ship ammunition"
|
|
icon = 'icons/obj/guns/ship/physical_projectiles.dmi'
|
|
icon_state = "small"
|
|
range = 250
|
|
anti_materiel_potential = 3
|
|
impact_sounds = list(BULLET_IMPACT_MEAT = SOUNDS_BULLET_MEAT, BULLET_IMPACT_METAL = SOUNDS_BULLET_METAL)
|
|
accuracy = 100
|
|
projectile_piercing = PASSGLASS|PASSGRILLE|PASSBLOB|PASSMOB|PASSCLOSEDTURF|PASSMACHINE|PASSSTRUCTURE|PASSFLAPS|PASSDOORS|PASSVEHICLE|PASSWINDOW|PASSSHIELD //It's a ship weapon let it try to penetrate everything.
|
|
pierce_decay_damage = 0.95 //Ship weapon projectiles don't lose much damage on pierce by default, but this can be set per projectile.
|
|
///This is passed to explosion(), it is stored here for when projectiles hit shields and need to damage the shield as if they had exploded.
|
|
var/list/explosion_strength = list(0, 0, 0)
|
|
///The last thing this projectile pierced. Used for spalling effects in on_hit()
|
|
var/atom/last_thing_pierced = null
|
|
var/obj/item/ship_ammunition/ammo
|
|
var/primed = FALSE
|
|
///First target we hit. Used to report if a hit was successful.
|
|
var/hit_target = FALSE
|
|
|
|
/obj/projectile/ship_ammo/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) //When the projectile moves from a dense tile to a non-dense tile.
|
|
. = ..()
|
|
if(last_thing_pierced)
|
|
var/turf/entered_turf = isturf(loc) ? loc : get_turf(loc)
|
|
if(!(entered_turf.check_density(FALSE, TRUE))) //Checks for mobs so we don't spawn spalling inside the poor bridge crew, getting hit by the shell is bad enough.
|
|
handle_spalling(entered_turf, movement_dir, last_thing_pierced)
|
|
last_thing_pierced = null
|
|
|
|
/**
|
|
* This creates a cone of shrapnel whenever a projectile pierces something dense and then crosses into a non-dense turf.
|
|
* This means that it won't spawn all the shrapnel inside the next thing it penetrates, to simulate spalling.
|
|
* All of of the projectile stats are set custom here, in future it might be good to set them dynmically based on the material of the thing pierced.
|
|
* Too many things don't have a material set, so that will have to wait.
|
|
*/
|
|
/obj/projectile/ship_ammo/proc/handle_spalling(atom/source, shrapnel_dir, thing_pierced)
|
|
set waitfor = FALSE
|
|
|
|
src.visible_message(SPAN_DANGER("Huge chunks of shrapnel spray out from \the [thing_pierced] as \the [src] punches through!"))
|
|
|
|
var/turf/O = get_turf(src)
|
|
var/list/target_turfs = list()
|
|
target_turfs += get_step(O, shrapnel_dir)
|
|
target_turfs += get_step(O, turn(shrapnel_dir, -45))
|
|
target_turfs += get_step(O, turn(shrapnel_dir, 45))
|
|
target_turfs += get_step(get_step(O, turn(shrapnel_dir, -45)), shrapnel_dir)
|
|
target_turfs += get_step(get_step(O, turn(shrapnel_dir, 45)), shrapnel_dir)
|
|
|
|
for(var/turf/T in target_turfs)
|
|
var/obj/projectile/bullet/pellet/fragment/spall/P
|
|
if(istype(thing_pierced, /obj/structure/window))
|
|
P = new /obj/projectile/bullet/pellet/fragment/spall/glass(O)
|
|
else if(istype(thing_pierced, /obj/structure/grille) || istype(thing_pierced, /obj/structure/window_frame))
|
|
P = new /obj/projectile/bullet/pellet/fragment/spall/metalrod(O)
|
|
else if(istype(thing_pierced, /obj/structure/machinery/door/airlock))
|
|
var/obj/structure/machinery/door/airlock/D = thing_pierced
|
|
if(D.window_material && D.window_material == GET_SINGLETON(MATERIAL_GLASS))
|
|
P = new /obj/projectile/bullet/pellet/fragment/spall/glass(O)
|
|
else
|
|
P = new /obj/projectile/bullet/pellet/fragment/spall(O)
|
|
else
|
|
P = new /obj/projectile/bullet/pellet/fragment/spall(O)
|
|
P.preparePixelProjectile(T, src)
|
|
P.firer = src
|
|
P.fired_from = thing_pierced
|
|
P.fire()
|
|
return TRUE
|
|
|
|
/obj/projectile/bullet/pellet/fragment/spall
|
|
damage = 2 //Between 30 and 3 damage, depending on how close you are. Pilot suits are 30 ballistic armour, so they should survive a lot of spall.
|
|
pellets = 15
|
|
armor_penetration = 10
|
|
range_step = 1
|
|
range = 15
|
|
embed_chance = 80 //Make the people hit pull big chunks of shrapnel out by hand.
|
|
maim_rate = -1 //We don't want this to decapitate people in the unlucky event they get hit by the shell (or shell explosion) directly, then more shrapnel afterwards.
|
|
anti_materiel_potential = 2 //Enough to break windows.
|
|
name = "spall"
|
|
shrapnel_type = /obj/item/material/shard/shrapnel/large
|
|
|
|
/obj/projectile/bullet/pellet/fragment/spall/glass
|
|
damage = 1
|
|
armor_penetration = 5
|
|
name = "glass"
|
|
shrapnel_type = /obj/item/material/shard
|
|
|
|
/obj/projectile/bullet/pellet/fragment/spall/metalrod
|
|
damage = 3
|
|
armor_penetration = 15
|
|
name = "metal rod"
|
|
shrapnel_type = /obj/item/stack/rods
|
|
|
|
/obj/projectile/ship_ammo/Destroy()
|
|
ammo = null
|
|
hit_target = null
|
|
return ..()
|
|
|
|
/obj/projectile/ship_ammo/touch_map_edge()
|
|
if(primed)
|
|
for(var/mob/living/carbon/human/H in GLOB.human_mob_list)
|
|
if(AreConnectedZLevels(H.z, z))
|
|
to_chat(H, SPAN_WARNING("The flooring below you vibrates a little as shells fly by the hull of the ship!"))
|
|
H.playsound_local(null, 'sound/effects/explosionfar.ogg', 25)
|
|
shake_camera(H, 2, 2)
|
|
..()
|
|
if(ammo.touch_map_edge(z))
|
|
ammo.original_projectile = src
|
|
forceMove(ammo)
|
|
|
|
/obj/projectile/ship_ammo/on_hit(atom/target, blocked, def_zone, var/is_landmark_hit = FALSE) //is_landmark_hit is TRUE when we hit a landmark on a visitable non-ship overmap object.
|
|
if(target && !hit_target)
|
|
hit_target = TRUE
|
|
var/target_name = target.name
|
|
var/list/hit_data = list(
|
|
"target_name" = target_name,
|
|
"target_area" = get_area(target),
|
|
"coordinates" = "[target.x], [target.y], [target.z]"
|
|
)
|
|
if(ammo && ammo.origin)
|
|
ammo.origin.signal_hit(hit_data)
|
|
|
|
for(var/mob/M in GLOB.dead_mob_list) //Print out a message about what we hit to all ghosts.
|
|
if(M.client)
|
|
to_chat(M, "<span class='deadsay'>" + create_text_tag("DEAD", M.client) + "[ghost_follow_link(target, M)] A [src.name] hit \the [target.name] in \the [get_area(target)] at [target.x], [target.y], [target.z]!</span>")
|
|
|
|
if(istype(target, /turf/simulated/wall) || istype(target, /obj/structure/machinery/door)) //Stores the last thing we pierced for spalling purposes.
|
|
last_thing_pierced = target
|
|
else if (istype(target, /obj/structure)) //If it is a structure on a dense turf, that uses health,
|
|
if (target.should_use_health)
|
|
var/turf/T = get_turf(target)
|
|
if (T.check_density(FALSE, TRUE))
|
|
last_thing_pierced = target
|
|
return ..()
|
|
|
|
/obj/projectile/ship_ammo/proc/on_translate(var/turf/entry_turf, var/target_turf) //This proc is called when the projectile enters a new ship's overmap zlevel.
|
|
if(ammo.burst)
|
|
for(var/i = 1 to ammo.burst)
|
|
var/turf/new_turf = get_random_turf_in_range(entry_turf, ammo.burst + rand(0, ammo.burst), 0, TRUE, FALSE)
|
|
var/obj/projectile/ship_ammo/pellet = new type
|
|
pellet.forceMove(new_turf)
|
|
pellet.ammo = new ammo.type
|
|
pellet.ammo.origin = ammo.origin
|
|
pellet.ammo.impact_type = ammo.impact_type
|
|
pellet.dir = dir
|
|
pellet.preparePixelProjectile(target_turf, new_turf, deviation = 3) //Deviation can be tuned. These spawn at the map edge so small deviations matter a lot.
|
|
pellet.fire()
|