Merge pull request #12834 from silicons/clickcd_experimental
Experimental hybrid clickdelay system (No seriously I'm trying my best to not call it Minecraft attack delays)
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* CLICKDELAY HANDLING SYSTEM
|
||||
* How this works is mobs can never do actions until their next_action is at or below world.time, but things can specify extra cooldown
|
||||
* to check for either from the time of last_action or from the end of next_action.
|
||||
*
|
||||
* Clickdelay should always be checked via [CheckActionCooldown()], never manually!
|
||||
*/
|
||||
|
||||
/mob
|
||||
// CLICKDELAY AND RELATED
|
||||
// Generic clickdelay - Hybrid time-since-last-attack and time-to-next-attack system.
|
||||
// next_action is a hard cooldown, as Click()s will not pass unless it is passed.
|
||||
// last_action is not a hard cooldown and different items can check for different delays.
|
||||
/// Generic clickdelay variable. Marks down the last world.time we did something that should cause or impact generic clickdelay. This should be directly set or set using [DelayNextAction()]. This should only be checked using [CheckActionCooldown()].
|
||||
var/last_action = 0
|
||||
/**
|
||||
* The difference between the above and this is this is set immediately before even the pre-attack begins to ensure clickdelay is respected.
|
||||
* Then, it is flushed or discarded using [FlushLastAttack()] or [DiscardLastAttack()] respectively.
|
||||
*/
|
||||
|
||||
var/last_action_immediate = 0
|
||||
/// Generic clickdelay variable. Next world.time we should be able to do something that respects generic clickdelay. This should be set using [DelayNextAction()] This should only be checked using [CheckActionCooldown()].
|
||||
var/next_action = 0
|
||||
/// Ditto
|
||||
var/next_action_immediate = 0
|
||||
/// Default clickdelay for an UnarmedAttack() that successfully passes. Respects action_cooldown_mod.
|
||||
var/unarmed_attack_speed = CLICK_CD_MELEE
|
||||
/// Simple modification variable multiplied to next action modifier on adjust and on checking time since last action using [CheckActionCooldown()].
|
||||
/// This should only be manually modified using multipliers.
|
||||
var/action_cooldown_mod = 1
|
||||
/// Simple modification variable added to amount on adjust and on checking time since last action using [CheckActionCooldown()].
|
||||
/// This should only be manually modified via addition.
|
||||
var/action_cooldown_adjust = 0
|
||||
|
||||
// Resisting - While resisting will give generic clickdelay, it is also on its own resist delay system. However, resisting does not check generic movedelay.
|
||||
// Resist cooldown should only be set at the start of a resist chain - whether this is clicking an alert button, pressing or hotkeying the resist button, or moving to resist out of a locker.
|
||||
/*
|
||||
* Special clickdelay variable for resisting. Last time we did a special action like resisting. This should only be set using [MarkResistTime()].
|
||||
* Use [CheckResistCooldown()] to check cooldowns, this should only be used for the resist action bar visual.
|
||||
*/
|
||||
var/last_resist = 0
|
||||
/// How long we should wait before allowing another resist. This should only be manually modified using multipliers.
|
||||
var/resist_cooldown = CLICK_CD_RESIST
|
||||
/// Minimum world time for another resist. This should only be checked using [CheckResistCooldown()].
|
||||
var/next_resist = 0
|
||||
|
||||
/**
|
||||
* Applies a delay to next_action before we can do our next action.
|
||||
*
|
||||
* @params
|
||||
* * amount - Amount to delay by
|
||||
* * ignore_mod - ignores next action adjust and mult
|
||||
* * considered_action - Defaults to TRUE - If TRUE, sets last_action to world.time.
|
||||
* * immediate - defaults to TRUE - if TRUE, writes to cached/last_attack_immediate instead of last_attack. This ensures it can't collide with any delay checks in the actual attack.
|
||||
* * flush - defaults to FALSE - Use this while using this proc outside of clickcode to ensure everything is set properly. This should never be set to TRUE if this is called from clickcode.
|
||||
*/
|
||||
/mob/proc/DelayNextAction(amount = 0, ignore_mod = FALSE, considered_action = TRUE, immediate = TRUE, flush = FALSE)
|
||||
if(immediate)
|
||||
if(considered_action)
|
||||
last_action_immediate = world.time
|
||||
next_action_immediate = max(next_action, world.time + (ignore_mod? amount : (amount * GetActionCooldownMod() + GetActionCooldownAdjust())))
|
||||
else
|
||||
if(considered_action)
|
||||
last_action = world.time
|
||||
next_action = max(next_action, world.time + (ignore_mod? amount : (amount * GetActionCooldownMod() + GetActionCooldownAdjust())))
|
||||
if(flush)
|
||||
FlushCurrentAction()
|
||||
else
|
||||
hud_used?.clickdelay?.mark_dirty()
|
||||
|
||||
/**
|
||||
* Get estimated time of next attack.
|
||||
*/
|
||||
/mob/proc/EstimatedNextActionTime()
|
||||
var/attack_speed = unarmed_attack_speed * GetActionCooldownMod() + GetActionCooldownAdjust()
|
||||
var/obj/item/I = get_active_held_item()
|
||||
if(I)
|
||||
attack_speed = I.GetEstimatedAttackSpeed()
|
||||
if(!I.clickdelay_mod_bypass)
|
||||
attack_speed = attack_speed * GetActionCooldownMod() + GetActionCooldownAdjust()
|
||||
return max(next_action, next_action_immediate, max(last_action, last_action_immediate) + attack_speed)
|
||||
|
||||
/**
|
||||
* Sets our next action to. The difference is DelayNextAction cannot reduce next_action under any circumstances while this can.
|
||||
*/
|
||||
/mob/proc/SetNextAction(amount = 0, ignore_mod = FALSE, considered_action = TRUE, immediate = TRUE, flush = FALSE)
|
||||
if(immediate)
|
||||
if(considered_action)
|
||||
last_action_immediate = world.time
|
||||
next_action_immediate = world.time + (ignore_mod? amount : (amount * GetActionCooldownMod() + GetActionCooldownAdjust()))
|
||||
else
|
||||
if(considered_action)
|
||||
last_action = world.time
|
||||
next_action = world.time + (ignore_mod? amount : (amount * GetActionCooldownMod() + GetActionCooldownAdjust()))
|
||||
if(flush)
|
||||
FlushCurrentAction()
|
||||
else
|
||||
hud_used?.clickdelay?.mark_dirty()
|
||||
|
||||
/**
|
||||
* Checks if we can do another action.
|
||||
* Returns TRUE if we can and FALSE if we cannot.
|
||||
*
|
||||
* @params
|
||||
* * cooldown - Time required since last action. Defaults to 0.5
|
||||
* * from_next_action - Defaults to FALSE. Should we check from the tail end of next_action instead of last_action?
|
||||
* * ignore_mod - Defaults to FALSE. Ignore all adjusts and multipliers. Do not use this unless you know what you are doing and have a good reason.
|
||||
* * ignore_next_action - Defaults to FALSE. Ignore next_action and only care about cooldown param and everything else. Generally unused.
|
||||
* * immediate - Defaults to FALSE. Checks last action using immediate, used on the head end of an attack. This is to prevent colliding attacks in case of sleep. Not that you should sleep() in an attack but.. y'know.
|
||||
*/
|
||||
/mob/proc/CheckActionCooldown(cooldown = 0.5, from_next_action = FALSE, ignore_mod = FALSE, ignore_next_action = FALSE, immediate = FALSE)
|
||||
return (ignore_next_action || (world.time >= (immediate? next_action_immediate : next_action))) && \
|
||||
(world.time >= ((from_next_action? (immediate? next_action_immediate : next_action) : (immediate? last_action_immediate : last_action)) + max(0, ignore_mod? cooldown : (cooldown * GetActionCooldownMod() + GetActionCooldownAdjust()))))
|
||||
|
||||
/**
|
||||
* Gets action_cooldown_mod.
|
||||
*/
|
||||
/mob/proc/GetActionCooldownMod()
|
||||
return action_cooldown_mod
|
||||
|
||||
/**
|
||||
* Gets action_cooldown_adjust
|
||||
*/
|
||||
/mob/proc/GetActionCooldownAdjust()
|
||||
return action_cooldown_adjust
|
||||
|
||||
/**
|
||||
* Flushes last_action and next_action
|
||||
*/
|
||||
/mob/proc/FlushCurrentAction()
|
||||
last_action = last_action_immediate
|
||||
next_action = next_action_immediate
|
||||
hud_used?.clickdelay?.mark_dirty()
|
||||
|
||||
/**
|
||||
* Discards last_action and next_action
|
||||
*/
|
||||
/mob/proc/DiscardCurrentAction()
|
||||
last_action_immediate = last_action
|
||||
next_action_immediate = next_action
|
||||
hud_used?.clickdelay?.mark_dirty()
|
||||
|
||||
/**
|
||||
* Checks if we can resist again.
|
||||
*/
|
||||
/mob/proc/CheckResistCooldown()
|
||||
return (world.time >= next_resist)
|
||||
|
||||
/**
|
||||
* Mark the last resist as now.
|
||||
*
|
||||
* @params
|
||||
* * extra_cooldown - Extra cooldown to apply to next_resist. Defaults to this mob's resist_cooldown.
|
||||
* * override - Defaults to FALSE - if TRUE, extra_cooldown will replace the old next_resist even if the old is longer.
|
||||
*/
|
||||
/mob/proc/MarkResistTime(extra_cooldown = resist_cooldown, override = FALSE)
|
||||
last_resist = world.time
|
||||
next_resist = override? (world.time + extra_cooldown) : max(next_resist, world.time + extra_cooldown)
|
||||
hud_used?.resistdelay?.mark_dirty()
|
||||
|
||||
/atom
|
||||
// Standard clickdelay variables
|
||||
// These 3 are all handled at base of atom/attack_hand so uh.. yeah. Make sure that's called.
|
||||
/// Amount of time to check for from a mob's last attack to allow an attack_hand().
|
||||
var/attack_hand_speed = CLICK_CD_MELEE
|
||||
/// Amount of time to hard stagger (no clicking at all) the mob post attack_hand(). Lower = better
|
||||
var/attack_hand_unwieldlyness = 0
|
||||
/// Should we set last action for attack hand? This implies that attack_hands to this atom should flush to clickdelay buffers instead of discarding.
|
||||
var/attack_hand_is_action = FALSE
|
||||
|
||||
/obj/item
|
||||
// Standard clickdelay variables
|
||||
/// Amount of time to check for from a mob's last attack, checked before an attack happens. Lower = faster attacks
|
||||
var/attack_speed = CLICK_CD_MELEE
|
||||
/// Amount of time to hard-stagger (no clicking at all) the mob when attacking. Lower = better
|
||||
var/attack_unwieldlyness = 0
|
||||
/// This item bypasses any click delay mods
|
||||
var/clickdelay_mod_bypass = FALSE
|
||||
/// This item checks clickdelay from a user's delayed next action variable rather than the last time they attacked.
|
||||
var/clickdelay_from_next_action = FALSE
|
||||
/// This item ignores next action delays.
|
||||
var/clickdelay_ignores_next_action = FALSE
|
||||
|
||||
/**
|
||||
* Checks if a user's clickdelay is met for a standard attack, this is called before an attack happens.
|
||||
*/
|
||||
/obj/item/proc/CheckAttackCooldown(mob/user, atom/target)
|
||||
return user.CheckActionCooldown(attack_speed, clickdelay_from_next_action, clickdelay_mod_bypass, clickdelay_ignores_next_action)
|
||||
|
||||
/**
|
||||
* Called after a successful attack to set a mob's clickdelay.
|
||||
*/
|
||||
/obj/item/proc/ApplyAttackCooldown(mob/user, atom/target, attackchain_flags)
|
||||
user.DelayNextAction(attack_unwieldlyness, clickdelay_mod_bypass, !(attackchain_flags & ATTACK_IGNORE_ACTION))
|
||||
|
||||
/**
|
||||
* Get estimated time that a user has to not attack for to use us
|
||||
*/
|
||||
/obj/item/proc/GetEstimatedAttackSpeed()
|
||||
return attack_speed
|
||||
@@ -5,13 +5,11 @@
|
||||
/mob/proc/get_active_held_item()
|
||||
return get_item_for_held_index(active_hand_index)
|
||||
|
||||
|
||||
//Finds the opposite limb for the active one (eg: upper left arm will find the item in upper right arm)
|
||||
//So we're treating each "pair" of limbs as a team, so "both" refers to them
|
||||
/mob/proc/get_inactive_held_item()
|
||||
return get_item_for_held_index(get_inactive_hand_index())
|
||||
|
||||
|
||||
//Finds the opposite index for the active one (eg: upper left arm will find the item in upper right arm)
|
||||
//So we're treating each "pair" of limbs as a team, so "both" refers to them
|
||||
/mob/proc/get_inactive_hand_index()
|
||||
@@ -24,12 +22,9 @@
|
||||
other_hand = 0
|
||||
return other_hand
|
||||
|
||||
|
||||
/mob/proc/get_item_for_held_index(i)
|
||||
if(i > 0 && i <= held_items.len)
|
||||
return held_items[i]
|
||||
return FALSE
|
||||
|
||||
|
||||
//Odd = left. Even = right
|
||||
/mob/proc/held_index_to_dir(i)
|
||||
@@ -37,17 +32,14 @@
|
||||
return "r"
|
||||
return "l"
|
||||
|
||||
|
||||
//Check we have an organ for this hand slot (Dismemberment), Only relevant for humans
|
||||
/mob/proc/has_hand_for_held_index(i)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Check we have an organ for our active hand slot (Dismemberment),Only relevant for humans
|
||||
/mob/proc/has_active_hand()
|
||||
return has_hand_for_held_index(active_hand_index)
|
||||
|
||||
|
||||
//Finds the first available (null) index OR all available (null) indexes in held_items based on a side.
|
||||
//Lefts: 1, 3, 5, 7...
|
||||
//Rights:2, 4, 6, 8...
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
laws.set_laws_config()
|
||||
|
||||
/obj/item/mmi/attackby(obj/item/O, mob/user, params)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(!user.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
user.DelayNextAction()
|
||||
if(istype(O, /obj/item/organ/brain)) //Time to stick a brain in it --NEO
|
||||
var/obj/item/organ/brain/newbrain = O
|
||||
if(brain)
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
to_chat(brainmob, "<span class='notice'>You feel slightly disoriented. That's normal when you're just a brain.</span>")
|
||||
|
||||
/obj/item/organ/brain/attackby(obj/item/O, mob/user, params)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.DelayNextAction(CLICK_CD_MELEE)
|
||||
if(brainmob)
|
||||
O.attack(brainmob, user) //Oh noooeeeee
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ In all, this is a lot like the monkey code. /N
|
||||
return attack_alien(L)
|
||||
|
||||
|
||||
/mob/living/carbon/alien/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/carbon/alien/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //To allow surgery to return properly.
|
||||
return
|
||||
@@ -74,7 +74,6 @@ In all, this is a lot like the monkey code. /N
|
||||
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
|
||||
apply_damage(rand(1, 3), BRUTE, affecting)
|
||||
|
||||
|
||||
/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M)
|
||||
. = ..()
|
||||
if(.)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"<span class='userdanger'>[user] has [hitverb] [src]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/carbon/alien/humanoid/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //To allow surgery to return properly.
|
||||
return
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/carbon/alien/larva/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(. || M.a_intent == INTENT_HELP || M.a_intent == INTENT_GRAB)
|
||||
return
|
||||
|
||||
@@ -58,8 +58,7 @@
|
||||
/obj/item/clothing/mask/facehugger/attack_alien(mob/user) //can be picked up by aliens
|
||||
return attack_hand(user)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clothing/mask/facehugger/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/clothing/mask/facehugger/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if((stat == CONSCIOUS && !sterile) && !isalien(user))
|
||||
if(Leap(user))
|
||||
return
|
||||
|
||||
@@ -320,14 +320,11 @@
|
||||
return
|
||||
if(restrained())
|
||||
// too soon.
|
||||
if(last_special > world.time)
|
||||
return
|
||||
var/buckle_cd = 600
|
||||
if(handcuffed)
|
||||
var/obj/item/restraints/O = src.get_item_by_slot(SLOT_HANDCUFFED)
|
||||
buckle_cd = O.breakouttime
|
||||
changeNext_move(min(CLICK_CD_BREAKOUT, buckle_cd))
|
||||
last_special = world.time + min(CLICK_CD_BREAKOUT, buckle_cd)
|
||||
MarkResistTime()
|
||||
visible_message("<span class='warning'>[src] attempts to unbuckle [p_them()]self!</span>", \
|
||||
"<span class='notice'>You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)</span>")
|
||||
if(do_after(src, buckle_cd, 0, target = src, required_mobility_flags = MOBILITY_RESIST))
|
||||
@@ -341,39 +338,26 @@
|
||||
buckled.user_unbuckle_mob(src,src)
|
||||
|
||||
/mob/living/carbon/resist_fire()
|
||||
if(last_special > world.time)
|
||||
return
|
||||
fire_stacks -= 5
|
||||
DefaultCombatKnockdown(60, TRUE, TRUE)
|
||||
spin(32,2)
|
||||
visible_message("<span class='danger'>[src] rolls on the floor, trying to put [p_them()]self out!</span>", \
|
||||
"<span class='notice'>You stop, drop, and roll!</span>")
|
||||
last_special = world.time + 30
|
||||
MarkResistTime(30)
|
||||
sleep(30)
|
||||
if(fire_stacks <= 0)
|
||||
visible_message("<span class='danger'>[src] has successfully extinguished [p_them()]self!</span>", \
|
||||
"<span class='notice'>You extinguish yourself.</span>")
|
||||
ExtinguishMob()
|
||||
|
||||
/mob/living/carbon/resist_restraints(ignore_delay = FALSE)
|
||||
/mob/living/carbon/resist_restraints()
|
||||
var/obj/item/I = null
|
||||
var/type = 0
|
||||
if(!ignore_delay && (last_special > world.time))
|
||||
to_chat(src, "<span class='warning'>You don't have the energy to resist your restraints that fast!</span>")
|
||||
return
|
||||
if(handcuffed)
|
||||
I = handcuffed
|
||||
type = 1
|
||||
else if(legcuffed)
|
||||
I = legcuffed
|
||||
type = 2
|
||||
if(I)
|
||||
if(type == 1)
|
||||
changeNext_move(min(CLICK_CD_BREAKOUT, I.breakouttime))
|
||||
last_special = world.time + CLICK_CD_BREAKOUT
|
||||
if(type == 2)
|
||||
changeNext_move(min(CLICK_CD_RANGE, I.breakouttime))
|
||||
last_special = world.time + CLICK_CD_RANGE
|
||||
MarkResistTime()
|
||||
cuff_resist(I)
|
||||
|
||||
/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 600, cuff_break = 0)
|
||||
@@ -418,7 +402,7 @@
|
||||
if (W)
|
||||
W.layer = initial(W.layer)
|
||||
W.plane = initial(W.plane)
|
||||
changeNext_move(0)
|
||||
SetNextAction(0)
|
||||
if (legcuffed)
|
||||
var/obj/item/W = legcuffed
|
||||
legcuffed = null
|
||||
@@ -431,7 +415,7 @@
|
||||
if (W)
|
||||
W.layer = initial(W.layer)
|
||||
W.plane = initial(W.plane)
|
||||
changeNext_move(0)
|
||||
SetNextAction(0)
|
||||
update_equipment_speed_mods() // In case cuffs ever change speed
|
||||
|
||||
/mob/living/carbon/proc/clear_cuffs(obj/item/I, cuff_break)
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
var/totitemdamage = pre_attacked_by(I, user) * damage_multiplier
|
||||
var/impacting_zone = (user == src)? check_zone(user.zone_selected) : ran_zone(user.zone_selected)
|
||||
var/list/block_return = list()
|
||||
if((user != src) && (mob_run_block(I, totitemdamage, "the [I]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone, block_return) & BLOCK_SUCCESS))
|
||||
if((user != src) && (mob_run_block(I, totitemdamage, "the [I]", ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone, block_return) & BLOCK_SUCCESS))
|
||||
return FALSE
|
||||
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(impacting_zone)
|
||||
@@ -111,8 +111,7 @@
|
||||
/mob/living/carbon/attack_drone(mob/living/simple_animal/drone/user)
|
||||
return //so we don't call the carbon's attack_hand().
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/mob/living/carbon/attack_hand(mob/living/carbon/human/user, act_intent, unarmed_attack_flags)
|
||||
/mob/living/carbon/on_attack_hand(mob/living/carbon/human/user, act_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.) //was the attack blocked?
|
||||
return
|
||||
@@ -151,15 +150,13 @@
|
||||
|
||||
if(M.a_intent == INTENT_HELP)
|
||||
help_shake_act(M)
|
||||
return 0
|
||||
return TRUE
|
||||
|
||||
. = ..()
|
||||
if(.) //successful monkey bite.
|
||||
for(var/thing in M.diseases)
|
||||
var/datum/disease/D = thing
|
||||
ForceContractDisease(D)
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
|
||||
. = ..()
|
||||
|
||||
@@ -735,8 +735,7 @@
|
||||
|
||||
/mob/living/carbon/human/resist_restraints()
|
||||
if(wear_suit && wear_suit.breakouttime)
|
||||
changeNext_move(CLICK_CD_BREAKOUT)
|
||||
last_special = world.time + CLICK_CD_BREAKOUT
|
||||
MarkResistTime()
|
||||
cuff_resist(wear_suit)
|
||||
else
|
||||
..()
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
apply_damage(15, BRUTE, wound_bonus=10)
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/mob/living/carbon/human/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.) //To allow surgery to return properly.
|
||||
return
|
||||
@@ -131,6 +131,9 @@
|
||||
dna.species.spec_attack_hand(H, src, null, act_intent, unarmed_attack_flags)
|
||||
|
||||
/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M)
|
||||
if(!M.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
M.DelayNextAction()
|
||||
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
|
||||
if(!affecting)
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
return ..()
|
||||
visible_message("<span class='warning'>[src] strikes back perfectly at [attacker], staggering them!</span>")
|
||||
if(D.parry_data["HUMAN_PARRY_PUNCH"])
|
||||
UnarmedAttack(attacker, TRUE, INTENT_HARM, UNARMED_ATTACK_PARRY)
|
||||
UnarmedAttack(attacker, TRUE, INTENT_HARM, ATTACK_IS_PARRY_COUNTERATTACK | ATTACK_IGNORE_ACTION | ATTACK_IGNORE_CLICKDELAY | NO_AUTO_CLICKDELAY_HANDLING)
|
||||
var/mob/living/L = attacker
|
||||
if(istype(L))
|
||||
L.Stagger(D.parry_data["HUMAN_PARRY_STAGGER"])
|
||||
|
||||
@@ -1448,7 +1448,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target.grabbedby(user)
|
||||
return 1
|
||||
|
||||
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style, unarmed_attack_flags = NONE)
|
||||
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style, attackchain_flags = NONE)
|
||||
if(!attacker_style && HAS_TRAIT(user, TRAIT_PACIFISM))
|
||||
to_chat(user, "<span class='warning'>You don't want to harm [target]!</span>")
|
||||
return FALSE
|
||||
@@ -1460,7 +1460,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target_message = "<span class='warning'>[target] blocks your attack!</span>")
|
||||
return FALSE
|
||||
|
||||
if(!(unarmed_attack_flags & UNARMED_ATTACK_PARRY))
|
||||
if(!(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK))
|
||||
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
|
||||
user.adjustStaminaLossBuffered(1.5)
|
||||
else
|
||||
@@ -1502,7 +1502,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
|
||||
|
||||
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
|
||||
if(unarmed_attack_flags & UNARMED_ATTACK_PARRY)
|
||||
if(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)
|
||||
miss_chance = 0
|
||||
else
|
||||
if(user.dna.species.punchdamagelow)
|
||||
@@ -1689,7 +1689,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
/datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
|
||||
return
|
||||
|
||||
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
|
||||
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, attackchain_flags)
|
||||
if(!istype(M))
|
||||
return
|
||||
CHECK_DNA_AND_SPECIES(M)
|
||||
@@ -1709,7 +1709,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
grab(M, H, attacker_style)
|
||||
|
||||
if("harm")
|
||||
harm(M, H, attacker_style, unarmed_attack_flags)
|
||||
harm(M, H, attacker_style, attackchain_flags)
|
||||
|
||||
if("disarm")
|
||||
disarm(M, H, attacker_style)
|
||||
@@ -1719,7 +1719,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
// Allows you to put in item-specific reactions based on species
|
||||
if(user != H)
|
||||
var/list/block_return = list()
|
||||
if(H.mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone, block_return) & BLOCK_SUCCESS)
|
||||
if(H.mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone, block_return) & BLOCK_SUCCESS)
|
||||
return 0
|
||||
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
|
||||
if(H.check_martial_melee_block())
|
||||
@@ -1830,6 +1830,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
return TRUE
|
||||
CHECK_DNA_AND_SPECIES(M)
|
||||
CHECK_DNA_AND_SPECIES(H)
|
||||
if(!M.CheckActionCooldown())
|
||||
return
|
||||
M.DelayNextAction(CLICK_CD_MELEE)
|
||||
|
||||
if(!istype(M)) //sanity check for drones.
|
||||
return TRUE
|
||||
|
||||
@@ -90,8 +90,7 @@
|
||||
else if(legcuffed)
|
||||
I = legcuffed
|
||||
if(I)
|
||||
changeNext_move(CLICK_CD_BREAKOUT)
|
||||
last_special = world.time + CLICK_CD_BREAKOUT
|
||||
MarkResistTime()
|
||||
cuff_resist(I)
|
||||
|
||||
/mob/living/carbon/monkey/proc/should_target(var/mob/living/L)
|
||||
@@ -354,7 +353,7 @@
|
||||
battle_screech()
|
||||
a_intent = INTENT_HARM
|
||||
|
||||
/mob/living/carbon/monkey/attack_hand(mob/living/L)
|
||||
/mob/living/carbon/monkey/on_attack_hand(mob/living/L)
|
||||
if(L.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
|
||||
retaliate(L)
|
||||
else if(L.a_intent == INTENT_DISARM && prob(MONKEY_RETALIATE_DISARM_PROB))
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
adjustBruteLoss(15)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/carbon/monkey/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //To allow surgery to return properly.
|
||||
return
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/mob/living/GetActionCooldownMod()
|
||||
. = ..()
|
||||
for(var/datum/status_effect/S in status_effects)
|
||||
. *= S.action_cooldown_mod()
|
||||
@@ -273,7 +273,7 @@
|
||||
return
|
||||
stop_pulling()
|
||||
|
||||
changeNext_move(CLICK_CD_GRABBING)
|
||||
DelayNextAction(CLICK_CD_GRABBING)
|
||||
|
||||
if(AM.pulledby)
|
||||
if(!supress_message)
|
||||
@@ -676,7 +676,7 @@
|
||||
..(pressure_difference, direction, pressure_resistance_prob_delta)
|
||||
|
||||
/mob/living/can_resist()
|
||||
return !((next_move > world.time) || !CHECK_MOBILITY(src, MOBILITY_RESIST))
|
||||
return CheckResistCooldown() && CHECK_MOBILITY(src, MOBILITY_RESIST)
|
||||
|
||||
/// Resist verb for attempting to get out of whatever is restraining your motion. Gives you resist clickdelay if do_resist() returns true.
|
||||
/mob/living/verb/resist()
|
||||
@@ -687,10 +687,12 @@
|
||||
return
|
||||
|
||||
if(do_resist())
|
||||
changeNext_move(CLICK_CD_RESIST)
|
||||
MarkResistTime()
|
||||
DelayNextAction(CLICK_CD_RESIST)
|
||||
|
||||
/// The actual proc for resisting. Return TRUE to give clickdelay.
|
||||
/// The actual proc for resisting. Return TRUE to give CLICK_CD_RESIST clickdelay.
|
||||
/mob/living/proc/do_resist()
|
||||
set waitfor = FALSE // some of these sleep.
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_RESIST, src)
|
||||
//resisting grabs (as if it helps anyone...)
|
||||
// only works if you're not cuffed.
|
||||
@@ -701,7 +703,7 @@
|
||||
return old_gs? TRUE : FALSE
|
||||
|
||||
// unbuckling yourself. stops the chain if you try it.
|
||||
if(buckled && last_special <= world.time)
|
||||
if(buckled)
|
||||
log_combat(src, buckled, "resisted buckle")
|
||||
return resist_buckle()
|
||||
|
||||
@@ -730,13 +732,12 @@
|
||||
|
||||
if(CHECK_MOBILITY(src, MOBILITY_USE) && resist_embedded()) //Citadel Change for embedded removal memes - requires being able to use items.
|
||||
// DO NOT GIVE DEFAULT CLICKDELAY - This is a combat action.
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
DelayNextAction(CLICK_CD_MELEE)
|
||||
return FALSE
|
||||
|
||||
if(last_special <= world.time)
|
||||
resist_restraints() //trying to remove cuffs.
|
||||
// DO NOT GIVE CLICKDELAY - last_special handles this.
|
||||
return FALSE
|
||||
resist_restraints() //trying to remove cuffs.
|
||||
// DO NOT GIVE CLICKDELAY
|
||||
return FALSE
|
||||
|
||||
/// Proc to resist a grab. moving_resist is TRUE if this began by someone attempting to move. Return FALSE if still grabbed/failed to break out. Use this instead of resist_grab() directly.
|
||||
/mob/proc/attempt_resist_grab(moving_resist, forced, log = TRUE)
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
REMOVE_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/active_block)
|
||||
var/datum/block_parry_data/data = I.get_block_parry_data()
|
||||
if(timeToNextMove() < data.block_end_click_cd_add)
|
||||
changeNext_move(data.block_end_click_cd_add)
|
||||
DelayNextAction(data.block_end_click_cd_add)
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/ACTIVE_BLOCK_START(obj/item/I)
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
var/full_parry_duration = data.parry_time_windup + data.parry_time_active + data.parry_time_spindown
|
||||
// no system in place to "fallback" if out of the 3 the top priority one can't parry due to constraints but something else can.
|
||||
// can always implement it later, whatever.
|
||||
if((data.parry_respect_clickdelay && (next_move > world.time)) || ((parry_end_time_last + data.parry_cooldown) > world.time))
|
||||
if((data.parry_respect_clickdelay && !CheckActionCooldown()) || ((parry_end_time_last + data.parry_cooldown) > world.time))
|
||||
to_chat(src, "<span class='warning'>You are not ready to parry (again)!</span>")
|
||||
return
|
||||
// Point of no return, make sure everything is set.
|
||||
@@ -121,7 +121,7 @@
|
||||
Stagger(data.parry_failed_stagger_duration)
|
||||
effect_text += "staggering themselves"
|
||||
if(data.parry_failed_clickcd_duration)
|
||||
changeNext_move(data.parry_failed_clickcd_duration)
|
||||
DelayNextAction(data.parry_failed_clickcd_duration, flush = TRUE)
|
||||
effect_text += "throwing themselves off balance"
|
||||
handle_parry_ending_effects(data, effect_text)
|
||||
parrying = NOT_PARRYING
|
||||
@@ -277,7 +277,7 @@
|
||||
if(data.parry_data[PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN])
|
||||
switch(parrying)
|
||||
if(ITEM_PARRY)
|
||||
active_parry_item.melee_attack_chain(src, attacker, null, ATTACKCHAIN_PARRY_COUNTERATTACK, data.parry_data[PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN])
|
||||
active_parry_item.melee_attack_chain(src, attacker, null, ATTACK_IS_PARRY_COUNTERATTACK | ATTACK_IGNORE_CLICKDELAY | ATTACK_IGNORE_ACTION | NO_AUTO_CLICKDELAY_HANDLING, data.parry_data[PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN])
|
||||
effect_text += "reflexively counterattacking with [active_parry_item]"
|
||||
if(UNARMED_PARRY) // WARNING: If you are using these two, the attackchain parry counterattack flags and damage multipliers are unimplemented. Be careful with how you handle this.
|
||||
UnarmedAttack(attacker)
|
||||
|
||||
@@ -216,8 +216,8 @@
|
||||
//proc to upgrade a simple pull into a more aggressive grab.
|
||||
/mob/living/proc/grippedby(mob/living/carbon/user, instant = FALSE)
|
||||
if(user.grab_state < GRAB_KILL)
|
||||
user.changeNext_move(CLICK_CD_GRABBING)
|
||||
playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
user.DelayNextAction(CLICK_CD_GRABBING, flush = TRUE)
|
||||
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
|
||||
if(user.grab_state) //only the first upgrade is instantaneous
|
||||
var/old_grab_state = user.grab_state
|
||||
@@ -271,10 +271,10 @@
|
||||
user.set_pull_offsets(src, grab_state)
|
||||
return 1
|
||||
|
||||
/mob/living/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/mob/living/on_attack_hand(mob/user, act_intent = user.a_intent, attackchain_flags)
|
||||
..() //Ignoring parent return value here.
|
||||
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
|
||||
if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((unarmed_attack_flags & UNARMED_ATTACK_PARRY)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
|
||||
if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
|
||||
log_combat(user, src, "attempted to touch")
|
||||
visible_message("<span class='warning'>[user] attempted to touch [src]!</span>",
|
||||
"<span class='warning'>[user] attempted to touch you!</span>", target = user,
|
||||
@@ -324,6 +324,9 @@
|
||||
|
||||
/mob/living/attack_animal(mob/living/simple_animal/M)
|
||||
M.face_atom(src)
|
||||
if(!M.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
M.DelayNextAction()
|
||||
if(M.melee_damage_upper == 0)
|
||||
M.visible_message("<span class='notice'>\The [M] [M.friendly_verb_continuous] [src]!</span>",
|
||||
"<span class='notice'>You [M.friendly_verb_simple] [src]!</span>", target = src,
|
||||
@@ -339,7 +342,7 @@
|
||||
return 0
|
||||
damage = block_calculate_resultant_damage(damage, return_list)
|
||||
if(M.attack_sound)
|
||||
playsound(loc, M.attack_sound, 50, 1, 1)
|
||||
playsound(src, M.attack_sound, 50, 1, 1)
|
||||
M.do_attack_animation(src)
|
||||
visible_message("<span class='danger'>\The [M] [M.attack_verb_continuous] [src]!</span>", \
|
||||
"<span class='userdanger'>\The [M] [M.attack_verb_continuous] you!</span>", null, COMBAT_MESSAGE_RANGE, null,
|
||||
@@ -348,6 +351,9 @@
|
||||
return damage
|
||||
|
||||
/mob/living/attack_paw(mob/living/carbon/monkey/M)
|
||||
if(!M.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
M.DelayNextAction()
|
||||
if (M.a_intent == INTENT_HARM)
|
||||
if(HAS_TRAIT(M, TRAIT_PACIFISM))
|
||||
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
|
||||
@@ -369,6 +375,7 @@
|
||||
visible_message("<span class='danger'>[M.name] has attempted to bite [src]!</span>", \
|
||||
"<span class='userdanger'>[M.name] has attempted to bite [src]!</span>", null, COMBAT_MESSAGE_RANGE, null,
|
||||
M, "<span class='danger'>You have attempted to bite [src]!</span>")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
|
||||
var/hallucination = 0 //Directly affects how long a mob will hallucinate for
|
||||
|
||||
var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out.
|
||||
var/timeofdeath = 0
|
||||
|
||||
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
fold_in(force = 1)
|
||||
DefaultCombatKnockdown(200)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/mob/living/silicon/pai/attack_hand(mob/living/carbon/human/user)
|
||||
/mob/living/silicon/pai/on_attack_hand(mob/living/carbon/human/user)
|
||||
switch(user.a_intent)
|
||||
if(INTENT_HELP)
|
||||
visible_message("<span class='notice'>[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.</span>",
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
return item
|
||||
return module_active
|
||||
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/uneq_module(obj/item/O)
|
||||
if(!O)
|
||||
return 0
|
||||
|
||||
@@ -289,7 +289,7 @@
|
||||
|
||||
/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.DelayNextAction(CLICK_CD_MELEE)
|
||||
if (!getBruteLoss())
|
||||
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
|
||||
return
|
||||
@@ -311,7 +311,7 @@
|
||||
return
|
||||
|
||||
else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.DelayNextAction(CLICK_CD_MELEE)
|
||||
if (getFireLoss() > 0 || getToxLoss() > 0)
|
||||
if(src == user)
|
||||
to_chat(user, "<span class='notice'>You start fixing yourself...</span>")
|
||||
|
||||
@@ -62,8 +62,7 @@
|
||||
|
||||
return
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user)
|
||||
/mob/living/silicon/robot/on_attack_hand(mob/living/carbon/human/user)
|
||||
add_fingerprint(user)
|
||||
if(opened && !wiresexposed && cell && !issilicon(user))
|
||||
cell.update_icon()
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/silicon/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //the attack was blocked
|
||||
return
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/simple_animal/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //the attack was blocked
|
||||
return
|
||||
|
||||
@@ -41,7 +41,11 @@
|
||||
to_chat(src, "<span class='notice'>Your astral projection is interrupted and your mind is sent back to your body with a shock!</span>")
|
||||
|
||||
/mob/living/simple_animal/astral/ClickOn(var/atom/A, var/params)
|
||||
..()
|
||||
. = ..()
|
||||
attempt_possess(A)
|
||||
|
||||
/mob/living/simple_animal/astral/proc/attempt_possess(atom/A)
|
||||
set waitfor = FALSE
|
||||
if(pseudo_death == FALSE)
|
||||
if(isliving(A))
|
||||
if(ishuman(A))
|
||||
|
||||
@@ -290,7 +290,7 @@
|
||||
return TRUE //Successful completion. Used to prevent child process() continuing if this one is ended early.
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/attack_hand(mob/living/carbon/human/H)
|
||||
/mob/living/simple_animal/bot/on_attack_hand(mob/living/carbon/human/H)
|
||||
if(H.a_intent == INTENT_HELP)
|
||||
interact(H)
|
||||
else
|
||||
@@ -335,7 +335,6 @@
|
||||
user.visible_message("<span class='notice'>[user] uses [W] to pull [paicard] out of [bot_name]!</span>","<span class='notice'>You pull [paicard] out of [bot_name] with [W].</span>")
|
||||
ejectpai(user)
|
||||
else
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM)
|
||||
if(health >= maxHealth)
|
||||
to_chat(user, "<span class='warning'>[src] does not need a repair!</span>")
|
||||
|
||||
@@ -177,7 +177,7 @@ Auto Patrol[]"},
|
||||
target = H
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/attack_hand(mob/living/carbon/human/H)
|
||||
/mob/living/simple_animal/bot/ed209/on_attack_hand(mob/living/carbon/human/H)
|
||||
if(H.a_intent == INTENT_HARM)
|
||||
retaliate(H)
|
||||
return ..()
|
||||
@@ -532,8 +532,10 @@ Auto Patrol[]"},
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/RangedAttack(atom/A)
|
||||
if(!on)
|
||||
return
|
||||
return ..()
|
||||
shootAt(A)
|
||||
DelayNextAction()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/stun_attack(mob/living/carbon/C)
|
||||
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
|
||||
|
||||
@@ -112,7 +112,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
|
||||
target = H
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/honkbot/attack_hand(mob/living/carbon/human/H)
|
||||
/mob/living/simple_animal/bot/honkbot/on_attack_hand(mob/living/carbon/human/H)
|
||||
if(H.a_intent == INTENT_HARM)
|
||||
retaliate(H)
|
||||
addtimer(CALLBACK(src, .proc/react_buzz), 5)
|
||||
|
||||
@@ -604,7 +604,7 @@
|
||||
/mob/living/simple_animal/bot/medbot/proc/get_healchem_toxin(mob/M)
|
||||
return HAS_TRAIT(M, TRAIT_TOXINLOVER)? treatment_tox_toxlover : treatment_tox
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/attack_hand(mob/living/carbon/human/H)
|
||||
/mob/living/simple_animal/bot/medbot/on_attack_hand(mob/living/carbon/human/H)
|
||||
if(H.a_intent == INTENT_DISARM && mode != BOT_TIPPED)
|
||||
H.visible_message("<span class='danger'>[H] begins tipping over [src].</span>", "<span class='warning'>You begin tipping over [src]...</span>")
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ Auto Patrol: []"},
|
||||
/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
|
||||
/mob/living/simple_animal/bot/secbot/on_attack_hand(mob/living/carbon/human/H)
|
||||
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
|
||||
retaliate(H)
|
||||
if(special_retaliate_after_attack(H))
|
||||
|
||||
@@ -283,7 +283,7 @@
|
||||
if(!D.is_decorated)
|
||||
D.decorate_donut()
|
||||
|
||||
/mob/living/simple_animal/pet/cat/cak/attack_hand(mob/living/L)
|
||||
/mob/living/simple_animal/pet/cat/cak/on_attack_hand(mob/living/L)
|
||||
. = ..()
|
||||
if(.) //the attack was blocked
|
||||
return
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
if(stat == CONSCIOUS)
|
||||
udder.generateMilk(milk_reagent)
|
||||
|
||||
/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M)
|
||||
/mob/living/simple_animal/cow/on_attack_hand(mob/living/carbon/M)
|
||||
if(!stat && M.a_intent == INTENT_DISARM && icon_state != icon_dead)
|
||||
M.visible_message("<span class='warning'>[M] tips over [src].</span>",
|
||||
"<span class='notice'>You tip over [src].</span>")
|
||||
|
||||
@@ -86,8 +86,7 @@
|
||||
/obj/guardian_bomb/attackby(mob/living/user)
|
||||
detonate(user)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/guardian_bomb/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/guardian_bomb/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
detonate(user)
|
||||
|
||||
/obj/guardian_bomb/examine(mob/user)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
obj_damage = 80
|
||||
next_move_modifier = 0.5 //attacks 50% faster
|
||||
action_cooldown_mod = 0.5 //attacks 50% faster
|
||||
environment_smash = ENVIRONMENT_SMASH_WALLS
|
||||
playstyle_string = "<span class='holoparasite'>As a <b>standard</b> type you have no special abilities, but take half damage and have powerful attack capable of smashing through walls.</span>"
|
||||
magic_fluff_string = "<span class='holoparasite'>..And draw the Assistant, faceless and generic, but never to be underestimated.</span>"
|
||||
|
||||
@@ -136,7 +136,7 @@ mob/living/simple_animal/hostile/bear/butter //The mighty companion to Cak. Seve
|
||||
if(health < maxHealth)
|
||||
heal_overall_damage(10) //Fast life regen, makes it hard for you to get eaten to death.
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/butter/attack_hand(mob/living/L) //Borrowed code from Cak, feeds people if they hit you. More nutriment but less vitamin to represent BUTTER.
|
||||
/mob/living/simple_animal/hostile/bear/butter/on_attack_hand(mob/living/L) //Borrowed code from Cak, feeds people if they hit you. More nutriment but less vitamin to represent BUTTER.
|
||||
..()
|
||||
if(L.a_intent == INTENT_HARM && L.reagents && !stat)
|
||||
L.reagents.add_reagent(/datum/reagent/consumable/nutriment, 1)
|
||||
|
||||
@@ -523,9 +523,9 @@ mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with mega
|
||||
if(ranged && ranged_cooldown <= world.time)
|
||||
target = A
|
||||
OpenFire(A)
|
||||
..()
|
||||
|
||||
|
||||
DelayNextAction()
|
||||
. = ..()
|
||||
return TRUE
|
||||
|
||||
////// AI Status ///////
|
||||
/mob/living/simple_animal/hostile/proc/AICanContinue(var/list/possible_targets)
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
target = A
|
||||
if(!isturf(loc))
|
||||
return
|
||||
if(next_move > world.time)
|
||||
if(!CheckActionCooldown())
|
||||
return
|
||||
if(hopping)
|
||||
return
|
||||
|
||||
@@ -70,7 +70,7 @@ Difficulty: Medium
|
||||
|
||||
/obj/item/melee/transforming/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
target.add_stun_absorption("miner", 10, INFINITY)
|
||||
..()
|
||||
. = ..()
|
||||
target.stun_absorption -= "miner"
|
||||
|
||||
/obj/item/projectile/kinetic/miner
|
||||
@@ -86,8 +86,8 @@ Difficulty: Medium
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
var/adjustment_amount = amount * 0.1
|
||||
if(world.time + adjustment_amount > next_move)
|
||||
changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
|
||||
if(world.time + adjustment_amount > next_action)
|
||||
DelayNextAction(adjustment_amount, considered_action = FALSE, flush = TRUE) //attacking it interrupts it attacking, but only briefly
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
|
||||
@@ -109,7 +109,7 @@ Difficulty: Medium
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(next_move > world.time || !Adjacent(target)) //some cheating
|
||||
if(!CheckActionCooldown() || !Adjacent(target)) //some cheating
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return
|
||||
face_atom(target)
|
||||
@@ -125,8 +125,8 @@ Difficulty: Medium
|
||||
adjustHealth(-(L.maxHealth * 0.5))
|
||||
L.gib()
|
||||
return TRUE
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
miner_saw.melee_attack_chain(src, target)
|
||||
miner_saw.melee_attack_chain(src, target, null, ATTACK_IGNORE_CLICKDELAY)
|
||||
FlushCurrentAction()
|
||||
if(guidance)
|
||||
adjustHealth(-2)
|
||||
transform_weapon()
|
||||
@@ -161,19 +161,19 @@ Difficulty: Medium
|
||||
face_atom(target)
|
||||
new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
|
||||
Shoot(target)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
DelayNextAction(CLICK_CD_RANGE, flush = TRUE)
|
||||
|
||||
//I'm still of the belief that this entire proc needs to be wiped from existence.
|
||||
// do not take my touching of it to be endorsement of it. ~mso
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
|
||||
while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
|
||||
while(!QDELETED(target) && !CheckActionCooldown()) //this is done this way because next_move can change to be sooner while we sleep.
|
||||
stoplag(1)
|
||||
sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
|
||||
sleep((next_action - world.time) * 1.5) //but don't ask me what the fuck this is about
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(dashing || next_move > world.time || !Adjacent(target))
|
||||
if(dashing && next_move <= world.time)
|
||||
next_move = world.time + 1
|
||||
if(dashing || !CheckActionCooldown() || !Adjacent(target))
|
||||
if(dashing && next_action <= world.time)
|
||||
SetNextAction(1, considered_action = FALSE, immediate = FALSE, flush = TRUE)
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
|
||||
return
|
||||
AttackingTarget()
|
||||
|
||||
@@ -385,10 +385,7 @@ Difficulty: Very Hard
|
||||
if(isliving(speaker))
|
||||
ActivationReaction(speaker, ACTIVATE_SPEECH)
|
||||
|
||||
/obj/machinery/anomalous_crystal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
/obj/machinery/anomalous_crystal/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
ActivationReaction(user, ACTIVATE_TOUCH)
|
||||
|
||||
/obj/machinery/anomalous_crystal/attackby(obj/item/I, mob/user, params)
|
||||
|
||||
@@ -105,7 +105,7 @@ IGNORE_PROC_IF_NOT_TARGET(attack_slime)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
if(L != set_target)
|
||||
L.changeNext_move(I.click_delay) //pre_attacked_by not called
|
||||
I.ApplyAttackCooldown(L, src)
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
|
||||
desc = "You're not quite sure how a signal can be menacing."
|
||||
invisibility = 100
|
||||
|
||||
/obj/structure/elite_tumor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/elite_tumor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(ishuman(user))
|
||||
switch(activity)
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
Bruise()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/simple_animal/hostile/mushroom/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) // the attack was blocked
|
||||
return
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
.=..()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/spawner/nether/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/spawner/nether/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
user.visible_message("<span class='warning'>[user] is violently pulled into the link!</span>", \
|
||||
"<span class='userdanger'>Touching the portal, you are quickly pulled through into a world of unimaginable horror!</span>")
|
||||
contents.Add(user)
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
else
|
||||
clear_alert("temp")
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/on_attack_hand(mob/living/carbon/human/M)
|
||||
..()
|
||||
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, TRUE)
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@
|
||||
* Attack responces
|
||||
*/
|
||||
//Humans, monkeys, aliens
|
||||
/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M)
|
||||
/mob/living/simple_animal/parrot/on_attack_hand(mob/living/carbon/M)
|
||||
..()
|
||||
if(client)
|
||||
return
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
discipline_slime(user)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/slime/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/simple_animal/slime/on_attack_hand(mob/living/carbon/human/M)
|
||||
if(buckled)
|
||||
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
|
||||
if(buckled == M)
|
||||
@@ -356,7 +356,7 @@
|
||||
attacked += 10
|
||||
if(prob(25))
|
||||
user.do_attack_animation(src)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
W.ApplyAttackCooldown(user, src)
|
||||
to_chat(user, "<span class='danger'>[W] passes right through [src]!</span>")
|
||||
return
|
||||
if(Discipline && prob(50)) // wow, buddy, why am I getting attacked??
|
||||
|
||||
@@ -13,9 +13,7 @@
|
||||
hud_used.show_hud(hud_used.hud_version)
|
||||
hud_used.update_ui_style(ui_style2icon(client.prefs.UI_style))
|
||||
|
||||
next_move = 1
|
||||
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
reset_perspective(loc)
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
blocks_emissive = EMISSIVE_BLOCK_GENERIC
|
||||
|
||||
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
|
||||
|
||||
attack_hand_is_action = TRUE
|
||||
attack_hand_unwieldlyness = CLICK_CD_MELEE
|
||||
attack_hand_speed = 0
|
||||
|
||||
/// What receives our keyboard input. src by default.
|
||||
var/datum/focus
|
||||
@@ -35,7 +39,6 @@
|
||||
var/list/logging = list()
|
||||
var/atom/machine = null
|
||||
|
||||
var/next_move = null
|
||||
var/create_area_cooldown
|
||||
/// Whether or not the mob is currently being transformed into another mob or into another state of being. This will prevent it from moving or doing realistically anything.
|
||||
/// Don't you DARE use this for a cheap way to ensure someone is stunned in your code.
|
||||
|
||||
Reference in New Issue
Block a user