mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-23 05:47:13 +01:00
213 lines
6.1 KiB
Plaintext
213 lines
6.1 KiB
Plaintext
/**
|
|
* Ammo system.
|
|
*
|
|
* TODO: indirect projectile_effects_add to projectile_effects list on `/datum/prototype/ammo_shell`
|
|
* for serialization.
|
|
*/
|
|
/obj/item/ammo_casing
|
|
name = "bullet casing"
|
|
desc = "A bullet casing."
|
|
icon = 'icons/modules/projectiles/casings/slim.dmi'
|
|
icon_state = "small"
|
|
slot_flags = SLOT_BELT | SLOT_EARS
|
|
item_flags = ITEM_EASY_LATHE_DECONSTRUCT | ITEM_ENCUMBERS_WHILE_HELD
|
|
throw_force = 1
|
|
w_class = WEIGHT_CLASS_TINY
|
|
drop_sound = 'sound/items/drop/ring.ogg'
|
|
pickup_sound = 'sound/items/pickup/ring.ogg'
|
|
belt_storage_class = BELT_CLASS_SMALL
|
|
belt_storage_size = BELT_SIZE_FOR_AMMO_CASING
|
|
weight_volume = ITEM_VOLUME_AMMO_CASING
|
|
|
|
//* Casing *//
|
|
/// casing flags - see __DEFINES/projectiles/ammo_casing.dm
|
|
var/casing_flags = NONE
|
|
/// what types of primer we react to
|
|
var/casing_primer = CASING_PRIMER_CHEMICAL
|
|
/// caliber - set to typepath of datum for compile checking
|
|
///
|
|
/// todo: rename to casing_caliber?
|
|
///
|
|
/// * may be typepath of caliber (recommended)
|
|
/// * may be instance of caliber (not recommended, but allowable for special cases)
|
|
/// * may NOT be string of caliber, currently
|
|
var/casing_caliber
|
|
/// Effective mass multiplier.
|
|
///
|
|
/// * This is used to calculate energy draw for magnetic weapons.
|
|
/// * Set this as a multiple of a parent type's multiplier.
|
|
var/casing_effective_mass_multiplier = 1
|
|
|
|
//* Projectile *//
|
|
/// projectile type
|
|
var/projectile_type
|
|
/// stored projectile - either null for un-init'd, FALSE for empty, or an instance
|
|
VAR_PROTECTED/obj/projectile/projectile_stored
|
|
/// passed to bullet in fire()
|
|
var/list/projectile_effects_add
|
|
|
|
//* Icon *//
|
|
/// switch to "[initial(state)]-spent" after expenditure
|
|
var/icon_spent = TRUE
|
|
|
|
//! unsorted / legacy
|
|
var/leaves_residue = 1
|
|
var/fall_sounds = list('sound/weapons/guns/casingfall1.ogg','sound/weapons/guns/casingfall2.ogg','sound/weapons/guns/casingfall3.ogg')
|
|
|
|
/obj/item/ammo_casing/Initialize(mapload)
|
|
. = ..()
|
|
// let's like, not randomize icon state when we're not somewhere relevant, shall we?
|
|
if(isturf(loc) || istype(loc, /obj/structure/closet))
|
|
pixel_x = rand(-10, 10)
|
|
pixel_y = rand(-10, 10)
|
|
|
|
/obj/item/ammo_casing/Destroy()
|
|
if(projectile_stored)
|
|
QDEL_NULL(projectile_stored)
|
|
return ..()
|
|
|
|
/obj/item/ammo_casing/get_intrinsic_worth(flags)
|
|
return is_loaded()? ..() : 0
|
|
|
|
/obj/item/ammo_casing/screwdriver_act(obj/item/I, datum/event_args/actor/clickchain/e_args, flags, hint)
|
|
. = TRUE
|
|
if(projectile_stored == FALSE)
|
|
e_args.chat_feedback(SPAN_WARNING("There is no bullet in [src] to inscribe."), src)
|
|
return
|
|
var/label_text = input(e_args.initiator, "Inscribe some text into [initial(projectile_stored.name)]", "Inscription", projectile_stored.name)
|
|
if(!e_args.performer.Adjacent(src))
|
|
return
|
|
label_text = sanitize(label_text, MAX_NAME_LEN, extra = FALSE)
|
|
get_projectile()
|
|
if(!projectile_stored)
|
|
CRASH("projectile stored isn't instanced when it shoudl be")
|
|
if(!label_text)
|
|
e_args.chat_feedback(SPAN_NOTICE("You scratch the inscription off of [initial(projectile_stored.name)]."), src)
|
|
projectile_stored.name = initial(projectile_stored.name)
|
|
return
|
|
e_args.chat_feedback(SPAN_NOTICE("You inscribe [label_text] into \the [initial(projectile_stored.name)]."), src)
|
|
projectile_stored.name = "[initial(projectile_stored.name)] (\"[label_text]\")"
|
|
|
|
/obj/item/ammo_casing/dynamic_tool_query(obj/item/I, datum/event_args/actor/clickchain/e_args, list/hint_images = list())
|
|
. = list(
|
|
TOOL_SCREWDRIVER = list(
|
|
"etch"
|
|
)
|
|
)
|
|
return merge_double_lazy_assoc_list(., ..())
|
|
|
|
/obj/item/ammo_casing/update_icon_state()
|
|
. = ..()
|
|
if(icon_spent && !is_loaded())
|
|
icon_state = "[base_icon_state || initial(icon_state)]-spent"
|
|
else
|
|
icon_state = base_icon_state || icon_state
|
|
|
|
/obj/item/ammo_casing/examine(mob/user, dist)
|
|
. = ..()
|
|
if(!is_loaded())
|
|
. += "This one is spent."
|
|
|
|
/obj/item/ammo_casing/attackby(obj/item/I, mob/living/user, list/params, clickchain_flags, damage_multiplier)
|
|
if(istype(I, /obj/item/ammo_magazine))
|
|
var/obj/item/ammo_magazine/mag = I
|
|
mag.quick_gather(get_turf(src), user)
|
|
return CLICKCHAIN_DID_SOMETHING | CLICKCHAIN_DO_NOT_PROPAGATE
|
|
return ..()
|
|
|
|
/obj/item/ammo_casing/throw_land(atom/A, datum/thrownthing/TT)
|
|
. = ..()
|
|
play_drop_sound()
|
|
|
|
//* Caliber *//
|
|
|
|
/obj/item/ammo_casing/proc/get_caliber_string()
|
|
return resolve_caliber(casing_caliber)?.caliber
|
|
|
|
/obj/item/ammo_casing/proc/get_caliber()
|
|
RETURN_TYPE(/datum/ammo_caliber)
|
|
return resolve_caliber(casing_caliber)
|
|
|
|
//* Firing *//
|
|
|
|
/**
|
|
* Called as we're fired.
|
|
*
|
|
* @params
|
|
* * priming_methods - the priming methods being used to fire us
|
|
*
|
|
* @return /obj/projectile to shoot, or a GUN_FIRED_* fail status
|
|
*/
|
|
/obj/item/ammo_casing/proc/process_fire(priming_methods)
|
|
if(!(priming_methods & casing_primer))
|
|
return GUN_FIRED_FAIL_INERT
|
|
. = expend()
|
|
if(!.)
|
|
return GUN_FIRED_FAIL_EMPTY
|
|
|
|
/**
|
|
* Uses the ammo casing, returning the projectile retrieved, updating icon, etc
|
|
*/
|
|
/obj/item/ammo_casing/proc/expend()
|
|
if(isnull(projectile_stored))
|
|
init_projectile()
|
|
. = projectile_stored
|
|
projectile_stored = FALSE
|
|
if(isnull(.))
|
|
return
|
|
projectile_stored = FALSE
|
|
setDir(pick(GLOB.cardinal)) //spin spent casings
|
|
update_icon()
|
|
|
|
/**
|
|
* Play sound when dropped
|
|
*/
|
|
/obj/item/ammo_casing/proc/play_drop_sound()
|
|
playsound(src, pick(fall_sounds), 50, TRUE)
|
|
|
|
//* Getters *//
|
|
|
|
/**
|
|
* sees if we're currently loaded
|
|
*/
|
|
/obj/item/ammo_casing/proc/is_loaded()
|
|
return projectile_stored != FALSE
|
|
|
|
/**
|
|
* grab projectile, initializing it if needed
|
|
*/
|
|
/obj/item/ammo_casing/proc/get_projectile()
|
|
switch(projectile_stored)
|
|
if(null)
|
|
return init_projectile()
|
|
if(FALSE)
|
|
return null
|
|
return projectile_stored
|
|
|
|
//* Projectile *//
|
|
|
|
/**
|
|
* makes a new projectile
|
|
*/
|
|
/obj/item/ammo_casing/proc/init_projectile()
|
|
if(istype(projectile_stored))
|
|
CRASH("double init?")
|
|
projectile_stored = new projectile_type(src)
|
|
projectile_stored.add_projectile_effects(projectile_effects_add)
|
|
return projectile_stored
|
|
|
|
//* Render *//
|
|
|
|
/**
|
|
* makes us look messier, basically
|
|
*/
|
|
/obj/item/ammo_casing/proc/randomize_offsets_after_eject()
|
|
pixel_x = rand(-8, 8)
|
|
pixel_y = rand(-8, 8)
|
|
|
|
//* Generic - Spent Subtype *//
|
|
|
|
/obj/item/ammo_casing/spent
|
|
icon_state = /obj/item/ammo_casing::icon_state + "-spent"
|
|
projectile_stored = FALSE
|