//! Light / Heavy punches
enum EFightLogicCooldownCategory
{
EVADE = 0
}
class DayZPlayerMeleeFightLogic_LightHeavy
{
//! cooldown timers settings
const float EVADE_COOLDOWN = 0.5;
//
const float CLOSE_TARGET_DISTANCE = 1.5;
//! dummy ammo types
const string DUMMY_LIGHT_AMMO = "Dummy_Light";
const string DUMMY_HEAVY_AMMO = "Dummy_Heavy";
protected PlayerBase m_Player;
protected ref DayZPlayerImplementMeleeCombat m_MeleeCombat;
protected EMeleeHitType m_HitType;
protected ref map <int, ref Timer> m_CooldownTimers;
protected Mission m_Mission;
protected bool m_IsInBlock;
protected bool m_IsEvading;
protected bool m_IsInComboRange;
protected bool m_WasPreviousHitProcessed;
void DayZPlayerMeleeFightLogic_LightHeavy(DayZPlayerImplement player)
{
Init(player);
}
void Init(DayZPlayerImplement player)
{
m_DZPlayer = player;
m_Player = PlayerBase.Cast(player);
m_MeleeCombat = m_Player.GetMeleeCombat();
m_Mission = g_Game.GetMission();
m_IsInBlock = false;
m_IsEvading = false;
m_WasPreviousHitProcessed = false;
m_HitType = EMeleeHitType.NONE;
RegisterCooldowns();
}
void ~DayZPlayerMeleeFightLogic_LightHeavy() {}
bool IsInBlock()
{
return m_IsInBlock;
}
void SetBlock(bool block)
{
m_IsInBlock = block;
}
bool IsEvading()
{
return m_IsEvading;
}
bool GetCurrentHitType()
{
return m_HitType;
}
bool CanFight()
{
if (m_Player.IsEmotePlaying())
return false;
if (m_Player.GetActionManager() && m_Player.GetActionManager().GetRunningAction())
return false;
return true;
}
protected void RegisterCooldowns()
{
m_CooldownTimers = new map<int, ref Timer>();
m_CooldownTimers.Insert(EFightLogicCooldownCategory.EVADE, new Timer(CALL_CATEGORY_SYSTEM)); // evades
}
protected EMeleeHitType GetAttackTypeFromInputs(HumanInputController pInputs)
{
if (pInputs.IsMeleeFastAttackModifier() && m_Player.CanConsumeStamina(EStaminaConsumers.MELEE_HEAVY))
{
return EMeleeHitType.HEAVY;
}
return EMeleeHitType.LIGHT;
}
protected EMeleeHitType GetAttackTypeByWeaponAttachments(EntityAI pEntity)
{
if (!m_Player.CanConsumeStamina(EStaminaConsumers.MELEE_HEAVY))
{
return EMeleeHitType.NONE;
}
//! use stabbing if the bayonet/knife is attached to firearm
if (pEntity.HasBayonetAttached())
{
return EMeleeHitType.WPN_STAB;
}
else if (pEntity.HasButtstockAttached())
{
return EMeleeHitType.WPN_HIT_BUTTSTOCK;
}
return EMeleeHitType.WPN_HIT;
}
protected float GetAttackTypeByDistanceToTarget(EntityAI pTarget, EMeleeTargetType pTargetType = EMeleeTargetType.ALIGNABLE)
{
if (pTargetType == EMeleeTargetType.NONALIGNABLE)
{
return 1.0;
}
//! target in short distance - in place attack
if (IsShortDistance(pTarget, Math.SqrFloat(CLOSE_TARGET_DISTANCE)))
{
return 1.0;
}
//! target is far from the player - forward movement attack
return 0.0;
}
bool HandleFightLogic(int pCurrentCommandID, HumanInputController pInputs, EntityAI pEntityInHands, HumanMovementState pMovementState, out bool pContinueAttack)
{
HumanInventoryWithFSM invFSM = HumanInventoryWithFSM.Cast(m_Player.GetHumanInventory());
if (invFSM && !invFSM.IsIdle())
return false;
HumanCommandMove hcm = m_Player.GetCommand_Move();
InventoryItem itemInHands = InventoryItem.Cast(pEntityInHands);
bool isFireWeapon = itemInHands && itemInHands.IsWeapon();
//! Check if we need to damage
HandleHitEvent(pCurrentCommandID, pInputs, itemInHands, pMovementState, pContinueAttack);
//! Actually pressing a button to start a melee attack
if ((pInputs.IsAttackButtonDown() && !isFireWeapon) || (pInputs.IsMeleeWeaponAttack() && isFireWeapon) || (pContinueAttack && isFireWeapon))
{
//Debug.MeleeLog(m_Player, string.Format("HandleFightLogic[1] attackButtonDown=%1, meleeWeaponAttack=%2, pContinueAttack=%3, isFireWeapon=%4", pInputs.IsAttackButtonDown(), pInputs.IsMeleeWeaponAttack(), pContinueAttack, isFireWeapon));
//! do not perform attacks when blocking
if (m_IsInBlock || m_IsEvading)
return false;
//! if the item in hands cannot be used as melee weapon
if (itemInHands && !itemInHands.IsMeleeWeapon() && !isFireWeapon)
return false;
//! Currently not performing any attacks, so here we start the initial
if (pCurrentCommandID == DayZPlayerConstants.COMMANDID_MOVE)
{
//Debug.MeleeLog(m_Player, "HandleFightLogic[1a]");
//! melee with firearm
if (isFireWeapon)
{
return HandleInitialFirearmMelee(pCurrentCommandID, pInputs, itemInHands, pMovementState, pContinueAttack);
}
else
{
//! first attack in raised erc (light or heavy if modifier is used). Also added support for finishers
if (pMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_RAISEDERECT)
{
return HandleInitialMeleeErc(pCurrentCommandID, pInputs, itemInHands, pMovementState, pContinueAttack);
}
//! kick from raised pne
else if (pMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_RAISEDPRONE)
{
return HandleProneKick(pCurrentCommandID, pInputs, itemInHands, pMovementState, pContinueAttack);
}
//! sprint attack in erc stance
else if (pMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_ERECT && m_Player.IsSprintFull())
{
return HandleSprintAttack(pCurrentCommandID, pInputs, itemInHands, pMovementState, pContinueAttack);
}
}
}
//! combo hits - when we are already in Melee command and clicking UseButton
else if (pCurrentCommandID == DayZPlayerConstants.COMMANDID_MELEE2)
{
m_IsInComboRange = m_Player.GetCommand_Melee2().IsInComboRange();
if (m_IsInComboRange)
{
return HandleComboHit(pCurrentCommandID, pInputs, itemInHands, pMovementState, pContinueAttack);
}
}
}
//! evade and blocking logic
else if (!isFireWeapon && pCurrentCommandID == DayZPlayerConstants.COMMANDID_MOVE)
{
//! evades in raised erc stance while moving
if (pMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_RAISEDERECT)
{
int roll = pInputs.IsMeleeLREvade();
if (roll != 0)
{
//! not enough stamina to do evades
if (!m_Player.CanConsumeStamina(EStaminaConsumers.MELEE_EVADE))
{
return false;
}
float angle;
if (roll == 1)
{
angle = -90; // left
}
else
{
angle = 90; // right
}
// start melee evade
m_IsEvading = true;
SetCooldown(EVADE_COOLDOWN, EFightLogicCooldownCategory.EVADE);
hcm.StartMeleeEvadeA(angle);
m_Player.DepleteStamina(EStaminaModifiers.MELEE_EVADE);
//Inflict shock when sidestepping with broken legs
if (m_Player.GetBrokenLegs() == eBrokenLegs.BROKEN_LEGS)
{
m_Player.m_ShockHandler.SetShock(PlayerConstants.BROKEN_LEGS_LIGHT_MELEE_SHOCK);
m_Player.m_ShockHandler.CheckValue(true);
}
}
}
//! stand up when crouching and raised pressed
if (pInputs.IsWeaponRaised() && pMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_CROUCH)
{
//Debug.MeleeLog(m_Player, "HandleFightLogic[2b]");
if (DayZPlayerUtils.PlayerCanChangeStance(m_Player, DayZPlayerConstants.STANCEIDX_RAISEDERECT))
{
//Debug.MeleeLog(m_Player, "HandleFightLogic[2c]");
hcm.ForceStance(DayZPlayerConstants.STANCEIDX_RAISEDERECT);
return false;
}
}
//! blocks in raised erc/pro stance
//! (bare hand or with melee weapon only)
if (!isFireWeapon && (pMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_RAISEDERECT || pMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_RAISEDPRONE))
{
float angle2;
if (hcm.GetCurrentInputAngle(angle2) && (angle2 < -130.0 || angle2 > 130))
{
hcm.SetMeleeBlock(true);
SetBlock(true);
}
else
{
hcm.SetMeleeBlock(false);
SetBlock(false);
}
}
else
{
hcm.SetMeleeBlock(false);
SetBlock(false);
}
}
return false;
}
//! Handle the event that our melee hit something
protected bool HandleHitEvent(int pCurrentCommandID, HumanInputController pInputs, InventoryItem itemInHands, HumanMovementState pMovementState, out bool pContinueAttack)
{
//! Check if we need to damage
if (pCurrentCommandID == DayZPlayerConstants.COMMANDID_MELEE2)
{
HumanCommandMelee2 hmc2a = m_Player.GetCommand_Melee2();
if (hmc2a)
{
//! on anim event Hit received
if (hmc2a.WasHit())
{
//Debug.MeleeLog(m_Player, "HandleHitEvent[START]");
//Debug.MeleeLog(m_Player, string.Format("HandleHitEvent[1] target=%1, hitPos=%2, hitZoneIdx=%3, finisherType=%4", m_MeleeCombat.GetTargetEntity(), m_MeleeCombat.GetHitPos().ToString(), m_MeleeCombat.GetHitZoneIdx(), m_MeleeCombat.GetFinisherType()));
if (m_MeleeCombat.GetFinisherType() == -1)
{
//Debug.MeleeLog(m_Player, string.Format("HandleHitEvent[2] target=%1, hitPos=%2, hitZoneIdx=%3, finisherType=%4", m_MeleeCombat.GetTargetEntity(), m_MeleeCombat.GetHitPos().ToString(), m_MeleeCombat.GetHitZoneIdx(), m_MeleeCombat.GetFinisherType()));
//! re-target (enemy can have moved out of range or disappeared)
m_MeleeCombat.Update(itemInHands, m_HitType, true);
}
//! evaluate hit - selection of cfg 'ammo' type
EvaluateHit(itemInHands);
//Get gloves
ClothingBase gloves;
if (m_HitType == EMeleeHitType.KICK)
{
//We kick so "gloves" will be the shoes
gloves = ClothingBase.Cast(m_Player.GetItemOnSlot("FEET"));
}
else
{
gloves = ClothingBase.Cast(m_Player.GetItemOnSlot("GLOVES"));
}
//If we hit something, inflict damage
DamageHands(m_Player, gloves, itemInHands);
m_MeleeCombat.ResetTarget();
EnableControls();
m_WasPreviousHitProcessed = true;
//Debug.MeleeLog(m_Player, "HandleHitEvent[END]");
return true;
}
}
}
return false;
}
//! NOTE: Only singular (or first) hits, combo attacks are handled in combo
protected bool HandleInitialFirearmMelee(int pCurrentCommandID, HumanInputController pInputs, InventoryItem itemInHands, HumanMovementState pMovementState, out bool pContinueAttack)
{
//! don't allow bash to interfere with actions like chambering or ejecting bullets
Weapon_Base weapon = Weapon_Base.Cast(itemInHands);
if (weapon.IsWaitingForActionFinish())
return false;
HumanCommandMove hcm = m_Player.GetCommand_Move();
//! perform firearm melee from raised erect or continue with attack after character stand up from crouch
if (hcm.GetCurrentMovementSpeed() <= 2.05 && (pMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_RAISEDERECT || pContinueAttack) && !m_Player.IsFighting())
{
m_HitType = GetAttackTypeByWeaponAttachments(itemInHands);
if ( m_HitType == EMeleeHitType.NONE )
{
pContinueAttack = false;
return false; //! exit if there is no suitable attack
}
m_MeleeCombat.Update(itemInHands, m_HitType);
EntityAI target;
EMeleeTargetType targetType;
GetTargetData(target, targetType);
float attackByDistance = GetAttackTypeByDistanceToTarget(target, targetType);
m_Player.StartCommand_Melee2(target, m_HitType == EMeleeHitType.WPN_STAB, attackByDistance, m_MeleeCombat.GetHitPos());
m_Player.DepleteStamina(EStaminaModifiers.MELEE_HEAVY);
DisableControls();
pContinueAttack = false; // reset continueAttack flag
return true;
}
//! char stand up when performing firearm melee from crouch
else if ( pMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_RAISEDCROUCH )
{
if (hcm)
{
hcm.ForceStance(DayZPlayerConstants.STANCEIDX_RAISEDERECT);
pContinueAttack = true;
return false;
}
}
return false;
}
//! First attack in raised erc (light or heavy if modifier is used). Also added support for finishers
protected bool HandleInitialMeleeErc(int pCurrentCommandID, HumanInputController pInputs, InventoryItem itemInHands, HumanMovementState pMovementState, out bool pContinueAttack)
{
//Debug.MeleeLog(m_Player, "HandleInitialMeleeErc[1]");
m_HitType = GetAttackTypeFromInputs(pInputs);
m_MeleeCombat.Update(itemInHands, m_HitType);
//Debug.MeleeLog(m_Player, string.Format("HandleInitialMeleeErc[2] %1", EnumTools.EnumToString(EMeleeHitType, m_HitType)));
EntityAI target;
EMeleeTargetType targetType;
GetTargetData(target, targetType);
float attackByDistance = GetAttackTypeByDistanceToTarget(target, targetType);
// finisher attack hittype override
int finisherType = m_MeleeCombat.GetFinisherType();
if (finisherType != -1)
{
int animationType = DetermineFinisherAnimation(finisherType);
if (animationType > -1)
{
//Debug.MeleeLog(m_Player, string.Format("HandleInitialMeleeErc[3a] target=%1, finisherType=%2, animationType=%3, hitPositionWS=%4", target, finisherType, animationType, m_MeleeCombat.GetHitPos().ToString()));
m_Player.StartCommand_Melee2(target, animationType, attackByDistance, m_MeleeCombat.GetHitPos());
}
else
{
//Debug.MeleeLog(m_Player, string.Format("HandleInitialMeleeErc[3b] target=%1, finisherType=%2, animationType=%3, hitPositionWS=%4", target, finisherType, (m_HitType == EMeleeHitType.HEAVY).ToString(), m_MeleeCombat.GetHitPos().ToString()));
m_Player.StartCommand_Melee2(target, m_HitType == EMeleeHitType.HEAVY, attackByDistance, m_MeleeCombat.GetHitPos());
}
m_HitType = finisherType;
target.SetBeingBackstabbed(finisherType);
}
else
{
//Debug.MeleeLog(m_Player, string.Format("HandleInitialMeleeErc[3d] target=%1, animationType=%2, hitPositionWS=%3", target, (m_HitType == EMeleeHitType.HEAVY).ToString(), m_MeleeCombat.GetHitPos().ToString()));
m_Player.StartCommand_Melee2(target, m_HitType == EMeleeHitType.HEAVY, attackByDistance, m_MeleeCombat.GetHitPos());
}
if (m_HitType == EMeleeHitType.HEAVY)
{
m_Player.DepleteStamina(EStaminaModifiers.MELEE_HEAVY);
if (m_Player.GetBrokenLegs() == eBrokenLegs.BROKEN_LEGS)
{
m_Player.m_ShockHandler.SetShock(PlayerConstants.BROKEN_LEGS_HEAVY_MELEE_SHOCK);
m_Player.m_ShockHandler.CheckValue(true);
}
}
else
{
m_Player.DepleteStamina(EStaminaModifiers.MELEE_LIGHT);
if (m_Player.GetBrokenLegs() == eBrokenLegs.BROKEN_LEGS)
{
m_Player.m_ShockHandler.SetShock(PlayerConstants.BROKEN_LEGS_LIGHT_MELEE_SHOCK);
m_Player.m_ShockHandler.CheckValue(true);
}
}
m_WasPreviousHitProcessed = false;
DisableControls();
return true;
}
//! kick from raised pne
protected bool HandleProneKick(int pCurrentCommandID, HumanInputController pInputs, InventoryItem itemInHands, HumanMovementState pMovementState, out bool pContinueAttack)
{
HumanCommandWeapons hcw = m_Player.GetCommandModifier_Weapons();
float hcw_angle = hcw.GetBaseAimingAngleLR();
//! check if player is on back
//! (situation where the player is raised in prone and on back is not in anim graph)
if ( ( hcw_angle < -90 || hcw_angle > 90 ) && m_Player.GetBrokenLegs() != eBrokenLegs.BROKEN_LEGS )
{
// targetting
m_HitType = EMeleeHitType.KICK;
m_MeleeCombat.Update(itemInHands, m_HitType);
EntityAI target;
EMeleeTargetType targetType;
GetTargetData(target, targetType);
float attackByDistance = GetAttackTypeByDistanceToTarget(target, targetType);
// command
m_Player.StartCommand_Melee2(target, false, attackByDistance, m_MeleeCombat.GetHitPos());
m_Player.DepleteStamina(EStaminaModifiers.MELEE_HEAVY);
DisableControls();
return true;
}
return false;
}
//! sprint attack in erc stance
protected bool HandleSprintAttack(int pCurrentCommandID, HumanInputController pInputs, InventoryItem itemInHands, HumanMovementState pMovementState, out bool pContinueAttack)
{
//! targetting
m_HitType = EMeleeHitType.SPRINT;
m_MeleeCombat.Update(itemInHands, m_HitType);
EntityAI target;
EMeleeTargetType targetType;
GetTargetData(target, targetType);
float attackByDistance = GetAttackTypeByDistanceToTarget(target, targetType);
//! command
//Debug.MeleeLog(m_Player, string.Format("HandleSprintAttack[1] target=%1, animationType=%2, hitPositionWS=%3", target, false, m_MeleeCombat.GetHitPos().ToString()));
m_Player.StartCommand_Melee2(target, EMeleeHitType.HEAVY, attackByDistance, m_MeleeCombat.GetHitPos());
m_Player.DepleteStamina(EStaminaModifiers.MELEE_HEAVY);
DisableControls();
return true;
}
//! combo hits - when we are already in Melee command and clicking UseButton
protected bool HandleComboHit(int pCurrentCommandID, HumanInputController pInputs, InventoryItem itemInHands, HumanMovementState pMovementState, out bool pContinueAttack)
{
//Debug.MeleeLog(m_Player, "HandleComboHit::");
EMeleeHitType hitType;
//! select if the next attack will be light or heavy (based on input/attachment modifier)
if (itemInHands && itemInHands.IsWeapon())
hitType = GetAttackTypeByWeaponAttachments(itemInHands);
else
hitType = GetAttackTypeFromInputs(pInputs);
//! no suitable attack - skip that
if (hitType == EMeleeHitType.NONE)
return false;
//! No combos for the finisher command
if (m_MeleeCombat.GetFinisherType() > -1)
return false;
bool isHeavy = (hitType == EMeleeHitType.HEAVY || hitType == EMeleeHitType.WPN_STAB);
EMeleeHitType previousHitType = m_HitType;
//! wait for the previous hit commit before hitting again if the next attack is heavy and the previous wasn't - otherwise the previous light attack will turn into heavy
if (!m_WasPreviousHitProcessed && previousHitType != EMeleeHitType.HEAVY && isHeavy)
{
return false;
}
m_HitType = hitType;
//! targetting
//Debug.MeleeLog(m_Player, string.Format("HandleComboHit:: %1", EnumTools.EnumToString(EMeleeHitType, m_HitType)));
m_MeleeCombat.Update(itemInHands, m_HitType);
EntityAI target;
EMeleeTargetType targetType;
GetTargetData(target, targetType);
float attackByDistance = GetAttackTypeByDistanceToTarget(target, targetType);
//! continue 'combo' - left hand attacks
m_Player.GetCommand_Melee2().ContinueCombo(isHeavy, attackByDistance, target, m_MeleeCombat.GetHitPos());
DisableControls();
//! broken legs shock
if (m_Player.GetBrokenLegs() == eBrokenLegs.BROKEN_LEGS)
{
float shock = PlayerConstants.BROKEN_LEGS_HEAVY_MELEE_SHOCK;
if (!isHeavy)
shock = PlayerConstants.BROKEN_LEGS_LIGHT_MELEE_SHOCK;
m_Player.m_ShockHandler.SetShock(PlayerConstants.BROKEN_LEGS_HEAVY_MELEE_SHOCK);
m_Player.m_ShockHandler.CheckValue(true);
}
//! stamina depletion per attack
switch (m_HitType)
{
case EMeleeHitType.HEAVY:
case EMeleeHitType.SPRINT:
case EMeleeHitType.WPN_STAB:
case EMeleeHitType.WPN_HIT_BUTTSTOCK:
case EMeleeHitType.WPN_HIT:
m_Player.DepleteStamina(EStaminaModifiers.MELEE_HEAVY);
break;
default:
m_Player.DepleteStamina(EStaminaModifiers.MELEE_LIGHT);
break;
}
return true;
}
protected void EvaluateHit(InventoryItem weapon)
{
EntityAI target = m_MeleeCombat.GetTargetEntity();
if (target)
{
if (target.IsInherited(DayZPlayer))
{
EvaluateHit_Player(weapon, target);
}
else if (target.IsInherited(DayZInfected))
{
EvaluateHit_Infected(weapon, target);
}
else if (target.GetMeleeTargetType() == EMeleeTargetType.NONALIGNABLE)
{
EvaluateHit_NonAlignableObjects(weapon, target);
}
else
{
EvaluateHit_Common(weapon, target);
}
m_MeleeCombat.CheckMeleeItem();
}
}
protected void EvaluateHit_Player(InventoryItem weapon, Object target)
{
int hitZoneIdx = m_MeleeCombat.GetHitZoneIdx();
int weaponMode = m_MeleeCombat.GetWeaponMode();
int forcedWeaponMode = -1;
vector hitPosWS;
bool forcedDummy = false;
PlayerBase targetPlayer = PlayerBase.Cast(target);
//! Melee Hit/Impact modifiers
if (targetPlayer)
{
vector targetPos = targetPlayer.GetPosition();
vector agressorPos = m_Player.GetPosition();
// We get the angle from which an infected hit the blocking player
float hitAngle = Math.RAD2DEG * Math.AbsFloat(Math3D.AngleFromPosition(targetPos, MiscGameplayFunctions.GetHeadingVector(targetPlayer), agressorPos));
//! if the oponnent is in Melee Block shift the damage down
if (targetPlayer.GetMeleeFightLogic() && targetPlayer.GetMeleeFightLogic().IsInBlock() && hitAngle <= GameConstants.PVP_MAX_BLOCKABLE_ANGLE)
{
if (weaponMode > 0)
{
forcedWeaponMode = --weaponMode; // Heavy -> Light shift
}
else
forcedDummy = true; // dummy hits, cannot shift lower than 0
}
}
EvaluateHit_Common(weapon, target, forcedDummy, forcedWeaponMode);
}
protected void EvaluateHit_Infected(InventoryItem weapon, Object target)
{
//If the finisher attack haven't been performed, then use normal hit
if (!EvaluateFinisherAttack(weapon, target))
EvaluateHit_Common(weapon, target);
}
//! Check and evaluate stealth kill, if applicable
protected bool EvaluateFinisherAttack(InventoryItem weapon, Object target)
{
//Debug.MeleeLog(m_Player, string.Format("EvaluateFinisherAttack[1] target=%1, hitPos=%2, hitZoneIdx=%3, finisherType=%4", m_MeleeCombat.GetTargetEntity(), m_MeleeCombat.GetHitPos().ToString(), m_MeleeCombat.GetHitZoneIdx(), m_MeleeCombat.GetFinisherType()));
if (m_MeleeCombat.GetFinisherType() > -1)
{
if (g_Game.IsServer())
DamageSystem.CloseCombatDamage(m_Player, target, m_MeleeCombat.GetHitZoneIdx(), DetermineFinisherAmmo(m_MeleeCombat.GetFinisherType()), m_MeleeCombat.GetHitPos(), ProcessDirectDamageFlags.NO_ATTACHMENT_TRANSFER);
return true;
}
return false;
}
protected void EvaluateHit_Common(InventoryItem weapon, Object target, bool forcedDummy=false, int forcedWeaponMode = -1)
{
int hitZoneIdx = m_MeleeCombat.GetHitZoneIdx();
int weaponMode = m_MeleeCombat.GetWeaponMode();
vector hitPosWS;
string ammo;
if (forcedWeaponMode > -1)
weaponMode = forcedWeaponMode;
EntityAI targetEntity = EntityAI.Cast(target);
//! check if we need to use dummy hit
if (!DummyHitSelector(m_HitType, ammo) && !forcedDummy)
{
//! normal hit with applied damage to targeted component
if (hitZoneIdx >= 0)
{
hitPosWS = targetEntity.ModelToWorld(targetEntity.GetDefaultHitPosition());
if (WeaponDestroyedCheck(weapon, ammo))
{
DamageSystem.CloseCombatDamage(m_Player, target, hitZoneIdx, ammo, hitPosWS);
//Debug.MeleeLog(m_Player, string.Format("EvaluateHit_Common[a]::CloseCombatDamage:: target: %1, hitzone: %2, ammo: %3", target, hitZoneIdx, ammo));
}
else
{
m_Player.ProcessMeleeHit(weapon, weaponMode, target, hitZoneIdx, hitPosWS);
//Debug.MeleeLog(m_Player, string.Format("EvaluateHit_Common[b]::ProcessMeleeHit:: target: %1, hitzone: %2, meleeMode: %3, forcedWeaponMode:%4", target, hitZoneIdx, weaponMode));
}
}
}
else
{
//! play hit animation for dummy hits
if (g_Game.IsServer() && targetEntity)
{
DummyHitSelector(m_HitType, ammo);
hitPosWS = targetEntity.ModelToWorld(targetEntity.GetDefaultHitPosition()); //! override hit pos by pos defined in type
DamageSystem.CloseCombatDamage(m_Player, target, hitZoneIdx, ammo, hitPosWS);
//Debug.MeleeLog(m_Player, string.Format("EvaluateHit_Common[c]::CloseCombatDamage:: target: %1, hitzone: %2, meleeMode: %3, ammo: %4", target, hitZoneIdx, weaponMode, ammo));
}
}
}
protected void EvaluateHit_NonAlignableObjects(InventoryItem weapon, Object target)
{
int hitZoneIdx = m_MeleeCombat.GetHitZoneIdx();
vector hitPosWS;
string ammo;
if (hitZoneIdx >= 0)
{
if (WeaponDestroyedCheck(weapon,ammo))
DamageSystem.CloseCombatDamage(m_Player, target, hitZoneIdx, ammo, m_MeleeCombat.GetHitPos());
else
m_Player.ProcessMeleeHit(weapon, m_MeleeCombat.GetWeaponMode(), target, hitZoneIdx, m_MeleeCombat.GetHitPos());
}
return;
}
bool WeaponDestroyedCheck(InventoryItem weapon, out string ammo)
{
if (!weapon)
return false;
Weapon_Base firearm = Weapon_Base.Cast(weapon);
ItemBase bayonet = ItemBase.Cast(weapon.GetInventory().FindAttachment(weapon.GetBayonetAttachmentIdx()));
if ( firearm && bayonet && bayonet.IsRuined() )
{
ammo = bayonet.GetRuinedMeleeAmmoType();
return true;
}
else if (weapon.IsRuined())
{
ammo = weapon.GetRuinedMeleeAmmoType();
return true;
}
return false;
}
protected void GetTargetData(out EntityAI target, out EMeleeTargetType targetType)
{
target = m_MeleeCombat.GetTargetEntity();
targetType = EMeleeTargetType.ALIGNABLE; //! default
// If there is no hitzone defined, then we won't be able to hit the target anyways..
if (m_MeleeCombat.GetHitZoneIdx() < 0)
{
target = null;
}
if ( target )
{
targetType = target.GetMeleeTargetType();
}
//! nullify target for nonalignable objects (big objects)
if ( targetType == EMeleeTargetType.NONALIGNABLE )
{
target = null;
}
}
//! evaluation of hit player vs. player
protected bool DummyHitSelector(EMeleeHitType hitType, out string ammoType)
{
switch (hitType)
{
//! in case of kick (on back or push from erc) change the ammo type to dummy
case EMeleeHitType.KICK:
ammoType = DUMMY_HEAVY_AMMO;
return true;
break;
}
ammoType = DUMMY_LIGHT_AMMO;
return false;
}
//! DEPRECATED - moved into DayZPlayerImplementMeleeCombat
protected bool IsBehindEntity(int angle, DayZPlayer source, Object target)
{
return false;
}
protected void SetCooldown(float time, EFightLogicCooldownCategory cooldownCategory)
{
//! stops currently running cooldown timer (for specific category)
if ( m_CooldownTimers.Get(cooldownCategory).IsRunning() )
{
m_CooldownTimers.Get(cooldownCategory).Stop();
}
//! param for ResetCooldown
Param1<int> param = new Param1<int>(cooldownCategory);
m_CooldownTimers.Get(cooldownCategory).Run(time, this, "ResetCooldown", param);
}
protected void ResetCooldown(EFightLogicCooldownCategory cooldownCategory)
{
switch (cooldownCategory)
{
case EFightLogicCooldownCategory.EVADE:
m_IsEvading = false;
break;
}
}
protected void EnableControls();
protected void DisableControls();
protected void DamageHands(DayZPlayer DZPlayer, ClothingBase gloves, InventoryItem itemInHands)
{
EntityAI target = m_MeleeCombat.GetTargetEntity();
//We did not hit anything
if (itemInHands || !target || !DZPlayer)
return;
//Check if server side
if (g_Game.IsServer())
{
int randNum;
//If gloves, damage gloves
if (gloves && gloves.GetHealthLevel() < GameConstants.STATE_RUINED)
{
gloves.DecreaseHealth("", "", 1);
}
else
{
//Do not add bleeding if hitting player, zombie or animal
if (PlayerBase.Cast(target) || DayZCreatureAI.Cast(target))
return;
BleedingSourcesManagerServer bleedingManager;
//We don't inflict bleeding to hands when kicking
if (m_HitType != EMeleeHitType.KICK)
{
//Random bleeding source
randNum = Math.RandomIntInclusive(1, 15);
switch (randNum)
{
case 1:
if (m_Player)
{
bleedingManager = m_Player.GetBleedingManagerServer();
if (bleedingManager)
bleedingManager.AttemptAddBleedingSourceBySelection("RightForeArmRoll");
}
break;
case 2:
if (m_Player)
{
bleedingManager = m_Player.GetBleedingManagerServer();
if (bleedingManager)
bleedingManager.AttemptAddBleedingSourceBySelection("LeftForeArmRoll");
}
break;
}
}
else
{
//Random bleeding source
randNum = Math.RandomIntInclusive(1, 15);
//We only add bleeding to left foot as character kicks with left foot
switch (randNum)
{
case 1:
if (m_Player)
{
bleedingManager = m_Player.GetBleedingManagerServer();
if (bleedingManager)
bleedingManager.AttemptAddBleedingSourceBySelection("LeftToeBase");
}
break;
case 2:
if (m_Player)
{
bleedingManager = m_Player.GetBleedingManagerServer();
if (bleedingManager)
bleedingManager.AttemptAddBleedingSourceBySelection("LeftFoot");
}
break;
}
}
}
}
}
//! Picks a specific finisher animation. Not used for mounted bayonet stabs
int DetermineFinisherAnimation(int finisher_type)
{
int animation = -1;
switch (finisher_type)
{
case EMeleeHitType.FINISHER_LIVERSTAB:
animation = HumanCommandMelee2.HIT_TYPE_FINISHER;
break;
case EMeleeHitType.FINISHER_NECKSTAB:
animation = HumanCommandMelee2.HIT_TYPE_FINISHER_NECK;
break;
}
return animation;
}
//! Picks a specific finisher ammo for the hit type. This gets synchronized and guides further behaviour of the target.
string DetermineFinisherAmmo(int finisher_type)
{
string ret = "";
switch (finisher_type)
{
case EMeleeHitType.FINISHER_NECKSTAB:
ret = "FinisherHitNeck";
break;
default:
ret = "FinisherHit";
break;
}
return ret;
}
protected bool IsShortDistance(EntityAI pTarget, float pDistanceSq)
{
return pTarget && (vector.DistanceSq(m_Player.GetPosition(), m_MeleeCombat.GetHitPos()) <= pDistanceSq) || (vector.DistanceSq(m_Player.GetBonePositionWS(m_Player.GetBoneIndexByName("Head")), m_MeleeCombat.GetHitPos()) <= pDistanceSq);
}
//!
//! DEPRECATED
protected DayZPlayerImplement m_DZPlayer;
protected bool m_IsFinisher;
int GetFinisherType(InventoryItem weapon, EntityAI target)
{
return -1;
}
bool IsHitTypeFinisher(int type)
{
return false;
}
int DetermineSpecificFinisherType(ItemBase weapon, int component)
{
return -1;
}
}