Skip to content

Commit

Permalink
No more swish sounds when harvesting
Browse files Browse the repository at this point in the history
  • Loading branch information
jhaakma committed Jul 31, 2023
1 parent 3b340ad commit 210a966
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 140 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
local Activator = require("mer.ashfall.activators.Activator")
local this = {}

--[[
TODO:
Move configs into integrations, move tables into Activator,
then remove this file.
]]
---@class Ashfall.Activator.Config
---@field name? string The name of the activator
---@field type string The type of the activator
---@field mcmSetting? string The name of the MCM setting that controls whether this activator is active
---@field ids? table<string, table> A table of ids to register for this activator. Key: id, Value: table of data
---@field patterns? table<string, boolean> A table of patterns to register for this activator. Key: pattern, Value: true
---@field isStewer boolean Whether this activator is a stewer
---@field owned? boolean Whether this activator is owned by NPCs, such as kegs


this.types = {
waterSource = "waterSource",
Expand Down
191 changes: 61 additions & 130 deletions Data Files/MWSE/mods/mer/ashfall/harvest/init.lua
Original file line number Diff line number Diff line change
@@ -1,186 +1,117 @@
local activatorController = require("mer.ashfall.activators.activatorController")
local harvestConfigs = require("mer.ashfall.harvest.config")
local common = require("mer.ashfall.common.common")
local logger = common.createLogger("harvestController")
local config = require("mer.ashfall.config").config
local service = require("mer.ashfall.harvest.service")



event.register("loaded", function()
timer.start{
type = timer.real,
iterations = -1,
duration = 0.1,
callback = service.updateDisabledHarvestables
}
end)

--- Attempt a harvest on attack swing
---@param e attackEventData
local function harvestOnAttack(e)
logger:debug("harvestOnAttack() ENTRY")
--Get the necessary objects and check conditions--

--Filter to player
if e.mobile.reference ~= tes3.player then
logger:debug("Harvest: Not player")
return
end

--Get player target Activator
local activator = activatorController.getCurrentActivator()
if not activator then
logger:debug("Harvest: No activator")
return
end

--Get activator Ref
local reference = activatorController.getCurrentActivatorReference()
if not reference then
logger:debug("Harvest: No reference")
local data = service.getCurrentHarvestData()
if not data then
logger:debug("Harvest: No current harvest data")
return
end

--Get harvest config from activator
---@type Ashfall.Harvest.Config
local harvestConfig = harvestConfigs.activatorHarvestData[activator.type]
if not harvestConfig then
logger:debug("Harvest: No harvest config")
logger:debug("activatorType: %s", activator.type)
return
end

--Get Player Weapon
local weapon = tes3.player.mobile.readiedWeapon
if not weapon then
logger:debug("Harvest: No weapon")
return
end

--Get harvest data from weapon
local weaponData = service.getWeaponHarvestData(weapon, harvestConfig)
if not weaponData then
logger:debug("Harvest: No weapon data")
return
end

--Check if Activator is active
local activatorActive = config[activator.mcmSetting] ~= false
if not activatorActive then
logger:debug("Harvest: Activator not active")
return
end

--Return if illegal to harvest
if service.checkIllegalToHarvest() then
service.showIllegalToHarvestMessage(harvestConfig)
logger:debug("Harvest: Illegal to harvest")
return
end

--Check attack direction
if not service.validAttackDirection(harvestConfig) then
logger:debug("Harvest: Invalid attack direction")
return
end

--Check if activator is already harvested
if service.checkHarvested(reference) then
logger:debug("Harvest: Can't harvest, already harvested")
return
end

logger:debug("Checks passed, swinging")
--CHECKS PASS, we are swinging at something
service.playSound(harvestConfig)

service.playSound(data.harvestConfig)
--Get strength of swing
local swingStrength = service.getSwingStrength(weapon, weaponData)

local swingStrength = service.getSwingStrength(data.weapon, data.weaponData)
--Degrade weapon and exit if it breaks
local weaponBroke = service.degradeWeapon(weapon, swingStrength, weaponData.degradeMulti)
local weaponBroke = service.degradeWeapon(data.weapon, swingStrength, data.weaponData.degradeMulti)
if weaponBroke then
logger:debug("Weapon broke")
return
end

--Accumulate swings and check if it's enough to harvest
local didHarvest = service.attemptSwing(swingStrength, reference, harvestConfig.swingsNeeded)
local didHarvest = service.attemptSwing(swingStrength, data.reference, data.harvestConfig.swingsNeeded)
if not didHarvest then return end
logger:debug("Enough swings, harvesting")
--Harvest the resources
service.harvest(reference, harvestConfig)
service.harvest(data.reference, data.harvestConfig)
--Disable if exhausted
if harvestConfig.destructionLimitConfig and config.disableHarvested then
if data.harvestConfig.destructionLimitConfig and config.disableHarvested then
logger:debug("Disabling exhausted harvestable")
service.disableExhaustedHarvestable(reference, harvestConfig)
service.disableExhaustedHarvestable(data.reference, data.harvestConfig)
end
logger:debug("harvestOnAttack() EXIT")
end
event.register("attack", harvestOnAttack )

-- Force a chop action if looking at a harvestable

--- Force a chop action if looking at a harvestable with a valid weapon
---@param e attackStartEventData
event.register("attackStart", function(e)
--Get player target Activator
local activator = activatorController.getCurrentActivator()
if not activator then
logger:debug("Harvest: No activator")
return
end


logger:debug("Activator type: %s", activator.type)

--Get harvest config from activator
---@type Ashfall.Harvest.Config
local harvestConfig = harvestConfigs.activatorHarvestData[activator.type]
if not harvestConfig then
logger:debug("Harvest: No harvest config")
return
end

--Get Player Weapon
local weapon = tes3.player.mobile.readiedWeapon
if not weapon then
logger:debug("Harvest: No weapon")
--Filter to player
if e.reference ~= tes3.player then
logger:debug("Harvest: Not player")
return
end

--Get harvest data from weapon
local weaponData = service.getWeaponHarvestData(weapon, harvestConfig)
if not weaponData then
logger:debug("Harvest: No weapon data")
local data = service.getCurrentHarvestData({ ignoreAttackDirection = true})
if not data then
logger:debug("Harvest: Not ready to harvest")
return
end

if not (harvestConfig.attackDirections and table.size(harvestConfig.attackDirections) > 0) then
local hasAttackDirections = data.harvestConfig.attackDirections
and table.size(data.harvestConfig.attackDirections) > 0
if not hasAttackDirections then
logger:debug("No attack directions")
return
end

--Check if current attack direction doesn't match valid directions for this harvestable
if not harvestConfig.attackDirections[e.attackType] then
if harvestConfig.defaultAttackDirection then
logger:debug("Forcing attack type %s", table.find(tes3.physicalAttackType, harvestConfig.defaultAttackDirection))
e.attackType = harvestConfig.defaultAttackDirection
else
--set to first one in list
for attackType, _ in pairs(harvestConfig.attackDirections) do
logger:debug("Forcing attack type %s", table.find(tes3.physicalAttackType, attackType))
e.attackType = attackType
break
end
if data.harvestConfig.attackDirections[e.attackType] then
--already a valid direction
return
end
if data.harvestConfig.defaultAttackDirection then
logger:debug("Forcing default attack type %s", table.find(tes3.physicalAttackType, data.harvestConfig.defaultAttackDirection))
e.attackType = data.harvestConfig.defaultAttackDirection
else
--set to first one in list
for attackType, _ in pairs(data.harvestConfig.attackDirections) do
logger:debug("Forcing attack type %s", table.find(tes3.physicalAttackType, attackType))
e.attackType = attackType
break
end
end

end)

--- Block swing sounds when harvesting
---@param e addSoundEventData
event.register("addSound", function(e)
--filter to player
if e.reference ~= tes3.player then return end
local data = service.getCurrentHarvestData()
if not data then return end
local swishSounds = {
["swishl"] = true,
["swishm"] = true,
["swishs"] = true,
["weapon swish"] = true,
["miss"] = true,
}
if swishSounds[e.sound.id:lower()] then
logger:debug("Blocking vanilla weapon swish sound")
return false
end
end, { priority = 500})

--- Reset harvestables on load.
event.register("loaded", function()
service.destroyedHarvestables:iterate(function(reference)
service.enableHarvestable(reference)
end)
timer.start{
type = timer.real,
iterations = -1,
duration = 0.1,
callback = service.updateDisabledHarvestables
}
end)

--- Clear any data added when an item was felled from a tree.
Expand Down
89 changes: 84 additions & 5 deletions Data Files/MWSE/mods/mer/ashfall/harvest/service.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,81 @@ function HarvestService.showIllegalToHarvestMessage(harvestConfig)
tes3.messageBox("You must be in the wilderness to harvest.")
end

---@class Ashfall.HarvestService.getCurrentHarvestData.params
---@field ignoreAttackDirection boolean If true, will ignore the attack direction check

--Get the config for the current harvestable
---@return Ashfall.Harvest.CurrentHarvestData|nil
---@param e Ashfall.HarvestService.getCurrentHarvestData.params|nil
function HarvestService.getCurrentHarvestData(e)
e = e or {}
--Get player target Activator
local activator = ActivatorController.getCurrentActivator()
if not activator then
logger:trace("Harvest: No activator")
return
end
--Get activator Ref
local reference = ActivatorController.getCurrentActivatorReference()
if not reference then
logger:debug("Harvest: No reference")
return
end
--Get harvest config from activator
---@type Ashfall.Harvest.Config
local harvestConfig = harvestConfigs.activatorHarvestData[activator.type]
if not harvestConfig then
logger:trace("Harvest: No harvest config")
return
end
--Get player Weapon
local weapon = tes3.player.mobile.readiedWeapon
if not weapon then
logger:debug("Harvest: No weapon")
return
end
--Get harvest data from weapon
local weaponData = HarvestService.getWeaponHarvestData(weapon, harvestConfig)
if not weaponData then
logger:debug("Harvest: No weapon data")
return
end
--Check if Activator is active
local activatorActive = config[activator.mcmSetting] ~= false
if not activatorActive then
logger:debug("Harvest: Activator not active")
return
end
--Return if illegal to harvest
if HarvestService.checkIllegalToHarvest() then
HarvestService.showIllegalToHarvestMessage(harvestConfig)
logger:debug("Harvest: Illegal to harvest")
return
end
if not e.ignoreAttackDirection then
--Check attack direction
if not HarvestService.validAttackDirection(harvestConfig) then
logger:debug("Harvest: Invalid attack direction")
return
end
end
--Check if activator is already harvested
if HarvestService.checkHarvested(reference) then
logger:debug("Harvest: Can't harvest, already harvested")
return
end
--All checks pass, return the harvest data
local currentHarvestData = {
reference = reference,
activator = activator,
harvestConfig = harvestConfig,
weapon = weapon,
weaponData = weaponData
}
return currentHarvestData
end


---@param weapon tes3equipmentStack
---@param harvestConfig Ashfall.Harvest.Config
---@return Ashfall.Harvest.WeaponData | nil
Expand Down Expand Up @@ -77,15 +152,19 @@ function HarvestService.getWeaponHarvestData(weapon, harvestConfig)
end
end

function HarvestService.getAttackDirection()
return tes3.mobilePlayer.actionData.attackDirection ---@diagnostic disable-line
end

function HarvestService.validAttackDirection(harvestConfig)
local attackDirection = tes3.mobilePlayer.actionData.attackDirection
local attackDirection = HarvestService.getAttackDirection()
return harvestConfig.attackDirections[attackDirection]
end

---@param weapon tes3equipmentStack
---@return number damageEffect
function HarvestService.getDamageEffect(weapon)
local attackDirection = tes3.mobilePlayer.actionData.attackDirection
local attackDirection = HarvestService.getAttackDirection()
local maxField = harvestConfigs.attackDirectionMapping[attackDirection].max
local maxDamage = weapon.object[maxField]
logger:trace("maxDamage: %s", maxDamage)
Expand Down Expand Up @@ -158,10 +237,10 @@ function HarvestService.degradeWeapon(weapon, swingStrength, degradeMulti)
degradeMulti = degradeMulti or 1.0
logger:trace("degrade multiplier: %s", degradeMulti)
--Weapon degradation
weapon.variables.condition = weapon.variables.condition - (4 * swingStrength * degradeMulti)
weapon.itemData.condition = weapon.itemData.condition - (4 * swingStrength * degradeMulti)
--weapon is broken, unequip
if weapon.variables.condition <= 0 then
weapon.variables.condition = 0
if weapon.itemData.condition <= 0 then
weapon.itemData.condition = 0
tes3.mobilePlayer:unequip{ type = tes3.objectType.weapon }
return true
end
Expand Down
7 changes: 7 additions & 0 deletions Data Files/MWSE/mods/mer/ashfall/harvest/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,10 @@
---@field fallSound string The sound to play when the harvestable is destroyed
---@field clutter table<string, boolean> A list of clutter items that are destroyed alongside this harvestable.
---@field dropLoot boolean If set, any items sitting on top of the reference will be "dropped" to the ground

---@class Ashfall.Harvest.CurrentHarvestData
---@field reference tes3reference The current harvestable reference
---@field activator Ashfall.Activator.Config The current activator
---@field harvestConfig Ashfall.Harvest.Config The current harvest config
---@field weapon tes3equipmentStack The currently equipped weapon
---@field weaponData Ashfall.Harvest.WeaponData The weapon data for the currently equipped weapon

0 comments on commit 210a966

Please sign in to comment.