mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 22:50:26 +01:00
Sparring Sect! (#61316)
Adds the sparring god. Your deity wants you to go out and spar people for self improvement. Sparring You can create contracts from paper as the chaplain. The contracts come with a set of conditions for the battle. You can set which weapons are allowed. You can set what you earn from winning. You can set where you fight. BOTH participants in the sparring match must agree to the terms for the fight to begin. Changing the terms will remove any other signatures on the contract, requiring them to review and willingly sign again. Setting the stakes to be holy will give you favor for winning the fight. You can only do this once per person, so you can't farm points. You can use points on declaring new areas as arenas, or if you save up enough, buff your heart to keep fighting in dangerous conditions.
This commit is contained in:
@@ -501,6 +501,8 @@
|
||||
#define COMSIG_MOVABLE_UPDATE_GLIDE_SIZE "movable_glide_size"
|
||||
///Called when a movable is hit by a plunger in layer mode, from /obj/item/plunger/attack_atom()
|
||||
#define COMSIG_MOVABLE_CHANGE_DUCT_LAYER "movable_change_duct_layer"
|
||||
///Called when a movable is teleported from `do_teleport()`: (destination, channel)
|
||||
#define COMSIG_MOVABLE_TELEPORTED "movable_teleported"
|
||||
|
||||
// /mob signals
|
||||
|
||||
@@ -1015,6 +1017,8 @@
|
||||
|
||||
///called in /obj/item/gun/process_fire (user, target, params, zone_override)
|
||||
#define COMSIG_GRENADE_DETONATE "grenade_prime"
|
||||
//called from many places in grenade code (armed_by, nade, det_time, delayoverride)
|
||||
#define COMSIG_MOB_GRENADE_ARMED "grenade_mob_armed"
|
||||
///called in /obj/item/gun/process_fire (user, target, params, zone_override)
|
||||
#define COMSIG_GRENADE_ARMED "grenade_armed"
|
||||
|
||||
|
||||
@@ -485,18 +485,6 @@ GLOBAL_LIST_INIT(pda_styles, sortList(list(MONO, VT, ORBITRON, SHARE)))
|
||||
#define FALL_NO_MESSAGE (1<<1) //Used to suppress the "[A] falls through [old_turf]" messages where it'd make little sense at all, like going downstairs.
|
||||
#define FALL_STOP_INTERCEPTING (1<<2) //Used in situations where halting the whole "intercept" loop would be better, like supermatter dusting (and thus deleting) the atom.
|
||||
|
||||
//Religion
|
||||
///role below priests, for losing most powers of priests but still being holy.
|
||||
#define HOLY_ROLE_DEACON 1
|
||||
///default priestly role
|
||||
#define HOLY_ROLE_PRIEST 2
|
||||
///the one who designates the religion
|
||||
#define HOLY_ROLE_HIGHPRIEST 3
|
||||
|
||||
#define ALIGNMENT_GOOD "good"
|
||||
#define ALIGNMENT_NEUT "neutral"
|
||||
#define ALIGNMENT_EVIL "evil"
|
||||
|
||||
|
||||
// Play time / EXP
|
||||
#define PLAYTIME_HARDCORE_RANDOM 120
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
///role below priests, for losing most powers of priests but still being holy.
|
||||
#define HOLY_ROLE_DEACON 1
|
||||
///default priestly role
|
||||
#define HOLY_ROLE_PRIEST 2
|
||||
///the one who designates the religion
|
||||
#define HOLY_ROLE_HIGHPRIEST 3
|
||||
|
||||
#define ALIGNMENT_GOOD "good"
|
||||
#define ALIGNMENT_NEUT "neutral"
|
||||
#define ALIGNMENT_EVIL "evil"
|
||||
|
||||
//## which weapons should we use?
|
||||
|
||||
// unused but for clarity
|
||||
#define CONDITION_FIST_FIGHT 1
|
||||
///can only use the ritual weapons the sparring chaplain makes.
|
||||
#define CONDITION_CEREMONIAL_ONLY 2
|
||||
///melee weapon condition, default sparring condition.
|
||||
#define CONDITION_MELEE_ONLY 3
|
||||
///any weapon is cool... probably a terrible idea against security
|
||||
#define CONDITION_ANY_WEAPON 4
|
||||
|
||||
//
|
||||
///must use weapons the chaplain makes from their sect. no fist fighting, even! it ensures a fair fight.
|
||||
// #define RITUAL_WEAPONS 2
|
||||
|
||||
//## where should we fight?
|
||||
|
||||
// default value - /area/service/chapel
|
||||
|
||||
//## what are the stakes? people you've beaten before can only fight in no stakes battles, to prevent farming
|
||||
|
||||
///just for fun
|
||||
#define STAKES_NONE 1
|
||||
///standard stakes, winning gets you a point. losing counts towards standard excommunication.
|
||||
#define STAKES_HOLY_MATCH 2
|
||||
///no stakes god wise, but whomever wins gets all the money of the other
|
||||
#define STAKES_MONEY_MATCH 3
|
||||
///the winner gets the other's soul. you said this was a neutral sect, right?
|
||||
#define STAKES_YOUR_SOUL 4
|
||||
|
||||
///the left signing part of the contract
|
||||
#define CONTRACT_LEFT_FIELD "left"
|
||||
|
||||
///curses the sinner
|
||||
#define PUNISHMENT_OMEN "omen"
|
||||
///smites the sinner
|
||||
#define PUNISHMENT_LIGHTNING "lightningbolt"
|
||||
///brands the sinner
|
||||
#define PUNISHMENT_BRAND "brand"
|
||||
@@ -325,6 +325,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define TRAIT_BYPASS_MEASURES "bypass_lagswitch_measures"
|
||||
/// Someone can safely be attacked with honorbound with ONLY a combat mode check, the trait is assuring holding a weapon and hitting won't hurt them..
|
||||
#define TRAIT_ALLOWED_HONORBOUND_ATTACK "allowed_honorbound_attack"
|
||||
/// The user is sparring
|
||||
#define TRAIT_SPARRING "sparring"
|
||||
|
||||
#define TRAIT_NOBLEED "nobleed" //This carbon doesn't bleed
|
||||
/// This atom can ignore the "is on a turf" check for simple AI datum attacks, allowing them to attack from bags or lockers as long as any other conditions are met
|
||||
@@ -526,6 +528,12 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
/// If present on a [/mob/living/carbon], will make them appear to have a medium level disease on health HUDs.
|
||||
#define TRAIT_DISEASELIKE_SEVERITY_MEDIUM "diseaselike_severity_medium"
|
||||
|
||||
/// trait denoting someone will crawl faster in soft crit
|
||||
#define TRAIT_TENACIOUS "tenacious"
|
||||
|
||||
/// trait denoting someone will sometimes recover out of crit
|
||||
#define TRAIT_UNBREAKABLE "unbreakable"
|
||||
|
||||
//Medical Categories for quirks
|
||||
#define CAT_QUIRK_ALL 0
|
||||
#define CAT_QUIRK_NOTES 1
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/datum/component/unbreakable
|
||||
COOLDOWN_DECLARE(surge_cooldown)
|
||||
|
||||
/datum/component/unbreakable/Initialize()
|
||||
if(!ishuman(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
ADD_TRAIT(parent, TRAIT_UNBREAKABLE, INNATE_TRAIT)
|
||||
|
||||
/datum/component/unbreakable/Destroy(force, silent)
|
||||
. = ..()
|
||||
REMOVE_TRAIT(parent, TRAIT_UNBREAKABLE, INNATE_TRAIT)
|
||||
|
||||
/datum/component/unbreakable/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_MOB_STATCHANGE, .proc/surge)
|
||||
|
||||
/datum/component/unbreakable/UnregisterFromParent()
|
||||
UnregisterSignal(parent, COMSIG_MOB_STATCHANGE)
|
||||
|
||||
/datum/component/unbreakable/proc/surge(mob/living/carbon/human/surged, new_stat)
|
||||
SIGNAL_HANDLER
|
||||
if(new_stat < SOFT_CRIT || new_stat >= DEAD)
|
||||
return
|
||||
if(!COOLDOWN_FINISHED(src, surge_cooldown))
|
||||
return
|
||||
COOLDOWN_START(src, surge_cooldown, 1 MINUTES)
|
||||
surged.balloon_alert(surged, "you refuse to give up!")//breaks balloon alert conventions by using a "!" for a fail message but that's okay because it's a pretty awesome moment
|
||||
surged.heal_overall_damage(15, 15, 0, BODYPART_ORGANIC)
|
||||
if(surged.reagents.get_reagent_amount(/datum/reagent/medicine/ephedrine) < 20)
|
||||
surged.reagents.add_reagent(/datum/reagent/medicine/ephedrine, 10)
|
||||
if(surged.reagents.get_reagent_amount(/datum/reagent/medicine/epinephrine) < 20)
|
||||
surged.reagents.add_reagent(/datum/reagent/medicine/epinephrine, 10)
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* tenacious element; which makes the parent move faster while crawling
|
||||
*
|
||||
* Used by sparring sect!
|
||||
*/
|
||||
/datum/element/tenacious
|
||||
element_flags = ELEMENT_DETACH
|
||||
|
||||
/datum/element/tenacious/Attach(datum/target)
|
||||
. = ..()
|
||||
|
||||
if(!ishuman(target))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/mob/living/carbon/human/valid_target = target
|
||||
on_stat_change(valid_target, new_stat = valid_target.stat) //immediately try adding movement bonus if they're in soft crit
|
||||
RegisterSignal(target, COMSIG_MOB_STATCHANGE, .proc/on_stat_change)
|
||||
ADD_TRAIT(target, TRAIT_TENACIOUS, INNATE_TRAIT)
|
||||
|
||||
/datum/element/tenacious/Detach(datum/target)
|
||||
. = ..()
|
||||
UnregisterSignal(target, COMSIG_MOB_STATCHANGE)
|
||||
REMOVE_TRAIT(target, TRAIT_TENACIOUS, INNATE_TRAIT)
|
||||
|
||||
///signal called by the stat of the target changing
|
||||
/datum/element/tenacious/proc/on_stat_change(mob/living/carbon/human/target, new_stat)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(new_stat == SOFT_CRIT)
|
||||
target.balloon_alert(target, "your tenacity kicks in")
|
||||
target.add_movespeed_modifier(/datum/movespeed_modifier/tenacious)
|
||||
else
|
||||
target.balloon_alert(target, "your tenacity wears off")
|
||||
target.remove_movespeed_modifier(/datum/movespeed_modifier/tenacious)
|
||||
@@ -283,6 +283,21 @@
|
||||
icon_file = 'icons/obj/items/cleric_mace.dmi'
|
||||
json_config = 'code/datums/greyscale/json_configs/items/cleric_mace_worn_gold.json'
|
||||
|
||||
/datum/greyscale_config/ceremonial_blade
|
||||
name = "Base Ceremonial Blade"
|
||||
icon_file = 'icons/obj/items/ritual_weapon.dmi'
|
||||
json_config = 'code/datums/greyscale/json_configs/items/ceremonial_blade.json'
|
||||
|
||||
/datum/greyscale_config/ceremonial_blade_lefthand
|
||||
name = "Base Held Ceremonial Blade, Left"
|
||||
icon_file = 'icons/obj/items/ritual_weapon.dmi'
|
||||
json_config = 'code/datums/greyscale/json_configs/items/ceremonial_blade_lefthand.json'
|
||||
|
||||
/datum/greyscale_config/ceremonial_blade_righthand
|
||||
name = "Base Held Ceremonial Blade, Right"
|
||||
icon_file = 'icons/obj/items/ritual_weapon.dmi'
|
||||
json_config = 'code/datums/greyscale/json_configs/items/ceremonial_blade_righthand.json'
|
||||
|
||||
/datum/greyscale_config/beret
|
||||
name = "Beret"
|
||||
icon_file = 'icons/obj/clothing/head/beret.dmi'
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"default": [
|
||||
{
|
||||
"type": "icon_state",
|
||||
"icon_state": "base",
|
||||
"blend_mode": "overlay",
|
||||
"color_ids": [ 1 ]
|
||||
},
|
||||
{
|
||||
"type": "icon_state",
|
||||
"icon_state": "handle",
|
||||
"blend_mode": "overlay"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"default": [
|
||||
{
|
||||
"type": "icon_state",
|
||||
"icon_state": "inhand_left",
|
||||
"blend_mode": "overlay",
|
||||
"color_ids": [ 1 ]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"default": [
|
||||
{
|
||||
"type": "icon_state",
|
||||
"icon_state": "inhand_right",
|
||||
"blend_mode": "overlay",
|
||||
"color_ids": [ 1 ]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -26,6 +26,8 @@
|
||||
if (isnull(precision))
|
||||
precision = 0
|
||||
|
||||
SEND_SIGNAL(teleatom, COMSIG_MOVABLE_TELEPORTED, destination, channel)
|
||||
|
||||
switch(channel)
|
||||
if(TELEPORT_CHANNEL_BLUESPACE)
|
||||
if(istype(teleatom, /obj/item/storage/backpack/holding))
|
||||
|
||||
@@ -199,15 +199,6 @@
|
||||
lightningbolt(user)
|
||||
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "honorbound", /datum/mood_event/holy_smite)//permanently lose your moodlet after this
|
||||
|
||||
/datum/mutation/human/honorbound/proc/lightningbolt(mob/living/user)
|
||||
var/turf/lightning_source = get_step(get_step(user, NORTH), NORTH)
|
||||
lightning_source.Beam(user, icon_state="lightning[rand(1,12)]", time = 5)
|
||||
user.adjustFireLoss(LIGHTNING_BOLT_DAMAGE)
|
||||
playsound(get_turf(user), 'sound/magic/lightningbolt.ogg', 50, TRUE)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/human_target = user
|
||||
human_target.electrocution_animation(LIGHTNING_BOLT_ELECTROCUTION_ANIMATION_LENGTH)
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/declare_evil
|
||||
name = "Declare Evil"
|
||||
desc = "If someone is so obviously an evil of this world you can spend a huge amount of favor to declare them guilty."
|
||||
|
||||
@@ -299,3 +299,10 @@
|
||||
infestation_rate = 0.075 // appx 4.33 minutes to reach sepsis without any treatment
|
||||
flesh_damage = 20
|
||||
scar_keyword = "burncritical"
|
||||
|
||||
///special severe wound caused by sparring interference or other god related punishments.
|
||||
/datum/wound/burn/severe/brand
|
||||
name = "Holy Brand"
|
||||
desc = "Patient is suffering extreme burns from a strange brand marking, creating serious risk of infection and greatly reduced limb integrity."
|
||||
examine_desc = "appears to have holy symbols painfully branded into their flesh, leaving severe burns."
|
||||
occur_text = "chars rapidly into a strange pattern of holy symbols, burned into the flesh."
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
icon_state = initial(icon_state) + "_active"
|
||||
playsound(src, 'sound/effects/hit_on_shattered_glass.ogg', volume, TRUE)
|
||||
SEND_SIGNAL(src, COMSIG_GRENADE_ARMED, det_time, delayoverride)
|
||||
if(user)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_GRENADE_ARMED, user, src, det_time, delayoverride)
|
||||
addtimer(CALLBACK(src, .proc/detonate), isnull(delayoverride)? det_time : delayoverride)
|
||||
|
||||
/obj/item/grenade/gas_crystal/healium_crystal
|
||||
|
||||
@@ -4,11 +4,15 @@
|
||||
|
||||
/datum/smite/lightning/effect(client/user, mob/living/target)
|
||||
. = ..()
|
||||
var/turf/lightning_source = get_step(get_step(target, NORTH), NORTH)
|
||||
lightning_source.Beam(target, icon_state="lightning[rand(1,12)]", time = 5)
|
||||
target.adjustFireLoss(LIGHTNING_BOLT_DAMAGE)
|
||||
playsound(get_turf(user), 'sound/magic/lightningbolt.ogg', 50, TRUE)
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/human_target = target
|
||||
human_target.electrocution_animation(LIGHTNING_BOLT_ELECTROCUTION_ANIMATION_LENGTH)
|
||||
lightningbolt(target)
|
||||
to_chat(target, span_userdanger("The gods have punished you for your sins!"), confidential = TRUE)
|
||||
|
||||
///this is the actual bolt effect and damage, made into its own proc because it is used elsewhere
|
||||
/proc/lightningbolt(mob/living/user)
|
||||
var/turf/lightning_source = get_step(get_step(user, NORTH), NORTH)
|
||||
lightning_source.Beam(user, icon_state="lightning[rand(1,12)]", time = 5)
|
||||
user.adjustFireLoss(LIGHTNING_BOLT_DAMAGE)
|
||||
playsound(get_turf(user), 'sound/magic/lightningbolt.ogg', 50, TRUE)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/human_target = user
|
||||
human_target.electrocution_animation(LIGHTNING_BOLT_ELECTROCUTION_ANIMATION_LENGTH)
|
||||
|
||||
@@ -123,8 +123,8 @@
|
||||
|
||||
/datum/antagonist/monkey/leader/on_gain()
|
||||
. = ..()
|
||||
var/obj/item/organ/heart/freedom/F = new
|
||||
F.Insert(owner.current, drop_if_replaced = FALSE)
|
||||
var/obj/item/organ/heart/freedom/super_heart = new
|
||||
super_heart.Insert(owner.current, drop_if_replaced = FALSE)
|
||||
owner.special_role = "Monkey Leader"
|
||||
|
||||
/datum/antagonist/monkey/leader/on_removal()
|
||||
|
||||
@@ -88,6 +88,15 @@
|
||||
one_use = TRUE
|
||||
grab_sleeping = FALSE
|
||||
|
||||
/obj/item/soulstone/anybody/chaplain/sparring
|
||||
icon_state = "purified_soulstone"
|
||||
theme = THEME_HOLY
|
||||
|
||||
/obj/item/soulstone/anybody/sparring/Initialize(mapload)
|
||||
. = ..()
|
||||
name = "[GLOB.deity]'s punishment"
|
||||
desc = "A prison for those who lost [GLOB.deity]'s game."
|
||||
|
||||
/obj/item/soulstone/anybody/mining
|
||||
grab_sleeping = FALSE
|
||||
|
||||
@@ -260,7 +269,8 @@
|
||||
return TRUE
|
||||
else
|
||||
to_chat(user, "[span_userdanger("Capture failed!")]: The soul has already fled its mortal frame. You attempt to bring it back...")
|
||||
return getCultGhost(victim,user)
|
||||
INVOKE_ASYNC(src, .proc/getCultGhost, victim, user)
|
||||
return TRUE //it'll probably get someone ;)
|
||||
|
||||
///captures a shade that was previously released from a soulstone.
|
||||
/obj/item/soulstone/proc/capture_shade(mob/living/simple_animal/shade/shade, mob/user)
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
multiplicative_slowdown = -7
|
||||
movetypes = GROUND
|
||||
|
||||
/datum/movespeed_modifier/tenacious
|
||||
multiplicative_slowdown = -0.7
|
||||
movetypes = GROUND
|
||||
|
||||
/datum/movespeed_modifier/sanity
|
||||
id = MOVESPEED_ID_SANITY
|
||||
movetypes = (~FLYING)
|
||||
|
||||
@@ -377,3 +377,32 @@
|
||||
return TRUE
|
||||
|
||||
#undef MINIMUM_YUCK_REQUIRED
|
||||
|
||||
/datum/religion_sect/spar
|
||||
name = "Sparring God"
|
||||
quote = "Your next swing must be faster, neophyte. Steel your heart."
|
||||
desc = "Spar other crewmembers to gain favor or other rewards. Exchange favor to steel yourself against real battles."
|
||||
tgui_icon = "fist-raised"
|
||||
altar_icon_state = "convertaltar-orange"
|
||||
alignment = ALIGNMENT_NEUT
|
||||
rites_list = list(
|
||||
/datum/religion_rites/sparring_contract,
|
||||
/datum/religion_rites/ceremonial_weapon,
|
||||
/datum/religion_rites/declare_arena,
|
||||
/datum/religion_rites/tenacious,
|
||||
/datum/religion_rites/unbreakable,
|
||||
)
|
||||
///the one allowed contract. making a new contract dusts the old one
|
||||
var/obj/item/sparring_contract/existing_contract
|
||||
///places you can spar in. rites can be used to expand this list with new arenas!
|
||||
var/list/arenas = list(
|
||||
"Recreation Area" = /area/commons/fitness/recreation,
|
||||
"Chapel" = /area/service/chapel
|
||||
)
|
||||
///how many matches you've lost with holy stakes. 3 = excommunication
|
||||
var/matches_lost = 0
|
||||
///past opponents who you've beaten in holy battles. You can't fight them again to prevent favor farming
|
||||
var/list/past_opponents = list()
|
||||
|
||||
/datum/religion_sect/spar/tool_examine(mob/living/holy_creature)
|
||||
return "You have [round(favor)] sparring matches won in [GLOB.deity]'s name to redeem. You have lost [matches_lost] holy matches. You will be excommunicated after losing three matches."
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
ritual_invocations =list( "Let your will power our forges.",
|
||||
"...Help us in our great conquest!")
|
||||
invoke_msg = "The end of flesh is near!"
|
||||
favor_cost = 2000
|
||||
favor_cost = 2000
|
||||
|
||||
/datum/religion_rites/machine_blessing/invoke_effect(mob/living/user, atom/movable/religious_tool)
|
||||
..()
|
||||
@@ -603,4 +603,141 @@
|
||||
new /obj/item/ritual_totem(altar_turf)
|
||||
return TRUE
|
||||
|
||||
///sparring god rites
|
||||
|
||||
/datum/religion_rites/sparring_contract
|
||||
name = "Summon Sparring Contract"
|
||||
desc = "Turns some paper into a sparring contract."
|
||||
invoke_msg = "I will train in the name of my god."
|
||||
///paper to turn into a sparring contract
|
||||
var/obj/item/paper/contract_target
|
||||
|
||||
/datum/religion_rites/sparring_contract/perform_rite(mob/living/user, atom/religious_tool)
|
||||
for(var/obj/item/paper/could_contract in get_turf(religious_tool))
|
||||
if(could_contract.info) //blank paper pls
|
||||
continue
|
||||
contract_target = could_contract
|
||||
return ..()
|
||||
to_chat(user, span_warning("You need to place blank paper on [religious_tool] to do this!"))
|
||||
return FALSE
|
||||
|
||||
/datum/religion_rites/sparring_contract/invoke_effect(mob/living/user, atom/movable/religious_tool)
|
||||
..()
|
||||
var/obj/item/paper/blank_paper = contract_target
|
||||
var/turf/tool_turf = get_turf(religious_tool)
|
||||
contract_target = null
|
||||
if(QDELETED(blank_paper) || !(tool_turf == blank_paper.loc)) //check if the same paper is still there
|
||||
to_chat(user, span_warning("Your target left the altar!"))
|
||||
return FALSE
|
||||
blank_paper.visible_message(span_notice("words magically form on [blank_paper]!"))
|
||||
playsound(tool_turf, 'sound/effects/pray.ogg', 50, TRUE)
|
||||
var/datum/religion_sect/spar/sect = GLOB.religious_sect
|
||||
if(sect.existing_contract)
|
||||
sect.existing_contract.visible_message(span_warning("[src] fizzles into nothing!"))
|
||||
qdel(sect.existing_contract)
|
||||
sect.existing_contract = new /obj/item/sparring_contract(tool_turf)
|
||||
qdel(blank_paper)
|
||||
return TRUE
|
||||
|
||||
/datum/religion_rites/declare_arena
|
||||
name = "Declare Arena"
|
||||
desc = "Declare a new area as fit for sparring. You'll be able to select it in contracts."
|
||||
ritual_length = 6 SECONDS
|
||||
ritual_invocations = list("I seek new horizons ...")
|
||||
invoke_msg = "... may my climb be steep."
|
||||
favor_cost = 1 //only costs one holy battle for a new area
|
||||
var/area/area_instance
|
||||
|
||||
/datum/religion_rites/declare_arena/perform_rite(mob/living/user, atom/religious_tool)
|
||||
var/list/filtered = list()
|
||||
for(var/area/unfiltered_area as anything in GLOB.sortedAreas)
|
||||
if(istype(unfiltered_area, /area/centcom)) //youuu dont need thaaat
|
||||
continue
|
||||
if(!(unfiltered_area.area_flags & HIDDEN_AREA))
|
||||
filtered += unfiltered_area
|
||||
area_instance = tgui_input_list(user, "Choose an area to mark as an arena!", "Arena Declaration", filtered)
|
||||
if(!area_instance)
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/datum/religion_rites/declare_arena/invoke_effect(mob/living/user, atom/movable/religious_tool)
|
||||
. = ..()
|
||||
var/datum/religion_sect/spar/sect = GLOB.religious_sect
|
||||
sect.arenas[area_instance.name] = area_instance.type
|
||||
to_chat(user, span_warning("[area_instance] is a now an option to select on sparring contracts."))
|
||||
|
||||
/datum/religion_rites/ceremonial_weapon
|
||||
name = "Forge Ceremonial Gear"
|
||||
desc = "Turn some material into ceremonial gear. Ceremonial blades are weak outside of sparring, and are quite heavy to lug around."
|
||||
ritual_length = 10 SECONDS
|
||||
invoke_msg = "Weapons in your name! Battles with your blood!"
|
||||
favor_cost = 0
|
||||
///the material that will be attempted to be forged into a weapon
|
||||
var/obj/item/stack/sheet/converted
|
||||
|
||||
/datum/religion_rites/ceremonial_weapon/perform_rite(mob/living/user, atom/religious_tool)
|
||||
for(var/obj/item/stack/sheet/could_blade in get_turf(religious_tool))
|
||||
if(!(GET_MATERIAL_REF(could_blade.material_type) in SSmaterials.materials_by_category[MAT_CATEGORY_ITEM_MATERIAL]))
|
||||
continue
|
||||
if(could_blade.amount < 5)
|
||||
continue
|
||||
converted = could_blade
|
||||
return ..()
|
||||
to_chat(user, span_warning("You need at least 5 sheets of a material that can be made into items!"))
|
||||
return FALSE
|
||||
|
||||
/datum/religion_rites/ceremonial_weapon/invoke_effect(mob/living/user, atom/movable/religious_tool)
|
||||
..()
|
||||
var/altar_turf = get_turf(religious_tool)
|
||||
var/obj/item/stack/sheet/used_for_blade = converted
|
||||
converted = null
|
||||
if(QDELETED(used_for_blade) || !(get_turf(religious_tool) == used_for_blade.loc) || used_for_blade.amount < 5) //check if the same food is still there
|
||||
to_chat(user, span_warning("Your target left the altar!"))
|
||||
return FALSE
|
||||
var/material_used = used_for_blade.material_type
|
||||
to_chat(user, span_warning("[used_for_blade] reshapes into a ceremonial blade!"))
|
||||
if(!used_for_blade.use(5))//use 5 of the material
|
||||
return
|
||||
var/obj/item/ceremonial_blade/blade = new(altar_turf)
|
||||
blade.set_custom_materials(list(GET_MATERIAL_REF(material_used) = MINERAL_MATERIAL_AMOUNT * 5))
|
||||
return TRUE
|
||||
|
||||
/datum/religion_rites/unbreakable
|
||||
name = "Become Unbreakable"
|
||||
desc = "Your training has made you unbreakable. In times of crisis, you will attempt to keep fighting on."
|
||||
ritual_length = 10 SECONDS
|
||||
invoke_msg = "My will must be unbreakable. Grant me this boon!"
|
||||
favor_cost = 4 //4 duels won
|
||||
|
||||
/datum/religion_rites/unbreakable/perform_rite(mob/living/carbon/human/user, atom/religious_tool)
|
||||
if(!ishuman(user))
|
||||
return FALSE
|
||||
if(HAS_TRAIT_FROM(user, TRAIT_UNBREAKABLE, INNATE_TRAIT))
|
||||
to_chat(user, span_warning("Your spirit is already unbreakable!"))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/religion_rites/unbreakable/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool)
|
||||
..()
|
||||
to_chat(user, span_nicegreen("You feel [GLOB.deity]'s will to keep fighting pouring into you!"))
|
||||
user.AddComponent(/datum/component/unbreakable)
|
||||
|
||||
/datum/religion_rites/tenacious
|
||||
name = "Become Tenacious"
|
||||
desc = "Your training has made you tenacious. In times of crisis, you will be able to crawl faster."
|
||||
ritual_length = 10 SECONDS
|
||||
invoke_msg = "Grant me your tenacity! I have proven myself!"
|
||||
favor_cost = 3 //3 duels won
|
||||
|
||||
/datum/religion_rites/tenacious/perform_rite(mob/living/carbon/human/user, atom/religious_tool)
|
||||
if(!ishuman(user))
|
||||
return FALSE
|
||||
if(HAS_TRAIT_FROM(user, TRAIT_TENACIOUS, INNATE_TRAIT))
|
||||
to_chat(user, span_warning("Your spirit is already tenacious!"))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/religion_rites/tenacious/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool)
|
||||
..()
|
||||
to_chat(user, span_nicegreen("You feel [GLOB.deity]'s tenacity pouring into you!"))
|
||||
user.AddElement(/datum/element/tenacious)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
///ritual weapons. they're really bad, but they become normal weapons when sparring.
|
||||
/obj/item/ceremonial_blade
|
||||
name = "ceremonial blade"
|
||||
desc = "A blade created to spar with. It seems weak, but if you spar with it...?"
|
||||
icon_state = "default"
|
||||
inhand_icon_state = "default"
|
||||
icon = 'icons/obj/items/ritual_weapon.dmi'
|
||||
|
||||
//does the exact thing we want so heck why not
|
||||
greyscale_config = /datum/greyscale_config/ceremonial_blade
|
||||
greyscale_config_inhand_left = /datum/greyscale_config/ceremonial_blade_lefthand
|
||||
greyscale_config_inhand_right = /datum/greyscale_config/ceremonial_blade_righthand
|
||||
greyscale_colors = "#FFFFFF"
|
||||
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
custom_materials = list(/datum/material/iron = 12000) //Defaults to an Iron blade.
|
||||
force = 2 //20
|
||||
throwforce = 1 //10
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts")
|
||||
attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut")
|
||||
block_chance = 3 //30
|
||||
sharpness = SHARP_EDGED
|
||||
max_integrity = 200
|
||||
material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE //doesn't affect stats of the weapon as to avoid gamering your opponent with a dope weapon
|
||||
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
/obj/item/ceremonial_blade/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/butchering, 40, 105)
|
||||
RegisterSignal(src, COMSIG_ITEM_SHARPEN_ACT, .proc/block_sharpening)
|
||||
|
||||
/obj/item/ceremonial_blade/melee_attack_chain(mob/user, atom/target, params)
|
||||
if(!HAS_TRAIT(target, TRAIT_SPARRING))
|
||||
return ..()
|
||||
var/old_force = force
|
||||
var/old_throwforce = throwforce
|
||||
force *= 10
|
||||
throwforce *= 10
|
||||
. = ..()
|
||||
force = old_force
|
||||
throwforce = old_throwforce
|
||||
|
||||
/obj/item/ceremonial_blade/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
if(attack_type != MELEE_ATTACK || !ishuman(hitby.loc))
|
||||
return ..()
|
||||
if(HAS_TRAIT(hitby.loc, TRAIT_SPARRING))
|
||||
//becomes 30 block
|
||||
final_block_chance *= 10
|
||||
. = ..()
|
||||
|
||||
/obj/item/ceremonial_blade/proc/block_sharpening(datum/source, increment, max)
|
||||
SIGNAL_HANDLER
|
||||
//this breaks it
|
||||
return COMPONENT_BLOCK_SHARPEN_BLOCKED
|
||||
@@ -0,0 +1,145 @@
|
||||
/obj/item/sparring_contract
|
||||
desc = "A contract for setting up sparring matches. Both sparring partners must agree with the terms to begin."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "scroll"
|
||||
drop_sound = 'sound/items/handling/paper_drop.ogg'
|
||||
pickup_sound = 'sound/items/handling/paper_pickup.ogg'
|
||||
throw_range = 1
|
||||
throw_speed = 1
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
///what weapons will be allowed during the sparring match
|
||||
var/weapons_condition = CONDITION_MELEE_ONLY
|
||||
///what arena the fight will take place in
|
||||
var/arena_condition = /area/service/chapel
|
||||
///what stakes the fight will have
|
||||
var/stakes_condition = STAKES_NONE
|
||||
///who has signed this contract. fills itself with WEAKREFS, to prevent hanging references
|
||||
var/list/datum/weakref/signed_by = list(null, null)
|
||||
|
||||
/obj/item/sparring_contract/Initialize()
|
||||
. = ..()
|
||||
name = "[GLOB.deity]'s sparring contract"
|
||||
|
||||
/obj/item/sparring_contract/Destroy()
|
||||
QDEL_NULL(signed_by)
|
||||
var/datum/religion_sect/spar/sect = GLOB.religious_sect
|
||||
sect?.existing_contract = null
|
||||
. = ..()
|
||||
|
||||
/obj/item/sparring_contract/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "SparringContract", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/sparring_contract/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/area/arena = GLOB.areas_by_type[arena_condition]
|
||||
data["set_weapon"] = weapons_condition
|
||||
data["set_area"] = arena?.name
|
||||
data["set_stakes"] = stakes_condition
|
||||
data["possible_areas"] = get_possible_areas()
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/sparring_contract/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/area/arena = GLOB.areas_by_type[arena_condition]
|
||||
var/mob/living/carbon/human/left_partner
|
||||
if(signed_by[1])
|
||||
left_partner = signed_by[1].resolve()
|
||||
var/mob/living/carbon/human/right_partner
|
||||
if(signed_by[2])
|
||||
right_partner = signed_by[2].resolve()
|
||||
data["in_area"] = ((left_partner && right_partner && arena) && (left_partner in arena.contents) && (right_partner in arena.contents))
|
||||
data["no_chaplains"] = (!left_partner?.mind?.holy_role && !right_partner?.mind?.holy_role)
|
||||
data["left_sign"] = left_partner ? left_partner.real_name : "none"
|
||||
data["right_sign"] = right_partner ? right_partner.real_name : "none"
|
||||
return data
|
||||
|
||||
/obj/item/sparring_contract/proc/get_possible_areas()
|
||||
var/list/area_names = list()
|
||||
var/datum/religion_sect/spar/sect = GLOB.religious_sect
|
||||
for(var/key in sect.arenas)
|
||||
area_names += key
|
||||
return area_names
|
||||
|
||||
/obj/item/sparring_contract/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/mob/user = usr
|
||||
|
||||
if(!ishuman(user))
|
||||
to_chat(user, span_warning("This contract refuses to be signed by a lesser creature such as yourself."))
|
||||
return
|
||||
|
||||
var/datum/religion_sect/spar/sect = GLOB.religious_sect
|
||||
|
||||
var/list/resolved_opponents = list()
|
||||
for(var/datum/weakref/resolve_me as anything in sect.past_opponents)
|
||||
var/resolved = resolve_me.resolve()
|
||||
if(!isnull(resolved))
|
||||
resolved_opponents += resolved
|
||||
|
||||
if(user in resolved_opponents && params["stakes"] == STAKES_HOLY_MATCH)
|
||||
to_chat(user, span_warning("This contract refuses to be signed up for a holy match by a previous holy match loser. Pick a different stake!"))
|
||||
|
||||
//any updating of the terms should update the UI to display new terms
|
||||
. = TRUE
|
||||
|
||||
var/mob/living/carbon/human/left_partner
|
||||
if(signed_by[1])
|
||||
left_partner = signed_by[1].resolve()
|
||||
var/mob/living/carbon/human/right_partner
|
||||
if(signed_by[2])
|
||||
right_partner = signed_by[2].resolve()
|
||||
|
||||
switch(action)
|
||||
if("clear")
|
||||
signed_by = list(null, null)//remove weakrefs
|
||||
if("fight")
|
||||
if(!left_partner || !right_partner || !left_partner.mind || !right_partner.mind)
|
||||
return
|
||||
if(HAS_TRAIT(left_partner, TRAIT_SPARRING) || HAS_TRAIT(right_partner, TRAIT_SPARRING))
|
||||
to_chat(user, span_warning("One participant is already sparring!"))
|
||||
return
|
||||
var/chaplain = left_partner.mind.holy_role ? left_partner : right_partner
|
||||
var/opponent = left_partner.mind.holy_role ? right_partner : left_partner
|
||||
new /datum/sparring_match(weapons_condition, GLOB.areas_by_type[arena_condition], stakes_condition, chaplain, opponent)
|
||||
qdel(src)
|
||||
if("sign")
|
||||
if(user == left_partner || user == right_partner)
|
||||
to_chat(user, span_warning("You've already signed one side of the contract."))
|
||||
return
|
||||
var/area/arena_condition_name = GLOB.areas_by_type[arena_condition]
|
||||
arena_condition_name = format_text(arena_condition_name.name)
|
||||
//setting/checking for terms changed
|
||||
var/terms_changed = FALSE
|
||||
if(params["weapon"] != weapons_condition)
|
||||
if(!params["weapon"])
|
||||
return //they hit f5 to clear data then submitted
|
||||
terms_changed = TRUE
|
||||
weapons_condition = params["weapon"]
|
||||
if(params["area"] != arena_condition_name)
|
||||
if(!params["area"])
|
||||
return //they hit f5 to clear data then submitted
|
||||
terms_changed = TRUE
|
||||
var/new_area_condition = sect.arenas[params["area"]]
|
||||
arena_condition = new_area_condition
|
||||
if(params["stakes"] != stakes_condition)
|
||||
if(!params["stakes"])
|
||||
return //they hit f5 to clear data then submitted
|
||||
terms_changed = TRUE
|
||||
stakes_condition = params["stakes"]
|
||||
//if you change the terms you have to get the other person to sign again.
|
||||
if(terms_changed && (left_partner || right_partner))
|
||||
signed_by = list(null, null)//remove weakrefs
|
||||
to_chat(user, span_warning("You will need to get your sparring partner to sign again under these new terms you've set."))
|
||||
//fluff and signing
|
||||
var/datum/weakref/user_ref = WEAKREF(user)
|
||||
if(params["sign_position"] == CONTRACT_LEFT_FIELD)
|
||||
signed_by[1] = user_ref
|
||||
else
|
||||
signed_by[2] = user_ref
|
||||
@@ -0,0 +1,304 @@
|
||||
/datum/sparring_match
|
||||
///the chaplain. it isn't actually a chaplain all the time, but in the cases where the chaplain is needed this will always be them.
|
||||
var/mob/living/carbon/human/chaplain
|
||||
///the other fighter
|
||||
var/mob/living/carbon/human/opponent
|
||||
///what weapons will be allowed during the sparring match
|
||||
var/weapons_condition
|
||||
///area instance the participants must stay in
|
||||
var/area/arena_condition
|
||||
///what stakes the fight will have
|
||||
var/stakes_condition
|
||||
///cheats from the chaplain
|
||||
var/chaplain_violations_allowed = 2
|
||||
///cheats from the non-chaplain
|
||||
var/opponent_violations_allowed = 2
|
||||
///outside interventions that ruin the match
|
||||
var/flubs = 2
|
||||
|
||||
/datum/sparring_match/New(weapons_condition, arena_condition, stakes_condition, mob/living/carbon/human/chaplain, mob/living/carbon/human/opponent)
|
||||
. = ..()
|
||||
src.weapons_condition = weapons_condition
|
||||
src.arena_condition = arena_condition
|
||||
src.stakes_condition = stakes_condition
|
||||
src.chaplain = chaplain
|
||||
src.opponent = opponent
|
||||
ADD_TRAIT(chaplain, TRAIT_SPARRING, TRAIT_GENERIC)
|
||||
ADD_TRAIT(opponent, TRAIT_SPARRING, TRAIT_GENERIC)
|
||||
hook_signals(chaplain)
|
||||
hook_signals(opponent)
|
||||
chaplain.add_filter("sparring_outline", 9, list("type" = "outline", "color" = "#e02200"))
|
||||
opponent.add_filter("sparring_outline", 9, list("type" = "outline", "color" = "#004ee0"))
|
||||
|
||||
/datum/sparring_match/proc/hook_signals(mob/living/carbon/human/sparring)
|
||||
//weapon conditions
|
||||
if(weapons_condition < CONDITION_ANY_WEAPON)
|
||||
RegisterSignal(sparring, COMSIG_MOB_FIRED_GUN, .proc/gun_violation)
|
||||
RegisterSignal(sparring, COMSIG_MOB_GRENADE_ARMED, .proc/grenade_violation)
|
||||
if(weapons_condition <= CONDITION_CEREMONIAL_ONLY)
|
||||
RegisterSignal(sparring, COMSIG_PARENT_ATTACKBY, .proc/melee_violation)
|
||||
//arena conditions
|
||||
RegisterSignal(sparring, COMSIG_MOVABLE_MOVED, .proc/arena_violation)
|
||||
//severe violations (insta violation win for other party) conditions
|
||||
RegisterSignal(sparring, COMSIG_MOVABLE_TELEPORTED, .proc/teleport_violation)
|
||||
//win conditions
|
||||
RegisterSignal(sparring, COMSIG_MOB_STATCHANGE, .proc/check_for_victory)
|
||||
//flub conditions
|
||||
RegisterSignal(sparring, COMSIG_PARENT_ATTACKBY, .proc/outsider_interference)
|
||||
RegisterSignal(sparring, COMSIG_ATOM_HULK_ATTACK, .proc/hulk_interference)
|
||||
RegisterSignal(sparring, COMSIG_ATOM_ATTACK_HAND, .proc/hand_interference)
|
||||
RegisterSignal(sparring, COMSIG_ATOM_ATTACK_PAW, .proc/paw_interference)
|
||||
RegisterSignal(sparring, COMSIG_ATOM_HITBY, .proc/thrown_interference)
|
||||
RegisterSignal(sparring, COMSIG_ATOM_BULLET_ACT, .proc/projectile_interference)
|
||||
//severe flubs (insta match ender, no winners) conditions
|
||||
RegisterSignal(sparring, COMSIG_LIVING_DEATH, .proc/death_flub)
|
||||
RegisterSignal(sparring, COMSIG_PARENT_QDELETING, .proc/deletion_flub)
|
||||
|
||||
/datum/sparring_match/proc/unhook_signals(mob/living/carbon/human/sparring)
|
||||
if(!sparring)
|
||||
return
|
||||
UnregisterSignal(sparring, list(
|
||||
COMSIG_MOB_FIRED_GUN,
|
||||
COMSIG_MOB_GRENADE_ARMED,
|
||||
COMSIG_MOB_ITEM_ATTACK,
|
||||
COMSIG_MOVABLE_MOVED,
|
||||
COMSIG_MOVABLE_TELEPORTED,
|
||||
COMSIG_MOB_STATCHANGE,
|
||||
COMSIG_PARENT_ATTACKBY,
|
||||
COMSIG_ATOM_HULK_ATTACK,
|
||||
COMSIG_ATOM_ATTACK_HAND,
|
||||
COMSIG_ATOM_ATTACK_PAW,
|
||||
COMSIG_ATOM_HITBY,
|
||||
COMSIG_ATOM_BULLET_ACT,
|
||||
COMSIG_LIVING_DEATH,
|
||||
COMSIG_PARENT_QDELETING,
|
||||
))
|
||||
|
||||
///someone is changing health state, end the fight in crit
|
||||
/datum/sparring_match/proc/check_for_victory(datum/participant, new_stat)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
//death needs to be a flub, conscious means they haven't won
|
||||
if(new_stat == CONSCIOUS || new_stat == DEAD)
|
||||
return
|
||||
if(participant == chaplain)
|
||||
end_match(opponent, chaplain)
|
||||
else
|
||||
end_match(chaplain, opponent)
|
||||
|
||||
// SIGNALS THAT ARE FOR BEING ATTACKED FIRST (GUILTY)
|
||||
/datum/sparring_match/proc/outsider_interference(datum/source, obj/item/I, mob/attacker)
|
||||
SIGNAL_HANDLER
|
||||
if(attacker == chaplain || attacker == opponent)
|
||||
return
|
||||
INVOKE_ASYNC(src, .proc/flub, attacker)
|
||||
|
||||
/datum/sparring_match/proc/hulk_interference(datum/source, mob/attacker)
|
||||
SIGNAL_HANDLER
|
||||
if((attacker == chaplain || attacker == opponent))
|
||||
// fist fighting a hulk is so dumb. i can't fathom why you would do this.
|
||||
return
|
||||
INVOKE_ASYNC(src, .proc/flub, attacker)
|
||||
|
||||
/datum/sparring_match/proc/hand_interference(datum/source, mob/living/attacker)
|
||||
SIGNAL_HANDLER
|
||||
if(attacker == chaplain || attacker == opponent)
|
||||
//you can pretty much always use fists as a participant
|
||||
return
|
||||
|
||||
INVOKE_ASYNC(src, .proc/flub, attacker)
|
||||
|
||||
/datum/sparring_match/proc/paw_interference(datum/source, mob/living/attacker)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(attacker == chaplain || attacker == opponent)
|
||||
//you can pretty much always use paws as a participant
|
||||
return
|
||||
|
||||
INVOKE_ASYNC(src, .proc/flub, attacker)
|
||||
|
||||
/datum/sparring_match/proc/thrown_interference(datum/source, atom/movable/thrown_movable, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
SIGNAL_HANDLER
|
||||
if(istype(thrown_movable, /obj/item))
|
||||
var/mob/living/honorbound = source
|
||||
var/obj/item/thrown_item = thrown_movable
|
||||
var/mob/thrown_by = thrown_item.thrownby?.resolve()
|
||||
if(thrown_item.throwforce < honorbound.health && ishuman(thrown_by))
|
||||
INVOKE_ASYNC(src, .proc/flub, thrown_by)
|
||||
|
||||
/datum/sparring_match/proc/projectile_interference(datum/participant, obj/projectile/proj)
|
||||
SIGNAL_HANDLER
|
||||
if(proj.firer == chaplain || proj.firer == opponent)
|
||||
//oh, well that's allowed. or maybe it isn't. doesn't matter because firing the gun will trigger a violation, so no additional violation needed
|
||||
return
|
||||
var/mob/living/interfering
|
||||
if(isliving(proj.firer))
|
||||
interfering = proj.firer
|
||||
INVOKE_ASYNC(src, .proc/flub, interfering)
|
||||
|
||||
///someone randomly fucking died
|
||||
/datum/sparring_match/proc/death_flub(datum/deceased)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
flubbed_match()
|
||||
|
||||
///someone randomly fucking deleted
|
||||
/datum/sparring_match/proc/deletion_flub(datum/qdeleting)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
flubbed_match()
|
||||
|
||||
///someone used a gun
|
||||
/datum/sparring_match/proc/gun_violation(datum/offender)
|
||||
SIGNAL_HANDLER
|
||||
violation(offender, "using guns")
|
||||
|
||||
///someone used a grenade
|
||||
/datum/sparring_match/proc/grenade_violation(datum/offender)
|
||||
SIGNAL_HANDLER
|
||||
violation(offender, "using grenades")
|
||||
|
||||
///someone used melee weapons
|
||||
/datum/sparring_match/proc/melee_violation(datum/offender, obj/item/thing, mob/user, params)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(weapons_condition != CONDITION_CEREMONIAL_ONLY)
|
||||
violation(offender, "using melee weapons")
|
||||
if(istype(thing, /obj/item/ceremonial_blade))
|
||||
return
|
||||
violation(offender, "using non ceremonial weapons")
|
||||
|
||||
/datum/sparring_match/proc/teleport_violation(datum/offender)
|
||||
SIGNAL_HANDLER
|
||||
if(offender == chaplain)
|
||||
end_match(opponent, chaplain, violation_victory = TRUE)
|
||||
else
|
||||
end_match(chaplain, opponent, violation_victory = TRUE)
|
||||
|
||||
///someone tried to leave
|
||||
/datum/sparring_match/proc/arena_violation(atom/movable/mover, atom/oldloc, direction)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/area/inhabited_area = get_area(mover)
|
||||
if(inhabited_area == arena_condition)
|
||||
return //still in the ring!! :)
|
||||
|
||||
violation(mover, "leaving the arena")
|
||||
var/atom/throw_target = get_edge_target_turf(mover, REVERSE_DIR(direction))
|
||||
mover.throw_at(throw_target, 6, 4)
|
||||
|
||||
/datum/sparring_match/proc/violation(mob/living/carbon/human/offender, reason)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(offender, span_userdanger("Violation! No [reason]!"))
|
||||
if(offender == chaplain)
|
||||
chaplain_violations_allowed--
|
||||
if(!chaplain_violations_allowed)
|
||||
end_match(opponent, chaplain, violation_victory = TRUE)
|
||||
else
|
||||
opponent_violations_allowed--
|
||||
if(!opponent_violations_allowed)
|
||||
end_match(chaplain, opponent, violation_victory = TRUE)
|
||||
|
||||
/datum/sparring_match/proc/flub(mob/living/interfering)
|
||||
if(interfering)
|
||||
var/list/possible_punishments = list(PUNISHMENT_OMEN, PUNISHMENT_LIGHTNING)
|
||||
if(ishuman(interfering))
|
||||
possible_punishments += PUNISHMENT_BRAND
|
||||
switch(pick(possible_punishments))
|
||||
if(PUNISHMENT_OMEN)
|
||||
to_chat(interfering, span_warning("You get a bad feeling... for interfering with [chaplain]'s sparring match..."))
|
||||
interfering.AddComponent(/datum/component/omen, TRUE, null, FALSE)
|
||||
if(PUNISHMENT_LIGHTNING)
|
||||
to_chat(interfering, span_warning("[GLOB.deity] has punished you for interfering with [chaplain]'s sparring match!"))
|
||||
lightningbolt(interfering)
|
||||
if(PUNISHMENT_BRAND)
|
||||
var/mob/living/carbon/human/branded = interfering
|
||||
to_chat(interfering, span_warning("[GLOB.deity] brands your flesh for interfering with [chaplain]'s sparring match!!"))
|
||||
var/obj/item/bodypart/branded_limb = pick(branded.bodyparts)
|
||||
branded_limb.force_wound_upwards(/datum/wound/burn/severe/brand)
|
||||
branded.emote("scream")
|
||||
|
||||
flubs--
|
||||
if(!flubs) //too many interferences
|
||||
flubbed_match()
|
||||
|
||||
///this match was interfered on, nobody wins or loses anything, just end
|
||||
/datum/sparring_match/proc/flubbed_match()
|
||||
cleanup_sparring_match()
|
||||
|
||||
if(chaplain) //flubing means we don't know who is still standing
|
||||
to_chat(chaplain, span_boldannounce("The match was flub'd! No winners, no losers. You may restart the match with another contract."))
|
||||
if(opponent)
|
||||
to_chat(opponent, span_boldannounce("The match was flub'd! No winners, no losers."))
|
||||
qdel(src)
|
||||
|
||||
///helper to remove all the effects after a match ends
|
||||
/datum/sparring_match/proc/cleanup_sparring_match()
|
||||
REMOVE_TRAIT(chaplain, TRAIT_SPARRING, TRAIT_GENERIC)
|
||||
REMOVE_TRAIT(opponent, TRAIT_SPARRING, TRAIT_GENERIC)
|
||||
unhook_signals(chaplain)
|
||||
unhook_signals(opponent)
|
||||
chaplain.remove_filter("sparring_outline")
|
||||
opponent.remove_filter("sparring_outline")
|
||||
|
||||
/datum/sparring_match/proc/end_match(mob/living/carbon/human/winner, mob/living/carbon/human/loser, violation_victory = FALSE)
|
||||
cleanup_sparring_match()
|
||||
to_chat(chaplain, span_boldannounce("[violation_victory ? "[loser] DISQUALIFIED!" : ""] [winner] HAS WON!"))
|
||||
to_chat(opponent, span_boldannounce("[violation_victory ? "[loser] DISQUALIFIED!" : ""] [winner] HAS WON!"))
|
||||
win(winner, loser, violation_victory)
|
||||
lose(loser, winner)
|
||||
if(stakes_condition != STAKES_YOUR_SOUL)
|
||||
var/healing_message = "You may want to heal up the loser now."
|
||||
if(winner == chaplain)
|
||||
healing_message += " Your bible will heal the loser for awhile."
|
||||
to_chat(winner, span_notice(healing_message))
|
||||
qdel(src)
|
||||
|
||||
///most of the effects are handled on `lose()` instead.
|
||||
/datum/sparring_match/proc/win(mob/living/carbon/human/winner, mob/living/carbon/human/loser, violation_victory)
|
||||
switch(stakes_condition)
|
||||
if(STAKES_HOLY_MATCH)
|
||||
if(winner == chaplain)
|
||||
if(violation_victory)
|
||||
to_chat(winner, span_warning("[GLOB.deity] is not entertained from a matched decided by violations. No favor awarded..."))
|
||||
else
|
||||
to_chat(winner, span_nicegreen("You've won favor with [GLOB.deity]!"))
|
||||
var/datum/religion_sect/spar/sect = GLOB.religious_sect
|
||||
sect.adjust_favor(1, winner)
|
||||
sect.past_opponents += WEAKREF(loser)
|
||||
if(STAKES_MONEY_MATCH)
|
||||
to_chat(winner, span_nicegreen("You've won all of [loser]'s money!"))
|
||||
if(STAKES_YOUR_SOUL)
|
||||
to_chat(winner, span_nicegreen("You've won [loser]'s SOUL!"))
|
||||
|
||||
/datum/sparring_match/proc/lose(mob/living/carbon/human/loser, mob/living/carbon/human/winner)
|
||||
if(!loser) //shit happened?
|
||||
return
|
||||
switch(stakes_condition)
|
||||
if(STAKES_HOLY_MATCH)
|
||||
if(loser == chaplain)
|
||||
var/datum/religion_sect/spar/sect = GLOB.religious_sect
|
||||
sect.matches_lost++
|
||||
if(sect.matches_lost < 3)
|
||||
to_chat(loser, span_userdanger("[GLOB.deity] is angry you lost in their name!"))
|
||||
return
|
||||
to_chat(loser, span_userdanger("[GLOB.deity] is enraged by your lackluster sparring record!"))
|
||||
lightningbolt(loser)
|
||||
SEND_SIGNAL(loser, COMSIG_ADD_MOOD_EVENT, "sparring", /datum/mood_event/banished)
|
||||
loser.mind.holy_role = NONE
|
||||
to_chat(loser, span_userdanger("You have been excommunicated! You are no longer holy!"))
|
||||
if(STAKES_MONEY_MATCH)
|
||||
to_chat(loser, span_userdanger("You've lost all your money to [winner]!"))
|
||||
var/datum/bank_account/loser_account = loser.get_bank_account()
|
||||
var/datum/bank_account/winner_account = winner.get_bank_account()
|
||||
if(!loser_account || !winner_account)//the winner is pretty owned in this case but whatever shoulda read the fine print of the contract
|
||||
return
|
||||
winner_account.transfer_money(loser_account, loser_account.account_balance)
|
||||
if(STAKES_YOUR_SOUL)
|
||||
var/turf/shard_turf = get_turf(loser)
|
||||
if(!shard_turf)
|
||||
return
|
||||
to_chat(loser, span_userdanger("You've lost ownership over your soul to [winner]!"))
|
||||
var/obj/item/soulstone/anybody/chaplain/sparring/shard = new(shard_turf)
|
||||
shard.capture_soul(loser, winner, forced = TRUE)
|
||||
@@ -253,9 +253,6 @@
|
||||
if(owner.reagents.get_reagent_amount(/datum/reagent/medicine/ephedrine) < 20)
|
||||
owner.reagents.add_reagent(/datum/reagent/medicine/ephedrine, 10)
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/item/organ/heart/ethereal
|
||||
name = "crystal core"
|
||||
icon_state = "ethereal_heart" //Welp. At least it's more unique in functionaliy.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -122,6 +122,7 @@
|
||||
#include "code\__DEFINES\reactions.dm"
|
||||
#include "code\__DEFINES\reagents.dm"
|
||||
#include "code\__DEFINES\reagents_specific_heat.dm"
|
||||
#include "code\__DEFINES\religion.dm"
|
||||
#include "code\__DEFINES\research.dm"
|
||||
#include "code\__DEFINES\robots.dm"
|
||||
#include "code\__DEFINES\role_preferences.dm"
|
||||
@@ -629,6 +630,7 @@
|
||||
#include "code\datums\components\trapdoor.dm"
|
||||
#include "code\datums\components\twohanded.dm"
|
||||
#include "code\datums\components\udder.dm"
|
||||
#include "code\datums\components\unbreakable.dm"
|
||||
#include "code\datums\components\uplink.dm"
|
||||
#include "code\datums\components\usb_port.dm"
|
||||
#include "code\datums\components\vacuum.dm"
|
||||
@@ -790,6 +792,7 @@
|
||||
#include "code\datums\elements\strippable.dm"
|
||||
#include "code\datums\elements\surgery_initiator.dm"
|
||||
#include "code\datums\elements\swabbable.dm"
|
||||
#include "code\datums\elements\tenacious.dm"
|
||||
#include "code\datums\elements\tool_flash.dm"
|
||||
#include "code\datums\elements\turf_transparency.dm"
|
||||
#include "code\datums\elements\undertile.dm"
|
||||
@@ -3441,6 +3444,9 @@
|
||||
#include "code\modules\religion\religion_sects.dm"
|
||||
#include "code\modules\religion\religion_structures.dm"
|
||||
#include "code\modules\religion\rites.dm"
|
||||
#include "code\modules\religion\sparring\ceremonial_gear.dm"
|
||||
#include "code\modules\religion\sparring\sparring_contract.dm"
|
||||
#include "code\modules\religion\sparring\sparring_datum.dm"
|
||||
#include "code\modules\requests\request.dm"
|
||||
#include "code\modules\requests\request_manager.dm"
|
||||
#include "code\modules\research\bepis.dm"
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { multiline } from 'common/string';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { BlockQuote, Button, Dropdown, Section, Stack } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
// defined this so the code is more readable
|
||||
const STAKES_HOLY_MATCH = 1;
|
||||
|
||||
const weaponlist = [
|
||||
"Fist Fight",
|
||||
"Ceremonial Weapons",
|
||||
"Melee Only",
|
||||
"Any Weapons",
|
||||
];
|
||||
|
||||
const stakelist = [
|
||||
"No Stakes",
|
||||
"Holy Match",
|
||||
"Money Match",
|
||||
"Your Soul",
|
||||
];
|
||||
|
||||
const weaponblurb = [
|
||||
"You will fight with your fists only. Any weapons will be considered a violation.",
|
||||
"You can only fight with ceremonial weapons. You will be at a severe disadvantage without one!",
|
||||
"You can fight with weapons, or fists if you have none. Ranged weapons are a violation.",
|
||||
"You can fight with any and all weapons as you please. Try not to kill them, okay?",
|
||||
];
|
||||
|
||||
const stakesblurb = [
|
||||
"No stakes, just for fun. Who doesn't love some recreational sparring?",
|
||||
"A match for the chaplain's deity. The Chaplain suffers large consequences for failure, but advances their sect by winning.",
|
||||
"A match with money on the line. Whomever wins takes all the money of whomever loses.",
|
||||
"A lethal match with the loser's soul becoming under ownership of the winner.",
|
||||
];
|
||||
|
||||
type Info = {
|
||||
set_weapon: number;
|
||||
set_area: string;
|
||||
set_stakes: number;
|
||||
left_sign: string;
|
||||
right_sign: string;
|
||||
in_area: BooleanLike;
|
||||
no_chaplains: BooleanLike;
|
||||
possible_areas: Array<string>;
|
||||
};
|
||||
|
||||
export const SparringContract = (props, context) => {
|
||||
const { data, act } = useBackend<Info>(context);
|
||||
const {
|
||||
set_weapon,
|
||||
set_area,
|
||||
set_stakes,
|
||||
possible_areas,
|
||||
left_sign,
|
||||
right_sign,
|
||||
in_area,
|
||||
no_chaplains,
|
||||
} = data;
|
||||
const [weapon, setWeapon] = useLocalState(context, "weapon", set_weapon);
|
||||
const [area, setArea] = useLocalState(context, "area", set_area);
|
||||
const [stakes, setStakes] = useLocalState(context, "stakes", set_stakes);
|
||||
return (
|
||||
<Window
|
||||
width={420}
|
||||
height={380}>
|
||||
<Window.Content>
|
||||
<Section fill>
|
||||
<Stack vertical fill>
|
||||
<Stack.Item>
|
||||
<Stack vertical>
|
||||
<Stack.Item fontSize="16px">
|
||||
Weapons:
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Dropdown
|
||||
width="100%"
|
||||
selected={weaponlist[weapon-1]}
|
||||
options={weaponlist}
|
||||
onSelected={value =>
|
||||
setWeapon(weaponlist.findIndex(title => (
|
||||
title === value
|
||||
))+1)} />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<BlockQuote>
|
||||
{weaponblurb[weapon-1]}
|
||||
</BlockQuote>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Stack vertical>
|
||||
<Stack.Item fontSize="16px">
|
||||
Arena:
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Dropdown
|
||||
width="100%"
|
||||
selected={area}
|
||||
options={possible_areas}
|
||||
onSelected={value => setArea(value)} />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<BlockQuote>
|
||||
This fight will take place in the {area}.
|
||||
Leaving the arena mid-fight is a violation.
|
||||
</BlockQuote>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Stack vertical>
|
||||
<Stack.Item fontSize="16px">
|
||||
Stakes:
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Dropdown
|
||||
width="100%"
|
||||
selected={stakelist[stakes-1]}
|
||||
options={stakelist}
|
||||
onSelected={value =>
|
||||
setStakes(stakelist.findIndex(title => (
|
||||
title === value
|
||||
))+1)} />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<BlockQuote>
|
||||
{stakesblurb[stakes-1]}
|
||||
</BlockQuote>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Stack grow textAlign="center">
|
||||
<Stack.Item
|
||||
fontSize={left_sign !== "none" && "14px"}
|
||||
grow>
|
||||
{left_sign === 'none' && (
|
||||
<Button
|
||||
icon="pen"
|
||||
onClick={() => act('sign', {
|
||||
"weapon": weapon,
|
||||
"area": area,
|
||||
"stakes": stakes,
|
||||
"sign_position": "left",
|
||||
})}>
|
||||
Sign Here
|
||||
</Button>
|
||||
) || (
|
||||
left_sign
|
||||
)}
|
||||
</Stack.Item>
|
||||
<Stack.Item fontSize="16px">
|
||||
VS
|
||||
</Stack.Item>
|
||||
<Stack.Item
|
||||
fontSize={right_sign !== "none" && "14px"}
|
||||
grow>
|
||||
{right_sign === "none" && (
|
||||
<Button
|
||||
icon="pen"
|
||||
onClick={() => act('sign', {
|
||||
"weapon": weapon,
|
||||
"area": area,
|
||||
"stakes": stakes,
|
||||
})}>
|
||||
Sign Here
|
||||
</Button>
|
||||
) || (
|
||||
right_sign
|
||||
)}
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item mb={-0.5}>
|
||||
<Stack fill>
|
||||
<Stack.Item grow>
|
||||
<Button
|
||||
disabled={
|
||||
!in_area
|
||||
|| (no_chaplains && set_stakes === STAKES_HOLY_MATCH)
|
||||
}
|
||||
icon="fist-raised"
|
||||
onClick={() => act('fight')} >
|
||||
FIGHT!
|
||||
</Button>
|
||||
<Button
|
||||
tooltip={multiline`
|
||||
If you've already signed but you want to renegotiate
|
||||
the terms, you can clear out the signatures with
|
||||
this button.
|
||||
`}
|
||||
icon="door-open"
|
||||
onClick={() => act('clear')} >
|
||||
Clear
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
tooltip={in_area
|
||||
&& "Both participants are present in the "+ area + "."
|
||||
|| "Both participants need to be in the arena!"}
|
||||
color={in_area && "green" || "red"}
|
||||
icon="ring" >
|
||||
Arena
|
||||
</Button>
|
||||
<Button
|
||||
tooltip={(left_sign !== "none" && right_sign !== "none")
|
||||
&& "Both signatures present, terms agreed upon."
|
||||
|| "You need signatures from both fighters on the terms!"}
|
||||
color={(left_sign !== "none" && right_sign !== "none")
|
||||
&& "green"
|
||||
|| "red"}
|
||||
icon="file-signature" >
|
||||
Signatures
|
||||
</Button>
|
||||
<Button
|
||||
tooltip={!no_chaplains
|
||||
&& "At least one chaplain is present. Holy matches allowed."
|
||||
|| "No chaplain present for this fight. No Holy Matches!"}
|
||||
color={!no_chaplains && "green" || "yellow"}
|
||||
icon="cross" >
|
||||
Chaplain
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user