Update FancyHandwork, add BrutalHandwork

This commit is contained in:
hlfstr
2023-02-17 04:50:47 -06:00
parent 679d00b839
commit a24dabe5b7
38 changed files with 88300 additions and 66 deletions

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<animNode>
<m_Name>AttackDefaultL</m_Name>
<m_AnimName>Bob_Attack1Hand01_Hit_L</m_AnimName>
<m_Priority>4</m_Priority>
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
<m_Looped>false</m_Looped>
<m_EarlyTransitionOut>true</m_EarlyTransitionOut>
<m_SpeedScale>LCombatSpeed</m_SpeedScale>
<m_BlendTime>0.15</m_BlendTime>
<m_BlendOutTime>0.25</m_BlendOutTime>
<m_Conditions>
<m_Name>PerformingAction</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>LAttack</m_StringValue>
</m_Conditions>
<m_Conditions>
<m_Name>LAttackType</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>bash</m_StringValue>
</m_Conditions>
<m_Transitions>
<m_Target>Idle</m_Target>
<m_AnimName>Bob_AimToIdle_1Hand</m_AnimName>
<m_blendInTime>0.5</m_blendInTime>
<m_blendOutTime>0.5</m_blendOutTime>
<m_speedScale>1.3</m_speedScale>
</m_Transitions>
<m_Events>
<m_EventName>AttackCollisionCheck</m_EventName>
<m_TimePc>0.25</m_TimePc>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>BlockMovement</m_EventName>
<m_TimePc>0.75</m_TimePc>
<m_ParameterValue>TRUE</m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>StartAttack</m_EventName>
<m_Time>Start</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>EndAttack</m_EventName>
<m_Time>End</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>SetVariable</m_EventName>
<m_TimePc>0.1</m_TimePc>
<m_ParameterValue>ZombieHitReaction=HeadRight</m_ParameterValue>
</m_Events>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine1</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Neck</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_BackPack</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Prop2</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine</boneName>
<includeDescendants>false</includeDescendants>
</m_SubStateBoneWeights>
</animNode>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<animNode>
<m_Name>BH_LeftPunch1</m_Name>
<m_AnimName>Bob_BH_AttackPunch01_L_Hit</m_AnimName>
<m_Priority>4</m_Priority>
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
<m_Looped>false</m_Looped>
<m_EarlyTransitionOut>true</m_EarlyTransitionOut>
<m_SpeedScale>LCombatSpeed</m_SpeedScale>
<m_BlendTime>0.15</m_BlendTime>
<m_BlendOutTime>0.25</m_BlendOutTime>
<m_Conditions>
<m_Name>PerformingAction</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>LAttack</m_StringValue>
</m_Conditions>
<m_Conditions>
<m_Name>LAttackType</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>lpunch1</m_StringValue>
</m_Conditions>
<m_Transitions>
<m_Target>Idle</m_Target>
<m_AnimName>Bob_AimToIdle_1Hand</m_AnimName>
<m_blendInTime>0.5</m_blendInTime>
<m_blendOutTime>0.5</m_blendOutTime>
<m_speedScale>1.3</m_speedScale>
</m_Transitions>
<m_Events>
<m_EventName>AttackCollisionCheck</m_EventName>
<m_TimePc>0.25</m_TimePc>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>BlockMovement</m_EventName>
<m_TimePc>0.75</m_TimePc>
<m_ParameterValue>TRUE</m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>StartAttack</m_EventName>
<m_Time>Start</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>EndAttack</m_EventName>
<m_Time>End</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>SetVariable</m_EventName>
<m_TimePc>0.1</m_TimePc>
<m_ParameterValue>ZombieHitReaction=HeadRight</m_ParameterValue>
</m_Events>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine1</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Neck</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_BackPack</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine</boneName>
<includeDescendants>false</includeDescendants>
</m_SubStateBoneWeights>
</animNode>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<animNode>
<m_Name>BH_LeftPunch1</m_Name>
<m_AnimName>Bob_BH_AttackPunch02_L_Hit</m_AnimName>
<m_Priority>4</m_Priority>
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
<m_Looped>false</m_Looped>
<m_EarlyTransitionOut>true</m_EarlyTransitionOut>
<m_SpeedScale>LCombatSpeed</m_SpeedScale>
<m_BlendTime>0.15</m_BlendTime>
<m_BlendOutTime>0.25</m_BlendOutTime>
<m_Conditions>
<m_Name>PerformingAction</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>LAttack</m_StringValue>
</m_Conditions>
<m_Conditions>
<m_Name>LAttackType</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>lpunch2</m_StringValue>
</m_Conditions>
<m_Transitions>
<m_Target>Idle</m_Target>
<m_AnimName>Bob_AimToIdle_1Hand</m_AnimName>
<m_blendInTime>0.5</m_blendInTime>
<m_blendOutTime>0.5</m_blendOutTime>
<m_speedScale>1.3</m_speedScale>
</m_Transitions>
<m_Events>
<m_EventName>AttackCollisionCheck</m_EventName>
<m_TimePc>0.25</m_TimePc>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>BlockMovement</m_EventName>
<m_TimePc>0.75</m_TimePc>
<m_ParameterValue>TRUE</m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>StartAttack</m_EventName>
<m_Time>Start</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>EndAttack</m_EventName>
<m_Time>End</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>SetVariable</m_EventName>
<m_TimePc>0.1</m_TimePc>
<m_ParameterValue>ZombieHitReaction=Uppercut</m_ParameterValue>
</m_Events>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine1</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Neck</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_BackPack</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine</boneName>
<includeDescendants>false</includeDescendants>
</m_SubStateBoneWeights>
</animNode>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<animNode>
<m_Name>BH_RightPunch1</m_Name>
<m_AnimName>Bob_BH_AttackPunch01_R_Hit</m_AnimName>
<m_Priority>4</m_Priority>
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
<m_Looped>false</m_Looped>
<m_EarlyTransitionOut>true</m_EarlyTransitionOut>
<m_SpeedScale>LCombatSpeed</m_SpeedScale>
<m_BlendTime>0.15</m_BlendTime>
<m_BlendOutTime>0.25</m_BlendOutTime>
<m_Conditions>
<m_Name>PerformingAction</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>LAttack</m_StringValue>
</m_Conditions>
<m_Conditions>
<m_Name>LAttackType</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>rpunch1</m_StringValue>
</m_Conditions>
<m_Transitions>
<m_Target>Idle</m_Target>
<m_AnimName>Bob_AimToIdle_1Hand</m_AnimName>
<m_blendInTime>0.5</m_blendInTime>
<m_blendOutTime>0.5</m_blendOutTime>
<m_speedScale>1.3</m_speedScale>
</m_Transitions>
<m_Events>
<m_EventName>AttackCollisionCheck</m_EventName>
<m_TimePc>0.25</m_TimePc>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>BlockMovement</m_EventName>
<m_TimePc>0.75</m_TimePc>
<m_ParameterValue>TRUE</m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>StartAttack</m_EventName>
<m_Time>Start</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>EndAttack</m_EventName>
<m_Time>End</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>SetVariable</m_EventName>
<m_TimePc>0.1</m_TimePc>
<m_ParameterValue>ZombieHitReaction=HeadLeft</m_ParameterValue>
</m_Events>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine1</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Neck</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_BackPack</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine</boneName>
<includeDescendants>false</includeDescendants>
</m_SubStateBoneWeights>
</animNode>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<animNode>
<m_Name>BH_RightPunch1</m_Name>
<m_AnimName>Bob_BH_AttackPunch02_R_Hit</m_AnimName>
<m_Priority>4</m_Priority>
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
<m_Looped>false</m_Looped>
<m_EarlyTransitionOut>true</m_EarlyTransitionOut>
<m_SpeedScale>LCombatSpeed</m_SpeedScale>
<m_BlendTime>0.15</m_BlendTime>
<m_BlendOutTime>0.25</m_BlendOutTime>
<m_Conditions>
<m_Name>PerformingAction</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>LAttack</m_StringValue>
</m_Conditions>
<m_Conditions>
<m_Name>LAttackType</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>rpunch2</m_StringValue>
</m_Conditions>
<m_Transitions>
<m_Target>Idle</m_Target>
<m_AnimName>Bob_AimToIdle_1Hand</m_AnimName>
<m_blendInTime>0.5</m_blendInTime>
<m_blendOutTime>0.5</m_blendOutTime>
<m_speedScale>1.3</m_speedScale>
</m_Transitions>
<m_Events>
<m_EventName>AttackCollisionCheck</m_EventName>
<m_TimePc>0.25</m_TimePc>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>BlockMovement</m_EventName>
<m_TimePc>0.75</m_TimePc>
<m_ParameterValue>TRUE</m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>StartAttack</m_EventName>
<m_Time>Start</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>EndAttack</m_EventName>
<m_Time>End</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>SetVariable</m_EventName>
<m_TimePc>0.1</m_TimePc>
<m_ParameterValue>ZombieHitReaction=Uppercut</m_ParameterValue>
</m_Events>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine1</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Neck</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_BackPack</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine</boneName>
<includeDescendants>false</includeDescendants>
</m_SubStateBoneWeights>
</animNode>

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<animNode>
<m_Name>KnifeDefaultL</m_Name>
<m_AnimName>Bob_AttackKnife01_Hit_L</m_AnimName>
<m_Priority>1</m_Priority>
<m_DeferredBoneName>Bip01</m_DeferredBoneName>
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
<m_maxTorsoTwist>70.0</m_maxTorsoTwist>
<m_Looped>false</m_Looped>
<m_EarlyTransitionOut>true</m_EarlyTransitionOut>
<m_SpeedScale>LCombatSpeed</m_SpeedScale>
<m_BlendTime>0.15</m_BlendTime>
<m_BlendOutTime>0.25</m_BlendOutTime>
<m_Conditions>
<m_Name>PerformingAction</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>LAttack</m_StringValue>
</m_Conditions>
<m_Conditions>
<m_Name>LAttackType</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>knife</m_StringValue>
</m_Conditions>
<m_Transitions>
<m_Target>Idle</m_Target>
<m_AnimName>Bob_AimToIdle_1Hand</m_AnimName>
<m_blendInTime>0.5</m_blendInTime>
<m_blendOutTime>0.5</m_blendOutTime>
<m_speedScale>1.3</m_speedScale>
</m_Transitions>
<m_Events>
<m_EventName>AttackCollisionCheck</m_EventName>
<m_TimePc>0.25</m_TimePc>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>BlockMovement</m_EventName>
<m_TimePc>0.6</m_TimePc>
<m_ParameterValue>TRUE</m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>StartAttack</m_EventName>
<m_Time>Start</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>EndAttack</m_EventName>
<m_Time>End</m_Time>
<m_ParameterValue></m_ParameterValue>
</m_Events>
<m_Events>
<m_EventName>SetVariable</m_EventName>
<m_TimePc>0.1</m_TimePc>
<m_ParameterValue>ZombieHitReaction=Uppercut</m_ParameterValue>
</m_Events>
<m_SubStateBoneWeights>
<boneName>Bip01</boneName>
<weight>0.0</weight>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine1</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Neck</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_BackPack</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Prop2</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Spine</boneName>
<includeDescendants>false</includeDescendants>
</m_SubStateBoneWeights>
</animNode>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<animNode>
<m_Name>BHUnarmedAimMask</m_Name>
<m_AnimName>Bob_BH_UnarmedAim</m_AnimName>
<m_Priority>10</m_Priority>
<m_deferredBoneAxis>Y</m_deferredBoneAxis>
<m_SyncTrackingEnabled>false</m_SyncTrackingEnabled>
<m_SpeedScale>0.80</m_SpeedScale>
<m_BlendTime>0.20</m_BlendTime>
<m_Conditions>
<m_Name>RightHandMask</m_Name>
<m_Type>STRING</m_Type>
<m_StringValue>bhunarmedaim</m_StringValue>
</m_Conditions>
<m_Conditions>
<m_Name>FHDoingAction</m_Name>
<m_Type>BOOL</m_Type>
<m_BoolValue>false</m_BoolValue>
</m_Conditions>
<m_Conditions>
<m_Name>Aim</m_Name>
<m_Type>BOOL</m_Type>
<m_BoolValue>true</m_BoolValue>
</m_Conditions>
<m_Conditions>
<m_Name>bShoveAiming</m_Name>
<m_Type>BOOL</m_Type>
<m_BoolValue>false</m_BoolValue>
</m_Conditions>
<m_SubStateBoneWeights>
<boneName>Bip01_Neck</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_R_Clavicle</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_L_Clavicle</boneName>
</m_SubStateBoneWeights>
</animNode>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,797 @@
-- BrutalAttack is intended to be a module that can be used by anyone
--- This is a more-or-less port of the Java functions to find and perform attacks
--- Not everything is exposed to us that is used, so some liberties were taken
local BrutalAttack = {}
-- for caching, let's reuse these
local checkValid = function(player, weapon)
return (player and instanceof(weapon, "HandWeapon"))
end
local function clamp(low, n, high) return math.min(math.max(n, low), high) end
BrutalAttack.SplitValueString = function(str)
local t = {}
for k, v in string.gmatch(str, "(%w+)=(%w+)") do
t[k] = v
end
return t
end
-- WARNING
---- This ONLY returns the available count, as the objects this returns are not exported for use in Lua
BrutalAttack.GetAvailableTargetCount = function(player, weapon)
local prone = ArrayList.new()
local stand = ArrayList.new()
-- we want a player, and a hand weapon
if not checkValid(player, weapon) then return end
SwipeStatePlayer.instance():calcValidTargets(player, weapon, true, prone, stand)
local pC = prone:size()
local sC = stand:size()
--prone:clear()
--stand:clear()
return pC, sC
end
local moodleOffset = {
0.5, 0.2, 0.1, 0.05
}
local weaponLevelOffset = {
0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3
}
BrutalAttack.GetWeaponLevel = function(player, weapon)
local lvl = -1
if weapon and player then
local cats = weapon:getCategories()
if cats:contains("Axe") then
lvl = lvl + player:getPerkLevel(Perks.Axe)
end
if cats:contains("Spear") then
lvl = lvl + player:getPerkLevel(Perks.Spear)
end
if cats:contains("SmallBlade") then
lvl = lvl + player:getPerkLevel(Perks.SmallBlade)
end
if cats:contains("LongBlade") then
lvl = lvl + player:getPerkLevel(Perks.LongBlade)
end
if cats:contains("Blunt") then
lvl = lvl + player:getPerkLevel(Perks.Blunt)
end
if cats:contains("SmallBlunt") then
lvl = lvl + player:getPerkLevel(Perks.SmallBlunt)
end
-- if cats:contains("Unarmed") then
-- lvl = lvl + player:getPerkLevel(Perks.Unarmed)
-- end
end
return (lvl == -1 and 0) or lvl
end
-- Yea, you see all this here? This is the FULL damage code ported from Java to Lua, made weapon agnostic.
---- This doesn't fucking work in MP though, as there is NO method to get a zombie remotely.
---- So, I cannot accurately sync hit reactions. This causes zombies to fall for you, and walk in place for others
---- I could fix this if I could just get a zombie by its online id or something. But noooooooooooo. I can't have nice things......
-- BrutalAttack.processHitDamage = function(weapon, player, target, damage, ignoreDamage, delta)
-- local dmg = damage * delta
-- local dmg2 = (ignoreDamage and dmg/2.7) or dmg
-- local force = dmg2 * player:getShovingMod()
-- if force > 1.0 then force = 1.0 end
-- if not weapon:isRanged() then
-- force = (player:HasTrait("Strong") and force*1.4) or (player:HasTrait("Weak") and force*0.6) or force
-- end
-- local dist = 1.0 - ((target:DistTo(player) - weapon:getMinRange())/weapon:getMaxRange(player))
-- if dist > 1.0 then dist = 1.0 end
-- -- Apparently, this is supposed to be modified by knockbackAttackMod, but this always seems to be 1
-- local endurance = player:getStats():getEndurance()
-- if endurance < 0.5 then
-- endurance = endurance * 1.3
-- if endurance < 0.4 then
-- endurance = 0.4
-- end
-- end
-- force = force * endurance
-- if not weapon:isRangeFalloff() then
-- dist = 1.0
-- end
-- if not weapon:isShareDamage() then
-- damage = 1.0
-- end
-- if not ignoreDamage then
-- force = force * 2.0
-- end
-- if player:isDoShove() then
-- local vec = Vector2.new()
-- vec:set(target:getX() - player:getX(), target:getY() - player:getY())
-- vec:normalize()
-- local vec2 = Vector2.new()
-- vec2:set(player:getX(), player:getY())
-- vec2 = target:getVectorFromDirection(vec2)
-- local dir = vec:dot(vec2)
-- if dir > -0.3 then
-- dmg = dmg * 1.5
-- end
-- end
-- dmg = (instanceof(target, "IsoPlayer") and dmg * 0.4) or dmg * 1.5
-- dmg = dmg * (weaponLevelOffset[BrutalAttack.GetWeaponLevel(player, weapon)] or 0.3)
-- if player:isAimAtFloor() and not player:isDoShove() and not ignoreDamage then
-- dmg = dmg * (math.max(5.0, weapon:getCritDmgMultiplier()))
-- end
-- if player:isCriticalHit() and not ignoreDamage then
-- dmg = dmg * math.max(2.0, weapon:getCritDmgMultiplier())
-- end
-- if weapon:isTwoHandWeapon() and not player:isItemInBothHands(weapon) then
-- dmg = dmg * 0.5
-- end
-- return dmg
-- end
-- local basehitConsequences = function(weapon, player, target, ignoreDamage, damage)
-- if not ignoreDamage then
-- if weapon:isAimedFirearm() then
-- target:setHealth(target:getHealth() - damage * 0.7)
-- else
-- target:setHealth(target:getHealth() - damage * 0.15)
-- end
-- end
-- if target:isDead() then
-- if target:isOnKillDone() and target:shouldDoInventory() then
-- target:Kill(player)
-- end
-- if target:isZombie() then
-- player:setZombieKills(player:getZombieKills() + 1)
-- end
-- else
-- if weapon:isSplatBloodOnNoDeath() then
-- target:splatBlood(2, 0.2)
-- end
-- if (weapon:isKnockBackOnNoDeath()) then
-- player:getXp():AddXP(Perks.Strength, 2.0)
-- end
-- end
-- end
-- local zedhitConsequences = function(weapon, player, target, ignoreDamage, damage)
-- if not target:isOnlyJawStab() or target:isCloseKilled() then
-- basehitConsequences(weapon, player, target, ignoreDamage, damage)
-- end
-- if getDebug() then
-- print("BRUTAL: Zombie #" .. tostring(target:getOnlineID()) .. " got hit for " .. tostring(damage))
-- end
-- target:reportEvent("wasHit")
-- if not ignoreDamage then
-- local react = player:getVariableString("ZombieHitReaction") or ""
-- local cats = weapon:getCategories()
-- if react == "Shot" then
-- -- Shot
-- elseif cats:contains("Blunt") or cats:contains("BHUnarmed") then
-- target:addBlood(BloodBodyPartType.FromIndex(ZombRand(BloodBodyPartType.MAX:index())), false, false, true)
-- elseif not cats:contains("Unarmed") then
-- target:addBlood(BloodBodyPartType.FromIndex(ZombRand(BloodBodyPartType.MAX:index())), false, true, true)
-- end
-- if react == "ShotHeadFwd" and ZombRand(2) == 0 then
-- react = "ShotHeadFwd02"
-- end
-- if target:getEatBodyTarget() ~= nil then
-- if target:getVariableBoolean("onknees") then
-- react = "OnKnees"
-- else
-- react = "Eating"
-- end
-- end
-- if string.lower(react) == "floor" and target:isCurrentState(ZombieGetUpState.instance()) and target:isFallOnFront() then
-- react = "GettingUpFront"
-- end
-- if react ~= "" then
-- target:setHitReaction(react)
-- else
-- target:setStaggerBack(true)
-- target:setHitReaction("")
-- if target:getPlayerAttackPosition() == "LEFT" or target:getPlayerAttackPosition() == "RIGHT" then
-- player:setCriticalHit(false)
-- end
-- end
-- end
-- local tgt = target:getTarget()
-- if not tgt or tgt == player or target:DistToSquared(player) < 10.0 then
-- target:setTarget(player)
-- end
-- if player:isLocalPlayer() and not target:isRemoteZombie() then
-- target:setKnockedDown(player:isCriticalHit() or target:isOnFloor() or target:isAlwaysKnockedDown())
-- end
-- if not target:isOnFloor() then
-- local windowFence = function(x,y)
-- local dir = target:getDir()
-- if dir == IsoDirections.W then
-- target:setX(x + 0.9)
-- target:setLx(target:getX())
-- elseif dir == IsoDirections.E then
-- target:setX(x + 0.1)
-- target:setLx(target:getX())
-- elseif dir == IsoDirections.N then
-- target:setY(y + 0.9)
-- target:setLy(target:getY())
-- elseif dir == IsoDirections.S then
-- target:setY(y + 0.1)
-- target:setLy(target:getY())
-- end
-- target:setStaggerBack(false);
-- target:setKnockedDown(true);
-- target:setOnFloor(true);
-- target:setFallOnFront(true);
-- target:setHitReaction("FenceWindow");
-- end
-- if target:isCurrentState(ClimbOverFenceState.instance()) and target:getVariableBoolean("ClimbFenceStarted") and not target:isVariable("ClimbFenceOutcome", "fall") and not target:getVariableBoolean("ClimbFenceFlopped") then
-- local map = target:getStateMachineParams(ClimbOverFenceState.instance())
-- windowFence(map:get(3), map:get(4))
-- elseif target:isCurrentState(ClimbThroughWindowState.instance()) and target:getVariableBoolean("ClimbWindowStarted") and not target:isVariable("ClimbWindowOutcome", "fall") and not target:getVariableBoolean("ClimbWindowFlopped") then
-- local map = target:getStateMachineParams(ClimbThroughWindowState.instance())
-- windowFence(map:get(12), map:get(13))
-- end
-- end
-- local crawler = false
-- if target:isBecomeCrawler() then
-- crawler = true
-- elseif target:isCrawling() or BrutalAttack.isLastStand or target:isDead() or target:isCloseKilled() then
-- crawler = false
-- else
-- if not player:isAimAtFloor() and player:isDoShove() then
-- crawler = false
-- elseif player:isAimAtFloor() and player:isDoShove() then
-- crawler = (ZombRand((target:isHitLegsWhileOnFloor() and 7) or 15) % 2) == 0
-- end
-- end
-- if crawler then
-- target:setBecomeCrawler(true)
-- end
-- end
-- local playerhitConsequences = function(weapon, player, target, ignoreDamage, damage)
-- end
-- BrutalAttack.hitConsequences = function(weapon, player, target, ignoreDamage, damage)
-- if instanceof(target, "IsoPlayer") then
-- playerhitConsequences(weapon, player, target, ignoreDamage, damage)
-- else
-- zedhitConsequences(weapon, player, target, ignoreDamage, damage)
-- end
-- end
-- BrutalAttack.OnWeaponHitCharacter = function(player, target, weapon, damage)
-- if not instanceof(weapon, "HandWeapon") or not instanceof(player, "IsoPlayer") or not instanceof(target, "IsoGameCharacter") then return false end
-- if weapon:isRanged() then return false end -- not implemented
-- local vec2 = Vector2.new()
-- vec2:set(target:getX()-player:getX(), target:getY()-player:getY())
-- local delta = BrutalAttack.calcDelta(player, weapon, vec2)
-- BrutalAttack.weaponHitCharacter(player, target, weapon, damage, false, delta)
-- return true
-- end
-- BrutalAttack.weaponHitCharacter = function(player, target, weapon, damage, ignoreDamage ,delta)
-- if target:avoidDamage() then
-- target:setAvoidDamage(false)
-- return 0
-- end
-- local ignoreDamage = target:getNoDamage()
-- if ignoreDamage then
-- target:setNoDamage(false)
-- end
-- if instanceof(target, "IsoSurvivor") then
-- local enemyList = target:getEnemyList()
-- if enemyList and not enemyList:contains(player) then
-- enemyList:add(player)
-- end
-- end
-- target:setStaggerTimeMod(weapon:getPushBackMod() * weapon:getKnockbackMod(player) * player:getShovingMod())
-- player:addWorldSoundUnlessInvisible(5, 1, false)
-- local vec2 = Vector2.new()
-- vec2:set(target:getX() - player:getX(), target:getY() - player:getY())
-- vec2:normalize()
-- vec2:set(vec2:getX() * weapon:getPushBackMod(), vec2:getY() * weapon:getPushBackMod())
-- -- Literally everything that I can find uses -30 for the HitAngleMod, including modded items. This parameter does not have a 'get', so lets just use -30
-- vec2:rotate(-30)
-- target:setHitDir(vec2)
-- target:setAttackedBy(player)
-- local finalDamage = BrutalAttack.processHitDamage(weapon, player, target, damage, ignoreDamage, delta)
-- local weight = 0
-- if weapon:isTwoHandWeapon() and player:isItemInBothHands(weapon) then
-- weight = weapon:getWeight()/0.15
-- end
-- weight = (weapon:getWeight() * 0.28 * weapon:getFatigueMod(player) * target:getFatigueMod() * weapon:getEnduranceMod() * 0.30 + weight) * 0.04
-- if instanceof(player, "IsoPlayer") and player:isAimAtFloor() and player:isDoShove() then
-- weight = weight * 2.0
-- end
-- local enduranceDmg = finalDamage * ((weapon:isAimedFirearm() and 0.7) or 0.15)
-- enduranceDmg = ((target:getHealth() < enduranceDmg and target:getHealth()) or enduranceDmg)/weapon:getMaxDamage()
-- if enduranceDmg > 1.0 then enduranceDmg = 1.0 end
-- enduranceDmg = (target:isCloseKilled() and 0.2) or enduranceDmg
-- if weapon:isUseEndurance() then
-- enduranceDmg = ((finalDamage <= 0) and 1.0) or enduranceDmg
-- player:getStats():setEndurance(player:getStats():getEndurance() - (weight * enduranceDmg))
-- end
-- --BrutalAttack.hitConsequences(weapon, player, target, ignoreDamage, finalDamage)
-- target:hitConsequences(weapon, player, ignoreDamage, finalDamage, false)
-- if target:isZombie() then
-- if not target:isRemoteZombie() then
-- target:addAggro(player, finalDamage)
-- end
-- target:setTargetSeenTime(0)
-- if not target:isDead() and not target:isOnFloor() and not ignoreDamage and weapon:getScriptItem():getCategories():contains("Blade") then
-- target:setHitForce(0.5)
-- target:changeState(StaggerBackState.instance())
-- end
-- end
-- return finalDamage
-- end
-- BrutalAttack.Hit = function(weapon, player, target, damage, ignoreDamage, delta)
-- if not instanceof(weapon, "HandWeapon") or not instanceof(player, "IsoPlayer") or not instanceof(target, "IsoGameCharacter") then return end
-- if not ignoreDamage and target:isZombie() then
-- target:setHitTime(target:getHitTime()+1)
-- if target:getHitTime() >= 4 then
-- damage = damage * ((target:getHitTime()-2) * 1.50)
-- end
-- end
-- -- Set the shove damage. probably un-needed, but lets do it anyways
-- if player:isDoShove() and not player:isAimAtFloor() then
-- ignoreDamage = true
-- delta = delta * 1.5
-- end
-- triggerEvent("OnWeaponHitCharacter", player, target, weapon, damage)
-- triggerEvent("OnPlayerGetDamage", target, "WEAPONHIT", damage)
-- BrutalAttack.weaponHitCharacter(player, target, weapon, damage, ignoreDamage, delta)
-- triggerEvent("OnWeaponHitXp", player, weapon, target, damage)
-- end
BrutalAttack.calcDelta = function(player, weapon, vec2)
local delta = 1.0
if weapon:isRangeFalloff() then
delta = 1.0
elseif weapon:isRanged() then
delta = 0.5
else
delta = vec2:getLength() / weapon:getMaxRange(player)
end
delta = delta * 2.0
if delta < 0.3 then delta = 1 end
-- I'm tired. I've written 3 methods for calculating damage, only to run into an issue.
--- So we're just going to correct it using math and the `delta` parameter
---- We must correct for the offhand weapon skill here
---- first, we divide by the primary hand's skill offset; later, this is counter-acted by the offset being multiplied
delta = delta / (weaponLevelOffset[BrutalAttack.GetWeaponLevel(player, player:getPrimaryHandItem())] or 0.3)
-- then we multiply the real skill offset
delta = delta * (weaponLevelOffset[BrutalAttack.GetWeaponLevel(player, weapon)] or 0.3)
return delta
end
BrutalAttack.calcDamage = function(player, weapon, target, count)
local vec2 = Vector2.new()
vec2:set(target:getX()-player:getX(), target:getY()-player:getY())
local delta = BrutalAttack.calcDelta(player, weapon, vec2)
local minDamage = weapon:getMinDamage() -- var50
local maxDamage = weapon:getMaxDamage() -- var28
local deltaDamage = maxDamage - minDamage -- var52
local twoHand = not weapon:isTwoHandWeapon() or player:isItemInBothHands(weapon) -- var54
local initDamage = 0 -- var51
if deltaDamage == 0.0 then
initDamage = minDamage
else
initDamage = minDamage + (ZombRand(maxDamage*1000.0)/1000.0)
end
if not weapon:isRanged() then
initDamage = initDamage * weapon:getDamageMod(player) * player:getHittingMod()
if not twoHand and maxDamage > minDamage then
initDamage = initDamage - minDamage
end
end
-- local damage = 0 --var34
-- local forward = target:getForwardDirection()
-- vec2:normalize()
-- forward:normalize()
-- damage = vec2.dot(forward)
-- local fromBehind = damage > 0.50
local damage = 0
for i=0,BodyPartType.ToIndex(BodyPartType.MAX) - 1 do
damage = damage + player:getBodyDamage():getBodyParts():get(i):getPain()
end
if damage > 10.0 then
initDamage = initDamage/clamp(damage/10.0, 1.0, 30.0)
end
if player:HasTrait("Underweight") then
initDamage = initDamage * 0.8
end
if player:HasTrait("VeryUnderweight") then
initDamage = initDamage * 0.6
end
if player:HasTrait("Emaciated") then
initDamage = initDamage * 0.4
end
-- this way, the other items hit get less damage, i get it
damage = initDamage/(count/2.0)
if player:isAttackWasSuperAttack() then
damage = damage * 5.0
end
if weapon:isRanged() and player:getPerkLevel(Perks.Aiming) < 6 and player:getMoodles():getMoodleLevel(MoodleType.Panic) > 2 then
damage = damage - (player:getMoodles():getMoodleLevel(MoodleType.Panic) * 0.2)
end
if not weapon:isRanged() and player:getMoodles():getMoodleLevel(MoodleType.Panic) > 1 then
damage = damage - (player:getMoodles():getMoodleLevel(MoodleType.Panic) * 0.1)
end
if player:getMoodles():getMoodleLevel(MoodleType.Stress) > 1 then
damage = damage - (player:getMoodles():getMoodleLevel(MoodleType.Stress) * 0.1)
end
if damage < 0 then damage = 0.1 end
if not weapon:isRanged() then
damage = damage * (moodleOffset[player:getMoodles():getMoodleLevel(MoodleType.Endurance)] or 1.0)
damage = damage * (moodleOffset[player:getMoodles():getMoodleLevel(MoodleType.Tired)] or 1.0)
end
-- local part = ZombRand(BodyPartType.ToIndex(BodyPartType.Hand_L), BodyPartType.ToIndex(BodyPartType.Neck) + 1)
-- local def = target:getBodyPartClothingDefense(part, false, weapon:isRanged())/2.0
-- def = def + target:getBodyPartClothingDefense(part, true, weapon:isRanged())
-- if def > 70.0 then def = 70.0 end
-- damage = damage * math.abs(1.0-def/100.0)
-- triggerEvent("OnHitZombie", target, player, part, weapon)
return damage, delta
end
local addToHitList = function(list, obj, player, weapon, extraRange, vec)
if obj and obj:isZombie() and obj:isAlive() then
obj:getPosition(vec)
if player:IsAttackRange(weapon, obj, vec, extraRange) then
-- Add our zed, cache the distance to the player
list[#list+1] = { obj = obj, dist = obj:DistTo(player) }
if isDebugEnabled() then
print("Found: " .. tostring(#list) .. " | Distance: " .. tostring(list[#list].dist))
end
end
end
end
local directions = {
[0] = IsoDirections.N,
[1] = IsoDirections.NW,
[2] = IsoDirections.W,
[3] = IsoDirections.SW,
[4] = IsoDirections.S,
[5] = IsoDirections.SE,
[6] = IsoDirections.E,
[7] = IsoDirections.NE,
}
local getAttackSquares = function(player)
local psquare = player:getSquare()
if not psquare then return nil end
local squares = {psquare}
local currentDir = player:getDir():index()
local leftIndex = currentDir+1
if leftIndex > 7 then leftIndex=0 end
--local middleIndex = currentDir
local rightIndex = currentDir-1
if rightIndex < 0 then rightIndex=7 end
-- this should collect any additional squares, only if we nothing is in the way
local sq = psquare:getAdjacentSquare(directions[leftIndex])
if sq and not sq:isBlockedTo(psquare) then
squares[#squares+1] = sq
end
sq = psquare:getAdjacentSquare(directions[currentDir])
if sq and not sq:isBlockedTo(psquare) then
squares[#squares+1] = sq
end
sq = psquare:getAdjacentSquare(directions[rightIndex])
if sq and not sq:isBlockedTo(psquare) then
squares[#squares+1] = sq
end
return squares
end
-- Finds and performs the attack on players in weapon range
BrutalAttack.FindAndAttackTargets = function(player, weapon, extraRange)
-- we want a player, and a hand weapon
if not checkValid(player, weapon) then return end
-- honor the max hit
local maxHit = (SandboxVars.MultiHitZombies and weapon:getMaxHitCount()) or 1
-- this seems to be the default sooooooooo
if extraRange == nil then extraRange = true end
-- We do everything so we can attack non-zeds too
--local objs = getCell():getObjectList()
local found = {}
local psquare = player:getSquare()
if not psquare then return end -- can't attack
local attackSquares = getAttackSquares(player)
if not attackSquares then return end -- no squares?
local vec = Vector3.new() -- reuse this
for i=1, #attackSquares do
local objs = attackSquares[i]:getMovingObjects()
if objs then
for j=0, objs:size()-1 do
addToHitList(found, objs:get(j), player, weapon, extraRange, vec)
end
end
end
if #found > 0 then
-- sort our found list by the closest zed
table.sort(found, function(a,b)
if a.obj:isZombie() then return true end
if b.obj:isZombie() then return false end
return a.dist < b.dist
end)
local count = 1
local sound = false
for _,v in ipairs(found) do
-- hit em!
local damage, dmgDelta = BrutalAttack.calcDamage(player, weapon, v.obj, count)
if isDebugEnabled() then
print("Damage: " .. tostring(damage) .. " | Delta: " .. tostring(dmgDelta))
end
v.obj:Hit(weapon, player, damage, false, dmgDelta)
--v.zed:splatBloodFloor()
if not sound then
-- if we haven't played the sound yet, do so
sound = true
local zSound = weapon:getZombieHitSound()
if zSound then v.obj:playSound(zSound) end
end
-- stop at maxhit
if count >= maxHit then break end
count = count + 1
end
luautils.weaponLowerCondition(weapon, player)
else
-- Swing and collide with anything not a zed
SwipeStatePlayer.instance():ConnectSwing(player, weapon)
end
end
BrutalAttack.CalcCombatSpeed = function(player, weapon, right)
-- we want a player, and a hand weapon
if not checkValid(player, weapon) then return nil end
local speed = weapon:getBaseSpeed()
local other
if right then
other = player:getSecondaryHandItem()
else
other = player:getPrimaryHandItem()
end
if weapon:isTwoHandWeapon() and weapon ~= other then
speed = speed * 0.77
end
if player:HasTrait("Axeman") and weapon:getCategories():contains("Axe") then
speed = speed * player:getChopTreeSpeed()
end
speed = speed - (player:getMoodles():getMoodleLevel(MoodleType.Endurance) * 0.07)
speed = speed - (player:getMoodles():getMoodleLevel(MoodleType.HeavyLoad) * 0.07)
speed = speed + (player:getWeaponLevel() * 0.03)
speed = speed + (player:getPerkLevel(Perks.Fitness) * 0.02)
if instanceof(other, "InventoryContainer") then
speed = speed * 0.95
end
local md = player:getModData()
-- our calculation is still just a bit too fast. So lets actually reduce it a bit instead of increasing:
speed = speed * ZombRandFloat(1.1, 1.2)
speed = speed * ((md.BrutalHandwork and md.BrutalHandwork.CombatSpeed) or 1)
speed = speed * BrutalAttack.getArmsInjurySpeedModifier(player, right)
if player:getBodyDamage() and player:getBodyDamage():getThermoregulator() then
speed = speed * player:getBodyDamage():getThermoregulator():getCombatModifier()
end
speed = math.min(1.6, speed)
speed = math.max(0.8, speed)
speed = speed * GameTime.getAnimSpeedFix()
return speed
end
BrutalAttack.calcInjurySpeed = function(part, pain)
if part:haveBullet() then return 1.0 end
local scratch = part:getScratchSpeedModifier()
local cut = part:getCutSpeedModifier()
local burn = part:getBurnSpeedModifier()
local wound = part:getDeepWoundSpeedModifier()
local temp = 0.0
if part:getScratchTime() > 2.0 or part:getCutTime() > 5.0 or part:getBurnTime() > 0
or part:getDeepWoundTime() > 0 or part:isSplint() or part:getFractureTime() > 0
or part:getBiteTime() > 0 then
temp = (part:getScratchTime()/scratch) + (part:getCutTime()/cut) + (part:getBurnTime()/burn) + (part:getDeepWoundTime()/wound)
temp = temp + (part:getBiteTime()/20.0)
if part:bandaged() then
temp = temp/2.0
end
if part:getFractureTime() > 0 then
local frac = 0.4
if part:getFractureTime() > 20 then
frac = 1.0
elseif part:getFractureTime() > 10 then
frac = 0.7
end
if part:getSplintFactor() > 0 then
frac = frac - 0.2
frac = frac - math.min(part:getSplintFactor()/10.0, 0.8)
end
temp = math.max(0, frac)
end
if pain and part:getPain() > 20 then
temp = temp + (part:getPain()/10.0)
end
end
return temp
end
BrutalAttack.getArmsInjurySpeedModifier = function(player, right)
local out = 1.0
local temp = 0.0
local part
if right then
part = player:getBodyDamage():getBodyPart(BodyPartType.Hand_R)
temp = BrutalAttack.calcInjurySpeed(part, true)
if temp > 0 then
out = out - temp
end
part = player:getBodyDamage():getBodyPart(BodyPartType.ForeArm_R)
temp = BrutalAttack.calcInjurySpeed(part, true)
if temp > 0 then
out = out - temp
end
part = player:getBodyDamage():getBodyPart(BodyPartType.UpperArm_R)
temp = BrutalAttack.calcInjurySpeed(part, true)
if temp > 0 then
out = out - temp
end
else
part = player:getBodyDamage():getBodyPart(BodyPartType.Hand_L)
temp = BrutalAttack.calcInjurySpeed(part, true)
if temp > 0 then
out = out - temp
end
part = player:getBodyDamage():getBodyPart(BodyPartType.ForeArm_L)
temp = BrutalAttack.calcInjurySpeed(part, true)
if temp > 0 then
out = out - temp
end
part = player:getBodyDamage():getBodyPart(BodyPartType.UpperArm_L)
temp = BrutalAttack.calcInjurySpeed(part, true)
if temp > 0 then
out = out - temp
end
end
return out
end
local onPlayerUpdateClothes = function(player)
-- recalc attack speeds
local speed = 1.0
local items = player:getWornItems()
for i=0, items:size()-1 do
local item = items:get(i):getItem()
if instanceof(item, "Clothing") then
speed = speed + item:getCombatSpeedModifier() - 1.0
end
-- if instanceof(item, "InventoryContainer") then
-- speed = speed + ((item:getActualWeight()/100.0) + 0.1) - 1.0
-- end
end
player:getModData().BrutalHandwork = player:getModData().BrutalHandwork or {}
player:getModData().BrutalHandwork.CombatSpeed = speed
end
local onPlayerCreate = function(player)
local character = getSpecificPlayer(player)
-- i know this is preserved, but i want to reset it
character:getModData().BrutalHandwork = {
wasShove = false,
leftAttack = false,
combo = 1,
}
end
local setup = function()
Events.OnCreatePlayer.Add(onPlayerCreate)
Events.OnClothingUpdated.Add(onPlayerUpdateClothes)
BrutalAttack.BareHands = InventoryItemFactory.CreateItem("Base.Fisticuffs")
--BrutalAttack.BareHands = InventoryItemFactory.CreateItem("Base.BareHands")
--BrutalAttack.isLastStand = getCore():getGameMode()=="LastStand"
end
BrutalAttack.setupGameEvents = function()
Events.OnGameBoot.Remove(setup)
Events.OnGameBoot.Add(setup)
end
return BrutalAttack

View File

@@ -0,0 +1,41 @@
-- Compatibility for The Only Cure
local TOC_Compat = {}
-- Raw access, must pass valid part
--- @param player
--- @param part string
--- @return boolean
TOC_Compat.hasArmPart = function(player, part)
if not player or not part then return false end
local data = (player:getModData().TOC and player:getModData().TOC.Limbs) or nil
if not data then return false end
return not data[part] or (data[part].is_cut and data[part].is_prosthesis_equipped) or not data[part].is_cut
end
-- Check if hand is available
--- @param player
--- @param left boolean -- optional
--- @return boolean
TOC_Compat.hasHand = function(player, left)
return TOC_Compat.hasArmPart(player, ((left and "Left_Hand") or "Right_Hand"))
end
-- Check if both hands are available
--- @param player
--- @return boolean
TOC_Compat.hasBothHands = function(player)
return TOC_Compat.hasHand(player) and TOC_Compat.hasHand(player, true)
end
-- This returns a number for the hands that you have
----- 11 == both hands
----- 10 == left hand
----- 01 (1) == right hand
----- 00 (0) == no hands
--- @param player
--- @return integer
TOC_Compat.getHands = function(player)
return ((TOC_Compat.hasHand(player) and 1) or 0) + ((TOC_Compat.hasHand(player, true) and 10) or 0)
end
return TOC_Compat

View File

@@ -0,0 +1,134 @@
require "TimedActions/ISBaseTimedAction"
BHMeleeAttack = ISBaseTimedAction:derive("BHMeleeAttack");
local BrutalAttack = require("BrutalAttack")
BrutalHands = BrutalHands or {}
function BHMeleeAttack:isValid()
return true
end
function BHMeleeAttack:waitToStart()
return false
end
function BHMeleeAttack:update()
-- we need to force the current facing direction until the animation starts
if self.lockDir then
self.character:setDirectionAngle(self.vec)
end
end
-- safeguard to make sure that the action is ended
function BHMeleeAttack:beDone()
self.character:setVariable("AttackAnim", false)
self.character:setBlockMovement(false)
self.character:setMeleeDelay(8)
end
function BHMeleeAttack:start()
local prone, stand = BrutalAttack.GetAvailableTargetCount(self.character, self.weapon)
if stand == 0 and prone > 0 then
self:forceStop()
-- Fall through to doing the character stomp or main attack
self.character:DoAttack(self.chargeDelta)
return
end
local atype = "bash"
if self.unarmed then
local hands = (BrutalHands.TOC and BrutalHands.TOC.getHands(self.character)) or 11
local rand = 4
local randoff = 1
if hands == 00 then
self:forceStop()
-- Fall through to doing the character stomp or push
return self.character:DoAttack(self.chargeDelta)
elseif hands == 01 then -- right only
rand = 2
elseif hands == 10 then -- left only
randoff = 3
end
local num = ZombRand(rand)+randoff
if num==1 then
atype = "rpunch1"
elseif num==2 then
atype = "rpunch2"
elseif num==3 then
atype = "lpunch2"
else
atype = "lpunch1"
end
--atype = (ZombRand(3) == 1 and "lpunch1") or "rpunch1"
elseif self.weapon:getSubCategory() == "Stab" then
self.maxHit = 1
atype = "knife"
end
self.character:setVariable("LCombatSpeed", self.speed)
self.character:setVariable("AttackAnim", true)
self:setActionAnim("LAttack")
self:setAnimVariable("LAttackType", atype)
end
function BHMeleeAttack:animEvent(event, parameter)
if event == 'StartAttack' then
if self.swingSound then
self.character:getEmitter():playSound(self.swingSound)
end
self.lockDir = false
elseif event == 'SetVariable' then
local str = BrutalAttack.SplitValueString(parameter)
for k,v in pairs(str) do
self.character:setVariable(k,v)
end
elseif event == 'AttackCollisionCheck' then
BrutalAttack.FindAndAttackTargets(self.character, self.weapon, true)
if isClient() then
sendClientCommand(self.character, "BrutalAttack", "Attack", {PID=self.character:getPlayerNum(), Offhand=true, extraRange=true})
end
elseif event == 'BlockMovement' and SandboxVars.AttackBlockMovements then
self.character:setBlockMovement((parameter == "TRUE" and true) or false)
elseif event == 'EndAttack' then
self:forceComplete()
end
end
function BHMeleeAttack:stop()
self:beDone()
ISBaseTimedAction.stop(self)
end
function BHMeleeAttack:perform()
self:beDone()
-- needed to remove from queue / start next.
ISBaseTimedAction.perform(self)
triggerEvent("OnPlayerAttackFinished", self.character, self.weapon)
end
function BHMeleeAttack:new(character, weapon, chargeDelta)
local o = ISBaseTimedAction.new(self, character)
o.weapon = weapon
o.speed = BrutalAttack.CalcCombatSpeed(character, weapon, false)
o.maxTime = -1
o.stopOnAim = false
o.stopOnWalk = false
o.stopOnRun = false
o.useProgressBar = false
o.swingSound = weapon:getSwingSound()
o.hitSound = weapon:getZombieHitSound()
o.vec = character:getDirectionAngle()
-- Needed if we fall through
o.chargeDelta = chargeDelta
o.lockDir = true
o.lHandAttack = true
o.unarmed = weapon and weapon:getCategories():contains("Unarmed")
return o
end

View File

@@ -0,0 +1,220 @@
------------------------------------------
-- Brutal Handwork Init
------------------------------------------
BrutalHands = BrutalHands or {}
------------------------------------------
-- Brutal Handwork Configuration
------------------------------------------
BrutalHands.config = {}
local BrutalAttack = require("BrutalAttack")
BrutalAttack.setupGameEvents()
BrutalHands.TOC = nil
if getActivatedMods():contains("Amputation2") then
BrutalHands.TOC = require('TOC_Compat')
end
------------------------------------------
-- Brutal Handwork Utilities
------------------------------------------
local function BrutalHandwork()
print(getText("UI_Init_BrutalHandwork"))
end
BrutalHandwork()
local mouseDown = false
local attackHook = function(character, chargeDelta, primary)
if not instanceof(character, "IsoPlayer") or character:isAttackStarted() or not character:isAuthorizeMeleeAction() then return end
-- Here we check if the primary weapon is actually a weapon
primary = (instanceof(primary, "HandWeapon") and primary) or nil
-- Get the secondary weapon, do the same check
local secondary = character:getSecondaryHandItem()
secondary = (instanceof(secondary, "HandWeapon") and secondary) or nil
-- check if we can actually use that arm, if applicable
---- set our weapons to nil if we don't have that arm
--local hasRArm = true
if BrutalHands.TOC then
primary = (BrutalHands.TOC.hasHand(character, false) and primary) or nil
secondary = (BrutalHands.TOC.hasHand(character, true) and secondary) or nil
--hasRArm = BrutalHands.TOC.hasHand(character, false)
end
-- get our mod data
local brutal = character:getModData().BrutalHandwork
-- get our ModKey
local mk = isFHModBindDown(character)
-- if we are always ready to punch, or the modkey is down.
if (SandboxVars.BrutalHandwork.AlwaysUnarmed or mk) then
-- we have nothing
if not primary and not secondary then
-- make our secondary hand the item so it doesn't trip the main attack
secondary = BrutalAttack.BareHands
elseif primary and twoH and primary:getCategories():contains("Unarmed") then
-- if we have an unarmed weapon equipped, then we use our custom attack; secondary will still be our weapon
primary = nil
-- This isn't really implemented yet
end
end
-- Check if its 2 handed
local twoH = primary and (primary == secondary)
-- If we made it here and there's still nothing equipped, then just push
---- This seems to set our push to start next update loop, otherwise we get a weird epic attack that is a push but it does like 100+ damage
if not primary and not secondary then
character:setInitiateAttack(false)
character:setDoShove(true)
brutal.wasShove = true
brutal.leftAttack = false
return
end
-- we could break our weapon, or just unequip it while the thing is going. bail if so
if not secondary then
brutal.leftAttack = false
end
-- override our modkey with left attack setting
mk = secondary and not twoH and (brutal.leftAttack or mk)
local did = false
-- if no modkey or shoving, and we have a primary
if not mk and primary then
-- fall through
ISReloadWeaponAction.attackHook(character, chargeDelta, primary or 1)
did = true
end
if not did and secondary then
ISTimedActionQueue.clear(character)
if secondary:isRanged() then
character:setDoShove(true)
return
-- Coming soon!
-- if ISReloadWeaponAction.canShoot(secondary) then
-- character:playSound(secondary:getSwingSound());
-- local radius = secondary:getSoundRadius();
-- if isClient() then -- limit sound radius in MP
-- radius = radius / 1.8;
-- end
-- character:addWorldSoundUnlessInvisible(radius, secondary:getSoundVolume(), false);
-- character:startMuzzleFlash()
-- character:DoAttack(0);
-- else
-- character:DoAttack(0);
-- character:setRangedWeaponEmpty(true);
-- end
-- nerf so players in vehicles cannot use melee attacks
elseif not character:getVehicle() then
ISTimedActionQueue.add(BHMeleeAttack:new(character, secondary, chargeDelta or 0))
end
end
-- if we have a left and right weapon, and its not 2handed, and we have the option to automelee enabled
if primary and secondary and not twoH and SandboxVars.BrutalHandwork.DualWieldMelee then
brutal.leftAttack = not (brutal.wasShove or brutal.leftAttack)
else
brutal.leftAttack = false
end
end
-- Removed the default attack hook
Hook.Attack.Remove(ISReloadWeaponAction.attackHook)
Hook.Attack.Add(attackHook)
-- We are going to override this function so that doing a left hand attack cannot be canceled :)
local _isPlayerDoingActionThatCanBeCancelled = isPlayerDoingActionThatCanBeCancelled
function isPlayerDoingActionThatCanBeCancelled(playerObj)
if not playerObj then return false end
local queue = ISTimedActionQueue.queues[playerObj]
if queue and #queue.queue > 0 and queue.queue[1].lHandAttack then
return false
end
return _isPlayerDoingActionThatCanBeCancelled(playerObj)
end
local forceAttack = function(character)
character:setDoShove(false)
attackHook(character, character:getPrimaryHandItem(), 1.0)
return true
end
local checkDoAttack = function(character)
if not character or not character:isAiming() or character:getMeleeDelay() > 0.0 then return false end
local queue = ISTimedActionQueue.queues[character]
if queue and #queue.queue > 0 and queue.queue[1].lHandAttack then
return false
end
local hands = (BrutalHands.TOC and BrutalHands.TOC.getHands(character)) or 11
local primary = character:getPrimaryHandItem()
primary = (instanceof(primary, "HandWeapon") and primary) or nil
local secondary = character:getSecondaryHandItem()
secondary = (instanceof(secondary, "HandWeapon") and secondary) or nil
-- just do nothing here
if not primary and not secondary and not (SandboxVars.BrutalHandwork.EnableUnarmed and (SandboxVars.BrutalHandwork.AlwaysUnarmed or isFHModBindDown(character))) then return false end
if hands == 1 then
-- if we only have the right hand, then the attackHook will handle everything
--if not instanceof(primary, "HandWeapon") then return forceAttack(character) end
return false -- we'll still do the base attack, so just ignore
elseif hands == 11 then
-- if we have a primary weapon, then the attackHook will do the thing
if primary then return false end
-- otherwise, manually attack
return forceAttack(character)
elseif hands == 10 then
-- just our left, do the attack
return forceAttack(character)
end
return false
end
-- soooooooooo, i guess TOC makes it so you no longer do the attack hook
---- That's fine, we'll just do it ourselves
local onMouseClick = function(x,y)
checkDoAttack(getSpecificPlayer(0))
mouseDown = true
end
-- This is a little hack so we can still hold the offhand attack
local onMouseUp = function(x,y)
mouseDown = false
end
local playerUpdate = function(player)
local num = player:getPlayerNum()
if (num == 0 and mouseDown) or (JoypadState.players[num+1] and (getControllerAxisValue(player:getJoypadBind(), 5) > 0.90)) then
checkDoAttack(player)
end
end
local OnWeaponHitCharacter = function(player, target, weapon, damage)
print("OnWeaponHitCharacter: " .. tostring(damage))
print("IsCritical: " .. tostring(player:isCriticalHit()))
end
Events.OnGameStart.Add(function()
Events.OnMouseDown.Add(onMouseClick)
Events.OnMouseUp.Add(onMouseUp)
Events.OnPlayerUpdate.Add(playerUpdate)
if isDebugEnabled() then
Events.OnWeaponHitCharacter.Add(OnWeaponHitCharacter)
end
-- if SandboxVars.BrutalHandwork.BaseAttackOverride then
-- --Hook.WeaponHitCharacter.Add(WeaponHitCharacter)
-- Hook.WeaponHitCharacter.Add(BrutalAttack.OnWeaponHitCharacter)
-- end
end)

View File

@@ -0,0 +1,15 @@
Sandbox_EN = {
Sandbox_BrutalHandwork = "Brutal Handwork",
Sandbox_BrutalHandwork_DualWieldMelee = "Automatically alternate left and right attacks when dual-wielding melee weapons",
Sandbox_BrutalHandwork_DualWieldMelee_tooltip = "When a player is dual-wielding melee weapons, automatically alternate between left and right attacks. Disable to require the Modifier to be pressed for an offhand attack.",
Sandbox_BrutalHandwork_EnableUnarmed = "Enable Unarmed Attacks",
Sandbox_BrutalHandwork_EnableUnarmed_tooltip = "Even when a player is unarmed, they will be able to attack. By default, must be aiming and holding the Modifier key to punch.",
Sandbox_BrutalHandwork_AlwaysUnarmed = "Always raise fists when unarmed",
Sandbox_BrutalHandwork_AlwaysUnarmed_tooltip = "When a player is unarmed, always raise their fists when aiming for unarmed attacks. Disable to require the Modifier to be held when aiming.",
Sandbox_BrutalHandwork_BaseAttackOverride = "EXPERIMENTAL: Main Attack Damage Override",
Sandbox_BrutalHandwork_BaseAttackOverride_tooltip = "Main Attacks use the damage calculation functions from BrutalHandwork instead of Vanilla. This forces consistency between the expected damage for both hand attacks. <LINE> WARNING: This option is currently experimental, but is likely to become the default and will be required for many additional options in the future. It is stable, but may cause inconsistencies compared to vanilla as it is still being developed. PLEASE READ the mod's description for current limitations!",
}

View File

@@ -0,0 +1,4 @@
UI_EN = {
UI_Init_BrtualHandwork = "Hello: Brutal Handwork!",
UI_optionscreen_binding_BrtualHandwork = Brutal Handwork",
}

View File

@@ -0,0 +1,21 @@
VERSION = 1,
option BrutalHandwork.DualWieldMelee
{
type = boolean, default = false,
page = BrutalHandwork,
translation = BrutalHandwork_DualWieldMelee,
}
option BrutalHandwork.EnableUnarmed
{
type = boolean, default = true,
page = BrutalHandwork,
translation = BrutalHandwork_EnableUnarmed,
}
option BrutalHandwork.AlwaysUnarmed
{
type = boolean, default = false,
page = BrutalHandwork,
translation = BrutalHandwork_AlwaysUnarmed,
}

View File

@@ -0,0 +1,33 @@
module Base {
item Fisticuffs {
DisplayCategory = Weapon,
MaxRange = 0.8,
WeaponSprite = null,
MinAngle = 0.65,
MinimumSwingTime = 2,
Type = Weapon,
SwingAnim = Shove,
KnockBackOnNoDeath = TRUE,
WeaponWeight = 0,
DisplayName = Bare Hands,
Categories = Unarmed,
SwingAmountBeforeImpact = 0.1,
SwingTime = 2,
MinDamage = 0.1,
SplatNumber = 1,
EnduranceMod = 1.7,
Weight = 1,
PushBackMod = 0.5,
MaxDamage = 0.25,
SplatBloodOnNoDeath = FALSE,
MaxHitCount = 1,
Icon = Axe,
DoorDamage = 2,
TreeDamage = 1,
RunAnim = Run_Weapon2,
IdleAnim = Idle,
DoorHitSound = BareHandsHit,
HitSound = BareHandsHit,
HitFloorSound = BareHandsHit,
}
}

View File

@@ -0,0 +1,11 @@
name=Brutal Handwork
id=BrutalHandwork
require=FancyHandwork
authors=dhert
description=An overhaul to combat to make your player more Brutal!
pzversion=41
tags=Realistic;Framework
poster=poster.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 KiB

BIN
BrutalHandwork/preview.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

9
BrutalHandwork/workshop.txt Executable file
View File

@@ -0,0 +1,9 @@
version=1
id=2934621024
title=Brutal Handwork
description=[h1]Supports B41+. Works in Multiplayer[/h1]
description=[h3]A new save is not required[/h3]
description=
description=[img]https://i.imgur.com/p7Fv1Z6.gif[/img]
tags=Build 41;Balance;Framework;Realistic
visibility=private

View File

@@ -11,4 +11,4 @@
<m_Type>STRING</m_Type>
<m_StringValue>GridlePan</m_StringValue>
</m_Conditions>
</animNode>
</animNode>

View File

@@ -11,35 +11,14 @@
<m_Type>STRING</m_Type>
<m_StringValue>FH_Boop</m_StringValue>
</m_Conditions>
<m_SubStateBoneWeights>
<boneName>Bip01</boneName>
<weight>0.00</weight>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_R_Clavicle</boneName>
<weight>0.80</weight>
<includeDescendants>false</includeDescendants>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_R_UpperArm</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_R_Forearm</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_R_Hand</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_R_Finger0</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_R_Finger0Nub</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_R_Finger1</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_R_Finger1Nub</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Prop1</boneName>
</m_SubStateBoneWeights>

View File

@@ -73,7 +73,7 @@
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Translation_Data</boneName>
<weight>0.4</weight>
<weight>0.25</weight>
</m_SubStateBoneWeights>
<m_Events>
<m_EventName>SetVariable</m_EventName>

View File

@@ -11,35 +11,14 @@
<m_Type>STRING</m_Type>
<m_StringValue>FH_BoopL</m_StringValue>
</m_Conditions>
<m_SubStateBoneWeights>
<boneName>Bip01</boneName>
<weight>0.00</weight>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_L_Clavicle</boneName>
<weight>0.80</weight>
<includeDescendants>false</includeDescendants>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_L_UpperArm</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_L_Forearm</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_L_Hand</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_L_Finger0</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_L_Finger0Nub</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_L_Finger1</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_L_Finger1Nub</boneName>
</m_SubStateBoneWeights>
<m_SubStateBoneWeights>
<boneName>Bip01_Prop2</boneName>
</m_SubStateBoneWeights>

View File

@@ -12,7 +12,7 @@ local function doOverride()
function ISHotbar:equipItem(item)
-- Get Modifier
local mod = isFHModKeyDown()
local mod = isFHModBindDown(self.chr)
local primary = self.chr:getPrimaryHandItem()
local secondary = self.chr:getSecondaryHandItem()
local equip = true

View File

@@ -94,18 +94,19 @@ end
local _ISAddItemInRecipe_start = ISAddItemInRecipe.start
function ISAddItemInRecipe:start()
local base = nil
if luautils.stringStarts(self.baseItem:getType(), "GridlePan") or luautils.stringStarts(self.baseItem:getType(), "GriddlePan") then
local baseType = self.baseItem:getType()
if string.find(baseType, "GridlePan") or string.find(baseType, "GriddlePan") then
base = "GridlePan"
elseif luautils.stringStarts(self.baseItem:getType(), "WaterSaucepan") or luautils.stringStarts(self.baseItem:getType(), "Saucepan") then
elseif string.find(baseType, "Saucepan") then
base = "SaucePan"
elseif luautils.stringStarts(self.baseItem:getType(), "WaterPot") or luautils.stringStarts(self.baseItem:getType(), "Pot") then
elseif string.find(baseType, "Pot") then
base = "CookingPot"
elseif luautils.stringStarts(self.baseItem:getType(), "RoastingPan") or luautils.stringStarts(self.baseItem:getType(), "RoastingPan") then
elseif string.find(baseType, "RoastingPan") then
base = "RoastingPan"
else
base = self.baseItem:getStaticModel() or "FryingPan"
end
self:setAnimVariable("BaseType", base)
self:setActionAnim("AddToPan")
self:setOverrideHandModelsString(self.usedItem:getStaticModel(), base)
@@ -201,3 +202,36 @@ function ISWearClothing:new(...)
return o
end
--- DON'T LOOK AT ME! :O
---- I'm trying to add some new animations for Transfer Actions, but wasn't able to get this completed before the next update.
-- -- Fix for the Transfer action.
-- --- Player will now only pick items off the ground when they are on the ground :)
-- local _ISInventoryTransferAction_doActionAnim = ISInventoryTransferAction.doActionAnim
-- function ISInventoryTransferAction:doActionAnim(cont)
-- _ISInventoryTransferAction_doActionAnim(self, cont)
-- if self.srcContainer:getType() == "floor" then
-- local worldItem = self.item:getWorldItem()
-- if worldItem then
-- --worldItem:removeFromSquare()
-- local anim = (self.item:getActualWeight() <= 1.0 and "FancyLoot") or nil
-- local posAnim = (anim and "FH_Hand") or "LootPosition"
-- local z = worldItem:getWorldPosZ() - self.character:getZ()
-- local position
-- if z > 0.1 then
-- position = (anim and ((ZombRand(3) == 1 and "left") or "right")) or "Mid"
-- elseif z > 0.5 then
-- position = "High"
-- end
-- if position == "left" then
-- self.action:setOverrideHandModels(nil, self.item)
-- else
-- self.action:setOverrideHandModels(self.item, nil)
-- end
-- if anim then
-- self:setActionAnim(anim)
-- end
-- self:setAnimVariable(posAnim, position)
-- end
-- end
-- end

View File

@@ -48,7 +48,7 @@ end
local _ISOvenUITimedAction_perform = ISOvenUITimedAction.perform
function ISOvenUITimedAction:perform()
ISTimedActionQueue.add(FHBoopAction:new(self.character, { item = self.object, extra = 0 }))
ISTimedActionQueue.add(FHBoopAction:new(self.character, { item = self.mcwave or self.stove, extra = 0 }))
_ISOvenUITimedAction_perform(self)
end
@@ -110,8 +110,10 @@ function ISInventoryPage:toggleStove()
end
local _ISRadioAction_perform = ISRadioAction.perform
function ISRadioAction:perform()
ISTimedActionQueue.add(FHBoopAction:new(self.character, { item = self.device, extra = 0 }))
-- Fix for the infinite error when the device is in your inventory
if not (instanceof(self.device, "InventoryItem") and self.device:isInPlayerInventory()) and not self.character:isSeatedInVehicle() then
ISTimedActionQueue.add(FHBoopAction:new(self.character, { item = self.device, extra = 0 }))
end
_ISRadioAction_perform(self)
end

View File

@@ -1,6 +1,8 @@
-- Animation Framework for Project Zomboid
---- Code inspired and modifed from "Tsarlib"
-- next release, this will be removed!
if not isClient() and not isServer() or AnimationFramework then return end
AnimationFramework = true

View File

@@ -14,13 +14,14 @@ local rearObjects = {
}
local function skipInstances(obj)
return not obj or rearObjects[obj:getObjectName()]
return not obj or rearObjects[obj:getObjectName()] or (obj:getObjectName() == "Thumpable" and obj:isDoor())
end
--character:getModData().FancyHands and not character:getModData().FancyHands.recentMove and (character:getModData().FancyHands.recentMove and not skipInstances(data.item) or true)
local function shouldDoTurn(obj, player)
if not obj or not player or player:isAiming() or not SandboxVars.FancyHandwork or SandboxVars.FancyHandwork.DisableTurn == 1 then return false end
if SandboxVars.FancyHandwork.DisableTurn == 3 then return true end
if instanceof(obj, "InventoryItem") and obj:isInPlayerInventory() then return false end -- safeguard
if SandboxVars.FancyHandwork.TurnBehavior <= 2 then
return (player:getModData().FancyHands and not player:getModData().FancyHands.recentMove)
elseif SandboxVars.FancyHandwork.TurnBehavior == 3 then
@@ -34,7 +35,6 @@ function FHBoopAction:isValid()
return true;
end
-- blech, I really want this, but turning overrides my animation
function FHBoopAction:waitToStart()
if self.character:isSeatedInVehicle() then
-- If we are in a car, we should just stop here actually
@@ -48,6 +48,51 @@ function FHBoopAction:waitToStart()
return false
end
---Brought to you by ChuckGPT
---@param char IsoPlayer|IsoGameCharacter|IsoMovingObject|IsoObject
local function getDotSide(char,mouseX,mouseY)
---@type Vector2
local lookVector = char:getLookVector(Vector2.new())
local lookVX, lookVY = lookVector:getX(), lookVector:getY()
local charX, charY, charZ, charNum = char:getX(), char:getY(), char:getZ(), char:getPlayerNum()
---@type Vector2
local charVector = Vector2.new(charX,charY)
local charVX, charVY = charVector:getX(), charVector:getY()
local objX = screenToIsoX(charNum, mouseX, mouseY, charZ)
local objY = screenToIsoY(charNum, mouseX, mouseY, charZ)
---@type Vector2
local objVector = Vector2.new(objX-charVX,objY-charVY)
objVector:normalize()
local dot = Vector2.dot(objVector:getX(), objVector:getY(), lookVX, lookVY)
local front = dot > 0.0
-- if dot < 0.0 then
-- results = false
-- else--if (dot < 0.0 and dot < -0.5) then
-- results = results.. "BEHIND"
-- end
-- results = results.."|"
local lcVX, lcVY = charVX + lookVX, charVY + lookVY
local dotSide = (objX - charVX) * (lcVY - charVY) - (objY - charVY) * (lcVX - charVX)
local left = dotSide > 0.0
-- if dotSide > 0.0 then
-- results = results.. "LEFT"
-- else
-- results = results.. "RIGHT"
-- end
return front, left
end
function FHBoopAction:isInRearRange()
-- This game is weird man
---- I tried to get the angle between the player and the object but its fucking inconsistent because large numbers, AND fucking light switches
@@ -133,7 +178,7 @@ function FHBoopAction:start()
self:doThing((((primary and secondary) and not self.character:isAiming() and primary ~= secondary) and 0) or 1)
else
self:doThing((not secondary and 0) or 2)
end
end
end
--self.character
-- set this here again to undo any moodles and such

View File

@@ -26,6 +26,19 @@ FancyHands.special = {
["Base.CorpseFemale"] = "holdingbody"
}
-- Use the animations from this mod instead!
if getActivatedMods():contains('Skizots Visible Boxes and Garbage2') then
FancyHands.special = {}
end
-- We will begin to store compatibility objects here
FancyHands.compat = {}
-- if getActivatedMods():contains('Amputation2') then -- now included in TOC!
-- FancyHands.compat.TOC = require('compat/FH_TOC')
-- end
if getActivatedMods():contains('BrutalHandwork') then
FancyHands.compat.brutal = true
end
------------------------------------------
-- Fancy Handwork Utilities
------------------------------------------
@@ -34,6 +47,10 @@ function isFHModKeyDown()
return isKeyDown(getCore():getKey('FHModifier'))
end
function isFHModBindDown(player)
return isFHModKeyDown() or (player and player:isLBPressed())
end
local FHswapItems = function(character)
local primary = character:getPrimaryHandItem()
local secondary = character:getSecondaryHandItem()
@@ -160,6 +177,16 @@ local function fancy(player)
return
end
end
if FancyHands.compat.brutal then
local equipped = instanceof(primary, "HandWeapon") and primary:getCategories():contains("Unarmed")
-- we already established that primary and secondary are the same, so if primary is nil then so is secondary
-- or, this is a 2h fist weapon and therefore we should still get ready to punch
if (not primary and player:isAiming() and (SandboxVars.BrutalHandwork.EnableUnarmed and (SandboxVars.BrutalHandwork.AlwaysUnarmed or isFHModBindDown(player)))) or equipped then
player:clearVariable("LeftHandMask")
player:setVariable("RightHandMask", "bhunarmedaim")
return
end
end
player:clearVariable("LeftHandMask")
player:clearVariable("RightHandMask")
return

View File

@@ -24,13 +24,13 @@ description=[*] [b]NEW:[/b] Wrench Repair Animation!
description=[/list]
description=
description=[h2]Updates[/h2]
description=Important information is updated on this page, but full information and release notes are available in the Discussions. Please see the latest:
description=Important information is updated on this page, but full information and release notes are available in the Discussions. Please see the latest: [url=https://steamcommunity.com/workshop/filedetails/discussion/2904920097/3762228679801751286/]Fancy Handwork - "It's Over 9,000!" Update[/url]
description=
description=[h2]IMPORTANT[/h2]
description=If you receive an error about missing actions, or world interactions are simply not playing, you may need to restart Project Zomboid. I have noticed that enabling this mod on an already-existing save and starting the game will result in the animations not being loaded until the game is restarted. This is a [b]BASE GAME[/b] issue!
description=If you receive an error about missing actions, or world interactions are simply not playing, you may need to restart Project Zomboid. I have noticed that enabling this mod for the first time on an already-existing save and starting the game will result in the new animations not being loaded until the game is restarted. This is a [b]BASE GAME[/b] issue, but should only happen the first time.
description=
description=If you receive an error following any update, please see: [url=https://theindiestone.com/forums/index.php?/topic/42925-how-to-fix-updated-mods-in-build-41-multiplayer/]How to fix updated mods in Build 41 Multiplayer[/url]
description=This mod adds many additional animation and action files, which may change between releases. I try to minimize this, but sometimes it is necessary. Unfortunately, Steam sometimes doesn't like to update these correctly.
description=This mod adds many additional animation and action files, which may change between releases. I try to minimize this, but sometimes it is necessary. Unfortunately, Steam sometimes doesn't like to update these correctly resulting in errors.
description=
description=[h2]Usage[/h2]
description=When Attaching or Detaching an item on your Hotbar, you have a chance for the action to automatically be done with your left hand.
@@ -42,18 +42,17 @@ description=When you press the Modifier Key and a Hotbar slot, the item slotted
description=
description=Pressing the Modifier and "E" will swap the items in your hands. (Configurable)
description=
description=Interacting with the world normally, such as opening and closing doors and curtains,flicking light switches, and more, all now have an Animation!
description=Interacting with the world normally, such as opening and closing doors and curtains, flicking light switches, and more, all now have an Animation!
description=
description=Almost ALL TimedActions now have an Animation! No longer will your character just stand there, waiting for a progress bar to fill up!
description=
description=[h3]Notes about World Interactions[/h3]
description=If you are standing still you will turn and face the object you are interacting with if you are not already doing so. There is a Sandbox setting to control how long of a delay before you character is standing still.
description=[b]NOTE:[/b] This is based on your selected Render Framerate. As such, you may need to change this according to your current framerate. A value of 60 is about 1 second at 60 FPS. I will update this at some point.
description=If you are standing still you will turn and face the object you are interacting with if you are not already doing so. There is a Sandbox setting to control how long of a delay before you character is standing still, or the forced turn can be disabled or required.
description=
description=When performing a World Interaction and moving your character will slow down slightly, and stop altogether in the case of opening a Garage Door, for a very brief moment. I have no plans on this being a configurable option, and this is done intentionally. It is a fantastic inclusion for immersion in my opinion, and in tight situations makes planning your movement all the more important. After time, you will hardly notice it.
description=[b]NEW 01/19/2023[/b] - The speed reduction has been reduced from 50% to 25%. This should help prevent the player from being trapped, while still being a nice addition to immersion.
description=
description=[h2]Multiplayer[/h2]
description=[b]NEW 01/07/2023 [/b] - New Animation Sync method is now being used!
description=Animations should sync across multiplayer with little to no issues!
description=
description=[h2]Controllers[/h2]
@@ -70,6 +69,5 @@ description=[url=https://steamcommunity.com/sharedfiles/filedetails/?id=28097195
description=[url=https://steamcommunity.com/sharedfiles/filedetails/?id=2651128766]Body Remodel - FINGERS.[/url] by Akyet
description=
description=Source: [url=https://github.com/hlfstr/pz-mods]GitHub[/url]
description=
tags=Build 41;Realistic;Silly/Fun
visibility=public