Initial Sync of the Fighter Engine

This commit is contained in:
2024-10-19 06:00:52 -04:00
commit 411eab152e
11 changed files with 623 additions and 0 deletions

219
src/scripts/alchemist.lua Normal file
View File

@@ -0,0 +1,219 @@
-- The alchemist implementation variables
alchemist = alchemist or {}
alchemist.pid = nil
alchemist.specialty = nil
alchemist.balances = alchemist.balances or {}
alchemist.balances.homunculus = true
alchemist.balances.humor = true
alchemist.humors.table = {
"Sanguine",
"Sanguine",
"Choleric",
"Sanguine",
"Melancholic",
"Sanguine",
"Phlegmatic"
}
alchemist.humors.index = 1
alchemist.wrackCount = 0
alchemist.inundate = false
-- The primary function to build pvp actions for the alchemist class
-- NOTE: This script was written for a Sublimation user and primarily pushes keeping class specific weaknesses and using bleeding/aurify as a killpath
function alchemist.decideAction()
if gmcp.Char.Status.class ~= "Alchemist" then
cecho("\n<firebrick>(BadPVP): Called Alchemist decision engine when not a Alchemist.")
return
end
if not target or target == nil then
cecho("\n<firebrick>(BadPVP): Called decision engine without a target.")
return
end
-- set alchemist specialty if blank
if gmcp.Char.Status.class == "Alchemist" and alchemist.specialty == nil then
alchemist.setSpecialty()
end
local commandString = { "setalias murder stand" }
local affsReport = {}
local enemyClass = nil
local humors = {
choleric = ak.alchemist.humour.choleric or 0,
melancholic = ak.alchemist.humour.melancholic or 0,
phlegmatic = ak.alcehmist.humour.phlegmatic or 0,
sanguine = ak.alchemist.humour.sanguine or 0
}
if table.contains(Legacy.CT.Enemies, target) then
enemyClass = Legacy.CT.Enemies[target]
elseif table.contains(Legacy.NDB.db, target) then
enemyClass = Legacy.NDB.db[target].class
end
-- Order: Homunculus Attack, Temper/Inundate, Educe/Wrack OR Truewrack <- That or a Killpath
-- Killpath Reave: At least two tempered targets, can attempt to reave (not used)
-- Killpath aurify: If HP/MP both < 60%, turn target to gold
if (tonumber(ak.manapercent) < 60) and (tonumber(ak.healthpercent) < 60) then
-- Unleash the Aurify!
-- This one should process immediately
table.insert(commandString, "aurify " .. target)
send(table.concat(commandString, "/"))
send("queue addclearfull eqbal murder")
send("pt Starting Aurify attempt on " .. target)
return
end
-- Homunculus - Homunculus Balance (Skip if not on balance)
-- homunculus attack target (do damage) (3 seconds)
-- homunculus shriek target (remove focus balance) (12 seconds) (unused)
-- homunculus corrupt target (flips bleed/clot. Bleed now causes mana loss, and clotting causes damage) (12 seconds)
if alchemist.balances.homunculus then
local hpOver = tonumber(ak.healthpercent) > 60
local mpOver = tonumber(ak.manapercent) > 60
if (hpOver and not mpOver) or (mpOver and not hpOver) then
-- One resource is high, the other is low. Corrupt to flip usage.
table.insert(commandString, "homunculus corrupt " .. target)
table.insert(affsReport, "homunculus corruption")
alchemist.balances.homunculus = false
alchemist.hopid = tempTimer(12, alchemist.resetBalance("homunculus"))
else
-- Just attack
table.insert(commandString, "homunculus attack " .. target)
alchemist.balances.homunculus = false
alchemist.hopid = tempTimer(3, alchemist.resetBalance("homunculus"))
end
end
-- Temper
-- temper target humour (1.7 seconds Humor)
-- inundate target humor (1.7 seconds humor)
-- This will rotate through the alchemist.humors.table and temper those humors in order until it is time to inundate
if humors.sanguine > 2 then
-- push inundate at 3+ sanguine to push bleeding
table.insert(commandString, "inundate " .. target .. " sanguine")
table.insert(affsReport, "bleeding")
alchemist.hupid = tempTimer(1.7, alchemist.resetBalance("humor"))
alchemist.inundate = true
elseif humors.phlegmatic >= 4 then
-- For some reason, they allowed us to push phlegmatic very high so inundate this for extra affs
table.insert(commandString, "inundate " .. target .. " phlegmatic")
table.insert(affsReport, "lethargy")
if humors.phlegmatic >= 4 then table.insert(affsReport, "anorexia") end
if humors.phlegmatic >= 6 then table.insert(affsReport, "slickness") end
if humors.phlegmatic >= 8 then table.insert(affsReport, "weariness") end
alchemist.hupid = tempTimer(1.7, alchemist.resetBalance("humor"))
else
-- Temper whatever humor we have
local ourHumor = alchemist.humors.table[alchemist.humors.index]
table.insert(commandString, "temper " .. target .. " " .. ourHumor)
table.insert(affsReport, "tempered" .. ourHumor .. "(" .. tostring(humors[ourHumor] + 1) .. ")")
alchemist.humors.index = alchemist.humors.index + 1
if alchemist.humors.index > #alchemist.humors.table then alchemist.humors.index = 1 end
alchemist.hupid = tempTimer(1.7, alchemist.resetBalance("humor"))
end
-- Educe
local hpPercent = ((gmcp.Char.Vitals.hp / gmcp.Char.Vitals.maxhp) * 100)
if alchemist.wrackCount ~= 0 and alchemist.wrackcount % 3 ~= 0 then
-- Educe here as we aren't truewracking
if ak.defs.shield then
-- Break Shield
table.insert(commandString, "educe copper " .. target)
elseif alchemist.inundate then
-- We inundated so we want to educe iron to push damage
-- We should only not do that when the target is shielded
table.insert(commandString, "educe iron" .. target)
alchemist.inundate = false
elseif hpPercent <= 40 then
-- Educe tin to give us a break
table.insert(commandString, "educe tin")
else
-- Just do damage
table.insert(commandString, "educe iron " .. target)
end
end
-- Wrack
-- wrack target humor/affliction (2 seconds Bal)
-- truewrack target humor/affliction humor/affliction (2.8 Seconds Bal)
if alchemist.wrackCount ~= 0 and alchemist.wrackCount % 3 ~= 0 then
-- Simple Wrack
table.insert(commandString, "wrack " .. target .. " impatience")
table.insert(affsReport, "impatience")
else
-- Truewrack
local ourSecondAff = nil
if table.contains(fighter.classes.clumsiness, enemyClass) then ourSecondAff = "clumsiness" end
if table.contains(fighter.classes.weariness, enemyClass) then ourSecondAff = "weariness" end
if table.contains(fighter.classes.stupidity, enemyClass) then ourSecondAff = "stupidity" end
if table.contains(fighter.classes.haemophilia, enemyClass) then ourSecondAff = "haemophilia" end
if ourSecondAff == nil then ourSecondAff = "haemophilia" end
table.insert(commandString, "truewrack " .. target .. " impatience " .. ourSecondAff)
table.insert(affsReport, "impatience")
table.insert(affsReport, ourSecondAff)
end
alchemist.wrackCount = alchemist.wrackCount + 1
-- Send final command, Report afflictions
send(table.concat(commandString, "/"))
send("queue addclearfull eqbal murder")
send("pt " .. target .. " hit with " .. table.concat(affsReport, " "))
if fighter.automate then
alchemist.pid = registerAnonymousEventHandler("gmcp.Char.Vitals", "alchemist.isReady")
end
end
-- Functioned used to reset special class balances for Alchemist
function alchemist.resetBalance(which)
if which == "homunculus" then
alchemist.balances.homunculus = true
cecho("\n<firebrick>COMBAT NOTICE: Homunculus balance restored.")
killTimer(alchemist.hopid)
elseif which == "humor" then
alchemist.balances.humor = true
cecho("\n<firebrick>COMBAT NOTICE: Humor balance restored.")
killTimer(alchemist.hupid)
else
cecho("\n<firebrick>COMBAT NOTICE: We were asked to reset the Alchemist balance " ..
which .. " but that isn't a valid balance.")
end
end
-- A function that sets our alchemy specialty so we can refer to this much faster later
function alchemist.setSpecialty()
local ourSpecialty = nil
for k, v in pairs(gmcp.Char.Skills.Groups) do
if v.name == "Sublimation" then
ourSpecialty = "Sublimation"
break
end
if v.name == "Formulation" then
ourSpecialty = "Formulation"
break
end
end
if ourSpecialty == nil then
cecho(
"\n<firebrick>COMBAT NOTICE: No alchemy specialty found. If you have not yet embraced your class or you are not currently an Alchemist this is normal. Otherwise, this is an error.")
else
alchemist.specialty = ourSpecialty
cecho("\n<firebrick>COMBAT NOTICE: Set alchemy specialty to " .. ourSpecialty)
end
end
-- This function is responsible for automating the combat system
-- This is an example of one that handles multiple balance timers
function alchemist.isReady()
-- Skip if we are still off balance
if (gmcp.Char.Vitals.eq == 0) or (gmcp.Char.Vitals.bal == 0) then return end
-- We want to make sure we at least have humor balance (Which we should generally)
if not alchemist.balances.humor then return end
killAnonymousEventHandler(alchemist.pid)
alchemist.decideAction()
end

68
src/scripts/fighter.lua Normal file
View File

@@ -0,0 +1,68 @@
fighter = fighter or {}
function fighter.Setup()
fighter.classes = {}
fighter.automate = false
-- To add a new class, put the name here
fighter.classes.implemented = {
"Psion",
"Alchemist"
}
-- Then in here, set the class name from above equal to the main object in that classes pvp script
-- Important Note: You always need a name.decideAction function as this is called to generate pvp actions
fighter.classes.implementations = {
Psion = psion,
Alchemist = alchemist
}
-- Classes where we want to push stupidity
fighter.classes.stupidity = {
"Alchemist"
}
-- Classes where we want to push clumsiness
fighter.classes.clumsiness = {
"Blademaster",
"Druid",
"Infernal",
"Monk",
"Paladin",
"Runewarden",
"Priest",
"Sentinel",
"Serpent",
"Shaman",
"Psion",
"Depthswalker"
}
-- classes where we want to push weariness
fighter.classes.weariness = {
"Blademaster",
"Druid",
"Monk",
"Priest",
"Pariah",
"Occultist",
"Sentinel",
"Serpent"
}
-- classes where we want to push confusion
fighter.classes.confusion = {
"Psion"
}
-- classes where we want to push haemophilia
fighter.classes.haemophilia = {
"Magi"
}
-- Here is an example of adding additional setup for your pvp systems
-- This will set the variable alchemist.specialty to Sublimation or Formulation depending
alchemist.setSpecialty()
end
registerAnonymousEventHandler("sysLoadEvent", "fighter.Setup")

197
src/scripts/psion.lua Normal file
View File

@@ -0,0 +1,197 @@
-- Psion Implementation Variables
psion = psion or {}
psion.timeToFlurry = false
psion.pid = nil
-- The primary function to build pvp actions for the psion class
-- NOTE: This script primarily pushes for keeping specific class weaknesses applied and stacking unweaved body/mind until it can be inverted to spirit and flurried against
function psion.decideAction()
if gmcp.Char.Status.class ~= "Psion" then
cecho("\n<firebrick>(BadPVP): Called Psion decision engine when not a Psion.")
return
end
if not target or target == nil then
cecho("\n<firebrick>(BadPVP): Called decision engine without a target.")
return
end
local commandString = { "setalias murder stand" }
local affsReport = {}
local limbs = nil
local enemyClass = nil
local unwoven = {}
local psionFlags = {}
local preferredLeg = nil
local preferredArm = nil
-- Preset flags
psionFlags.clumsiness = false
psionFlags.weariness = false
psionFlags.stupidity = false
-- Check enemy class
if table.contains(Legacy.CT.Enemies, target) then
enemyClass = Legacy.CT.Enemies[target]
elseif table.contains(Legacy.NDB.db, target) then
enemyClass = Legacy.NDB.db[target].class
end
-- check limb damage
if table.contains(lb, target) then limbs = lb[target] end
-- Set preferred limbs
if limbs ~= nil then
local limbTable = { "right", "left" }
if limbs.hits['left leg'] > limbs.hits['right leg'] then
preferredLeg = 'left'
elseif limbs.hits['left leg'] == limbs.hits['right leg'] then
preferredLeg = limbTable[math.random(#limbTable)]
else
preferredLeg = 'right'
end
if limbs.hits['left arm'] > limbs.hits['right arm'] then
preferredArm = 'left'
elseif limbs.hits['left arm'] == limbs.hits['right arm'] then
preferredArm = limbTable[math.random(#limbTable)]
else
preferredArm = 'right'
end
end
-- Set unweavings
if table.contains(ak.psion.unweaving, 'body') then unwoven.body = ak.psion.unweaving.body else unwoven.body = 0 end
if table.contains(ak.psion.unweaving, 'mind') then unwoven.mind = ak.psion.unweaving.mind else unwoven.mind = 0 end
if table.contains(ak.psion.unweaving, 'spirit') then unwoven.spirit = ak.psion.unweaving.spirit else unwoven.spirit = 0 end
-- Weave Prepare
-- Disruption = paralysis
-- Laceration = haemophilia
-- Dazzle = clumsiness
-- Rattle = epilepsy
-- Vapours = asthma
-- Incisive = beats clumsiness
-- Order: Incisive for Clumsiness, Paralysis, Class Specific, Asthma, Haemophilia, Epilepsy, Clumsy
if Legacy.Curing.Affs['clumsiness'] then
-- We have clumsiness so use incisive
table.insert(commandString, "weave prepare incisive")
elseif not ak.check('paralysis', 100) then
table.insert(commandString, "weave prepare disruption")
table.insert(affsReport, "paralysis")
elseif enemyClass ~= nil and table.contains(fighter.classes.clumsiness, enemyClass) and not ak.check('clumsiness', 100) then
table.insert(commandString, "weave prepare dazzle")
table.insert(affsReport, "clumsiness")
psionFlags.clumsiness = true
elseif enemyClass ~= nil and table.contains(fighter.classes.haemophilia, enemyClass) and not ak.check('haemophilia', 100) then
table.insert(commandString, "weave prepare laceration")
table.insert(affsReport, "haemophilia")
elseif not ak.check('asthma', 100) then
table.insert(commandString, "weave prepare vapours")
table.insert(affsReport, "asthma")
elseif not ak.check('haemophilia', 100) then
table.insert(commandString, "weave prepare laceration")
table.insert(affsReport, "haemophilia")
elseif not ak.check('epilepsy', 100) then
table.insert(commandString, "weave prepare rattle")
table.insert(affsReport, "epilepsy")
elseif not ak.check('clumsiness', 100) then
table.insert(commandString, "weave prepare dazzle")
table.insert(affsReport, "clumsiness")
psionFlags.clumsiness = true
end
-- We do not have transcend, but once we do decide psionics action here
-- examples:
-- If paralized, we can psi manipulate touch tree
-- we can excise if mana less than 30% on enemy
-- we can use psi splinter to break shields
-- we can use psi combustion to push bleeding
-- we can use psi expunge to cure impatience
-- we can use psi muddle on stupidity inflicted enemies
-- we can just straight up psi shatter them
-- Weaving
if ak.defs.shield then
table.insert(commandString, "weave cleave " .. target)
elseif unwoven.mind == 0 then
table.insert(commandString, "weave unweave " .. target .. " mind")
table.insert(affsReport, "unweavingmind(1)")
elseif unwoven.body == 0 then
table.insert(commandString, "weave unweave " .. target .. " body")
table.insert(affsReport, "unweavingbody(1)")
elseif not psionFlags.clumsiness and enemyClass ~= nil and table.contains(fighter.classes.clumsiness, enemyClass) and not ak.check("clumsiness", 100) then
table.insert(commandString, "weave sever " .. target .. " " .. preferredArm)
table.insert(affsReport, "clumsiness")
psionFlags.clumsiness = true
elseif not psionFlags.weariness and enemyClass ~= nil and table.contains(fighter.classes.weariness, enemyClass) and not ak.check("weariness", 100) then
table.insert(commandString, "weave puncture " .. target .. " " .. preferredArm)
table.insert(affsReport, "weariness")
psionFlags.weariness = true
elseif not psionFlags.stupidity and enemyClass ~= nil and table.contains(fighter.classes.stupidity, enemyClass) and not ak.check("stupidity", 100) then
table.insert(commandString, "weave backhand " .. target)
table.insert(affsReport, "stupidity")
table.insert(affsReport, "dizziness")
psionFlags.stupidity = true
elseif not ak.check("nausea", 100) then
-- exsanguinate for nausea
table.insert(commandString, "weave exsanguinate " .. target)
table.insert(affsReport, "nausea")
if ak.bleeding >= 150 then table.insert(affsReport, "anorexia") end
elseif not ak.check("asthma", 100) then
-- deathblow for asthma
table.insert(commandString, "weave deathblow " .. target)
table.insert(affsReport, "asthma")
table.insert(affsReport, "bleeding")
elseif not ak.check("stupidity", 100) or not ak.check("dizziness", 100) then
-- backhand for stupidity and dizziness
table.insert(commandString, "weave backhand " .. target)
table.insert(affsReport, "stupidity")
table.insert(affsReport, "dizziness")
psionFlags.stupidity = true
elseif not ak.check("blackout", 100) and ak.check("prone", 100) then
-- lightsteal for blackout
table.insert(commandString, "weave lightsteal " .. target)
table.insert(affsReport, "trueblind")
table.insert(affsReport, "blackout")
elseif unwoven.body == 5 then
-- invert!
table.insert(commandString, "weave invert " .. target .. " body spirit")
table.insert(affsReport, "unweavingspirit(5)")
psion.timeToFlurry = true
elseif unwoven.mind == 5 then
-- invert!
table.insert(commandString, "weave invert " .. target .. " mind spirit")
table.insert(affsReport, "unweavingspirit(5)")
psion.timeToFlurry = true
elseif psion.timeToFlurry then
-- Unleash Flurry!
table.insert(commandString, "weave flurry " .. target)
psion.timeToFlurry = false
elseif unwoven.body < 5 then
table.insert(commandString, "weave unweave " .. target .. " body")
table.insert(affsReport, "unweavingbody(" .. tostring(unwoven.body + 1) .. ")")
elseif unwoven.mind < 5 then
table.insert(commandString, "weave unweave " .. target .. " mind")
table.insert(affsReport, "unweavingmind(" .. tostring(unwoven.mind + 1) .. ")")
end
-- Send final command, Report afflictions
send(table.concat(commandString, "/"))
send("queue addclearfull eqbal murder")
send("pt " .. target .. " hit with " .. table.concat(affsReport, " "))
-- If we are automating, start automation
if fighter.automate then
psion.pid = registerAnonymousEventHandler("gmcp.Char.Vitals", "psion.isReady")
end
end
-- This function is responsible for automating the combat system
function psion.isReady()
if (gmcp.Char.Vitals.eq == 0) or (gmcp.Char.Vitals.bal == 0) then return end
killAnonymousEventHandler(psion.pid)
psion.decideAction()
end

14
src/scripts/scripts.json Normal file
View File

@@ -0,0 +1,14 @@
[
{
"name": "fighter",
"isActive": "yes"
},
{
"name": "psion",
"isActive": "yes"
},
{
"name": "alchemist",
"isActive": "yes"
}
]