This commit is contained in:
silicons
2021-02-28 00:00:14 -07:00
parent 59ba3155e0
commit 70b8d833c0
15 changed files with 173 additions and 91 deletions
+26 -21
View File
@@ -1,23 +1,24 @@
/**
* Higher overhead "advanced" version of do_after.
* @params
* - atom/user is the atom doing the action or the "physical" user
* - delay is time in deciseconds
* - atom/target is the atom the action is being done to, defaults to user
* - do_after_flags see __DEFINES/flags/do_after.dm for details.
* - datum/callback/extra_checks - Every time this ticks, extra_checks() is invoked with (user, delay, target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool).
* Stage can be DO_AFTER_STARTING, DO_AFTER_PROGRESSING, DO_AFTER_FINISHING
* If it returns DO_AFTER_STOP, this breaks.
* If it returns nothing, all other checks are done.
* If it returns DO_AFTER_PROCEED, all other checks are ignored.
* - required_mobility_flags is checked with CHECK_ALL_MOBILITY. Will immediately fail if the user isn't a mob.
* - requried_combat_flags is checked with CHECK_MULTIPLE_BITFIELDS. Will immediately fail if the user isn't a mob.
* - mob/living/mob_redirect - advanced option: If this is specified, movement and mobility/combat flag checks will use this instead of user. Progressbars will also go to this.
* - obj/item/tool - The tool we're using. See do_after flags for details.
*/
#define INVOKE_CALLBACK cb_return = extra_checks?.Invoke(user, delay, target, world.time - starttime, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool)
* Higher overhead "advanced" version of do_after.
* @params
* - atom/user is the atom doing the action or the "physical" user
* - delay is time in deciseconds
* - atom/target is the atom the action is being done to, defaults to user
* - do_after_flags see __DEFINES/flags/do_after.dm for details.
* - datum/callback/extra_checks - Every time this ticks, extra_checks() is invoked with (user, delay, target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, passed_in).
* Stage can be DO_AFTER_STARTING, DO_AFTER_PROGRESSING, DO_AFTER_FINISHING
* If it returns DO_AFTER_STOP, this breaks.
* If it returns nothing, all other checks are done.
* If it returns DO_AFTER_PROCEED, all other checks are ignored.
* passed_in is a list[PROGRESS_MULTIPLIER], for modification.
* - required_mobility_flags is checked with CHECK_ALL_MOBILITY. Will immediately fail if the user isn't a mob.
* - requried_combat_flags is checked with CHECK_MULTIPLE_BITFIELDS. Will immediately fail if the user isn't a mob.
* - mob/living/mob_redirect - advanced option: If this is specified, movement and mobility/combat flag checks will use this instead of user. Progressbars will also go to this.
* - obj/item/tool - The tool we're using. See do_after flags for details.
*/
#define INVOKE_CALLBACK cb_return = extra_checks?.Invoke(user, delay, target, timeleft, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, passed_in)
#define CHECK_FLAG_FAILURE ((required_mobility_flags || required_combat_flags) && (!living_user || (required_mobility_flags && !CHECK_ALL_MOBILITY(living_user, required_mobility_flags)) || (required_combat_flags && !CHECK_MULTIPLE_BITFIELDS(living_user.combat_flags, required_combat_flags))))
#define TIMELEFT (world.time - starttime)
#define TIMELEFT (timeleft)
/proc/do_after_advanced(atom/user, delay, atom/target, do_after_flags, datum/callback/extra_checks, required_mobility_flags, required_combat_flags, mob/living/mob_redirect, obj/item/tool)
// CHECK AND SET VARIABLES
if(!user)
@@ -40,8 +41,7 @@
return FALSE
if(!(do_after_flags & DO_AFTER_NO_COEFFICIENT) && living_user)
delay *= living_user.cached_multiplicative_actions_slowdown
var/starttime = world.time
var/endtime = world.time + delay
var/timeleft = delay
var/obj/item/initially_held_item = mob_redirect?.get_active_held_item()
var/atom/movable/AM_user = ismovable(user) && user
var/drifting = AM_user?.Process_Spacemove(NONE) && AM_user.inertia_dir
@@ -70,13 +70,18 @@
var/locchanged
var/ctu
var/ctt
while(world.time < endtime)
var/tick_time = world.time
var/list/passed_in = list(1)
while(timeleft > 0)
stoplag(1)
var/timepassed = world.time - tick_time
timepassed = world.time
progbar?.update(TIMELEFT)
if(QDELETED(user) || QDELETED(target) || (user.loc == null) || (target.loc == null))
. = FALSE
break
INVOKE_CALLBACK
timeleft -= timepassed * passed_in[1]
if(cb_return == DO_AFTER_STOP)
. = FALSE
break
+1 -1
View File
@@ -255,7 +255,7 @@
if(!isnull(stagger_force))
return stagger_force
/// totally not an untested, arbitrary equation.
return clamp((1.5 + (w_class/5)) * ((force_override || force) / 1.5), 0, 10 SECONDS)
return clamp((1.5 + (w_class/5)) * ((force_override || force) / 1.5), 0, 10 SECONDS) * CONFIG_GET(number/melee_stagger_factor)
/obj/item/proc/do_stagger_action(mob/living/target, mob/living/user, force_override)
if(!CHECK_BITFIELD(target.status_flags, CANSTAGGER))
@@ -262,6 +262,15 @@
/mob/living/carbon/alien/humanoid/royal/queen = 2
)
/datum/config_entry/number/sprintless_stagger_slowdown
config_entry_value = 0
/datum/config_entry/number/melee_stagger_factor
config_entry_value = 1
/datum/config_entry/number/sprintless_off_balance_slowdown
config_entry_value = 0.85
/datum/config_entry/number/movedelay //Used for modifying movement speed for mobs.
abstract_type = /datum/config_entry/number/movedelay
integer = FALSE
+11 -1
View File
@@ -95,21 +95,31 @@
/datum/status_effect/staggered/on_creation(mob/living/new_owner, set_duration)
if(isnum(set_duration))
duration = set_duration
if(!CONFIG_GET(flag/sprint_enabled))
new_owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/stagger, TRUE, CONFIG_GET(number/sprintless_stagger_slowdown))
return ..()
/datum/status_effect/staggered/on_remove()
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/stagger)
return ..()
/datum/status_effect/off_balance
id = "offbalance"
blocks_sprint = TRUE
alert_type = null
/datum/status_effect/off_balance/on_creation(mob/living/new_owner, set_duration)
if(isnum(set_duration))
duration = set_duration
if(!CONFIG_GET(flag/sprint_enabled))
new_owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/off_balance, TRUE, CONFIG_GET(number/sprintless_off_balance_slowdown))
return ..()
/datum/status_effect/off_balance/on_remove()
var/active_item = owner.get_active_held_item()
if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
owner.visible_message("<span class='warning'>[owner.name] regains their grip on \the [active_item]!</span>", "<span class='warning'>You regain your grip on \the [active_item]</span>", null, COMBAT_MESSAGE_RANGE)
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/off_balance)
return ..()
/obj/screen/alert/status_effect/asleep
@@ -162,7 +172,7 @@
id = "tased"
alert_type = null
var/movespeed_mod = /datum/movespeed_modifier/status_effect/tased
var/stamdmg_per_ds = 0 //a 20 duration would do 20 stamdmg, disablers do 24 or something
var/stamdmg_per_ds = 1 //a 20 duration would do 20 stamdmg, disablers do 24 or something
var/last_tick = 0 //fastprocess processing speed is a goddamn sham, don't trust it.
/datum/status_effect/electrode/on_creation(mob/living/new_owner, set_duration)
+51
View File
@@ -19,10 +19,61 @@
icon = 'icons/obj/chempuff.dmi'
pass_flags = PASSTABLE | PASSGRILLE
layer = FLY_LAYER
var/stream = FALSE
var/speed = 1
var/range = 3
var/hits_left = 3
var/range_left = 3
/obj/effect/decal/chempuff/blob_act(obj/structure/blob/B)
return
/obj/effect/decal/chempuff/Initialize(mapload, stream_mode, speed, range, hits_left)
. = ..()
stream = stream_mode
src.speed = speed
src.range = scc.range_left = range
src.hits_left = hits_left
/obj/effect/decal/chempuff/proc/hit_thing(atom/A)
if(A == src || A.invisibility)
return
if(!hits_left)
return
if(stream)
if(ismob(A))
var/mob/M = A
if(!M.lying || !range_left)
reagents.reaction(M, VAPOR)
hits_left--
else
if(!range_left)
reagents.reaction(A, VAPOR)
else
reagents.reaction(A)
if(ismob(A))
hits_left--
/obj/effect/decal/chempuff/Crossed(atom/movable/AM, oldloc)
. = ..()
hit_thing(AM)
/obj/effect/decal/chempuff/proc/run(atom/target)
for(var/i in 1 to range)
range_left--
if(!isturf(loc))
break
for(var/atom/T in loc)
hit_thing(T)
if(!hits_left || !isturf(loc))
break
if(hits_left && isturf(loc) && (!stream || !range_left))
reagents.reaction(loc, VAPOR)
hits_left--
if(!hits_left)
break
qdel(src)
/obj/effect/decal/fakelattice
name = "lattice"
desc = "A lightweight support lattice."
+18 -2
View File
@@ -358,10 +358,11 @@
return
I.item_flags |= BEING_REMOVED
breakouttime = I.breakouttime
var/datum/cuffbreak_checker/cuffbreak_checker = new(get_turf(src))
if(!cuff_break)
visible_message("<span class='warning'>[src] attempts to remove [I]!</span>")
to_chat(src, "<span class='notice'>You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)</span>")
if(do_after(src, breakouttime, 0, target = src, required_mobility_flags = MOBILITY_RESIST))
if(do_after_advanced(src, breakouttime, src, NONE, CALLBACK(cuffbreak_checker, /datum/cuffbreak_checker.proc/check_movement), required_mobility_flags = MOBILITY_RESIST))
clear_cuffs(I, cuff_break)
else
to_chat(src, "<span class='warning'>You fail to remove [I]!</span>")
@@ -370,15 +371,30 @@
breakouttime = 50
visible_message("<span class='warning'>[src] is trying to break [I]!</span>")
to_chat(src, "<span class='notice'>You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)</span>")
if(do_after(src, breakouttime, 0, target = src))
if(do_after_advanced(src, breakouttime, src, NONE, CALLBACK(cuffbreak_checker, /datum/cuffbreak_checker.proc/check_movement), required_mobility_flags = MOBILITY_RESIST))
clear_cuffs(I, cuff_break)
else
to_chat(src, "<span class='warning'>You fail to break [I]!</span>")
else if(cuff_break == INSTANT_CUFFBREAK)
clear_cuffs(I, cuff_break)
QDEL_NULL(cuffbreak_checker)
I.item_flags &= ~BEING_REMOVED
/datum/cuffbreak_checker
var/turf/last
/datum/cuffbreak_checker/New(turf/initial_turf)
last = initial_turf
/datum/cuffbreak_checker/proc/check_movement(atom/user, delay, atom/target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, list/passed_in)
if(get_turf(user) != last)
last = get_turf(user)
passed_in[1] = 0.5
else
passed_in[1] = 1
/mob/living/carbon/proc/uncuff()
if (handcuffed)
var/obj/item/W = handcuffed
@@ -1053,10 +1053,10 @@
return
if(!HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN)) //if we want to ignore slowdown from damage, but not from equipment
var/scaling = maxHealth / 100
var/health_deficiency = ((maxHealth / scaling) - (health / scaling) + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it
var/health_deficiency = max(((maxHealth / scaling) - (health / scaling)), (getStaminaLoss()*0.75))
if(health_deficiency >= 40)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, (health_deficiency-39) / 75)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, (health_deficiency-39) / 25)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, (health_deficiency - 15) / 75)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, (health_deficiency - 15) / 25)
else
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
@@ -1834,6 +1834,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(CHECK_MOBILITY(target, MOBILITY_STAND))
target.adjustStaminaLoss(5)
else
target.adjustStaminaLoss(target.getStaminaLoss() > 75? 5 : 75)
if(target.is_shove_knockdown_blocked())
return
@@ -1876,7 +1878,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.visible_message("<span class='danger'>[user.name] shoves [target.name]!</span>",
"<span class='danger'>[user.name] shoves you!</span>", null, COMBAT_MESSAGE_RANGE, null,
user, "<span class='danger'>You shove [target.name]!</span>")
target.Stagger(SHOVE_STAGGER_DURATION)
var/obj/item/target_held_item = target.get_active_held_item()
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
target_held_item = null
+13 -8
View File
@@ -266,16 +266,10 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
eavesdrop_range = EAVESDROP_EXTRA_RANGE
var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source)
var/list/the_dead = list()
var/list/yellareas //CIT CHANGE - adds the ability for yelling to penetrate walls and echo throughout areas
if(!eavesdrop_range && say_test(message) == "2") //CIT CHANGE - ditto
yellareas = get_areas_in_range(message_range*0.5, source) //CIT CHANGE - ditto
for(var/_M in GLOB.player_list)
var/mob/M = _M
if(M.stat != DEAD) //not dead, not important
if(yellareas) //CIT CHANGE - see above. makes yelling penetrate walls
var/area/A = get_area(M) //CIT CHANGE - ditto
if(istype(A) && A.ambientsounds != SPACE && (A in yellareas)) //CIT CHANGE - ditto
listening |= M //CIT CHANGE - ditto
continue
if(!M.client || !client) //client is so that ghosts don't have to listen to mice
continue
@@ -302,6 +296,9 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
AM.Hear(rendered, src, message_language, message, null, spans, message_mode, source)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message)
if(!eavesdrop_range && say_test(message) == "2") // Yell hook
process_yelling(listening, rendered, src, message_language, message, spans, message_mode, source)
//speech bubble
var/list/speech_bubble_recipients = list()
for(var/mob/M in listening)
@@ -311,6 +308,14 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_recipients, 30)
/atom/movable/proc/process_yelling(list/already_heard, rendered, atom/movable/speaker, datum/language/message_language, list/spans, message_mode, obj/source)
var/list/overhearing = list()
#warn todo: yelling
overhearing -= already_heard
for(var/_AM in overhearing)
var/atom/movable/AM = _AM
AM.Hear(rendered, speaker, message_language, message, null, spans, message_mode, source)
/mob/proc/binarycheck()
return FALSE
@@ -333,7 +338,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/obj/item/bodypart/rightarm = get_bodypart(BODY_ZONE_R_ARM)
if(HAS_TRAIT(src, TRAIT_MUTE) && get_selected_language() != /datum/language/signlanguage)
return 0
if (get_selected_language() == /datum/language/signlanguage)
var/left_disabled = FALSE
var/right_disabled = FALSE
@@ -42,3 +42,9 @@
/datum/movespeed_modifier/status_effect/mkultra
multiplicative_slowdown = -2
blacklisted_movetypes= FLYING|FLOATING
/datum/movespeed_modifier/status_effect/staggered
variable = TRUE
/datum/movespeed_modifier/status_effect/off_balance
variable = TRUE
+2 -2
View File
@@ -118,7 +118,7 @@ Contents:
ADD_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT)
n_shoes = H.shoes
ADD_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT)
n_shoes.slowdown--
n_shoes.slowdown -= 0.5
n_gloves = H.gloves
ADD_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT)
return TRUE
@@ -139,7 +139,7 @@ Contents:
REMOVE_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT)
if(n_shoes)
REMOVE_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT)
n_shoes.slowdown++
n_shoes.slowdown += 0.5
if(n_gloves)
n_gloves.icon_state = "s-ninja"
n_gloves.item_state = "s-ninja"
@@ -9,6 +9,10 @@
projectile_type = /obj/item/projectile/energy/electrode/security
e_cost = 100
/obj/item/ammo_casing/energy/electrode/hos
projectile_type = /obj/item/projectile/energy/electrode/hos
e_cost = 100
/obj/item/ammo_casing/energy/electrode/spec
e_cost = 100
@@ -48,13 +48,23 @@
/obj/item/gun/energy/e_gun/hos
name = "\improper X-01 MultiPhase Energy Gun"
desc = "This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time in exchange for inbuilt advanced firearm EMP shielding."
desc = "This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time in exchange for inbuilt advanced firearm EMP shielding. <span class='boldnotice'>Right click in combat mode to fire a taser shot with a cooldown.</span>"
icon_state = "hoslaser"
force = 10
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/ion/hos)
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/ion/hos, /obj/item/ammo_casing/energy/electrode/hos)
ammo_x_offset = 4
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/obj/item/gun/energy/e_gun/hos/altafterattack(atom/target, mob/user, proximity_flag, params)
. = TRUE
if(last_altfire + altfire_delay > world.time)
return
var/current_index = current_firemode_index
set_firemode_to_type(/obj/item/ammo_casing/energy/electrode)
process_afterattack(target, user, proximity_flag, params)
set_firemode_index(current_index)
last_altfire = world.time
/obj/item/gun/energy/e_gun/hos/emp_act(severity)
return
@@ -37,15 +37,17 @@
..()
/obj/item/projectile/energy/electrode/security
tase_duration = 30
tase_duration = 40
knockdown = 0
stamina = 10
stamina = 0
knockdown_stamoverride = 0
knockdown_stam_max = 0
strong_tase = FALSE
/obj/item/projectile/energy/electrode/security/hos
knockdown = 100
knockdown_stamoverride = 30
knockdown_stam_max = null
tase_duration = 10
tase_duration = 40
knockdown = 0
stamina = 0
knockdown_stamoverride = 0
knockdown_stam_max = 0
strong_tase = FALSE
@@ -18,7 +18,8 @@
var/spray_range = 3 //the range of tiles the sprayer will reach when in spray mode.
var/stream_range = 1 //the range of tiles the sprayer will reach when in stream mode.
var/stream_amount = 10 //the amount of reagents transfered when in stream mode.
var/spray_delay = 3 //The amount of sleep() delay between each chempuff step.
/// Amount of time it takes for a spray to completely travel.
var/spray_delay = 8
/// Last world.time of spray
var/last_spray = 0
/// Spray cooldown
@@ -72,58 +73,20 @@
if((last_spray + spray_cooldown) > world.time)
return
var/range = clamp(get_dist(src, A), 1, current_range)
var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src))
var/wait_step = CEILING(spray_delay * INVERSE(range), world.tick_lag)
var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src), stream_mode, wait_step, range, stream_mode? 1 : range)
log_reagent("SPRAY: [key_name(usr)] fired [src] ([REF(src)]) [COORD(T)] at [A] ([REF(A)]) [COORD(A)] (chempuff: [D.reagents.log_list()])")
D.create_reagents(amount_per_transfer_from_this, NONE, NO_REAGENTS_VALUE)
var/puff_reagent_left = range //how many turf, mob or dense objet we can react with before we consider the chem puff consumed
if(stream_mode)
reagents.trans_to(D, amount_per_transfer_from_this)
puff_reagent_left = 1
else
reagents.trans_to(D, amount_per_transfer_from_this, 1/range)
D.color = mix_color_from_reagents(D.reagents.reagent_list)
var/turf/T = get_turf(src)
if(!T)
return
log_reagent("SPRAY: [key_name(usr)] fired [src] ([REF(src)]) [COORD(T)] at [A] ([REF(A)]) [COORD(A)] (chempuff: [D.reagents.log_list()])")
var/wait_step = max(round(2+ spray_delay * INVERSE(range)), 2)
last_spray = world.time
INVOKE_ASYNC(src, .proc/do_spray, A, wait_step, D, range, puff_reagent_left)
return TRUE
/obj/item/reagent_containers/spray/proc/do_spray(atom/A, wait_step, obj/effect/decal/chempuff/D, range, puff_reagent_left)
var/range_left = range
for(var/i=0, i<range, i++)
range_left--
step_towards(D,A)
sleep(wait_step)
for(var/atom/T in get_turf(D))
if(T == D || T.invisibility) //we ignore the puff itself and stuff below the floor
continue
if(puff_reagent_left <= 0)
break
if(stream_mode)
if(ismob(T))
var/mob/M = T
if(!M.lying || !range_left)
D.reagents.reaction(M, VAPOR)
puff_reagent_left -= 1
else if(!range_left)
D.reagents.reaction(T, VAPOR)
else
D.reagents.reaction(T, VAPOR)
if(ismob(T))
puff_reagent_left -= 1
if(puff_reagent_left > 0 && (!stream_mode || !range_left))
D.reagents.reaction(get_turf(D), VAPOR)
puff_reagent_left -= 1
if(puff_reagent_left <= 0) // we used all the puff so we delete it.
qdel(D)
return
qdel(D)
D.run((A)
/obj/item/reagent_containers/spray/attack_self(mob/user)
stream_mode = !stream_mode
@@ -207,7 +170,7 @@
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
volume = 40
stream_range = 4
spray_delay = 1
spray_delay = 2
amount_per_transfer_from_this = 5
list_reagents = list(/datum/reagent/consumable/condensedcapsaicin = 40)