Initial Sync of the Fighter Engine

This commit is contained in:
Charles Click 2024-10-19 06:00:52 -04:00
commit 411eab152e
Signed by: roryejinn
GPG Key ID: EDECB89DEDB998C0
11 changed files with 623 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
docs/*

46
.woodpecker.yml Normal file
View File

@ -0,0 +1,46 @@
steps:
- name: build-Fighter
image: git.vertinext.com/roryejinn/alpine_muddler
when:
- path:
include: [ 'Fighter/*' ]
event: [push, pull_request]
environment:
GITEATKN:
from_secret: GITEA_TOKEN
VERSION: 1.0.5
commands:
- apk add tea
- java -jar /muddle/muddle.jar
- tea login add --name=temp --url=https://git.vertinext.com/ --token=$GITEATKN
- tea releases create --asset "build/Fighter.mpackage" --asset "build/Fighter.xml" --tag $VERSION --title "Latest Compiled Release"
- name: notify-Failure
image: codeberg.org/l-x/woodpecker-ntfy
when:
- status: [ failure ]
event: [push, pull_request]
settings:
url: https://gotify.vertinext.com/woodpecker
token:
from_secret: GOTIFY_TOKEN
title: ${CI} - ${CI_REPO_NAME}
actions: "http, Open Build, ${CI_PIPELINE_URL}, clear=true"
tags: warning
icon: https://woodpecker-ci.org/img/logo.svg
message: Failed to build Fighter Plugins
- name: notify-Success
image: codeberg.org/l-x/woodpecker-ntfy
when:
- status: [ success ]
event: [push, pull_request]
settings:
url: https://gotify.vertinext.com/woodpecker
token:
from_secret: GOTIFY_TOKEN
title: ${CI} - ${CI_REPO_NAME}
actions: "http, Open Build, ${CI_PIPELINE_URL}, clear=true"
tags: white_check_mark
icon: https://woodpecker-ci.org/img/logo.svg
message: Built new release packages for Fighter Plugins

47
README.md Normal file
View File

@ -0,0 +1,47 @@
# Fighter
Fighter is a simple, alias based PVP system for Achaea. The Fighter Engine is of a simplistic design and only handles managing and automating pvp actions. It does not send actions to the game on your behalf. Your specific Class Engines will do this. This package consists of the Fighter engine itself and two additional scripts demonstrating how to create PVP systems for different classes. The requirements for each vary and are explained in further detail below.
## Fighter Engine
### Base Components
The Fighter Engine consists of all code in the aliases folder (automatFight, callAction) and the primary engine script (fighter.lua) under scripts. These components have no other plugin requirements. They only require Mudlet OR that gmcp data is exposed via a variable named gmcp. Even then, that sole requirement only comes up under the callAction script and is easy to remove if unwanted.
### Example PVP Scripts
alchemist.lua and psion.lua are two example PVP scripts that demonstrate how to create a PVP decision engine that works with the Fighter Engine. These two example scripts are available for Legacy and Orion depending on which curing system you use. Additionally, this implementation relies on AK 8.5 and Romaen's Limb Tracker 1.3. Other versions of Romaen's Limb Tracker will probably work as long as they don't change how limb damage is accessed (IE: limbs[target].hits[limb]). AK on the other hand is a large, varied script and I can't guarantee any compatibility with other versions.
Additionally, each script demonstrates different use cases and implementations. Psion relies heavily on limb damage and shows how you might change your actions based on that. On the other hand, the alchemist example demonstrates how one might handle multiple balance timers.
## Creating Your Own Class Engines
While I've included an example alchemist and psion class engine, you might not have the same priorities as me. You might also want to add other classes. It is easy to do so.
### Step 1 - Write Your Class Engine
Create a new script with a name that helps you identify it. In that script, you will write your entire Class Engine. This file is responsible for deciding what actions to take, managing affliction reporting, sending the commands to the game, storing and managing data specific to the classes implementation, and managing any created temporary objects such as timers, triggers or aliases. Your Class Engine has to follow four rules but can otherwise be written however you want.
1) You must have a decideAction() function. decideAction() is the primary function called by the Fighter Engine to generate a pvp command string.
2) You must have an isReady() function. isReady() is responsible for making automation work. The isReady function should determine when a new action should be taken and then kill the temporary event handler spawned by decideAction and recall decideAction to generate a new command.
3) When designing your Class Engine, enclose everything in a single table which will act like a class. You can see an example of this in both example scripts where functions are held within a table. This makes it easier for Fighter to manipulate the implementations and call the Class Engines.
4) Every Class Engine should be written in such a way that when fighter.Setup() is called it is able to rebuild itself. fighter.Setup() is designed as a basic hot reload function and will recreate Fighter and all sub-components each time. This allows you to force Mudlet to update any changes you make to the Fighter Engine or Class Engines.
### Step 2 - Add it to fighter.lua
Open up fighter.lua and at the top you'll see two tables that we need to modify slightly for your new Class Engine to work.
This table is responsible for noting which Class Engines are available for us to use. This is an important distinction as you can have a Class Engine listed under implementations for testing, but leave it out of implemented so Fighter won't call it during PVP.
```lua
fighter.classes.implemented = {
"Psion",
"Alchemist"
}
```
This table is responsible for holding references to each Class Engine. The names on the left should be the same as the class name reported by `gmcp.Char.Status.class` since that is the variable used to pull the implementation. The Fighter Engine works by calling these references to reach the functions and data contained within. Please note that there are no quotes here. This syntax is not an error. This is how lua defines tables with named keys instead of standard indexes.
```lua
fighter.classes.implementations = {
Psion = psion,
Alchemist = alchemist
}
```
### Step 3 - Profit
That's it. You've added your custom Class Engine. Now when you type fight (the default alias to call the next action) while switched to this new class, Fighter will automatically call the decideAction() function under the correct Class Engine for you.

5
mfile Normal file
View File

@ -0,0 +1,5 @@
{
"package": "Fighter",
"description": "A simple, alias based pvp engine written in Lua for Achaea.",
"version": "1.0.5"
}

12
src/aliases/aliases.json Normal file
View File

@ -0,0 +1,12 @@
[
{
"name": "callAction",
"isActive": "yes",
"regex": "^fight$"
},
{
"name": "automateFight",
"isActive": "yes",
"regex": "^autofight$"
}
]

View File

@ -0,0 +1,7 @@
if fighter.automate then
cecho("\n<firebrick>COMBAT NOTICE: Will no longer automate sending the next pvp command. Please use the pvp alias when you want to send a command string.")
fighter.automate = false
else
cecho("\n<firebrick>COMBAT NOTICE: Will automate sending the next pvp command.")
fighter.automate = true
end

View File

@ -0,0 +1,7 @@
local ourClass = gmcp.Char.Status.class
if table.contains(fighter.classes.implemented, ourClass) then
fighter.classes.implementations[ourClass].decideAction()
else
cecho("\n<firebrick>COMBAT NOTICE: No implementation for " .. ourClass)
end

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"
}
]