День добрый.
Собственно, пишу ИИ для одной старой кастомки и в какой-то момент столкнулся с ошибкой
Too many nested ifs (Max is 50)
У меня образовалось большое количество блоков if-then-else...
Но они мне нужны все без исключения.
Пытался разделять код по разным функция, триггерам, library, пытался запускать часть кода через "ExecuteFunc" - не помогает
Процесс гугления тоже не помог.
Может кто сталкивался с данной проблемой и знает, как ее решить?
Собственно, пишу ИИ для одной старой кастомки и в какой-то момент столкнулся с ошибкой
Too many nested ifs (Max is 50)
У меня образовалось большое количество блоков if-then-else...
Но они мне нужны все без исключения.
Пытался разделять код по разным функция, триггерам, library, пытался запускать часть кода через "ExecuteFunc" - не помогает
Процесс гугления тоже не помог.
Может кто сталкивался с данной проблемой и знает, как ее решить?
Часть кода, ответственная за ИИ
AIActivity
library AIMain uses AIBuild, CustomFuncs
void AIChooseTarget(int id){
local group g = CreateGroup()
GroupEnumUnitsInRect(g, gg_rct_Castle_Back, null) //Проверяем область вокруг портала
loop {
bj_lastCreatedUnit = FirstOfGroup(g)
if IsPlayerEnemy(GetOwningPlayer(bj_lastCreatedUnit), GetOwningPlayer(Heroes[id])) and GetWidgetLife(bj_lastCreatedUnit) > 0.405{
AITarget[id] = bj_lastCreatedUnit
DestroyGroup(g)
g = null
return
else
GroupRemoveUnit(g, bj_lastCreatedUnit)
}
exitwhen bj_lastCreatedUnit == null
}
GroupEnumUnitsInRect(g, gg_rct_Castle_Center, null)//Проверяем центральную площадь
loop {
bj_lastCreatedUnit = FirstOfGroup(g)
if IsPlayerEnemy(GetOwningPlayer(bj_lastCreatedUnit), GetOwningPlayer(Heroes[id])) and GetWidgetLife(bj_lastCreatedUnit) > 0.405{
AITarget[id] = bj_lastCreatedUnit
DestroyGroup(g)
g = null
return
else
GroupRemoveUnit(g, bj_lastCreatedUnit)
}
exitwhen bj_lastCreatedUnit == null
}
local int rand = GetRandomInt(0,2)
if rand == 0 {
GroupEnumUnitsInRect(g, gg_rct_Castle_West, null)//Проверяем зону на западе
loop {
bj_lastCreatedUnit = FirstOfGroup(g)
if IsPlayerEnemy(GetOwningPlayer(bj_lastCreatedUnit), GetOwningPlayer(Heroes[id])) and GetWidgetLife(bj_lastCreatedUnit) > 0.405{
AITarget[id] = bj_lastCreatedUnit
DestroyGroup(g)
g = null
return
else
GroupRemoveUnit(g, bj_lastCreatedUnit)
}
exitwhen bj_lastCreatedUnit == null
}
elseif rand == 1
GroupEnumUnitsInRect(g, gg_rct_Castle_Front, null)//Проверяем зону на Севере
loop {
bj_lastCreatedUnit = FirstOfGroup(g)
if IsPlayerEnemy(GetOwningPlayer(bj_lastCreatedUnit), GetOwningPlayer(Heroes[id])) and GetWidgetLife(bj_lastCreatedUnit) > 0.405{
AITarget[id] = bj_lastCreatedUnit
DestroyGroup(g)
g = null
return
else
GroupRemoveUnit(g, bj_lastCreatedUnit)
}
exitwhen bj_lastCreatedUnit == null
}
else
GroupEnumUnitsInRect(g, gg_rct_Castle_East, null)//Проверяем зону на Востоке
loop {
bj_lastCreatedUnit = FirstOfGroup(g)
if IsPlayerEnemy(GetOwningPlayer(bj_lastCreatedUnit), GetOwningPlayer(Heroes[id])) and GetWidgetLife(bj_lastCreatedUnit) > 0.405{
AITarget[id] = bj_lastCreatedUnit
DestroyGroup(g)
g = null
return
else
GroupRemoveUnit(g, bj_lastCreatedUnit)
}
exitwhen bj_lastCreatedUnit == null
}
}
AITarget[id] = null
DestroyGroup(g)
g = null
}
void AIUnitMove(unit hero){
local real x = GetUnitX(hero)
local real y = GetUnitY(hero)
local int id = GetPlayerId(GetOwningPlayer(hero))
if AITarget[id] == null or GetWidgetLife(AITarget[id]) < 0.405{
AIChooseTarget(id)
}
if AITarget[id] != null {
IssuePointOrder(hero, "attack", GetUnitX(AITarget[id]), GetUnitY(AITarget[id]))
else
if GetUnitStatePercent(bj_lastCreatedUnit, UNIT_STATE_MANA, UNIT_STATE_MAX_MANA) <=50.0{
IssuePointOrder(hero, "move", -1150.0, -7420.0) //.идет к фонтану маны
else
HeroState[id] = STATE_SHOP
}
}
if HasFreeInvSpace(id) {//По возможности подбираем предметы
ItemCheck = null
SetRect(ItemCheckRect, x-AIItemSearchRadius, y-AIItemSearchRadius, x+AIItemSearchRadius, y+AIItemSearchRadius)
//ItemCheckRect = Rect(x-300.0, y-300.0, x+300.0, y+300.0)
//
EnumItemsInRect(ItemCheckRect, null, function AIItemCheck)
if ItemCheck != null and not IgnorItem(hero){
IssueTargetOrderById( hero, OrderId("smart"), ItemCheck )
}
}
}
void AIFollowHero(){
bj_lastCreatedUnit = GetEnumUnit()
local int id = GetPlayerId(GetOwningPlayer(bj_lastCreatedUnit))
if HeroState[id] != STATE_DEFEND{
if GetWidgetLife(bj_lastCreatedUnit) > 0.405{
if GetUnitStatePercent(bj_lastCreatedUnit, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE) <= 30.0{
UnitAddAbility(bj_lastCreatedUnit, 'A016')
elseif GetUnitStatePercent(bj_lastCreatedUnit, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE) >= 75.0
UnitRemoveAbility(bj_lastCreatedUnit, 'A016')
}
if GetUnitAbilityLevel(bj_lastCreatedUnit, 'A016') > 0{
if GetDistance(GetUnitX(bj_lastCreatedUnit), GetUnitY(bj_lastCreatedUnit), 64.0, -2864.0) < GetDistance(GetUnitX(bj_lastCreatedUnit), GetUnitY(bj_lastCreatedUnit), -1140.0, -6264.0){
AttackExPoint(bj_lastCreatedUnit, 64.0, -2864.0, 300.0)
else
AttackExPoint(bj_lastCreatedUnit, -1140.0, -6264.0, 300.0)
}
else
if HeroState[id] == STATE_RETREAT {
AttackExPoint(bj_lastCreatedUnit, 64.0, -4730.0, 1500.0)
}
if HeroState[id] == STATE_IDLE {
if GetDistance(GetUnitX(bj_lastCreatedUnit), GetUnitY(bj_lastCreatedUnit),GetUnitX(Heroes[id]), GetUnitY(Heroes[id])) < 2000.0{
local real x = GetRandomReal(GetUnitX(Heroes[id]) - AIFollowRadius, GetUnitX(Heroes[id]) + AIFollowRadius)
local real y = GetRandomReal(GetUnitY(Heroes[id]) - AIFollowRadius, GetUnitY(Heroes[id]) + AIFollowRadius)
IssuePointOrder(bj_lastCreatedUnit, "attack", x,y)
else
AttackExPoint(bj_lastCreatedUnit, GetUnitX(Heroes[id]), GetUnitY(Heroes[id]), 1500.0)
}
}
if HeroState[id] == STATE_HEAL or HeroState[id] == STATE_SHOP {
AttackExPoint(bj_lastCreatedUnit, -380.0, -6400.0, 1000.0)
}
}
}
else
//Защищать портал
UnitRemoveAbility(bj_lastCreatedUnit, 'A016')
AttackEx(bj_lastCreatedUnit, DefendTarget, 1500.0)
}
}
void AIcheckHero(unit hero){
local int id = GetPlayerId(GetOwningPlayer(hero))
if GetUnitStatePercent(hero, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE) <= 30.0{
HeroState[id] = STATE_HEAL
}
if HeroState[id] == STATE_IDLE { //Патрулирует территорию.
if GetUnitCurrentOrder(hero) != OrderId("voodoo") or GetUnitCurrentOrder(hero) != OrderId("cloudoffog") or GetUnitCurrentOrder(hero) != OrderId("monsoon") or GetUnitCurrentOrder(hero) != OrderId("tornado") or GetUnitCurrentOrder(hero) != OrderId("starfall") or GetUnitCurrentOrder(hero) != OrderId("flamestrike") or GetUnitCurrentOrder(hero) != OrderId("stampede") or GetUnitCurrentOrder(hero) != OrderId("tranquility"){
AIUnitMove(hero)
ForGroup(Gang[id], function AIFollowHero)
}
}
if HeroState[id] == STATE_HEAL { //Ранен. Отправляется залечивать раны
IssuePointOrder(hero, "move", GetRectCenterX(gg_rct_Heal_Player), GetRectCenterY(gg_rct_Heal_Player))
if GetUnitStatePercent(hero, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE) > 70.0{
HeroState[id] = STATE_SHOP
}
}
if HeroState[id] == STATE_SHOP {
if GetWidgetLife(Shop) > 0.405 {//Магазин не уничтожен
if HasItemToSell(hero) or HasFreeInvSpace(id) {//Отправляемся в магазин
IssuePointOrder(hero, "move", GetUnitX(Shop), GetUnitY(Shop))
if GetDistance(GetUnitX(hero),GetUnitY(hero), GetUnitX(Shop), GetUnitY(Shop)) < 256.0 { //Готовимся торговать (ожидаем, пока магазин выберет героя в качестве покупателя)
//HeroState[id] = STATE_IDLE
AIWait[id]+= Update
if AIWait[id] > 1.6 {//Прошло достаточно времени, чтобы герой мог торговать с магазином
//Продаем ненужные предметы
local int ind = convertIndex(GetUnitTypeId(hero))
for (int i = SellItemStart[ind]; i < SellItemEnd[ind]; i++){
if UnitHasItemOfTypeBJ(hero, SellItemIndex[i]) {
UnitDropItemTarget(hero, GetItemOfTypeFromUnitBJ(hero, SellItemIndex[i]), Shop)
}
}
//Закупаемся
if HasFreeInvSpace(id) {
if UnitHasItemOfTypeBJ(hero, 'stwp') != true{ //Сперва всегда докупаем спиток портала, если закончился
IssueNeutralImmediateOrderById(Player(id), Shop, 'stwp')
}
}
for (int i = ShopListStart; i < ShopListEnd; i++){//Затем затариваемся согласно списку
if HasFreeInvSpace(id) {
if not UnitHasItemOfTypeBJ(hero, ShopList[i]) {
IssueNeutralImmediateOrderById(Player(id), Shop, ShopList[i])
}
else
return
HeroState[id] = STATE_IDLE
AITarget[id] = null
AIWait[id]= 0.0
}
}
HeroState[id] = STATE_IDLE
AITarget[id] = null
AIWait[id]= 0.0
else //Иначе держим позицию и ждем...
IssueImmediateOrder(hero, "hold")
}
}
else
HeroState[id] = STATE_IDLE
AITarget[id] = null
AIWait[id]= 0.0
}
else
HeroState[id] = STATE_IDLE
AITarget[id] = null
}
}
if HeroState[id] == STATE_RETREAT {
AIWait[id]+= Update
if AIWait[id] > 5.0 {
AttackExPoint(hero, 64.0, -4730.0, 1500.0)
}
if GetDistance(GetUnitX(hero), GetUnitY(hero), 64.0, -4730.0) <= 1500.0 {
HeroState[id] = STATE_IDLE
AITarget[id] = null
AIWait[id] = 0.0
}
}
if HeroState[id] == STATE_DEFEND{
local group g = CreateGroup()
local int num = 0
GroupEnumUnitsInRect(g, gg_rct_Rect_164, null) //Проверяем область вокруг портала
loop {
bj_lastCreatedUnit = FirstOfGroup(g)
if IsPlayerEnemy(GetOwningPlayer(bj_lastCreatedUnit), GetOwningPlayer(Heroes[id])) and GetWidgetLife(bj_lastCreatedUnit) > 0.405{
num++
GroupRemoveUnit(g, bj_lastCreatedUnit)
else
GroupRemoveUnit(g, bj_lastCreatedUnit)
}
exitwhen bj_lastCreatedUnit == null
}
DestroyGroup(g)
g = null
if num > 0 {
//Продолжаем оборону
if GetDistance(GetUnitX(hero), GetUnitY(hero), GetUnitX(DefendTarget), GetUnitY(DefendTarget)) > 2000.0 and UnitHasItemOfTypeBJ(hero, 'stwp') {
UnitUseItemPoint(hero, GetItemOfTypeFromUnitBJ(hero, 'stwp'), -1090.0, -6590.0)
else
AttackEx(hero, DefendTarget, 1500.0)
}
else
HeroState[id] = STATE_SHOP
}
}
}
void AIFirstStep(){
for (int i = 0; i < 10; i++){
if IsPlayerInForce(Player(i), AIPlayers){
//Компьютерный игрок
AIcheckHero(Heroes[i])
AIWorkerStart(i)
}
}
}
//===========================================================================
function InitTrig_AIActivity takes nothing returns nothing
local timer t = CreateTimer()
TimerStart(t, Update, true, function AIFirstStep)
t= null
endfunction
endlibrary
AIBuild
library AIBuild
void AIBuild(){
BJDebugMsg(I2S(TemptId))
if AIConstructIndex[TemptId] <= ConstructIndexMax{ //Строим здание согласно плану строительства
//Определяем место для строительства
local real startX = -1536.0
local real startY = -8064.0
local real size = BuildingSize[AIConstructIndex[TemptId]]
for (int i = 0; i < 100; i++){
for (int v = 0; v < 27; v++){
SetRect(gg_rct_AIBuild1, startX+i*TILESIZE, startY-v*TILESIZE, startX+i*TILESIZE+size*TILESIZE, startY-v*TILESIZE-size*TILESIZE)
//debug
DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl", GetRectMinX(gg_rct_AIBuild1), GetRectMinY(gg_rct_AIBuild1)))
DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl", GetRectMinX(gg_rct_AIBuild1), GetRectMaxY(gg_rct_AIBuild1)))
DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl", GetRectMaxX(gg_rct_AIBuild1), GetRectMinY(gg_rct_AIBuild1)))
DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl", GetRectMaxX(gg_rct_AIBuild1), GetRectMaxY(gg_rct_AIBuild1)))
//
local boolean a
local boolean b
local centX = ((startX+i*TILESIZE)+(startX+i*TILESIZE+size*TILESIZE))/2
local centY = ((startY-v*TILESIZE)+(startY-v*TILESIZE-size*TILESIZE))/2
DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl", centX, centY))
if CheckRect(centX, centY) = true {
BJDebugMsg("Build")
IssueBuildOrderByIdLocBJ( HumanWorker[TemptId], ConstructPlan[AIConstructIndex[TemptId]], GetRectCenter(gg_rct_AIBuild1) )
return
else
BJDebugMsg("Not build")
}
}
}
else
//строим бесконечно ополченцев
IssueBuildOrderByIdLocBJ( HumanWorker[TemptId], 'h007', GetRandomLocInRect(gg_rct_Castle_Building) )
}
}
void AIWorkerStart(int id){
if (HumanWorker[id] == null or GetWidgetLife(HumanWorker[id]) < 0.405) and GetPlayerState(Player(id), PLAYER_STATE_RESOURCE_GOLD) >= 20 {
//нанять рабочего
HumanWorker[id] = CreateUnit(Player(id), 'h004', -512.0, -7372.0, 0.0)
IssuePointOrder(HumanWorker[id], "move", 960.0, -8320.0)
SetPlayerState(Player(id), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Player(id), PLAYER_STATE_RESOURCE_GOLD)-20)
else // Направить рабочего на работу
if HumanWorker[id] != null and GetUnitCurrentOrder(HumanWorker[id]) == 0{ //Рабочий простаивает
if GetUnitStatePercent(TownHall, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE) == 100.0 and GetUnitStatePercent(Shop, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE) == 100.0 {
bj_lastCreatedUnit = FirstOfGroup(UnfinishedStructures[id])
if bj_lastCreatedUnit != null{ //отправить достраивать незавершенное здание
IssueTargetOrder( HumanWorker[id], "repair", bj_lastCreatedUnit )
else
TemptId = id
ExecuteFunc("AIBuild")
}
else //Отправить чинить ратушу или магазин
if GetUnitStatePercent(TownHall, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE) != 100.0 {
IssueTargetOrder( HumanWorker[id], "repair", TownHall )
else
IssueTargetOrder( HumanWorker[id], "repair", Shop )
}
}
}
}
}
endlibrary
CustomFuncs
library CustomFuncs
real GetDistance(real Ax, real Ay, real Bx, real By){
local real dx = Bx - Ax
local real dy = By - Ay
return SquareRoot(dx * dx + dy * dy)
}
boolean CheckRect(real dx, real dy){
item it = CreateItem( 'spsh', 500.00, 500.00 )
real x
real y
SetItemPosition( it, dx, dy )
SetItemVisible( it, false )
x = GetItemX( it )
y = GetItemY( it )
if ( x + 1.00 < 0.00 or x - 1.00 > 0.00 ) or ( y + 1.00 < 0.00 or y - 1.00 > 0.00 ) and GetTerrainType(x,y) != 'Xhdg' then
BJDebugMsg( "Предмет: непроходимо" )
return false
else
BJDebugMsg( "Предмет: проходимо" )
return true
endif
}
void AttackEx(unit a, unit b, real dis){
real ax = GetUnitX(a)
real ay = GetUnitY(a)
real bx = GetUnitX(b)
real by = GetUnitY(b)
if GetDistance(ax,ay, bx,by) <= dis{
IssuePointOrder(a, "attack", bx, by)
else
IssuePointOrder(a, "move", bx, by)
}
}
void AttackExPoint(unit a, real x, real y, real dis){
real ax = GetUnitX(a)
real ay = GetUnitY(a)
if GetDistance(ax,ay, x,y) <= dis{
IssuePointOrder(a, "attack", x, y)
else
IssuePointOrder(a, "move", x, y)
}
}
int convertIndex(int id){
if id == 'E005' {
return 0
elseif id == 'E009'
return 1
elseif id == 'E000'
return 2
elseif id == 'H000'
return 3
elseif id == 'H01A'
return 4
elseif id == 'H009'
return 5
elseif id == 'H00B'
return 6
elseif id == 'O007'
return 7
elseif id == 'O00X'
return 8
elseif id == 'O008'
return 9
elseif id == 'O00J'
return 10
elseif id == 'N00P'
return 11
elseif id == 'H001'
return 12
elseif id == 'H019'
return 13
elseif id == 'N00O'
return 14
elseif id == 'H00D'
return 15
}
BJDebugMsg("Ошибка при попытке конвертации ID героя")
return -1
}
void AIItemCheck(){
ItemCheck = GetEnumItem()
}
boolean HasItemToSell(unit hero){
local int ind = convertIndex(GetUnitTypeId(hero))
for (int i = SellItemStart[ind]; i < SellItemEnd[ind]; i++){
if UnitHasItemOfTypeBJ(hero, SellItemIndex[i]) {
return true
}
}
return false
}
boolean IgnorItem(unit hero){
local int ind = convertIndex(GetUnitTypeId(hero))
for (int i = IgnorItemStart[ind]; i < IgnorItemEnd[ind]; i++){
if GetItemTypeId(ItemCheck) == IgnorItemIndex[i]{
return true
}
}
return false
}
boolean HasFreeInvSpace(int id){
for (int i = 0; i < 6; i++){
if UnitItemInSlot(Heroes[id], i) == null {
return true
}
}
return false
}
endlibrary
Принятый ответ
Типичная ошибка при не правильном использовании дефайнов. Скорее всего гдето забыт "=" После скобок.
Да, я и сам сталкивался с тем, что порой забывал ставить "==", но не в данной ситуации.
И да, я забыл вторую "=" в блоке if
И да, я забыл вторую "=" в блоке if
if CheckRect(centX, centY) = true {
...
Но и это не корень проблемы...
В общем, я долблюсь в глаза, а дебаг - всему голова.
Причина проблемы - забыл указать тип у локальных переменных
Причина проблемы - забыл указать тип у локальных переменных
local centX = ((startX+i*TILESIZE)+(startX+i*TILESIZE+size*TILESIZE))/2
local centY = ((startY-v*TILESIZE)+(startY-v*TILESIZE-size*TILESIZE))/2
похоже,из-за этого компилятор оч. странно реагировал на строку
if CheckRect(centX, centY) == true {
...
и выдавал ошибку "Too many nested ifs (Max is 50)"
Все как всегда, нужно дебажить свой код и тщательно все проверять
Вопрос закрыт, всем спасибо.
Вопрос закрыт, всем спасибо.
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Ред. ScorpioT1000
Ред. Алексей Андреич
И да, я забыл вторую "=" в блоке if
Причина проблемы - забыл указать тип у локальных переменных
Вопрос закрыт, всем спасибо.