Files
Bubberstation/code/modules/projectiles/pins.dm
TemporalOroboros 9f598a9662 Makes the explosive compressor and blastcannon actually use the TTVs they're given + the explosion changes to support that. (#58015)
* Adds explosion SFX to the blastcannon and explosive compressor

- Extracts the explosion SFX and screenshake proc from the SSexplosions explosion handling proc and lets the explosive compressor and blastcannon use it.

* Miscellaneous changes

- Adds defines for the internal explosion arglist keys
- Reverses the values of the explosion severity defines
- Changes almost everything that uses `/proc/explosion` to use named arguments

- Removes a whole bunch of argname = 0 in explosion calls.

* Removes named callback arguments.

* Changes the explosion signals to just use the arguments list

Adds a simple framework to let objects respond to explosions occurring inside of them.

Changes a whole bunch of explosions to use the object being exploded as the origin of the explosion rather than the turf the object is on.

Makes the explosive compressor and blastcannon actually use the TTVs they are given.

Adds support for things responding to internal explosions.
Less snowflake code for the explosive compressor and blastcannon calculating bomb range.*
Less confusing explosion severity defines.
Less opaque explosion arguments

*does not guarantee that the solution to letting them actually use the TTV is any less snowflake.
2021-04-26 17:31:25 -07:00

357 lines
14 KiB
Plaintext

/obj/item/firing_pin
name = "electronic firing pin"
desc = "A small authentication device, to be inserted into a firearm receiver to allow operation. NT safety regulations require all new designs to incorporate one."
icon = 'icons/obj/device.dmi'
icon_state = "firing_pin"
inhand_icon_state = "pen"
worn_icon_state = "pen"
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_TINY
attack_verb_continuous = list("pokes")
attack_verb_simple = list("poke")
var/fail_message = "<span class='warning'>INVALID USER.</span>"
var/selfdestruct = FALSE // Explode when user check is failed.
var/force_replace = FALSE // Can forcefully replace other pins.
var/pin_removeable = FALSE // Can be replaced by any pin.
var/obj/item/gun/gun
/obj/item/firing_pin/New(newloc)
..()
if(istype(newloc, /obj/item/gun))
gun = newloc
/obj/item/firing_pin/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(proximity_flag)
if(istype(target, /obj/item/gun))
var/obj/item/gun/G = target
var/obj/item/firing_pin/old_pin = G.pin
if(old_pin && (force_replace || old_pin.pin_removeable))
to_chat(user, "<span class='notice'>You remove [old_pin] from [G].</span>")
if(Adjacent(user))
user.put_in_hands(old_pin)
else
old_pin.forceMove(G.drop_location())
old_pin.gun_remove(user)
if(!G.pin)
if(!user.temporarilyRemoveItemFromInventory(src))
return
gun_insert(user, G)
to_chat(user, "<span class='notice'>You insert [src] into [G].</span>")
else
to_chat(user, "<span class='notice'>This firearm already has a firing pin installed.</span>")
/obj/item/firing_pin/emag_act(mob/user)
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
to_chat(user, "<span class='notice'>You override the authentication mechanism.</span>")
/obj/item/firing_pin/proc/gun_insert(mob/living/user, obj/item/gun/G)
gun = G
forceMove(gun)
gun.pin = src
return
/obj/item/firing_pin/proc/gun_remove(mob/living/user)
gun.pin = null
gun = null
return
/obj/item/firing_pin/proc/pin_auth(mob/living/user)
return TRUE
/obj/item/firing_pin/proc/auth_fail(mob/living/user)
if(user)
user.show_message(fail_message, MSG_VISUAL)
if(selfdestruct)
if(user)
user.show_message("<span class='danger'>SELF-DESTRUCTING...</span><br>", MSG_VISUAL)
to_chat(user, "<span class='userdanger'>[gun] explodes!</span>")
explosion(src, devastation_range = -1, light_impact_range = 2, flash_range = 3)
if(gun)
qdel(gun)
/obj/item/firing_pin/magic
name = "magic crystal shard"
desc = "A small enchanted shard which allows magical weapons to fire."
// Test pin, works only near firing range.
/obj/item/firing_pin/test_range
name = "test-range firing pin"
desc = "This safety firing pin allows weapons to be fired within proximity to a firing range."
fail_message = "<span class='warning'>TEST RANGE CHECK FAILED.</span>"
pin_removeable = TRUE
/obj/item/firing_pin/test_range/pin_auth(mob/living/user)
if(!istype(user))
return FALSE
if (istype(get_area(user), /area/security/range))
return TRUE
return FALSE
// Implant pin, checks for implant
/obj/item/firing_pin/implant
name = "implant-keyed firing pin"
desc = "This is a security firing pin which only authorizes users who are implanted with a certain device."
fail_message = "<span class='warning'>IMPLANT CHECK FAILED.</span>"
var/obj/item/implant/req_implant = null
/obj/item/firing_pin/implant/pin_auth(mob/living/user)
if(user)
for(var/obj/item/implant/I in user.implants)
if(req_implant && I.type == req_implant)
return TRUE
return FALSE
/obj/item/firing_pin/implant/mindshield
name = "mindshield firing pin"
desc = "This Security firing pin authorizes the weapon for only mindshield-implanted users."
icon_state = "firing_pin_loyalty"
req_implant = /obj/item/implant/mindshield
/obj/item/firing_pin/implant/pindicate
name = "syndicate firing pin"
icon_state = "firing_pin_pindi"
req_implant = /obj/item/implant/weapons_auth
// Honk pin, clown's joke item.
// Can replace other pins. Replace a pin in cap's laser for extra fun!
/obj/item/firing_pin/clown
name = "hilarious firing pin"
desc = "Advanced clowntech that can convert any firearm into a far more useful object."
color = "#FFFF00"
fail_message = "<span class='warning'>HONK!</span>"
force_replace = TRUE
/obj/item/firing_pin/clown/pin_auth(mob/living/user)
playsound(src, 'sound/items/bikehorn.ogg', 50, TRUE)
return FALSE
// Ultra-honk pin, clown's deadly joke item.
// A gun with ultra-honk pin is useful for clown and useless for everyone else.
/obj/item/firing_pin/clown/ultra
name = "ultra hilarious firing pin"
/obj/item/firing_pin/clown/ultra/pin_auth(mob/living/user)
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, TRUE)
if(QDELETED(user)) //how the hell...?
stack_trace("/obj/item/firing_pin/clown/ultra/pin_auth called with a [isnull(user) ? "null" : "invalid"] user.")
return TRUE
if(HAS_TRAIT(user, TRAIT_CLUMSY)) //clumsy
return TRUE
if(user.mind)
if(user.mind.assigned_role == "Clown") //traitor clowns can use this, even though they're technically not clumsy
return TRUE
if(user.mind.has_antag_datum(/datum/antagonist/nukeop/clownop)) //clown ops aren't clumsy by default and technically don't have an assigned role of "Clown", but come on, they're basically clowns
return TRUE
if(user.mind.has_antag_datum(/datum/antagonist/nukeop/leader/clownop)) //Wanna hear a funny joke?
return TRUE //The clown op leader antag datum isn't a subtype of the normal clown op antag datum.
return FALSE
/obj/item/firing_pin/clown/ultra/gun_insert(mob/living/user, obj/item/gun/G)
..()
G.clumsy_check = FALSE
/obj/item/firing_pin/clown/ultra/gun_remove(mob/living/user)
gun.clumsy_check = initial(gun.clumsy_check)
..()
// Now two times deadlier!
/obj/item/firing_pin/clown/ultra/selfdestruct
name = "super ultra hilarious firing pin"
desc = "Advanced clowntech that can convert any firearm into a far more useful object. It has a small nitrobananium charge on it."
selfdestruct = TRUE
// DNA-keyed pin.
// When you want to keep your toys for yourself.
/obj/item/firing_pin/dna
name = "DNA-keyed firing pin"
desc = "This is a DNA-locked firing pin which only authorizes one user. Attempt to fire once to DNA-link."
icon_state = "firing_pin_dna"
fail_message = "<span class='warning'>DNA CHECK FAILED.</span>"
var/unique_enzymes = null
/obj/item/firing_pin/dna/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(proximity_flag && iscarbon(target))
var/mob/living/carbon/M = target
if(M.dna && M.dna.unique_enzymes)
unique_enzymes = M.dna.unique_enzymes
to_chat(user, "<span class='notice'>DNA-LOCK SET.</span>")
/obj/item/firing_pin/dna/pin_auth(mob/living/carbon/user)
if(user && user.dna && user.dna.unique_enzymes)
if(user.dna.unique_enzymes == unique_enzymes)
return TRUE
return FALSE
/obj/item/firing_pin/dna/auth_fail(mob/living/carbon/user)
if(!unique_enzymes)
if(user && user.dna && user.dna.unique_enzymes)
unique_enzymes = user.dna.unique_enzymes
to_chat(user, "<span class='notice'>DNA-LOCK SET.</span>")
else
..()
/obj/item/firing_pin/dna/dredd
desc = "This is a DNA-locked firing pin which only authorizes one user. Attempt to fire once to DNA-link. It has a small explosive charge on it."
selfdestruct = TRUE
// Paywall pin, brought to you by ARMA 3 DLC.
// Checks if the user has a valid bank account on an ID and if so attempts to extract a one-time payment to authorize use of the gun. Otherwise fails to shoot.
/obj/item/firing_pin/paywall
name = "paywall firing pin"
desc = "A firing pin with a built-in configurable paywall."
color = "#FFD700"
fail_message = ""
var/list/gun_owners = list() //list of people who've accepted the license prompt. If this is the multi-payment pin, then this means they accepted the waiver that each shot will cost them money
var/payment_amount //how much gets paid out to license yourself to the gun
var/obj/item/card/id/pin_owner
var/multi_payment = FALSE //if true, user has to pay everytime they fire the gun
var/owned = FALSE
var/active_prompt = FALSE //purchase prompt to prevent spamming it
/obj/item/firing_pin/paywall/attack_self(mob/user)
multi_payment = !multi_payment
to_chat(user, "<span class='notice'>You set the pin to [( multi_payment ) ? "process payment for every shot" : "one-time license payment"].</span>")
/obj/item/firing_pin/paywall/examine(mob/user)
. = ..()
if(pin_owner)
. += "<span class='notice'>This firing pin is currently authorized to pay into the account of [pin_owner.registered_name].</span>"
/obj/item/firing_pin/paywall/gun_insert(mob/living/user, obj/item/gun/G)
if(!pin_owner)
to_chat(user, "<span class='warning'>ERROR: Please swipe valid identification card before installing firing pin!</span>")
return
gun = G
forceMove(gun)
gun.pin = src
if(multi_payment)
gun.desc += "<span class='notice'> This [gun.name] has a per-shot cost of [payment_amount] credit[( payment_amount > 1 ) ? "s" : ""].</span>"
return
gun.desc += "<span class='notice'> This [gun.name] has a license permit cost of [payment_amount] credit[( payment_amount > 1 ) ? "s" : ""].</span>"
return
/obj/item/firing_pin/paywall/gun_remove(mob/living/user)
gun.desc = initial(desc)
..()
/obj/item/firing_pin/paywall/attackby(obj/item/M, mob/user, params)
if(istype(M, /obj/item/card/id))
var/obj/item/card/id/id = M
if(!id.registered_account)
to_chat(user, "<span class='warning'>ERROR: Identification card lacks registered bank account!</span>")
return
if(id != pin_owner && owned)
to_chat(user, "<span class='warning'>ERROR: This firing pin has already been authorized!</span>")
return
if(id == pin_owner)
to_chat(user, "<span class='notice'>You unlink the card from the firing pin.</span>")
gun_owners -= user
pin_owner = null
owned = FALSE
return
var/transaction_amount = input(user, "Insert valid deposit amount for gun purchase", "Money Deposit") as null|num
if(transaction_amount < 1)
to_chat(user, "<span class='warning'>ERROR: Invalid amount designated.</span>")
return
if(!transaction_amount)
return
pin_owner = id
owned = TRUE
payment_amount = transaction_amount
gun_owners += user
to_chat(user, "<span class='notice'>You link the card to the firing pin.</span>")
/obj/item/firing_pin/paywall/pin_auth(mob/living/user)
if(!istype(user))//nice try commie
return FALSE
var/datum/bank_account/credit_card_details = user.get_bank_account()
if(user in gun_owners)
if(multi_payment && credit_card_details)
if(credit_card_details.adjust_money(-payment_amount))
pin_owner.registered_account.adjust_money(payment_amount)
return TRUE
to_chat(user, "<span class='warning'>ERROR: User balance insufficent for successful transaction!</span>")
return FALSE
return TRUE
if(credit_card_details && !active_prompt)
var/license_request = alert(user, "Do you wish to pay [payment_amount] credit[( payment_amount > 1 ) ? "s" : ""] for [( multi_payment ) ? "each shot of [gun.name]" : "usage license of [gun.name]"]?", "Weapon Purchase", "Yes", "No")
active_prompt = TRUE
if(!user.canUseTopic(src, BE_CLOSE))
active_prompt = FALSE
return FALSE
switch(license_request)
if("Yes")
if(credit_card_details.adjust_money(-payment_amount))
pin_owner.registered_account.adjust_money(payment_amount)
gun_owners += user
to_chat(user, "<span class='notice'>Gun license purchased, have a secure day!</span>")
active_prompt = FALSE
return FALSE //we return false here so you don't click initially to fire, get the prompt, accept the prompt, and THEN the gun
to_chat(user, "<span class='warning'>ERROR: User balance insufficent for successful transaction!</span>")
return FALSE
if("No")
to_chat(user, "<span class='warning'>ERROR: User has declined to purchase gun license!</span>")
return FALSE
to_chat(user, "<span class='warning'>ERROR: User has no valid bank account to substract neccesary funds from!</span>")
return FALSE
// Explorer Firing Pin- Prevents use on station Z-Level, so it's justifiable to give Explorers guns that don't suck.
/obj/item/firing_pin/explorer
name = "outback firing pin"
desc = "A firing pin used by the austrailian defense force, retrofit to prevent weapon discharge on the station."
icon_state = "firing_pin_explorer"
fail_message = "<span class='warning'>CANNOT FIRE WHILE ON STATION, MATE!</span>"
// This checks that the user isn't on the station Z-level.
/obj/item/firing_pin/explorer/pin_auth(mob/living/user)
var/turf/station_check = get_turf(user)
if(!station_check||is_station_level(station_check.z))
to_chat(user, "<span class='warning'>You cannot use your weapon while on the station!</span>")
return FALSE
return TRUE
// Laser tag pins
/obj/item/firing_pin/tag
name = "laser tag firing pin"
desc = "A recreational firing pin, used in laser tag units to ensure users have their vests on."
fail_message = "<span class='warning'>SUIT CHECK FAILED.</span>"
var/obj/item/clothing/suit/suit_requirement = null
var/tagcolor = ""
/obj/item/firing_pin/tag/pin_auth(mob/living/user)
if(ishuman(user))
var/mob/living/carbon/human/M = user
if(istype(M.wear_suit, suit_requirement))
return TRUE
to_chat(user, "<span class='warning'>You need to be wearing [tagcolor] laser tag armor!</span>")
return FALSE
/obj/item/firing_pin/tag/red
name = "red laser tag firing pin"
icon_state = "firing_pin_red"
suit_requirement = /obj/item/clothing/suit/redtag
tagcolor = "red"
/obj/item/firing_pin/tag/blue
name = "blue laser tag firing pin"
icon_state = "firing_pin_blue"
suit_requirement = /obj/item/clothing/suit/bluetag
tagcolor = "blue"
/obj/item/firing_pin/Destroy()
if(gun)
gun.pin = null
return ..()