Cleans up + Improves bows, Sorts files, Adds the Divine Archer clothing, weapon, rite (#74811)

## About The Pull Request

### Divine Archer 🏹 


![image](https://user-images.githubusercontent.com/40974010/232647927-aace69ea-bda8-4ec9-9bf1-60140034fbb3.png)

Adds a new chaplain weapon and suit of armor, the divine archer. It's an
orderable set of armor, but provides less armor than the rest, but you
get more pieces of armor (boots, bracer, undersuit).

The divine bow comes with a quiver that holds holy arrows. The holy
arrows come with bane support, dealing critical damage to revenants.

### Bow Features  

- arrows can now be dipped in poison

### Bow Improvements 🔧 

- bows now drop their arrow when you put them on your back while nocking
a bow
- bows give feedback for trying to draw without a nocked arrow
- codewise, bows support subtypes much better. They still have
hard-sprited loaded arrows, but one day that'll change.

## Why It's Good For The Game

Yeah, we could add null rod #2342 that does almost the same as the
others, or we could have a unique bow weapon!

Player Dev Project thread:
https://discord.com/channels/326822144233439242/1093521091957370940/1093521091957370940

## Changelog
🆑 tralezab code, Drag for the commission and player project, cre#0484
for their spritework
add: Divine Archer Armor and Weapon
qol: Bows give more feedback when you're doing something wrong, like
trying to draw without a nocked arrow
code: Sorted files, cleaned bow code up to allow subtypes
/🆑
This commit is contained in:
tralezab
2023-04-29 02:07:44 +00:00
committed by GitHub
parent e5cf268dd5
commit bc813ab93d
57 changed files with 678 additions and 293 deletions
@@ -1,10 +1,11 @@
/obj/item/gun/ballistic/bow
name = "longbow"
desc = "While pretty finely crafted, surely you can find something better to use in the current year."
icon = 'icons/obj/weapons/guns/ballistic.dmi'
icon = 'icons/obj/weapons/guns/bows/bows.dmi'
lefthand_file = 'icons/mob/inhands/weapons/bows_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/bows_righthand.dmi'
icon_state = "bow"
inhand_icon_state = "bow"
base_icon_state = "bow"
load_sound = null
fire_sound = null
mag_type = /obj/item/ammo_box/magazine/internal/bow
@@ -16,11 +17,12 @@
internal_magazine = TRUE
cartridge_wording = "arrow"
bolt_type = BOLT_TYPE_NO_BOLT
/// whether the bow is drawn back
var/drawn = FALSE
/obj/item/gun/ballistic/bow/update_icon_state()
. = ..()
icon_state = chambered ? "bow_[drawn]" : "bow"
icon_state = chambered ? "[base_icon_state]_[drawn ? "drawn" : "nocked"]" : "[base_icon_state]"
/obj/item/gun/ballistic/bow/proc/drop_arrow()
drawn = FALSE
@@ -38,7 +40,9 @@
chambered.forceMove(src)
/obj/item/gun/ballistic/bow/attack_self(mob/user)
if(chambered)
if(!chambered)
balloon_alert(user, "no arrow nocked!")
else
balloon_alert(user, "[drawn ? "string released" : "string drawn"]")
drawn = !drawn
update_appearance()
@@ -56,8 +60,16 @@
. = ..() //fires, removing the arrow
update_appearance()
/obj/item/gun/ballistic/bow/equipped(mob/user, slot, initial)
. = ..()
if(slot == ITEM_SLOT_BACK && chambered)
balloon_alert(user, "the arrow falls out!")
drop_arrow()
drawn = FALSE
update_appearance()
/obj/item/gun/ballistic/bow/shoot_with_empty_chamber(mob/living/user)
return //so clicking sounds please
return //no clicking sounds please
/obj/item/ammo_box/magazine/internal/bow
name = "bowstring"
@@ -65,58 +77,3 @@
max_ammo = 1
start_empty = TRUE
caliber = CALIBER_ARROW
/obj/item/ammo_casing/caseless/arrow
name = "arrow"
desc = "Stabby Stabman!"
icon_state = "arrow"
inhand_icon_state = "arrow"
flags_1 = NONE
throwforce = 1
projectile_type = /obj/projectile/bullet/reusable/arrow
firing_effect_type = null
caliber = CALIBER_ARROW
heavy_metal = FALSE
/obj/item/ammo_casing/caseless/arrow/despawning/dropped()
. = ..()
addtimer(CALLBACK(src, PROC_REF(floor_vanish)), 5 SECONDS)
/obj/item/ammo_casing/caseless/arrow/despawning/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/obj/projectile/bullet/reusable/arrow
name = "arrow"
desc = "Ow! Get it out of me!"
ammo_type = /obj/item/ammo_casing/caseless/arrow
damage = 50
speed = 1
range = 25
/obj/item/storage/bag/quiver
name = "quiver"
desc = "Holds arrows for your bow. Good, because while pocketing arrows is possible, it surely can't be pleasant."
icon_state = "quiver"
inhand_icon_state = null
worn_icon_state = "harpoon_quiver"
var/arrow_path = /obj/item/ammo_casing/caseless/arrow
/obj/item/storage/bag/quiver/Initialize(mapload)
. = ..()
atom_storage.max_specific_storage = WEIGHT_CLASS_TINY
atom_storage.max_slots = 40
atom_storage.max_total_storage = 100
atom_storage.set_holdable(list(
/obj/item/ammo_casing/caseless/arrow
))
/obj/item/storage/bag/quiver/PopulateContents()
. = ..()
for(var/i in 1 to 10)
new arrow_path(src)
/obj/item/storage/bag/quiver/despawning
arrow_path = /obj/item/ammo_casing/caseless/arrow/despawning
@@ -0,0 +1,94 @@
///base arrow
/obj/item/ammo_casing/caseless/arrow
name = "arrow"
desc = "Stabby Stabman!"
icon = 'icons/obj/weapons/guns/bows/arrows.dmi'
icon_state = "arrow"
inhand_icon_state = "arrow"
projectile_type = /obj/projectile/bullet/reusable/arrow
flags_1 = NONE
throwforce = 1
firing_effect_type = null
caliber = CALIBER_ARROW
heavy_metal = FALSE
/obj/item/ammo_casing/caseless/arrow/Initialize(mapload)
. = ..()
AddComponent(/datum/element/envenomable_casing)
///base arrow projectile
/obj/projectile/bullet/reusable/arrow
name = "arrow"
desc = "Ow! Get it out of me!"
icon = 'icons/obj/weapons/guns/bows/arrows.dmi'
icon_state = "arrow_projectile"
ammo_type = /obj/item/ammo_casing/caseless/arrow
damage = 50
speed = 1
range = 25
///*sigh* NON-REUSABLE base arrow projectile. In the future: let's componentize the reusable subtype, jesus
/obj/projectile/bullet/arrow
name = "arrow"
desc = "Ow! Get it out of me!"
icon = 'icons/obj/weapons/guns/bows/arrows.dmi'
icon_state = "arrow_projectile"
damage = 50
speed = 1
range = 25
/// despawning arrow type
/obj/item/ammo_casing/caseless/arrow/despawning/dropped()
. = ..()
addtimer(CALLBACK(src, PROC_REF(floor_vanish)), 5 SECONDS)
/obj/item/ammo_casing/caseless/arrow/despawning/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/// holy arrows
/obj/item/ammo_casing/caseless/arrow/holy
name = "holy arrow"
desc = "A holy diver seeking its target."
icon_state = "holy_arrow"
inhand_icon_state = "holy_arrow"
projectile_type = /obj/projectile/bullet/reusable/arrow/holy
/// holy arrow projectile
/obj/projectile/bullet/reusable/arrow/holy
name = "holy arrow"
desc = "Here it comes, cultist scum!"
icon_state = "holy_arrow_projectile"
ammo_type = /obj/item/ammo_casing/caseless/arrow/holy
damage = 20 //still a lot but this is roundstart gear so far less
/obj/projectile/bullet/reusable/arrow/holy/Initialize(mapload)
. = ..()
//50 damage to revenants
AddElement(/datum/element/bane, target_type = /mob/living/simple_animal/revenant, damage_multiplier = 0, added_damage = 30)
/// special pyre sect arrow
/// in the future, this needs a special sprite, but bows don't support non-hardcoded arrow sprites
/obj/item/ammo_casing/caseless/arrow/holy/blazing
name = "blazing star arrow"
desc = "A holy diver seeking its target, blessed with fire. Will ignite on hit, destroying the arrow. But if you hit an already ignited target...?"
projectile_type = /obj/projectile/bullet/arrow/blazing
/obj/projectile/bullet/arrow/blazing
name = "blazing arrow"
desc = "THE UNMATCHED POWER OF THE SUN"
icon_state = "holy_arrow_projectile"
damage = 20
/obj/projectile/bullet/arrow/blazing/on_hit(atom/target, blocked, pierce_hit)
. = ..()
if(!ishuman(target))
return
var/mob/living/carbon/human/human_target = target
if(!human_target.on_fire)
to_chat(human_target, span_danger("[src] explodes into flames which quickly envelop you!"))
human_target.adjust_fire_stacks(2)
human_target.ignite_mob()
return
to_chat(human_target, span_danger("[src] reacts with the flames on y-"))
explosion(src, light_impact_range = 1, flame_range = 2) //ow
@@ -0,0 +1,35 @@
/obj/item/storage/bag/quiver
name = "quiver"
desc = "Holds arrows for your bow. Good, because while pocketing arrows is possible, it surely can't be pleasant."
icon = 'icons/obj/weapons/guns/bows/quivers.dmi'
icon_state = "quiver"
inhand_icon_state = null
worn_icon_state = "harpoon_quiver"
/// type of arrow the quivel should hold
var/arrow_path = /obj/item/ammo_casing/caseless/arrow
/obj/item/storage/bag/quiver/Initialize(mapload)
. = ..()
atom_storage.max_specific_storage = WEIGHT_CLASS_TINY
atom_storage.max_slots = 40
atom_storage.max_total_storage = 100
atom_storage.set_holdable(list(
/obj/item/ammo_casing/caseless/arrow,
))
/obj/item/storage/bag/quiver/PopulateContents()
. = ..()
for(var/i in 1 to 10)
new arrow_path(src)
/obj/item/storage/bag/quiver/despawning
arrow_path = /obj/item/ammo_casing/caseless/arrow/despawning
/obj/item/storage/bag/quiver/holy
name = "divine quiver"
desc = "Holds arrows for your divine bow, where they wait to find their target."
icon_state = "holyquiver"
inhand_icon_state = "holyquiver"
worn_icon_state = "holyquiver"
arrow_path = /obj/item/ammo_casing/caseless/arrow/holy
@@ -0,0 +1,47 @@
///basic bow, used for medieval sim
/obj/item/gun/ballistic/bow/longbow
name = "longbow"
desc = "While pretty finely crafted, surely you can find something better to use in the current year."
///chaplain's divine archer bow
/obj/item/gun/ballistic/bow/divine
name = "divine bow"
desc = "Holy armament to pierce the souls of sinners."
icon_state = "holybow"
inhand_icon_state = "holybow"
base_icon_state = "holybow"
worn_icon_state = "holybow"
slot_flags = ITEM_SLOT_BACK
mag_type = /obj/item/ammo_box/magazine/internal/bow/holy
/obj/item/ammo_box/magazine/internal/bow/holy
name = "divine bowstring"
ammo_type = /obj/item/ammo_casing/caseless/arrow/holy
/obj/item/gun/ballistic/bow/divine/Initialize(mapload)
. = ..()
AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE|MAGIC_RESISTANCE_HOLY)
AddComponent(/datum/component/effect_remover, \
success_feedback = "You disrupt the magic of %THEEFFECT with %THEWEAPON.", \
success_forcesay = "BOW-GONE FOUL MAGIKS!!", \
tip_text = "Clear rune", \
on_clear_callback = CALLBACK(src, PROC_REF(on_cult_rune_removed)), \
effects_we_clear = list(/obj/effect/rune, /obj/effect/heretic_rune) \
)
AddElement(/datum/element/bane, target_type = /mob/living/simple_animal/revenant, damage_multiplier = 0, added_damage = 25, requires_combat_mode = FALSE)
/obj/item/gun/ballistic/bow/divine/proc/on_cult_rune_removed(obj/effect/target, mob/living/user)
SIGNAL_HANDLER
if(!istype(target, /obj/effect/rune))
return
var/obj/effect/rune/target_rune = target
if(target_rune.log_when_erased)
user.log_message("erased [target_rune.cultist_name] rune using a null rod", LOG_GAME)
message_admins("[ADMIN_LOOKUPFLW(user)] erased a [target_rune.cultist_name] rune with a null rod.")
SSshuttle.shuttle_purchase_requirements_met[SHUTTLE_UNLOCK_NARNAR] = TRUE
/obj/item/gun/ballistic/bow/divine/with_quiver/Initialize(mapload)
. = ..()
new /obj/item/storage/bag/quiver/holy(loc)
+2 -2
View File
@@ -242,14 +242,14 @@
* pierce_hit - are we piercing through or regular hitting
*/
/obj/projectile/proc/on_hit(atom/target, blocked = FALSE, pierce_hit)
if(fired_from)
SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle)
// i know that this is probably more with wands and gun mods in mind, but it's a bit silly that the projectile on_hit signal doesn't ping the projectile itself.
// maybe we care what the projectile thinks! See about combining these via args some time when it's not 5AM
var/obj/item/bodypart/hit_limb
if(isliving(target))
var/mob/living/L = target
hit_limb = L.check_limb_hit(def_zone)
if(fired_from)
SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb)
SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb)
if(QDELETED(src)) // in case one of the above signals deleted the projectile for whatever reason