mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-31 09:08:30 +01:00
Adds The Liberator: Doorhickey Corporation's brand new gun (#89495)
## About The Pull Request The Liberator is a brand-new 3D printable gun, holding a single 10mm shot in it's barrel. It has a damage multiplier of x0.5, dealing 20 damage per shot. However, shooting someone point blank gives it an x2 modifier, and shooting someone while holding them at gunpoint adds additional x1.5 multiplier. https://github.com/user-attachments/assets/b27adf1a-5b02-4817-90ad-2ba922cc6bf9 They can be printed for dirt cheap 3 sheets of plastic and 2 sheets of iron from an autolathe. However, as a downside, whenever you're firing a liberator you're risking it blowing up in your hands, potentially wounding you! Reloading is also a bit tricky, since you need to unscrew the barrel before placing the bullet in, and screwing it back on. In order to print them, you'll need to find a (mildly rare) disk in maintenance and upload the design to an autolathe. You also can find a whole gun, albeit at a lower chance. ## Why It's Good For The Game Funny gun that can be used for some gimmicks, not too overpowered but a nifty tool for assistants. Can be countered by a well timed baton, or a shove if your opponent is next to a wall. ## Changelog 🆑 add: Added a new 3D printable gun "The Liberator", you can find the gun itself or its design disc in maintenance tunnels. /🆑
This commit is contained in:
@@ -262,6 +262,7 @@ GLOBAL_LIST_INIT(uncommon_loot, list(//uncommon: useful items
|
||||
/obj/item/computer_disk/maintenance/modsuit_control = 1,
|
||||
/obj/item/computer_disk/maintenance/spectre_meter = 1,
|
||||
/obj/item/computer_disk/maintenance/arcade = 1,
|
||||
/obj/item/disk/design_disk/liberator = 1,
|
||||
/obj/item/computer_disk/maintenance/theme = 3,
|
||||
) = 4,
|
||||
|
||||
@@ -309,6 +310,7 @@ GLOBAL_LIST_INIT(rarity_loot, list(//rare: really good items
|
||||
/obj/item/weldingtool/hugetank = 1,
|
||||
/obj/item/fishing_rod/telescopic/master = 1,
|
||||
/obj/item/spess_knife = 1,
|
||||
/obj/item/gun/ballistic/automatic/pistol/doorhickey = 1,
|
||||
) = 1,
|
||||
|
||||
list(//equipment
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
icon_state = "s-casing"
|
||||
embed_type = null
|
||||
|
||||
/obj/item/shrapnel/plastic
|
||||
name = "plastic shard"
|
||||
custom_materials = list(/datum/material/plastic = SMALL_MATERIAL_AMOUNT * 0.5)
|
||||
icon_state = "titaniummedium"
|
||||
sharpness = SHARP_EDGED
|
||||
embed_type = /datum/embedding/shrapnel
|
||||
|
||||
/obj/projectile/bullet/shrapnel
|
||||
name = "flying shrapnel shard"
|
||||
damage = 14
|
||||
|
||||
@@ -111,3 +111,12 @@
|
||||
price_max = CARGO_CRATE_VALUE * 5
|
||||
stock_max = 1
|
||||
availability_prob = 25
|
||||
|
||||
/datum/market_item/weapon/liberator
|
||||
name = "illegal 3D printer designs"
|
||||
desc = "Designs for a dirt cheap 3D printable gun, well known for exploding in unfortunate assistants' hands."
|
||||
item = /obj/item/disk/design_disk/liberator
|
||||
price_min = CARGO_CRATE_VALUE * 2
|
||||
price_max = CARGO_CRATE_VALUE * 5
|
||||
stock_max = 1
|
||||
availability_prob = 35
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/obj/item/ammo_box/magazine/internal/doorhickey
|
||||
name = "single-shot barrel"
|
||||
ammo_type = /obj/item/ammo_casing/c10mm
|
||||
caliber = CALIBER_10MM
|
||||
max_ammo = 1
|
||||
@@ -198,7 +198,7 @@
|
||||
shake_camera(user, recoil + 1, recoil)
|
||||
fire_sounds()
|
||||
if(suppressed || !message)
|
||||
return
|
||||
return FALSE
|
||||
if(tk_firing(user))
|
||||
visible_message(
|
||||
span_danger("[src] fires itself[pointblank ? " point blank at [pbtarget]!" : "!"]"),
|
||||
@@ -226,6 +226,7 @@
|
||||
|
||||
if(chambered?.integrity_damage)
|
||||
take_damage(chambered.integrity_damage, sound_effect = FALSE)
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/atom_destruction(damage_flag)
|
||||
if(!isliving(loc))
|
||||
@@ -496,10 +497,12 @@
|
||||
else
|
||||
shoot_with_empty_chamber(user)
|
||||
return
|
||||
process_chamber()
|
||||
update_appearance()
|
||||
semicd = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(reset_semicd)), modified_delay)
|
||||
// If gun gets destroyed as a result of firing
|
||||
if (!QDELETED(src))
|
||||
process_chamber()
|
||||
update_appearance()
|
||||
semicd = TRUE
|
||||
addtimer(CALLBACK(src, PROC_REF(reset_semicd)), modified_delay)
|
||||
|
||||
if(user)
|
||||
user.update_held_items()
|
||||
|
||||
@@ -399,58 +399,74 @@
|
||||
/obj/item/gun/ballistic/can_shoot()
|
||||
return chambered?.loaded_projectile
|
||||
|
||||
/obj/item/gun/ballistic/attackby(obj/item/A, mob/user, params)
|
||||
/obj/item/gun/ballistic/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
||||
. = ..()
|
||||
if (.)
|
||||
return
|
||||
if (!internal_magazine && istype(A, /obj/item/ammo_box/magazine))
|
||||
var/obj/item/ammo_box/magazine/AM = A
|
||||
|
||||
if (!internal_magazine && istype(tool, /obj/item/ammo_box/magazine))
|
||||
if (!magazine)
|
||||
insert_magazine(user, AM)
|
||||
else
|
||||
if (tac_reloads)
|
||||
eject_magazine(user, FALSE, AM)
|
||||
else
|
||||
balloon_alert(user, "already loaded!")
|
||||
return
|
||||
if (isammocasing(A) || istype(A, /obj/item/ammo_box))
|
||||
insert_magazine(user, tool)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if (tac_reloads)
|
||||
eject_magazine(user, FALSE, tool)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
balloon_alert(user, "already loaded!")
|
||||
return ITEM_INTERACT_FAILURE
|
||||
|
||||
if (isammocasing(tool) || istype(tool, /obj/item/ammo_box))
|
||||
if (must_hold_to_load && !check_if_held(user))
|
||||
return
|
||||
return NONE
|
||||
|
||||
if (bolt_type == BOLT_TYPE_NO_BOLT || internal_magazine)
|
||||
if (chambered && !chambered.loaded_projectile)
|
||||
chambered.forceMove(drop_location())
|
||||
if(chambered != magazine?.stored_ammo[1])
|
||||
magazine.stored_ammo -= chambered
|
||||
chambered = null
|
||||
var/num_loaded = magazine?.attackby(A, user, params, TRUE)
|
||||
if (num_loaded)
|
||||
balloon_alert(user, "[num_loaded] [cartridge_wording]\s loaded")
|
||||
playsound(src, load_sound, load_sound_volume, load_sound_vary)
|
||||
if (chambered == null && bolt_type == BOLT_TYPE_NO_BOLT)
|
||||
chamber_round()
|
||||
A.update_appearance()
|
||||
update_appearance()
|
||||
return
|
||||
if(istype(A, /obj/item/suppressor))
|
||||
var/obj/item/suppressor/S = A
|
||||
if (load_gun(tool, user))
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
return ITEM_INTERACT_FAILURE
|
||||
|
||||
if(istype(tool, /obj/item/suppressor))
|
||||
if(!can_suppress)
|
||||
balloon_alert(user, "[S.name] doesn't fit!")
|
||||
return
|
||||
balloon_alert(user, "[tool.name] doesn't fit!")
|
||||
return ITEM_INTERACT_FAILURE
|
||||
|
||||
if(!user.is_holding(src))
|
||||
balloon_alert(user, "not in hand!")
|
||||
return
|
||||
return ITEM_INTERACT_FAILURE
|
||||
|
||||
if(suppressed)
|
||||
balloon_alert(user, "already has a supressor!")
|
||||
return
|
||||
if(user.transferItemToLoc(A, src))
|
||||
balloon_alert(user, "[S.name] attached")
|
||||
install_suppressor(A)
|
||||
return
|
||||
if (can_be_sawn_off)
|
||||
if (sawoff(user, A))
|
||||
return
|
||||
return ITEM_INTERACT_FAILURE
|
||||
|
||||
return FALSE
|
||||
if(!user.transferItemToLoc(tool, src))
|
||||
balloon_alert(user, "cannot attach!")
|
||||
return ITEM_INTERACT_FAILURE
|
||||
|
||||
balloon_alert(user, "[tool.name] attached")
|
||||
install_suppressor(tool)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if (can_be_sawn_off && sawoff(user, tool))
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/item/gun/ballistic/proc/load_gun(obj/item/ammo, mob/living/user)
|
||||
if (chambered && !chambered.loaded_projectile)
|
||||
chambered.forceMove(drop_location())
|
||||
if(chambered != magazine?.stored_ammo[1])
|
||||
magazine.stored_ammo -= chambered
|
||||
chambered = null
|
||||
|
||||
var/num_loaded = magazine?.attackby(ammo, user, silent = TRUE)
|
||||
if (!num_loaded)
|
||||
return FALSE
|
||||
|
||||
balloon_alert(user, "[num_loaded] [cartridge_wording]\s loaded")
|
||||
playsound(src, load_sound, load_sound_volume, load_sound_vary)
|
||||
if (chambered == null && bolt_type == BOLT_TYPE_NO_BOLT)
|
||||
chamber_round()
|
||||
ammo.update_appearance()
|
||||
update_appearance()
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/ballistic/proc/check_if_held(mob/user)
|
||||
if(src != user.get_inactive_held_item())
|
||||
@@ -540,20 +556,7 @@
|
||||
eject_magazine(user)
|
||||
return
|
||||
if(bolt_type == BOLT_TYPE_NO_BOLT)
|
||||
var/num_unloaded = 0
|
||||
for(var/obj/item/ammo_casing/casing as anything in get_ammo_list(FALSE))
|
||||
casing.forceMove(drop_location())
|
||||
casing.bounce_away(FALSE, NONE)
|
||||
num_unloaded++
|
||||
var/turf/T = get_turf(drop_location())
|
||||
if(T && is_station_level(T.z))
|
||||
SSblackbox.record_feedback("tally", "station_mess_created", 1, casing.name)
|
||||
if (num_unloaded)
|
||||
balloon_alert(user, "[num_unloaded] [cartridge_wording]\s unloaded")
|
||||
playsound(user, eject_sound, eject_sound_volume, eject_sound_vary)
|
||||
update_appearance()
|
||||
else
|
||||
balloon_alert(user, "it's empty!")
|
||||
unload_ammo(user)
|
||||
return
|
||||
if(bolt_type == BOLT_TYPE_LOCKING && bolt_locked)
|
||||
drop_bolt(user)
|
||||
@@ -564,6 +567,25 @@
|
||||
rack(user)
|
||||
return
|
||||
|
||||
/obj/item/gun/ballistic/proc/unload_ammo(mob/living/user, forced = FALSE)
|
||||
var/num_unloaded = 0
|
||||
var/turf/drop_turf = get_turf(drop_location())
|
||||
for(var/obj/item/ammo_casing/casing as anything in get_ammo_list(FALSE))
|
||||
casing.forceMove(drop_location())
|
||||
casing.bounce_away(FALSE, NONE)
|
||||
num_unloaded++
|
||||
if(drop_turf && is_station_level(drop_turf.z))
|
||||
SSblackbox.record_feedback("tally", "station_mess_created", 1, casing.name)
|
||||
|
||||
if (!num_unloaded)
|
||||
if (!forced)
|
||||
balloon_alert(user, "it's empty!")
|
||||
return
|
||||
|
||||
if (!forced)
|
||||
balloon_alert(user, "[num_unloaded] [cartridge_wording]\s unloaded")
|
||||
playsound(user, eject_sound, eject_sound_volume, eject_sound_vary)
|
||||
update_appearance()
|
||||
|
||||
/obj/item/gun/ballistic/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -212,3 +212,117 @@
|
||||
else
|
||||
to_chat(user, span_notice("..and falls into view. Whew, that was a close one."))
|
||||
user.dropItemToGround(src)
|
||||
|
||||
#define DOORHICKEY_GUN_MIN_DAMAGE 70
|
||||
#define DOORHICKEY_GUN_MAX_DAMAGE 140
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/doorhickey
|
||||
name = "\improper Liberator"
|
||||
desc = "A poorly made 3D printed \"gun\", only capable of firing a single shot. Well-known throughout the Spinward Sector \
|
||||
after an incident where 3 assistants were killed by shrapnel from such a device exploding while attempting to shoot a mouse."
|
||||
icon_state = "doorhickey"
|
||||
custom_materials = list(/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 2)
|
||||
bolt_type = BOLT_TYPE_NO_BOLT
|
||||
internal_magazine = TRUE
|
||||
casing_ejector = FALSE
|
||||
force = 10
|
||||
max_integrity = 100
|
||||
accepted_magazine_type = /obj/item/ammo_box/magazine/internal/doorhickey
|
||||
can_suppress = FALSE
|
||||
semi_auto = FALSE
|
||||
show_bolt_icon = FALSE
|
||||
projectile_damage_multiplier = 0.5
|
||||
spread = 10
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/doorhickey/unload_ammo(mob/living/user, forced = FALSE)
|
||||
if (forced)
|
||||
return ..()
|
||||
|
||||
balloon_alert(user, "unscrewing the barrel...")
|
||||
playsound(user, 'sound/items/tools/screwdriver_operating.ogg', 75, FALSE, MEDIUM_RANGE_SOUND_EXTRARANGE)
|
||||
if (!do_after(user, 2 SECONDS, src))
|
||||
balloon_alert(user, "interrupted!")
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/doorhickey/load_gun(obj/item/ammo, mob/living/user)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return
|
||||
|
||||
balloon_alert(user, "screwing the barrel on...")
|
||||
playsound(user, 'sound/items/tools/screwdriver_operating.ogg', 75, FALSE, MEDIUM_RANGE_SOUND_EXTRARANGE)
|
||||
if (do_after(user, 2 SECONDS, src))
|
||||
return TRUE
|
||||
|
||||
balloon_alert(user, "interrupted!")
|
||||
unload_ammo(user, forced = TRUE)
|
||||
return FALSE
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/doorhickey/fire_gun(atom/target, mob/living/user, flag, params)
|
||||
var/dmg_multiplier = 1
|
||||
|
||||
if (get_dist(target, user) <= 1)
|
||||
dmg_multiplier *= 2
|
||||
|
||||
if (isliving(target))
|
||||
var/mob/living/victim = target
|
||||
var/datum/status_effect/grouped/heldup/gunpoint = victim.has_status_effect(/datum/status_effect/grouped/heldup)
|
||||
if (gunpoint)
|
||||
for (var/datum/weakref/pointer_ref as anything in gunpoint.sources)
|
||||
if (pointer_ref.resolve() == user)
|
||||
dmg_multiplier *= 1.5 // Caps at 60 damage
|
||||
break
|
||||
|
||||
projectile_damage_multiplier *= dmg_multiplier
|
||||
. = ..()
|
||||
projectile_damage_multiplier /= dmg_multiplier
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/doorhickey/shoot_live_shot(mob/living/user, pointblank = FALSE, atom/pbtarget = null, message = TRUE)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return
|
||||
|
||||
var/damage_to_take = rand(DOORHICKEY_GUN_MIN_DAMAGE, DOORHICKEY_GUN_MAX_DAMAGE)
|
||||
if (atom_integrity > damage_to_take)
|
||||
take_damage(damage_to_take)
|
||||
return
|
||||
|
||||
playsound(loc, SFX_SHATTER, 75, TRUE)
|
||||
if (loc != user)
|
||||
take_damage(damage_to_take)
|
||||
return
|
||||
|
||||
var/shrapnel_bomb = FALSE
|
||||
var/obj/item/bodypart/arm/poor_sod = user.get_active_hand()
|
||||
if (prob(damage_to_take - atom_integrity) && poor_sod)
|
||||
shrapnel_bomb = TRUE
|
||||
|
||||
user.visible_message(span_danger("[src] explodes into small pieces[shrapnel_bomb ? ", chunk of it embedding in [user]'s [user.parse_zone_with_bodypart(poor_sod.body_zone)]" : ""]!"),
|
||||
span_userdanger("[src] explodes into small pieces[shrapnel_bomb ? ", chunk of it embedding in your [poor_sod]!" : ""]!"),
|
||||
span_hear("You can hear sound of plastic shattering."))
|
||||
|
||||
if (poor_sod)
|
||||
poor_sod.receive_damage((damage_to_take - atom_integrity) * 0.5, wound_bonus = -10, bare_wound_bonus = 20, sharpness = SHARP_EDGED, damage_source = src)
|
||||
else
|
||||
user.take_bodypart_damage((damage_to_take - atom_integrity) * 0.5, wound_bonus = -10, bare_wound_bonus = 20, sharpness = SHARP_EDGED)
|
||||
|
||||
if (shrapnel_bomb)
|
||||
var/obj/item/shrapnel/plastic/shrapnel = new(user.loc)
|
||||
if (!shrapnel.force_embed(user, poor_sod))
|
||||
qdel(shrapnel)
|
||||
else if(!HAS_TRAIT(user, TRAIT_ANALGESIA))
|
||||
user.emote("scream")
|
||||
|
||||
new /obj/effect/decal/cleanable/plastic(get_turf(src))
|
||||
take_damage(damage_to_take)
|
||||
|
||||
/obj/item/disk/design_disk/liberator
|
||||
name = "illegal 3D printer design disk"
|
||||
|
||||
/obj/item/disk/design_disk/liberator/Initialize(mapload)
|
||||
. = ..()
|
||||
blueprints += new /datum/design/liberator_gun
|
||||
|
||||
#undef DOORHICKEY_GUN_MIN_DAMAGE
|
||||
#undef DOORHICKEY_GUN_MAX_DAMAGE
|
||||
|
||||
@@ -560,6 +560,15 @@
|
||||
build_path = /obj/item/melee/cleric_mace
|
||||
category = list(RND_CATEGORY_IMPORTED)
|
||||
|
||||
/datum/design/liberator_gun
|
||||
name = "The Liberator"
|
||||
desc = "A dirt cheap 3D printed gun. Only holds one bullet, and is infamous for sometimes exploding on it's user."
|
||||
id = "liberator_gun"
|
||||
build_type = AUTOLATHE
|
||||
materials = list(/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 2, /datum/material/iron = SMALL_MATERIAL_AMOUNT * 15)
|
||||
build_path = /obj/item/gun/ballistic/automatic/pistol/doorhickey
|
||||
category = list(RND_CATEGORY_IMPORTED)
|
||||
|
||||
/datum/design/stun_boomerang
|
||||
name = "OZtek Boomerang"
|
||||
desc = "Uses reverse flow gravitodynamics to flip its personal gravity back to the thrower mid-flight. Also functions similar to a stun baton."
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 32 KiB |
@@ -5663,6 +5663,7 @@
|
||||
#include "code\modules\projectiles\boxes_magazines\internal\_internal.dm"
|
||||
#include "code\modules\projectiles\boxes_magazines\internal\grenade.dm"
|
||||
#include "code\modules\projectiles\boxes_magazines\internal\meathook.dm"
|
||||
#include "code\modules\projectiles\boxes_magazines\internal\pistol.dm"
|
||||
#include "code\modules\projectiles\boxes_magazines\internal\revolver.dm"
|
||||
#include "code\modules\projectiles\boxes_magazines\internal\rifle.dm"
|
||||
#include "code\modules\projectiles\boxes_magazines\internal\shotgun.dm"
|
||||
|
||||
Reference in New Issue
Block a user