diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index c1fb05bfd6a..486ae93e3f7 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -80,3 +80,6 @@ /// Global signal called after the station changes its name. /// (new_name, old_name) #define COMSIG_GLOB_STATION_NAME_CHANGED "!station_name_changed" + +/// global signal when a global nullrod type is picked +#define COMSIG_GLOB_NULLROD_PICKED "!nullrod_picked" diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index bddf68d1008..9f6d20023f5 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -321,9 +321,9 @@ // /obj/projectile signals (sent to the firer) -///from base of /obj/projectile/proc/on_hit(), like COMSIG_PROJECTILE_ON_HIT but on the projectile itself and with the hit limb (if any): (atom/movable/firer, atom/target, Angle, hit_limb) +///from base of /obj/projectile/proc/on_hit(), like COMSIG_PROJECTILE_ON_HIT but on the projectile itself and with the hit limb (if any): (atom/movable/firer, atom/target, angle, hit_limb) #define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" -///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle) +///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, angle, hit_limb) #define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" ///from base of /obj/projectile/proc/fire(): (obj/projectile, atom/original_target) #define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" diff --git a/code/datums/components/on_hit_effect.dm b/code/datums/components/on_hit_effect.dm new file mode 100644 index 00000000000..32496ccc44b --- /dev/null +++ b/code/datums/components/on_hit_effect.dm @@ -0,0 +1,76 @@ +/** + * ## On Hit Effect Component! + * + * Component for other elements/components to rely on for on-hit effects without duplicating the on-hit code. + * See Lifesteal, or bane for examples. + * + * THIS COULD EASILY SUPPORT COMPONENT_DUPE_ALLOWED but the getcomponent makes it throw errors. if you can figure that out feel free to readd the dupe types + */ +/datum/component/on_hit_effect + ///callback used by other components to apply effects + var/datum/callback/on_hit_callback + ///callback optionally used for more checks + var/datum/callback/extra_check_callback + +/datum/component/on_hit_effect/Initialize(on_hit_callback, extra_check_callback) + src.on_hit_callback = on_hit_callback + src.extra_check_callback = extra_check_callback + if(!(ismachinery(parent) || isstructure(parent) || isgun(parent) || isprojectilespell(parent) || isitem(parent) || isanimal_or_basicmob(parent) || isprojectile(parent))) + return ELEMENT_INCOMPATIBLE + +/datum/component/on_hit_effect/RegisterWithParent() + if(ismachinery(parent) || isstructure(parent) || isgun(parent) || isprojectilespell(parent)) + RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, PROC_REF(on_projectile_hit)) + else if(isitem(parent)) + RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, PROC_REF(item_afterattack)) + else if(isanimal_or_basicmob(parent)) + RegisterSignal(parent, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(hostile_attackingtarget)) + else if(isprojectile(parent)) + RegisterSignal(parent, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_projectile_self_hit)) + +/datum/component/on_hit_effect/UnregisterFromParent() + UnregisterSignal(parent, list( + COMSIG_PROJECTILE_ON_HIT, + COMSIG_ITEM_AFTERATTACK, + COMSIG_HOSTILE_POST_ATTACKINGTARGET, + COMSIG_PROJECTILE_SELF_ON_HIT, + )) + +/datum/component/on_hit_effect/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters) + SIGNAL_HANDLER + + if(!proximity_flag) + return + + if(extra_check_callback) + if(!extra_check_callback.Invoke(user, target)) + return + on_hit_callback.Invoke(source, user, target, user.zone_selected) + return COMPONENT_AFTERATTACK_PROCESSED_ITEM + +/datum/component/on_hit_effect/proc/hostile_attackingtarget(mob/living/attacker, atom/target, success) + SIGNAL_HANDLER + + if(!success) + return + + if(extra_check_callback) + if(!extra_check_callback.Invoke(attacker, target)) + return + on_hit_callback.Invoke(attacker, attacker, target, attacker.zone_selected) + +/datum/component/on_hit_effect/proc/on_projectile_hit(datum/fired_from, atom/movable/firer, atom/target, angle, obj/item/bodypart/hit_limb) + SIGNAL_HANDLER + + if(extra_check_callback) + if(!extra_check_callback.Invoke(firer, target)) + return + on_hit_callback.Invoke(fired_from, firer, target, hit_limb.body_zone) + +/datum/component/on_hit_effect/proc/on_projectile_self_hit(datum/source, mob/firer, atom/target, angle, obj/item/bodypart/hit_limb) + SIGNAL_HANDLER + + if(extra_check_callback) + if(!extra_check_callback.Invoke(firer, target)) + return + on_hit_callback.Invoke(source, firer, target, hit_limb.body_zone) diff --git a/code/datums/components/religious_tool.dm b/code/datums/components/religious_tool.dm index d5eb30a69ed..0aedee328ea 100644 --- a/code/datums/components/religious_tool.dm +++ b/code/datums/components/religious_tool.dm @@ -120,7 +120,7 @@ message_admins("[ADMIN_LOOKUPFLW(usr)] has tried to spawn an item when selecting a sect.") return if(user.mind.holy_role != HOLY_ROLE_HIGHPRIEST) - to_chat(user, "You are not the high priest, and therefore cannot select a religious sect.") + to_chat(user, span_warning("You are not the high priest, and therefore cannot select a religious sect.")) return if(!user.can_perform_action(parent, FORBID_TELEKINESIS_REACH)) to_chat(user,span_warning("You cannot select a sect at this time.")) diff --git a/code/datums/components/sect_nullrod_bonus.dm b/code/datums/components/sect_nullrod_bonus.dm new file mode 100644 index 00000000000..bfba8e7e97a --- /dev/null +++ b/code/datums/components/sect_nullrod_bonus.dm @@ -0,0 +1,35 @@ +/** + * sect nullrod bonus component; for sekret rite combos + * + * Good example is the bow and pyre sect. pick the bow, get a special rite in the pyre sect. + */ +/datum/component/sect_nullrod_bonus + /// assoc list of nullrod type -> rites it unlocks + var/list/bonus_rites + /// has this component given the bonus yet + var/bonus_applied = FALSE + +/datum/component/sect_nullrod_bonus/Initialize(list/bonus_rites) + if(!istype(parent, /datum/religion_sect)) + return COMPONENT_INCOMPATIBLE + src.bonus_rites = bonus_rites + check_bonus_rites() + +/datum/component/sect_nullrod_bonus/RegisterWithParent() + RegisterSignal(SSdcs, COMSIG_GLOB_NULLROD_PICKED, PROC_REF(on_nullrod_picked)) + +/datum/component/sect_nullrod_bonus/UnregisterFromParent() + UnregisterSignal(SSdcs, COMSIG_GLOB_NULLROD_PICKED) + +/datum/component/sect_nullrod_bonus/proc/on_nullrod_picked(datum/source) + SIGNAL_HANDLER + check_bonus_rites() + +/datum/component/sect_nullrod_bonus/proc/check_bonus_rites() + if(bonus_applied || !GLOB.holy_weapon_type) + return + var/list/unlocked_rites = bonus_rites[GLOB.holy_weapon_type] + if(!unlocked_rites) + return + GLOB.religious_sect.rites_list.Add(unlocked_rites) + bonus_applied = TRUE diff --git a/code/datums/elements/bane.dm b/code/datums/elements/bane.dm index e050c41b61c..5d7b5f0b96f 100644 --- a/code/datums/elements/bane.dm +++ b/code/datums/elements/bane.dm @@ -18,14 +18,8 @@ /datum/element/bane/Attach(datum/target, target_type = /mob/living, mob_biotypes = NONE, damage_multiplier=1, added_damage = 0, requires_combat_mode = TRUE) . = ..() - if(!isitem(target)) - return ELEMENT_INCOMPATIBLE - if(ispath(target_type, /mob/living)) - RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(mob_check)) - else if(ispath(target_type, /datum/species)) - RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(species_check)) - else + if(!ispath(target_type, /mob/living) && !ispath(target_type, /datum/species)) return ELEMENT_INCOMPATIBLE src.target_type = target_type @@ -33,39 +27,54 @@ src.added_damage = added_damage src.requires_combat_mode = requires_combat_mode src.mob_biotypes = mob_biotypes + target.AddComponent(/datum/component/on_hit_effect, CALLBACK(src, PROC_REF(do_bane)), CALLBACK(src, PROC_REF(check_bane))) -/datum/element/bane/Detach(datum/source) - UnregisterSignal(source, COMSIG_ITEM_AFTERATTACK) +/datum/element/bane/Detach(datum/target) + qdel(target.GetComponent(/datum/component/on_hit_effect)) return ..() -/datum/element/bane/proc/species_check(obj/item/source, mob/living/target, mob/user, proximity_flag, click_parameters) - SIGNAL_HANDLER - - if(!proximity_flag || !istype(target) || !is_species(target, target_type)) +/datum/element/bane/proc/check_bane(mob/living/bane_applier, atom/target) + if(!isliving(target)) return - - var/is_correct_biotype = target.mob_biotypes & mob_biotypes + var/mob/living/living_target = target + if(bane_applier) + if(requires_combat_mode && !bane_applier.combat_mode) + return + var/is_correct_biotype = living_target.mob_biotypes & mob_biotypes if(mob_biotypes && !(is_correct_biotype)) + return FALSE + if(ispath(target_type, /mob/living)) + return istype(living_target, target_type) + else //species type + return is_species(living_target, target_type) + +/datum/element/bane/proc/do_bane(datum/element_owner, mob/living/bane_applier, mob/living/baned_target, hit_zone) + var/force_boosted + var/applied_dam_type + + if(isitem(element_owner)) + var/obj/item/item_owner = element_owner + force_boosted = item_owner.force + applied_dam_type = item_owner.damtype + else if(isprojectile(element_owner)) + var/obj/projectile/projectile_owner = element_owner + force_boosted = projectile_owner.damage + applied_dam_type = projectile_owner.damage_type + else if (isliving(element_owner)) + var/mob/living/living_owner = element_owner + force_boosted = (living_owner.melee_damage_lower + living_owner.melee_damage_upper) / 2 + //commence crying. yes, these really are the same check. FUCK. + if(isbasicmob(living_owner)) + var/mob/living/basic/basic_owner = living_owner + applied_dam_type = basic_owner.melee_damage_type + else if(isanimal(living_owner)) + var/mob/living/simple_animal/simple_owner = living_owner + applied_dam_type = simple_owner.melee_damage_type + else + return + else return - activate(source, target, user) - -/datum/element/bane/proc/mob_check(obj/item/source, mob/living/target, mob/user, proximity_flag, click_parameters) - SIGNAL_HANDLER - - if(!proximity_flag || !istype(target, target_type)) - return - - var/is_correct_biotype = target.mob_biotypes & mob_biotypes - if(mob_biotypes && !(is_correct_biotype)) - return - - activate(source, target, user) - -/datum/element/bane/proc/activate(obj/item/source, mob/living/target, mob/living/attacker) - if(requires_combat_mode && !attacker.combat_mode) - return - - var/extra_damage = max(0, (source.force * damage_multiplier) + added_damage) - target.apply_damage(extra_damage, source.damtype, attacker.zone_selected) - SEND_SIGNAL(target, COMSIG_LIVING_BANED, source, attacker) // for extra effects when baned. + var/extra_damage = max(0, (force_boosted * damage_multiplier) + added_damage) + baned_target.apply_damage(extra_damage, applied_dam_type, hit_zone) + SEND_SIGNAL(baned_target, COMSIG_LIVING_BANED, bane_applier, baned_target) // for extra effects when baned. diff --git a/code/datums/elements/envenomable_casing.dm b/code/datums/elements/envenomable_casing.dm new file mode 100644 index 00000000000..fe68d7408ad --- /dev/null +++ b/code/datums/elements/envenomable_casing.dm @@ -0,0 +1,57 @@ +/** + * ### envenomable caseless element! + * + * Non bespoke element (1 in existence) that lets caseless bullets be dippable. + * When you fire the bullet, it will gain venomous. The casing itself isn't venomous to prevent bullshit + */ +/datum/element/envenomable_casing + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// how much reagent can you dip the caseless in? + var/amount_allowed + +/datum/element/envenomable_casing/Attach(datum/target, amount_allowed = 5) + . = ..() + if(!istype(target, /obj/item/ammo_casing)) + return ELEMENT_INCOMPATIBLE + src.amount_allowed = amount_allowed + RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_afterattack)) + RegisterSignal(target, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine)) + +/datum/element/envenomable_casing/Detach(datum/target) + . = ..() + UnregisterSignal(target, list(COMSIG_ITEM_AFTERATTACK, COMSIG_PARENT_EXAMINE)) + +///signal called on the parent attacking an item +/datum/element/envenomable_casing/proc/on_afterattack(obj/item/ammo_casing/casing, atom/target, mob/user, proximity_flag, click_parameters) + SIGNAL_HANDLER + if(!is_reagent_container(target)) + return + var/obj/item/reagent_containers/venom_container = target + if(!casing.loaded_projectile) + user.balloon_alert(user, "casing is already spent!") + return + if(!(venom_container.reagent_flags & OPENCONTAINER)) + user.balloon_alert(user, "open the container!") + return + var/datum/reagent/venom_applied = venom_container.reagents.get_master_reagent() + if(!venom_applied) + return + var/amount_applied = min(venom_applied.volume, amount_allowed) + + casing.loaded_projectile.AddComponent(/datum/element/venomous, venom_applied.type, amount_applied) + to_chat(user, span_notice("You coat [casing] in [venom_applied].")) + venom_container.reagents.remove_reagent(venom_applied.type, amount_applied) + ///stops further poison application + UnregisterSignal(casing, COMSIG_ITEM_AFTERATTACK) + +///signal called on parent being examined +/datum/element/envenomable_casing/proc/on_examine(obj/item/ammo_casing/casing, mob/user, list/examine_list) + SIGNAL_HANDLER + + if(!casing.loaded_projectile) + return + if(casing.loaded_projectile.GetComponent(/datum/element/venomous)) + examine_list += span_warning("It's coated in some kind of chemical...") + else + examine_list += span_notice("You can dip it in a chemical to deliver a poisonous kick.") diff --git a/code/datums/elements/lifesteal.dm b/code/datums/elements/lifesteal.dm index 3727c8122cc..48f812fc1f1 100644 --- a/code/datums/elements/lifesteal.dm +++ b/code/datums/elements/lifesteal.dm @@ -7,46 +7,19 @@ argument_hash_start_idx = 2 /// heals a constant amount every time a hit occurs var/flat_heal + /// static list shared that tells which order of damage types to prioritize var/static/list/damage_heal_order = list(BRUTE, BURN, OXY) -/datum/element/lifesteal/Attach(datum/target, flat_heal) +/datum/element/lifesteal/Attach(datum/target, flat_heal = 10) . = ..() - if(ismachinery(target) || isstructure(target) || isgun(target) || isprojectilespell(target)) - RegisterSignal(target, COMSIG_PROJECTILE_ON_HIT, PROC_REF(projectile_hit)) - else if(isitem(target)) - RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(item_afterattack)) - else if(ishostile(target)) - RegisterSignal(target, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(hostile_attackingtarget)) - else - return ELEMENT_INCOMPATIBLE - src.flat_heal = flat_heal + target.AddComponent(/datum/component/on_hit_effect, CALLBACK(src, PROC_REF(do_lifesteal))) -/datum/element/lifesteal/Detach(datum/source) - UnregisterSignal(source, list(COMSIG_PROJECTILE_ON_HIT, COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_POST_ATTACKINGTARGET)) +/datum/element/lifesteal/Detach(datum/target) + qdel(target.GetComponent(/datum/component/on_hit_effect)) return ..() -/datum/element/lifesteal/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters) - SIGNAL_HANDLER - - if(!proximity_flag) - return - do_lifesteal(user, target) - return COMPONENT_AFTERATTACK_PROCESSED_ITEM - -/datum/element/lifesteal/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target, success) - SIGNAL_HANDLER - - if(!success) - return - do_lifesteal(attacker, target) - -/datum/element/lifesteal/proc/projectile_hit(datum/fired_from, atom/movable/firer, atom/target, Angle) - SIGNAL_HANDLER - - do_lifesteal(firer, target) - -/datum/element/lifesteal/proc/do_lifesteal(atom/heal_target, atom/damage_target) +/datum/element/lifesteal/proc/do_lifesteal(datum/element_owner, atom/heal_target, atom/damage_target, hit_zone) if(isliving(heal_target) && isliving(damage_target)) var/mob/living/healing = heal_target var/mob/living/damaging = damage_target diff --git a/code/datums/elements/venomous.dm b/code/datums/elements/venomous.dm index 1ff46843e66..b310e01bafc 100644 --- a/code/datums/elements/venomous.dm +++ b/code/datums/elements/venomous.dm @@ -13,44 +13,15 @@ /datum/element/venomous/Attach(datum/target, poison_type, amount_added) . = ..() - - if(ismachinery(target) || isstructure(target) || isgun(target) || isprojectilespell(target)) - RegisterSignal(target, COMSIG_PROJECTILE_ON_HIT, PROC_REF(projectile_hit)) - else if(isitem(target)) - RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(item_afterattack)) - else if(ishostile(target) || isbasicmob(target)) - RegisterSignal(target, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(hostile_attackingtarget)) - else - return ELEMENT_INCOMPATIBLE - src.poison_type = poison_type src.amount_added = amount_added + target.AddComponent(/datum/component/on_hit_effect, CALLBACK(src, PROC_REF(do_venom))) /datum/element/venomous/Detach(datum/target) - UnregisterSignal(target, list(COMSIG_PROJECTILE_ON_HIT, COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_POST_ATTACKINGTARGET)) + qdel(target.GetComponent(/datum/component/on_hit_effect)) return ..() -/datum/element/venomous/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle) - SIGNAL_HANDLER - - add_reagent(target) - -/datum/element/venomous/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters) - SIGNAL_HANDLER - - if(!proximity_flag) - return - add_reagent(target) - return COMPONENT_AFTERATTACK_PROCESSED_ITEM - -/datum/element/venomous/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target, success) - SIGNAL_HANDLER - - if(!success) - return - add_reagent(target) - -/datum/element/venomous/proc/add_reagent(mob/living/target) +/datum/element/venomous/proc/do_venom(datum/element_owner, atom/venom_source, mob/living/target, hit_zone) if(!istype(target)) return if(target.stat == DEAD) diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 304939398fd..2265f99d1b4 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -542,6 +542,7 @@ /obj/item/storage/bag/harpoon_quiver name = "harpoon quiver" desc = "A quiver for holding harpoons." + icon = 'icons/obj/weapons/guns/bows/quivers.dmi' icon_state = "quiver" inhand_icon_state = null worn_icon_state = "harpoon_quiver" diff --git a/code/game/objects/items/storage/boxes/clothes_boxes.dm b/code/game/objects/items/storage/boxes/clothes_boxes.dm index 2df843c5a63..0fe4210e249 100644 --- a/code/game/objects/items/storage/boxes/clothes_boxes.dm +++ b/code/game/objects/items/storage/boxes/clothes_boxes.dm @@ -186,3 +186,13 @@ new /obj/item/clothing/suit/hooded/chaplain_hoodie(src) new /obj/item/clothing/suit/hooded/chaplain_hoodie(src) new /obj/item/clothing/suit/hooded/chaplain_hoodie/leader(src) + +/obj/item/storage/box/holy/divine_archer + name = "Divine Archer Kit" + typepath_for_preview = /obj/item/clothing/suit/hooded/chaplain_hoodie/divine_archer + +/obj/item/storage/box/holy/divine_archer/PopulateContents() + new /obj/item/clothing/under/rank/civilian/chaplain/divine_archer(src) + new /obj/item/clothing/suit/hooded/chaplain_hoodie/divine_archer(src) + new /obj/item/clothing/gloves/divine_archer(src) + new /obj/item/clothing/shoes/divine_archer(src) diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm index dfbcc7db4fe..6a7cfb72642 100644 --- a/code/modules/clothing/suits/toggles.dm +++ b/code/modules/clothing/suits/toggles.dm @@ -8,6 +8,8 @@ var/alternative_mode = FALSE ///Whether the hood is flipped up var/hood_up = FALSE + /// What should be added to the end of the icon state when the hood is up? Set to "" for the suit sprite to not change at all + var/hood_up_affix = "_t" /// Are we zipped? Mostly relevant for wintercoats, leaving this here to simplify logic and so someone else can extend it if they ever wish to. var/zipped = FALSE @@ -86,7 +88,7 @@ RemoveHood() return hood_up = TRUE - icon_state = "[initial(icon_state)]_t" + icon_state = "[initial(icon_state)][hood_up_affix]" worn_icon_state = icon_state zipped = TRUE // Just to maintain the same behavior, and so we avoid any bugs that otherwise relied on this behavior of zipping the jacket when bringing up the hood H.update_worn_oversuit() diff --git a/code/modules/jobs/job_types/chaplain.dm b/code/modules/jobs/job_types/chaplain/chaplain.dm similarity index 100% rename from code/modules/jobs/job_types/chaplain.dm rename to code/modules/jobs/job_types/chaplain/chaplain.dm diff --git a/code/modules/clothing/suits/chaplainsuits.dm b/code/modules/jobs/job_types/chaplain/chaplain_costumes.dm similarity index 100% rename from code/modules/clothing/suits/chaplainsuits.dm rename to code/modules/jobs/job_types/chaplain/chaplain_costumes.dm diff --git a/code/modules/jobs/job_types/chaplain/chaplain_divine_archer.dm b/code/modules/jobs/job_types/chaplain/chaplain_divine_archer.dm new file mode 100644 index 00000000000..48bdf25a22f --- /dev/null +++ b/code/modules/jobs/job_types/chaplain/chaplain_divine_archer.dm @@ -0,0 +1,63 @@ + +// this costume has so many fugging parts 😭. fuck it, it's a file. +//in fact, we should strive to make the chaplain kits of this quality, moreso than the other way around. + +/// undersuit +/obj/item/clothing/under/rank/civilian/chaplain/divine_archer + name = "divine archer's garb" + desc = "Inner garb for divine archers." + icon_state = "archergarb" + inhand_icon_state = "archergarb" + can_adjust = TRUE + +/// suit +/obj/item/clothing/suit/hooded/chaplain_hoodie/divine_archer + name = "divine archer coat" + desc = "Outer coat for divine archers. Offers some protection." + icon_state = "archercoat" + inhand_icon_state = "archercoat" + body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + armor_type = /datum/armor/chaplainsuit_armor_weaker + clothing_flags = BLOCKS_SHOVE_KNOCKDOWN + strip_delay = 80 + equip_delay_other = 60 + hoodtype = /obj/item/clothing/head/hooded/chaplain_hood/divine_archer + hood_up_affix = "" + +/datum/armor/chaplainsuit_armor_weaker + melee = 40 + bullet = 5 + laser = 5 + energy = 5 + fire = 60 + acid = 60 + wound = 10 + +/// hood +/obj/item/clothing/head/hooded/chaplain_hood/divine_archer + name = "divine archer hood" + desc = "A divine hood included, because have you ever got the sun in your eyes during archery? Oh, it's just the worst." + icon_state = "archerhood" + +/// gloves +/obj/item/clothing/gloves/divine_archer + name = "divine archer bracers" + desc = "Bracers, a wise choice for archers who do not want their outfit to get in the way of drawing and firing their weapon." + icon_state = "archerbracers" + inhand_icon_state = "archerbracers" + strip_delay = 40 + equip_delay_other = 20 + resistance_flags = NONE + +/// boots +/obj/item/clothing/shoes/divine_archer + name = "divine archer boots" + desc = "Boots, For steady footing while aiming." + icon_state = "archerboots" + inhand_icon_state = "archerboots" + strip_delay = 30 + equip_delay_other = 50 + resistance_flags = NONE + can_be_tied = FALSE diff --git a/code/game/objects/items/holy_weapons.dm b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm similarity index 99% rename from code/game/objects/items/holy_weapons.dm rename to code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm index 36a3a643fde..084f89643a9 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm @@ -29,8 +29,8 @@ success_forcesay = "BEGONE 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, /obj/effect/cosmic_rune)) - + effects_we_clear = list(/obj/effect/rune, /obj/effect/heretic_rune, /obj/effect/cosmic_rune), \ + ) AddElement(/datum/element/bane, target_type = /mob/living/simple_animal/revenant, damage_multiplier = 0, added_damage = 25, requires_combat_mode = FALSE) if(!GLOB.holy_weapon_type && type == /obj/item/nullrod) @@ -39,10 +39,13 @@ if(!initial(nullrod_type.chaplain_spawnable)) continue rods[nullrod_type] = initial(nullrod_type.menu_description) + //special non-nullrod subtyped shit + rods[/obj/item/gun/ballistic/bow/divine/with_quiver] = "A divine bow and 10 quivered holy arrows." AddComponent(/datum/component/subtype_picker, rods, CALLBACK(src, PROC_REF(on_holy_weapon_picked))) /obj/item/nullrod/proc/on_holy_weapon_picked(obj/item/nullrod/holy_weapon_type) GLOB.holy_weapon_type = holy_weapon_type + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NULLROD_PICKED) SSblackbox.record_feedback("tally", "chaplain_weapon", 1, "[initial(holy_weapon_type.name)]") /obj/item/nullrod/proc/on_cult_rune_removed(obj/effect/target, mob/living/user) diff --git a/code/modules/projectiles/guns/ballistic/bow.dm b/code/modules/projectiles/guns/ballistic/bows/_bow.dm similarity index 50% rename from code/modules/projectiles/guns/ballistic/bow.dm rename to code/modules/projectiles/guns/ballistic/bows/_bow.dm index 930acaa5330..afb1ca180f8 100644 --- a/code/modules/projectiles/guns/ballistic/bow.dm +++ b/code/modules/projectiles/guns/ballistic/bows/_bow.dm @@ -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 diff --git a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm new file mode 100644 index 00000000000..c056b2cf704 --- /dev/null +++ b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm @@ -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 diff --git a/code/modules/projectiles/guns/ballistic/bows/bow_quivers.dm b/code/modules/projectiles/guns/ballistic/bows/bow_quivers.dm new file mode 100644 index 00000000000..19a00a95c96 --- /dev/null +++ b/code/modules/projectiles/guns/ballistic/bows/bow_quivers.dm @@ -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 diff --git a/code/modules/projectiles/guns/ballistic/bows/bow_types.dm b/code/modules/projectiles/guns/ballistic/bows/bow_types.dm new file mode 100644 index 00000000000..2b387a6b657 --- /dev/null +++ b/code/modules/projectiles/guns/ballistic/bows/bow_types.dm @@ -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) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 50c833133df..c4d0fffc98d 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -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 diff --git a/code/modules/religion/honorbound/honorbound_rites.dm b/code/modules/religion/honorbound/honorbound_rites.dm index ad3a826a734..d2718fe1bde 100644 --- a/code/modules/religion/honorbound/honorbound_rites.dm +++ b/code/modules/religion/honorbound/honorbound_rites.dm @@ -128,7 +128,7 @@ var/obj/item/paper/autograph = writ_target var/turf/tool_turf = get_turf(religious_tool) writ_target = null - if(QDELETED(autograph) || !(tool_turf == autograph.loc)) //check if the same food is still there + if(QDELETED(autograph) || !(tool_turf == autograph.loc)) //check if the paper is still there to_chat(user, span_warning("Your target left the altar!")) return FALSE autograph.visible_message(span_notice("Words magically form on [autograph]!")) diff --git a/code/modules/religion/pyre_rites.dm b/code/modules/religion/pyre_rites.dm new file mode 100644 index 00000000000..28ef53968f9 --- /dev/null +++ b/code/modules/religion/pyre_rites.dm @@ -0,0 +1,151 @@ + +///apply a bunch of fire immunity effect to clothing +/datum/religion_rites/fireproof/proc/apply_fireproof(obj/item/clothing/fireproofed) + fireproofed.name = "unmelting [fireproofed.name]" + fireproofed.max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + fireproofed.heat_protection = chosen_clothing.body_parts_covered + fireproofed.resistance_flags |= FIRE_PROOF + +/datum/religion_rites/fireproof + name = "Unmelting Protection" + desc = "Grants fire immunity to any piece of clothing." + ritual_length = 15 SECONDS + ritual_invocations = list("And so to support the holder of the Ever-Burning candle...", + "... allow this unworthy apparel to serve you ...", + "... make it strong enough to burn a thousand time and more ...") + invoke_msg = "... Come forth in your new form, and join the unmelting wax of the one true flame!" + favor_cost = 1000 +///the piece of clothing that will be fireproofed, only one per rite + var/obj/item/clothing/chosen_clothing + +/datum/religion_rites/fireproof/perform_rite(mob/living/user, atom/religious_tool) + for(var/obj/item/clothing/apparel in get_turf(religious_tool)) + if(apparel.max_heat_protection_temperature >= FIRE_IMMUNITY_MAX_TEMP_PROTECT) + continue //we ignore anything that is already fireproof + chosen_clothing = apparel //the apparel has been chosen by our lord and savior + return ..() + return FALSE + +/datum/religion_rites/fireproof/invoke_effect(mob/living/user, atom/religious_tool) + ..() + if(!QDELETED(chosen_clothing) && get_turf(religious_tool) == chosen_clothing.loc) //check if the same clothing is still there + if(istype(chosen_clothing,/obj/item/clothing/suit/hooded)) + for(var/obj/item/clothing/head/integrated_helmet in chosen_clothing.contents) //check if the clothing has a hood/helmet integrated and fireproof it if there is one. + apply_fireproof(integrated_helmet) + apply_fireproof(chosen_clothing) + playsound(get_turf(religious_tool), 'sound/magic/fireball.ogg', 50, TRUE) + chosen_clothing = null //our lord and savior no longer cares about this apparel + return TRUE + chosen_clothing = null + to_chat(user, span_warning("The clothing that was chosen for the rite is no longer on the altar!")) + return FALSE + + +/datum/religion_rites/burning_sacrifice + name = "Burning Offering" + desc = "Sacrifice a buckled burning corpse for favor, the more burn damage the corpse has the more favor you will receive." + ritual_length = 20 SECONDS + ritual_invocations = list("Burning body ...", + "... cleansed by the flame ...", + "... we were all created from fire ...", + "... and to it ...") + invoke_msg = "... WE RETURN! " +///the burning corpse chosen for the sacrifice of the rite + var/mob/living/carbon/chosen_sacrifice + +/datum/religion_rites/burning_sacrifice/perform_rite(mob/living/user, atom/religious_tool) + if(!ismovable(religious_tool)) + to_chat(user, span_warning("This rite requires a religious device that individuals can be buckled to.")) + return FALSE + var/atom/movable/movable_reltool = religious_tool + if(!movable_reltool) + return FALSE + if(!LAZYLEN(movable_reltool.buckled_mobs)) + to_chat(user, span_warning("Nothing is buckled to the altar!")) + return FALSE + for(var/corpse in movable_reltool.buckled_mobs) + if(!iscarbon(corpse))// only works with carbon corpse since most normal mobs can't be set on fire. + to_chat(user, span_warning("Only carbon lifeforms can be properly burned for the sacrifice!")) + return FALSE + chosen_sacrifice = corpse + if(chosen_sacrifice.stat != DEAD) + to_chat(user, span_warning("You can only sacrifice dead bodies, this one is still alive!")) + return FALSE + if(!chosen_sacrifice.on_fire) + to_chat(user, span_warning("This corpse needs to be on fire to be sacrificed!")) + return FALSE + return ..() + +/datum/religion_rites/burning_sacrifice/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + if(!(chosen_sacrifice in religious_tool.buckled_mobs)) //checks one last time if the right corpse is still buckled + to_chat(user, span_warning("The right sacrifice is no longer on the altar!")) + chosen_sacrifice = null + return FALSE + if(!chosen_sacrifice.on_fire) + to_chat(user, span_warning("The sacrifice is no longer on fire, it needs to burn until the end of the rite!")) + chosen_sacrifice = null + return FALSE + if(chosen_sacrifice.stat != DEAD) + to_chat(user, span_warning("The sacrifice has to stay dead for the rite to work!")) + chosen_sacrifice = null + return FALSE + var/favor_gained = 100 + round(chosen_sacrifice.getFireLoss()) + GLOB.religious_sect.adjust_favor(favor_gained, user) + to_chat(user, span_notice("[GLOB.deity] absorbs the burning corpse and any trace of fire with it. [GLOB.deity] rewards you with [favor_gained] favor.")) + chosen_sacrifice.dust(force = TRUE) + playsound(get_turf(religious_tool), 'sound/effects/supermatter.ogg', 50, TRUE) + chosen_sacrifice = null + return TRUE + +/datum/religion_rites/infinite_candle + name = "Immortal Candles" + desc = "Creates 5 candles that never run out of wax." + ritual_length = 10 SECONDS + invoke_msg = "Burn bright, little candles, for you will only extinguish along with the universe." + favor_cost = 200 + +/datum/religion_rites/infinite_candle/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + var/altar_turf = get_turf(religious_tool) + for(var/i in 1 to 5) + new /obj/item/flashlight/flare/candle/infinite(altar_turf) + playsound(altar_turf, 'sound/magic/fireball.ogg', 50, TRUE) + return TRUE + +/datum/religion_rites/blazing_star + name = "Blazing Star" + desc = "Enchants a holy arrow to set someone on fire on hit, or if the victim is already on fire... note, this consumes the arrow." + ritual_length = 15 SECONDS + ritual_invocations = list( + "And so to keep the Ever-Burning candle protected ...", + "... grant this feeble bolt your blessing ...", + "... make it burn bright ...", + ) + invoke_msg = "... a blazing star is born!" + favor_cost = 2000 + ///arrow to enchant + var/obj/item/ammo_casing/caseless/arrow/holy/enchant_target + +/datum/religion_rites/blazing_star/perform_rite(mob/living/user, atom/religious_tool) + for(var/obj/item/ammo_casing/caseless/arrow/holy/can_enchant in get_turf(religious_tool)) + if(istype(can_enchant, /obj/item/ammo_casing/caseless/arrow/holy/blazing)) + continue + enchant_target = can_enchant + return ..() + to_chat(user, span_warning("You need to place a holy arrow on [religious_tool] to do this!")) + return FALSE + +/datum/religion_rites/blazing_star/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + var/obj/item/ammo_casing/caseless/arrow/holy/enchanting = enchant_target + var/turf/tool_turf = get_turf(religious_tool) + enchant_target = null + if(QDELETED(enchanting) || !(tool_turf == enchanting.loc)) //check if the arrow is still there + to_chat(user, span_warning("Your target left the altar!")) + return FALSE + enchanting.visible_message(span_notice("[enchant_target] is blessed by holy fire!")) + playsound(tool_turf, 'sound/effects/pray.ogg', 50, TRUE) + new /obj/item/ammo_casing/caseless/arrow/holy/blazing(tool_turf) + qdel(enchanting) + return TRUE diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index 8817de3f23b..0095aa973b5 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -208,6 +208,14 @@ rites_list = list(/datum/religion_rites/fireproof, /datum/religion_rites/burning_sacrifice, /datum/religion_rites/infinite_candle) altar_icon_state = "convertaltar-red" +/datum/religion_sect/pyre/on_select() + . = ..() + AddComponent(/datum/component/sect_nullrod_bonus, list( + /obj/item/gun/ballistic/bow/divine/with_quiver = list( + /datum/religion_rites/blazing_star, + ), + )) + //candle sect bibles don't heal or do anything special apart from the standard holy water blessings /datum/religion_sect/pyre/sect_bless(mob/living/target, mob/living/chap) return TRUE diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index 41277d3dd16..19eb5321459 100644 --- a/code/modules/religion/rites.dm +++ b/code/modules/religion/rites.dm @@ -139,124 +139,6 @@ new blessing(altar_turf) return TRUE -/**** Pyre God ****/ - -///apply a bunch of fire immunity effect to clothing -/datum/religion_rites/fireproof/proc/apply_fireproof(obj/item/clothing/fireproofed) - fireproofed.name = "unmelting [fireproofed.name]" - fireproofed.max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - fireproofed.heat_protection = chosen_clothing.body_parts_covered - fireproofed.resistance_flags |= FIRE_PROOF - -/datum/religion_rites/fireproof - name = "Unmelting Protection" - desc = "Grants fire immunity to any piece of clothing." - ritual_length = 15 SECONDS - ritual_invocations = list("And so to support the holder of the Ever-Burning candle...", - "... allow this unworthy apparel to serve you ...", - "... make it strong enough to burn a thousand time and more ...") - invoke_msg = "... Come forth in your new form, and join the unmelting wax of the one true flame!" - favor_cost = 1000 -///the piece of clothing that will be fireproofed, only one per rite - var/obj/item/clothing/chosen_clothing - -/datum/religion_rites/fireproof/perform_rite(mob/living/user, atom/religious_tool) - for(var/obj/item/clothing/apparel in get_turf(religious_tool)) - if(apparel.max_heat_protection_temperature >= FIRE_IMMUNITY_MAX_TEMP_PROTECT) - continue //we ignore anything that is already fireproof - chosen_clothing = apparel //the apparel has been chosen by our lord and savior - return ..() - return FALSE - -/datum/religion_rites/fireproof/invoke_effect(mob/living/user, atom/religious_tool) - ..() - if(!QDELETED(chosen_clothing) && get_turf(religious_tool) == chosen_clothing.loc) //check if the same clothing is still there - if(istype(chosen_clothing,/obj/item/clothing/suit/hooded)) - for(var/obj/item/clothing/head/integrated_helmet in chosen_clothing.contents) //check if the clothing has a hood/helmet integrated and fireproof it if there is one. - apply_fireproof(integrated_helmet) - apply_fireproof(chosen_clothing) - playsound(get_turf(religious_tool), 'sound/magic/fireball.ogg', 50, TRUE) - chosen_clothing = null //our lord and savior no longer cares about this apparel - return TRUE - chosen_clothing = null - to_chat(user, span_warning("The clothing that was chosen for the rite is no longer on the altar!")) - return FALSE - - -/datum/religion_rites/burning_sacrifice - name = "Burning Offering" - desc = "Sacrifice a buckled burning corpse for favor, the more burn damage the corpse has the more favor you will receive." - ritual_length = 20 SECONDS - ritual_invocations = list("Burning body ...", - "... cleansed by the flame ...", - "... we were all created from fire ...", - "... and to it ...") - invoke_msg = "... WE RETURN! " -///the burning corpse chosen for the sacrifice of the rite - var/mob/living/carbon/chosen_sacrifice - -/datum/religion_rites/burning_sacrifice/perform_rite(mob/living/user, atom/religious_tool) - if(!ismovable(religious_tool)) - to_chat(user, span_warning("This rite requires a religious device that individuals can be buckled to.")) - return FALSE - var/atom/movable/movable_reltool = religious_tool - if(!movable_reltool) - return FALSE - if(!LAZYLEN(movable_reltool.buckled_mobs)) - to_chat(user, span_warning("Nothing is buckled to the altar!")) - return FALSE - for(var/corpse in movable_reltool.buckled_mobs) - if(!iscarbon(corpse))// only works with carbon corpse since most normal mobs can't be set on fire. - to_chat(user, span_warning("Only carbon lifeforms can be properly burned for the sacrifice!")) - return FALSE - chosen_sacrifice = corpse - if(chosen_sacrifice.stat != DEAD) - to_chat(user, span_warning("You can only sacrifice dead bodies, this one is still alive!")) - return FALSE - if(!chosen_sacrifice.on_fire) - to_chat(user, span_warning("This corpse needs to be on fire to be sacrificed!")) - return FALSE - return ..() - -/datum/religion_rites/burning_sacrifice/invoke_effect(mob/living/user, atom/movable/religious_tool) - ..() - if(!(chosen_sacrifice in religious_tool.buckled_mobs)) //checks one last time if the right corpse is still buckled - to_chat(user, span_warning("The right sacrifice is no longer on the altar!")) - chosen_sacrifice = null - return FALSE - if(!chosen_sacrifice.on_fire) - to_chat(user, span_warning("The sacrifice is no longer on fire, it needs to burn until the end of the rite!")) - chosen_sacrifice = null - return FALSE - if(chosen_sacrifice.stat != DEAD) - to_chat(user, span_warning("The sacrifice has to stay dead for the rite to work!")) - chosen_sacrifice = null - return FALSE - var/favor_gained = 100 + round(chosen_sacrifice.getFireLoss()) - GLOB.religious_sect.adjust_favor(favor_gained, user) - to_chat(user, span_notice("[GLOB.deity] absorbs the burning corpse and any trace of fire with it. [GLOB.deity] rewards you with [favor_gained] favor.")) - chosen_sacrifice.dust(force = TRUE) - playsound(get_turf(religious_tool), 'sound/effects/supermatter.ogg', 50, TRUE) - chosen_sacrifice = null - return TRUE - - - -/datum/religion_rites/infinite_candle - name = "Immortal Candles" - desc = "Creates 5 candles that never run out of wax." - ritual_length = 10 SECONDS - invoke_msg = "Burn bright, little candles, for you will only extinguish along with the universe." - favor_cost = 200 - -/datum/religion_rites/infinite_candle/invoke_effect(mob/living/user, atom/movable/religious_tool) - ..() - var/altar_turf = get_turf(religious_tool) - for(var/i in 1 to 5) - new /obj/item/flashlight/flare/candle/infinite(altar_turf) - playsound(altar_turf, 'sound/magic/fireball.ogg', 50, TRUE) - return TRUE - /*********Greedy God**********/ ///all greed rites cost money instead diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index 1de907be97c..69818836ac4 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi index 0ac34fa5328..cee63e28b68 100644 Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ diff --git a/icons/mob/clothing/feet.dmi b/icons/mob/clothing/feet.dmi index 135c1f951e9..27c10710952 100644 Binary files a/icons/mob/clothing/feet.dmi and b/icons/mob/clothing/feet.dmi differ diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index 844628ec847..b0399d58041 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/mob/clothing/head/chaplain.dmi b/icons/mob/clothing/head/chaplain.dmi index 7c34306918f..810d76ea358 100644 Binary files a/icons/mob/clothing/head/chaplain.dmi and b/icons/mob/clothing/head/chaplain.dmi differ diff --git a/icons/mob/clothing/suits/chaplain.dmi b/icons/mob/clothing/suits/chaplain.dmi index 99049027f17..4a61238cc27 100644 Binary files a/icons/mob/clothing/suits/chaplain.dmi and b/icons/mob/clothing/suits/chaplain.dmi differ diff --git a/icons/mob/clothing/under/civilian.dmi b/icons/mob/clothing/under/civilian.dmi index 15cfcc93fb4..667d98b5361 100644 Binary files a/icons/mob/clothing/under/civilian.dmi and b/icons/mob/clothing/under/civilian.dmi differ diff --git a/icons/mob/inhands/clothing/gloves_lefthand.dmi b/icons/mob/inhands/clothing/gloves_lefthand.dmi index 9ffc8a03cfe..6277d146ffc 100644 Binary files a/icons/mob/inhands/clothing/gloves_lefthand.dmi and b/icons/mob/inhands/clothing/gloves_lefthand.dmi differ diff --git a/icons/mob/inhands/clothing/gloves_righthand.dmi b/icons/mob/inhands/clothing/gloves_righthand.dmi index 70c6e6fd1f0..7479dd8c505 100644 Binary files a/icons/mob/inhands/clothing/gloves_righthand.dmi and b/icons/mob/inhands/clothing/gloves_righthand.dmi differ diff --git a/icons/mob/inhands/clothing/shoes_lefthand.dmi b/icons/mob/inhands/clothing/shoes_lefthand.dmi index 2c4c678e733..a5fd6d3318c 100644 Binary files a/icons/mob/inhands/clothing/shoes_lefthand.dmi and b/icons/mob/inhands/clothing/shoes_lefthand.dmi differ diff --git a/icons/mob/inhands/clothing/shoes_righthand.dmi b/icons/mob/inhands/clothing/shoes_righthand.dmi index dce5521a172..8f5a3c374ca 100644 Binary files a/icons/mob/inhands/clothing/shoes_righthand.dmi and b/icons/mob/inhands/clothing/shoes_righthand.dmi differ diff --git a/icons/mob/inhands/clothing/suits_lefthand.dmi b/icons/mob/inhands/clothing/suits_lefthand.dmi index b59ee57a4b3..757fb8b8593 100644 Binary files a/icons/mob/inhands/clothing/suits_lefthand.dmi and b/icons/mob/inhands/clothing/suits_lefthand.dmi differ diff --git a/icons/mob/inhands/clothing/suits_righthand.dmi b/icons/mob/inhands/clothing/suits_righthand.dmi index 42265a7db98..c749a2ed98a 100644 Binary files a/icons/mob/inhands/clothing/suits_righthand.dmi and b/icons/mob/inhands/clothing/suits_righthand.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index b6249d725db..03538d84a0e 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index ef6781c98cf..ce4ae52ac69 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/bows_lefthand.dmi b/icons/mob/inhands/weapons/bows_lefthand.dmi new file mode 100644 index 00000000000..78e74393262 Binary files /dev/null and b/icons/mob/inhands/weapons/bows_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/bows_righthand.dmi b/icons/mob/inhands/weapons/bows_righthand.dmi new file mode 100644 index 00000000000..04ea8cf0bc6 Binary files /dev/null and b/icons/mob/inhands/weapons/bows_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi index d2e0da8c8c5..e866650e19f 100644 Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi index 65c9cc5279e..89a9d42f280 100644 Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index d7d10e87126..27dc670cda4 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/clothing/head/chaplain.dmi b/icons/obj/clothing/head/chaplain.dmi index 5686520a267..d95436fdd2d 100644 Binary files a/icons/obj/clothing/head/chaplain.dmi and b/icons/obj/clothing/head/chaplain.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi index d6967789599..5fcc46dbb22 100644 Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/clothing/suits/chaplain.dmi b/icons/obj/clothing/suits/chaplain.dmi index b992fa615ab..3e9dd8665c9 100644 Binary files a/icons/obj/clothing/suits/chaplain.dmi and b/icons/obj/clothing/suits/chaplain.dmi differ diff --git a/icons/obj/clothing/under/civilian.dmi b/icons/obj/clothing/under/civilian.dmi index 1e46725d080..04c37b2356e 100644 Binary files a/icons/obj/clothing/under/civilian.dmi and b/icons/obj/clothing/under/civilian.dmi differ diff --git a/icons/obj/storage/storage.dmi b/icons/obj/storage/storage.dmi index 848f8326c84..1aabd198b12 100644 Binary files a/icons/obj/storage/storage.dmi and b/icons/obj/storage/storage.dmi differ diff --git a/icons/obj/weapons/guns/ammo.dmi b/icons/obj/weapons/guns/ammo.dmi index b72874b1105..5dd3d83b206 100644 Binary files a/icons/obj/weapons/guns/ammo.dmi and b/icons/obj/weapons/guns/ammo.dmi differ diff --git a/icons/obj/weapons/guns/ballistic.dmi b/icons/obj/weapons/guns/ballistic.dmi index c00eb265379..aacb9457de0 100644 Binary files a/icons/obj/weapons/guns/ballistic.dmi and b/icons/obj/weapons/guns/ballistic.dmi differ diff --git a/icons/obj/weapons/guns/bows/arrows.dmi b/icons/obj/weapons/guns/bows/arrows.dmi new file mode 100644 index 00000000000..691551f2bea Binary files /dev/null and b/icons/obj/weapons/guns/bows/arrows.dmi differ diff --git a/icons/obj/weapons/guns/bows/bows.dmi b/icons/obj/weapons/guns/bows/bows.dmi new file mode 100644 index 00000000000..81b2fc48220 Binary files /dev/null and b/icons/obj/weapons/guns/bows/bows.dmi differ diff --git a/icons/obj/weapons/guns/bows/quivers.dmi b/icons/obj/weapons/guns/bows/quivers.dmi new file mode 100644 index 00000000000..74a7b4bc8bb Binary files /dev/null and b/icons/obj/weapons/guns/bows/quivers.dmi differ diff --git a/icons/obj/weapons/guns/projectiles.dmi b/icons/obj/weapons/guns/projectiles.dmi index 7d065335fae..4ffb43a3e79 100644 Binary files a/icons/obj/weapons/guns/projectiles.dmi and b/icons/obj/weapons/guns/projectiles.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 13a29ec9bdd..9c7e5e04e84 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -949,6 +949,7 @@ #include "code\datums\components\mutant_hands.dm" #include "code\datums\components\nuclear_bomb_operator.dm" #include "code\datums\components\omen.dm" +#include "code\datums\components\on_hit_effect.dm" #include "code\datums\components\onwear_mood.dm" #include "code\datums\components\orbiter.dm" #include "code\datums\components\overlay_lighting.dm" @@ -973,6 +974,7 @@ #include "code\datums\components\rotation.dm" #include "code\datums\components\scope.dm" #include "code\datums\components\seclight_attachable.dm" +#include "code\datums\components\sect_nullrod_bonus.dm" #include "code\datums\components\seethrough.dm" #include "code\datums\components\shell.dm" #include "code\datums\components\shielded.dm" @@ -1176,6 +1178,7 @@ #include "code\datums\elements\effect_trail.dm" #include "code\datums\elements\embed.dm" #include "code\datums\elements\empprotection.dm" +#include "code\datums\elements\envenomable_casing.dm" #include "code\datums\elements\eyestab.dm" #include "code\datums\elements\falling_hazard.dm" #include "code\datums\elements\firestacker.dm" @@ -1823,7 +1826,6 @@ #include "code\game\objects\items\handcuffs.dm" #include "code\game\objects\items\his_grace.dm" #include "code\game\objects\items\holosign_creator.dm" -#include "code\game\objects\items\holy_weapons.dm" #include "code\game\objects\items\hot_potato.dm" #include "code\game\objects\items\hourglass.dm" #include "code\game\objects\items\inducer.dm" @@ -3170,7 +3172,6 @@ #include "code\modules\clothing\suits\ablativecoat.dm" #include "code\modules\clothing\suits\armor.dm" #include "code\modules\clothing\suits\bio.dm" -#include "code\modules\clothing\suits\chaplainsuits.dm" #include "code\modules\clothing\suits\cloaks.dm" #include "code\modules\clothing\suits\costume.dm" #include "code\modules\clothing\suits\ethereal.dm" @@ -3576,7 +3577,6 @@ #include "code\modules\jobs\job_types\botanist.dm" #include "code\modules\jobs\job_types\captain.dm" #include "code\modules\jobs\job_types\cargo_technician.dm" -#include "code\modules\jobs\job_types\chaplain.dm" #include "code\modules\jobs\job_types\chemist.dm" #include "code\modules\jobs\job_types\chief_engineer.dm" #include "code\modules\jobs\job_types\chief_medical_officer.dm" @@ -3625,6 +3625,10 @@ #include "code\modules\jobs\job_types\antagonists\space_wizard.dm" #include "code\modules\jobs\job_types\antagonists\wizard_apprentice.dm" #include "code\modules\jobs\job_types\antagonists\xenomorph.dm" +#include "code\modules\jobs\job_types\chaplain\chaplain.dm" +#include "code\modules\jobs\job_types\chaplain\chaplain_costumes.dm" +#include "code\modules\jobs\job_types\chaplain\chaplain_divine_archer.dm" +#include "code\modules\jobs\job_types\chaplain\chaplain_nullrod.dm" #include "code\modules\jobs\job_types\ert\ert_generic.dm" #include "code\modules\jobs\job_types\event\admin.dm" #include "code\modules\jobs\job_types\event\fugitive.dm" @@ -4526,13 +4530,16 @@ #include "code\modules\projectiles\guns\energy.dm" #include "code\modules\projectiles\guns\magic.dm" #include "code\modules\projectiles\guns\ballistic\automatic.dm" -#include "code\modules\projectiles\guns\ballistic\bow.dm" #include "code\modules\projectiles\guns\ballistic\launchers.dm" #include "code\modules\projectiles\guns\ballistic\pistol.dm" #include "code\modules\projectiles\guns\ballistic\revolver.dm" #include "code\modules\projectiles\guns\ballistic\rifle.dm" #include "code\modules\projectiles\guns\ballistic\shotgun.dm" #include "code\modules\projectiles\guns\ballistic\toy.dm" +#include "code\modules\projectiles\guns\ballistic\bows\_bow.dm" +#include "code\modules\projectiles\guns\ballistic\bows\bow_arrows.dm" +#include "code\modules\projectiles\guns\ballistic\bows\bow_quivers.dm" +#include "code\modules\projectiles\guns\ballistic\bows\bow_types.dm" #include "code\modules\projectiles\guns\energy\beam_rifle.dm" #include "code\modules\projectiles\guns\energy\dueling.dm" #include "code\modules\projectiles\guns\energy\energy_gun.dm" @@ -4668,6 +4675,7 @@ #include "code\modules\recycling\disposal\outlet.dm" #include "code\modules\recycling\disposal\pipe.dm" #include "code\modules\recycling\disposal\pipe_sorting.dm" +#include "code\modules\religion\pyre_rites.dm" #include "code\modules\religion\religion_sects.dm" #include "code\modules\religion\religion_structures.dm" #include "code\modules\religion\rites.dm"