Bonjour, voici ma nouvelle IA.
Avant toute chose, cette IA ne fonctionne que sur la version FlatyCloud du bot.
Cette nouvelle IA se sert d'une configuration de sorts par priorité pour attaquer l'ennemi de la manière la plus performante possible en suivant le schéma suivant.
Voici l'exemple de configuration que vous retrouverez en haut du fichier lua.
Tous les champs sont necessaires ! (Si le sort n'a pas de valeur en utilisation maximum ou en utilisation maximum par cible, choisissez-en une arbitraire)
Vous pouvez rentrer plus de sorts que 2 si vous le désirez. (Plus il y en as, plus la charge de calcul est grande, n'abusez pas)
Si cela n'est pas déja evident, la priorité se matérialise par l'ordre dans lequel ils sont décrit dans la configuration. Le premier est le plus prioritaire.
Les sorts qui possèdent une portée minimum ne sont pas encore géré mais le seront a la prochaine mise a jour de l'IA.
Pensez a adapter la premiere ligne du script en fonction de la classe que vous decidez d'utiliser.
Merci de me tenir au courant d’éventuels bugs et n'hésitez pas a partager vos configurations de sorts qui fonctionnent bien!
Code:
DofusClass="9" -- CRA
-- ne pas toucher ces 2 lignes
local CellArray = {}
local CellArrayInit = 0
local Spells = {
[1] = {
name = "Fleche de Recul", -- nom du sort
maxRange = 4, -- la portee du sort (Sans aucun bonus)
canRangeBeBoosted = false, -- si le sort a une portee modifiable
apCost = 3, -- le cout en PA du sort
maxShots = 2, -- le nombre d'utilisation maximum en un tour
maxShotsPerTarget = 1, -- le nombre d'utilisation maximum par tour par cible
},
[2] = {
name = "Fleche Magique",
maxRange = 8,
canRangeBeBoosted = true,
apCost = 3,
maxShots = 3,
maxShotsPerTarget = 2,
},
}
local distToFlee = 8 -- en dessous de cette distance le bot tentera de reculer en fin de tour, sinon, il tentera d'avancer.
function InitCellsArray()
local b = 0
local startX = 0
local startY = 0
local cell = 0
local a = 0
while (a < 20) do
b = 0
while (b < 14) do
CellArray[cell] = {x = startX + b, y = startY + b}
cell = cell + 1
b = b + 1
end
startX = startX + 1
b = 0
while (b < 14) do
CellArray[cell] = {x = startX + b, y = startY + b}
cell = cell + 1
b = b + 1
end
startY = startY - 1
a = a + 1
end
end
function CellIdToCoord(cellId)
if (not(CellArrayInit == 1)) then
InitCellsArray()
end
CellArrayInit = 1
if (IsCellIdValid(cellId)) then
return CellArray[cellId]
end
return nil
end
function TableFilter(tbl, func)
local newtbl= {}
for i, v in pairs(tbl) do
if func(v) then
table.insert(newtbl, v)
end
end
return newtbl
end
function GetIndex(tbl, obj)
for i, v in ipairs(tbl) do
if v == obj then
return i
end
end
return nil
end
function CoordToCellId(coord)
return math.floor((((coord.x - coord.y) * 14) + coord.y) + ((coord.x - coord.y) / 2))
end
function IsCellIdValid(cellId)
return (cellId >= 0 and cellId < 560)
end
function ManhattanDistanceCellId(fromCellId, toCellId)
local fromCoord = CellIdToCoord(fromCellId)
local toCoord = CellIdToCoord(toCellId)
if fromCoord ~= nil and toCoord ~= nil then
return (math.abs(toCoord.x - fromCoord.x) + math.abs(toCoord.y - fromCoord.y))
end
return nil
end
function ManhattanDistanceCoord(fromCoord, toCoord)
return (math.abs(toCoord.x - fromCoord.x) + math.abs(toCoord.y - fromCoord.y))
end
function GetAllEntitiesArray()
local entities = fight:getAllEntities()
local ret = {}
for i = 0, fight:getEntitiesCount() -1 do
table.insert(ret, entities[i])
end
return ret
end
function FindShotsBySpellForEntity(memory, spell, entity)
if #memory == 0 then
return nil
end
for _, v in ipairs(memory) do
if v.s == spell and v.e == entity then
return v
end
end
return nil
end
function AddShotBySpellForEntity(memory, spell, entity)
local foundEntry = FindShotsBySpellForEntity(memory, spell, entity)
if foundEntry ~= nil then
foundEntry.count = foundEntry.count + 1
else
table.insert(memory, {s = spell, e = entity, count = 1})
end
end
function GetReachableCellIds()
local coord = CellIdToCoord(fighter:getCellId())
local mp = fighter:getMP()
local ret = {}
for i = -mp, mp do
local d = mp - math.abs(i)
if d == 0 then
local newCoord = {x = coord.x + i, y = coord.y}
local newCellId = CoordToCellId(newCoord)
if IsCellIdValid(newCellId) and fight:isCellWalkable(newCellId) and fight:isFreeCell(newCellId) then
table.insert(ret, newCellId)
end
else
for j = d * -1, d do
local newCoord = {x = coord.x + i, y = coord.y + j}
local newCellId = CoordToCellId(newCoord)
if IsCellIdValid(newCellId) and fight:isCellWalkable(newCellId) and fight:isFreeCell(newCellId) then
table.insert(ret, newCellId)
end
end
end
end
return ret
end
function GetCellIdToAttackFrom(cellIdToAttack, spell)
local reachableCellIds = GetReachableCellIds()
local spellTotalRange
if spell.canRangeBeBoosted then
spellTotalRange = spell.maxRange + fighter:getRange()
else
spellTotalRange = spell.maxRange
end
reachableCellIds = TableFilter(reachableCellIds, function(a)
return IsCellIdValid(a) and IsCellIdValid(cellIdToAttack) and ManhattanDistanceCellId(a, cellIdToAttack) <= spellTotalRange
end)
if #reachableCellIds < 1 then
return nil
end
if #reachableCellIds >= 2 then
table.sort(reachableCellIds, function(a, b)
return (fight:getDistance(fighter:getCellId(), a) < fight:getDistance(fighter:getCellId(), b))
end)
end
for _, v in ipairs(reachableCellIds) do
if fight:test(spell.name, v, cellIdToAttack) then
return v
end
end
return nil
end
function PickATarget(entitiesToPickFrom, spell)
local spellTotalRange
if spell.canRangeBeBoosted then
spellTotalRange = spell.maxRange + fighter:getRange()
else
spellTotalRange = spell.maxRange
end
local filteredEntities = TableFilter(entitiesToPickFrom, function(a)
return a.Alive and IsCellIdValid(a.CellId) and ManhattanDistanceCellId(fighter:getCellId(), a.CellId) <= spellTotalRange + fighter:getMP()
end)
if #filteredEntities < 1 then
return nil, nil
end
if #filteredEntities >= 2 then
table.sort(filteredEntities, function(a, b)
return (fight:getDistance(fighter:getCellId(), a.CellId) < fight:getDistance(fighter:getCellId(), b.CellId))
end)
end
for _, v in ipairs(filteredEntities) do
local bestOption = GetCellIdToAttackFrom(v.CellId, spell)
if bestOption ~= nil then
return v, bestOption
end
end
return nil, nil
end
function debug_print_memory(memory)
if #memory ~= 0 then
for _, v in ipairs(memory) do
util:debug('s = ' .. v.s.name .. ' | e = ' .. tostring(v.e) .. ' | count = ' .. v.count)
end
end
end
function Main()
local target
local bestOption
local d
local shotsMemory = {}
for _, v in ipairs(Spells) do
if fighter:getAP() >= v.apCost then
local allEntities = GetAllEntitiesArray()
local countShots = 0
while countShots < v.maxShots and fighter:getAP() >= v.apCost do
-- debug_print_memory(shotsMemory)
-- util:debug('Looking for a target for ' .. v.name)
target, bestOption = PickATarget(allEntities, v)
if target == nil then -- le sort n'est pas utilsable en l'etat
-- util:debug('Did not find one')
break -- on passe au sort suivant
else
-- util:debug('Found one : ' .. target:GetName() .. ' (lvl. ' .. target.Level .. ' ) at a distance of ' .. fight:getDistance(fighter:getCellId(), target.CellId))
if bestOption ~= fighter:getCellId() then
fight:moveToCell(bestOption)
end
local debug = fight:launchSpellInCell(target.CellId, v.name)
if debug ~= 1 then -- si le lance du sort n'a pas fonctionne, quelle que soit la raison
break -- on passe au sort suivant
end
-- sinon
countShots = countShots + 1
AddShotBySpellForEntity(shotsMemory, v, target)
if FindShotsBySpellForEntity(shotsMemory, v, target).count >= v.maxShotsPerTarget then
local tmp = GetIndex(allEntities, target)
if tmp ~= nil then
table.remove(allEntities, tmp)
end
end
end
end
end
end
d = ManhattanDistanceCellId(fighter:getCellId(), fight:getNearestEnemy())
if d ~= nil then
if d > distToFlee then
fight:moveToWardCell(fight:getNearestEnemy())
else
fight:moveFarthestCell(fight:getNearestEnemy())
end
end
fighter:passTurn()
end
Avant toute chose, cette IA ne fonctionne que sur la version FlatyCloud du bot.
Cette nouvelle IA se sert d'une configuration de sorts par priorité pour attaquer l'ennemi de la manière la plus performante possible en suivant le schéma suivant.
- Trouver la cible la plus proche pour le sort ayant la priorité [1]
- Trouver la meilleure ligne de vue a portée de PM pour cette cible. Si pas possible, retour au point 1 avec le sort de priorité [2], et ainsi de suite
- Si ligne de vue trouvée, se rendre sur la cellule permettant la ligne de vue et attaquer.
- Si échec de l'attaque (Raison inconnue), retour au point 1 avec le sort de priorité inférieure
- Si tir réussi, retour au point 1 avec le meme sort.
- Reculer si l'ennemi est trop proche, avancer s'il est trop loin
- Passer son tour
Voici l'exemple de configuration que vous retrouverez en haut du fichier lua.
Code:
local Spells = {
[1] = {
name = "Fleche de Recul", -- nom du sort
maxRange = 4, -- la portee du sort (Sans aucun bonus)
canRangeBeBoosted = false, -- si le sort a une portee modifiable
apCost = 3, -- le cout en PA du sort
maxShots = 2, -- le nombre d'utilisation maximum en un tour
maxShotsPerTarget = 1, -- le nombre d'utilisation maximum par tour par cible
},
[2] = {
name = "Fleche Magique",
maxRange = 8,
canRangeBeBoosted = true,
apCost = 3,
maxShots = 3,
maxShotsPerTarget = 2,
},
}
local distToFlee = 8 -- en dessous de cette distance le bot tentera de reculer en fin de tour, sinon, il tentera d'avancer.
Vous pouvez rentrer plus de sorts que 2 si vous le désirez. (Plus il y en as, plus la charge de calcul est grande, n'abusez pas)
Si cela n'est pas déja evident, la priorité se matérialise par l'ordre dans lequel ils sont décrit dans la configuration. Le premier est le plus prioritaire.
Les sorts qui possèdent une portée minimum ne sont pas encore géré mais le seront a la prochaine mise a jour de l'IA.
Pensez a adapter la premiere ligne du script en fonction de la classe que vous decidez d'utiliser.
Code:
DofusClass="9" -- CRA
Code:
1 - Feca
2 - Osamodas
3 - Enutrof
4 - Sram
5 - Xelor
6 - Ecaflip
7 - Eniripsa
8 - Iop
9 - Cra
10 - Sadida
11 - Sacrieur
12 - Pandawa
13 - Roublard
14 - Zobal
15 - Steamer
16 - Eliotrope
17 - Huppermage
18 - Ouginak
Merci de me tenir au courant d’éventuels bugs et n'hésitez pas a partager vos configurations de sorts qui fonctionnent bien!
Attachments
Last edited: