Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
I have some questions about AI, since I'm good with the AI campaign scripts (Not made by the AI Editor), but some mysteries still haunt me...
Controlling units during battle against an enemy base
When units are being charmed or possessed by the attackers, the victims refuse to join the attacking team, because they've been set as defenders and they'll simply go to their new home base.
When units are being resurrected or reincarnated, they refuse to keep fighting, because they've been set as defenders and they'll simply retreat to their bases.
Is there a way to force the charmed, possessed, resurrected and reincarnated units/Heroes to keep going as attackers? I know a solution for the possessed and charmed units, but I want to know if there are better ones.
Transport Bug
I want the computer player to attack the enemies from one island to another. Yeah, I know it's done with Zeppelins, but I want with the Transport Ships.
I've noticed that Zeppelins are controlled thanks to the Fly move type, I've tried to set the Transport Ship as a "flying" unit and it worked. Now, how do I do this as an Amphibious move type? Just like the good old WC2's transport ships.
Shipyard Bug
I want the computer player to build a Shipyard, but the peon-type unit just wanders around, looking for a land to build where it's supposed to build at the shores. How do I force the peon-type unit to build a Shipyard at the shores?
I have some questions about AI, since I'm good with the AI campaign scripts (Not made by the AI Editor), but some mysteries still haunt me...
Controlling units during battle against an enemy base
When units are being charmed or possessed by the attackers, the victims refuse to join the attacking team, because they've been set as defenders and they'll simply go to their new home base.
When units are being resurrected or reincarnated, they refuse to keep fighting, because they've been set as defenders and they'll simply retreat to their bases.
Is there a way to force the charmed, possessed, resurrected and reincarnated units/Heroes to keep going as attackers? I know a solution for the possessed and charmed units, but I want to know if there are better ones.
If I recall correctly you can use timed units, like summons, parasites, stuff like that in attack groups calling the function GroupTimedLife(true)
However in order to include possessions, charms, or other permanent units, you'd have to modify the forming of attack groups. This isn't hard to do, I've done it too because I didn't like the way Blizzard implemented campaign attacks. All you have to do here is rewrite the CampaignAttacker and SuicideOnPlayer functions. There's a function called FormGroup where the attack group called with CampaignAttacker is actually formed. The attackers are built in a seperate thread. This thread is called in CampaignBasicsA, which is started by CampaignAI. You need to write a function in your new formgroup function where you check for possessed, charmed, etc. units and add them to the assault group. If you don't like rewriting all functions, or are satisfied with the way attacks are setup, then just copy and paste all the stuff from Common.ai and write a new function in your custom FormGroup function.
Another solution without creating custom functions is creating a seperate thread and check for those unit types, and suicide them on the enemy player. This has some disadvantages though. Units will not be included in the attack group itself, and they will attack on their own without support. However you could send them after the attack party is sent. You can do this with the CaptainInCombat function, where you check wether the attack captain is already in combat or not. You could do this whenever the attack or defense captain is in combat with the enemy player.
Transport Bug
I want the computer player to attack the enemies from one island to another. Yeah, I know it's done with Zeppelins, but I want with the Transport Ships.
I've noticed that Zeppelins are controlled thanks to the Fly move type, I've tried to set the Transport Ship as a "flying" unit and it worked. Now, how do I do this as an Amphibious move type? Just like the good old WC2's transport ships.
I've tried this too and haven't come up with a solution for this. The AI is programmed to only use air transports. There're no functions available that deal with sea transports. You could simulate this with trigger code, but that would screw up the AI script, and this would make the AI entirely trigger driven. Controlling an AI only through triggers would be a pain to do. If only the AI script was able to communicate with the map script then this could be simulated without messing up the AI script execution flow.
Shipyard Bug
I want the computer player to build a Shipyard, but the peon-type unit just wanders around, looking for a land to build where it's supposed to build at the shores. How do I force the peon-type unit to build a Shipyard at the shores?
Use the ShiftTownSpot(x, y) function. Set a point in shallow water where you'd like the shipyard to be built. What this function does is shift the town location build spot to the point you specify on the map. Be sure to shift the spot back inside your town after a peasant has started the shipyard, otherwise you end up with an AI building everything near the water.
If I recall correctly you can use timed units, like summons, parasites, stuff like that in attack groups calling the function GroupTimedLife(true)
However in order to include possessions, charms, or other permanent units, you'd have to modify the forming of attack groups. This isn't hard to do, I've done it too because I didn't like the way Blizzard implemented campaign attacks. All you have to do here is rewrite the CampaignAttacker and SuicideOnPlayer functions. There's a function called FormGroup where the attack group called with CampaignAttacker is actually formed. The attackers are built in a seperate thread. This thread is called in CampaignBasicsA, which is started by CampaignAI. You need to write a function in your new formgroup function where you check for possessed, charmed, etc. units and add them to the assault group. If you don't like rewriting all functions, or are satisfied with the way attacks are setup, then just copy and paste all the stuff from Common.ai and write a new function in your custom FormGroup function.
Another solution without creating custom functions is creating a seperate thread and check for those unit types, and suicide them on the enemy player. This has some disadvantages though. Units will not be included in the attack group itself, and they will attack on their own without support. However you could send them after the attack party is sent. You can do this with the CaptainInCombat function, where you check wether the attack captain is already in combat or not. You could do this whenever the attack or defense captain is in combat with the enemy player.
No problem, I already have modified my own Common.ai file to fix some things. I might as well try rewriting those codes you've said.
As for my AI scripts, the possessed units are easy to control thanks to a separate function that, each second of the function loop, uses the AddAssaultUnit and include that unitID type which is not Undead. The problem is, when units are being resurrected or reincarnated, the AI can't gain control of them, since the AI picks on random units of the same UnitIDs, which is so unlike the triggers in WE Trigger Editor that allow us to pick on specific units. But still, I'll give it a try, and see what happens.
As for the GroupTimedLife, I never use it, because rarely, or sometimes, the AI ends up screwing around with their attack waves, and their attack timings rarely get messed up.
I've tried this too and haven't come up with a solution for this. The AI is programmed to only use air transports. There're no functions available that deal with sea transports. You could simulate this with trigger code, but that would screw up the AI script, and this would make the AI entirely trigger driven. Controlling an AI only through triggers would be a pain to do. If only the AI script was able to communicate with the map script then this could be simulated without messing up the AI script execution flow.
Just as I thought, only for air transports. Well, I'll stick with the zeppelins and the sky barges then. And yes, I could try simulating a sea attack with two players of the same team, one with AI, and the other without AI.
Use the ShiftTownSpot(x, y) function. Set a point in shallow water where you'd like the shipyard to be built. What this function does is shift the town location build spot to the point you specify on the map. Be sure to shift the spot back inside your town after a peasant has started the shipyard, otherwise you end up with an AI building everything near the water.
As for my AI scripts, the possessed units are easy to control thanks to a separate function that, each second of the function loop, uses the AddAssaultUnit and include that unitID type which is not Undead. The problem is, when units are being resurrected or reincarnated, the AI can't gain control of them, since the AI picks on random units of the same UnitIDs, which is so unlike the triggers in WE Trigger Editor that allow us to pick on specific units. But still, I'll give it a try, and see what happens.
Well I looked into this matter a little bit further and have come up with a
solution for timed, possessed, charmed and resurrected units The real problem like you found out lies within resurrected units. You have no event from which you can detect resurrected units. You can however for Heroes but that isn't useful for detecting unit resurrection from an ability like Resurrection. The following is the code I used to do it. It's a combination of triggers and AI script code. It shows why the combined power of trigger code and AI script code makes the AI so much more flexible.
JASS:
function Trig_CheckPossession_Conditions takes nothing returns boolean
local integer ability_id = GetSpellAbilityId()
return ability_id == 'ANch' or ability_id == 'ACch' or ability_id == 'Apos' or ability_id == 'ACps'
endfunction
function Trig_CheckPossession_Actions takes nothing returns nothing
local unit caster_unit = GetSpellAbilityUnit()
local unit target_unit = GetSpellTargetUnit()
call DisplayTextToPlayer(udg_user, 0, 0, "Caster is: " + GetUnitName(caster_unit))
if target_unit != null then
call DisplayTextToPlayer(udg_user, 0, 0, "Target is: " + GetUnitName(target_unit))
set udg_last_caster_unit = caster_unit
set udg_last_target_unit = target_unit
else
call DisplayTextToPlayer(udg_user, 0, 0, "Invalid target!")
endif
set caster_unit = null
set target_unit = null
endfunction
//===========================================================================
function InitTrig_CheckPossession takes nothing returns nothing
set gg_trg_CheckPossession = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_CheckPossession, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( gg_trg_CheckPossession, Condition( function Trig_CheckPossession_Conditions ) )
call TriggerAddAction( gg_trg_CheckPossession, function Trig_CheckPossession_Actions )
endfunction
CheckPossession: This trigger I used to catch possession and charm casters, and the target. It still needs an unit changed owner event because there is no way to be sure the unit is actually possessed or charmed. The caster could die or select a unit which is already being charmed, possessed by another caster.
JASS:
function Trig_CheckOwnerState_Actions takes nothing returns nothing
local unit changing_unit = GetChangingUnit()
local integer unit_id = GetUnitTypeId(changing_unit)
local player prev_owner = GetChangingUnitPrevOwner()
local player new_owner = GetOwningPlayer(changing_unit)
if udg_last_target_unit != null then
if changing_unit == udg_last_target_unit then
//call RemoveGuardPosition(changing_unit)
//call RecycleGuardPosition(changing_unit)
//call DisplayTextToPlayer(udg_user, 0, 0, "Removed AI guard position from unit.")
call DisplayTextToPlayer(udg_user, 0, 0, "Possession succesfull.")
call DisplayTextToPlayer(udg_user, 0, 0, "Previous unit owner was " + GetPlayerName(prev_owner))
if prev_owner != udg_user then
call CommandAI(prev_owner, 9, unit_id)
endif
if new_owner != udg_user then
call CommandAI(new_owner, 8, unit_id)
endif
set udg_last_caster_unit = null
set udg_last_target_unit = null
endif
endif
set changing_unit = null
set prev_owner = null
set new_owner = null
endfunction
//===========================================================================
function InitTrig_CheckOwnerState takes nothing returns nothing
set gg_trg_CheckOwnerState = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_CheckOwnerState, EVENT_PLAYER_UNIT_CHANGE_OWNER )
call TriggerAddAction( gg_trg_CheckOwnerState, function Trig_CheckOwnerState_Actions )
endfunction
CheckOwnerState: This trigger is used to actually check if the target unit was possessed successfully. This isn't a foolproof system, however. I don't know what happens if two target units get possessed by two different casters at the exact same time. But this happening is very unlikely. Even when this happens it won't mess up things. The worst scenario being that a possessed unit isn't tracked. However during tests I didn't encounter any problems. I've actually seen possessions occurring at the same time, however we can't distinguish events in micro seconds or less, so for a human it seems like it's occurring at the same moment.
It sends an AI command with the unit id of the unit that's possessed. The AI script stores that unit in a possessions array. I'll explain that later.
JASS:
function Trig_PossessionDies_Actions takes nothing returns nothing
local unit u = GetDyingUnit()
local player owner = GetOwningPlayer(u)
if u == udg_last_caster_unit then
call DisplayTextToPlayer(udg_user, 0, 0, "Caster unit died before finishing possession!")
set udg_last_caster_unit = null
set udg_last_target_unit = null
endif
if owner != udg_user then
call CommandAI(owner, 9, GetUnitTypeId(u))
set udg_dead_units[udg_index] = u
set udg_index = udg_index + 1
if udg_index > 256 then
set udg_index = 0
endif
endif
set u = null
set owner = null
endfunction
//===========================================================================
function InitTrig_PossessionDies takes nothing returns nothing
set gg_trg_PossessionDies = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_PossessionDies, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( gg_trg_PossessionDies, function Trig_PossessionDies_Actions )
endfunction
PossessionDies: Here it checks if the caster unit died before completing the ability. If the caster dies the AI shouldn't be informed of a new unit. When a unit dies a command is sent to the AI player owner of the dying unit. This is needed so the AI script can check if the unit type is present in the possessions array. This won't track the exact unit object. This isn't necessary because there aren't any natives in common.ai that can send a specific unit to attack a player. You could send a unit object through though abusing the return bug and sending an integer pointer to the AI script. However this isn't very usefull in this case. The main purpose is to be sure the AI maintains the same amount of a unit type it has for defending the base. This can occur in Undead vs Undead scenarios.
This also keeps track of AI units dying. This system I used to track resurrected units. I keep an array of 256 unit handles to unit objects of units that died. The next trigger shows why.
JASS:
function Trig_CheckResurrections_Actions takes nothing returns nothing
local integer index = 0
local unit u
loop
exitwhen index == udg_index
set u = udg_dead_units[index]
if u != null and GetUnitState(u, UNIT_STATE_LIFE) > 0 then
if IsUnitType(u, UNIT_TYPE_HERO) then
call DisplayTextToPlayer(udg_user, 0, 0, "Hero is resurrected!")
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MAX_MANA))
else
call DisplayTextToPlayer(udg_user, 0, 0, "Unit is resurrected!")
call CommandAI(GetOwningPlayer(u), 10, GetUnitTypeId(u))
endif
set udg_dead_units[index] = null
endif
set index = index + 1
endloop
set u = null
endfunction
//===========================================================================
function InitTrig_CheckResurrections takes nothing returns nothing
set gg_trg_CheckResurrections = CreateTrigger( )
call TriggerRegisterTimerEvent(gg_trg_CheckResurrections, 0.50, true)
call TriggerAddAction( gg_trg_CheckResurrections, function Trig_CheckResurrections_Actions )
endfunction
CheckResurrections: This trigger checks if the units that died are resurrected. The hero part I used for debugging purposes. I used it to fill mana so the hero can use his resurrect ability. If a unit is resurrected it normally tries to go back to his main base and stay there as a defender. With this periodic timer you can now check for resurrected units and command the AI to do something with those units.
Code:
function SuicideUnitOnBattlefield takes integer unit_id returns nothing
if CaptainInCombat(true) and not CaptainIsHome() then
call DisplayTextToPlayer(dbg, 0, 0, "Sending unit to the battlefield.")
call SuicideUnitEx(1, unit_id, pid)
else
call DisplayTextToPlayer(dbg, 0, 0, "Captain isn't in combat on the battlefield.")
endif
endfunction
SuicideUnitOnBattlefield is a function from my AI script. Whenever the AI received a command that a unit was possessed, charmed or resurrected it calls this function. This is where you get the difference between suicide loops and triggered suicides. When you use suicide loops the AI tries to suicide more than one unit of the unit type. What's nice about this, is that it will check the nearest unused unit near the combat zone to send out on an attack. It won't pull units from his base, in case of Undead vs Undead where possessions etc. can be of the same unit type of the race the AI plays. That's why I've included a check for attack captain in combat and if the captain is currently in his main base. If he's in his main base and in combat then don't suicide. In that case you include the possessed etc. in the next attack wave, and that's the reason why you keep track of the possessed etc. units in the possessions array.
Code:
function SetPossessedUnit takes boolean add_unit, integer unit_id returns nothing
local integer index = 0
loop
exitwhen possessions[index] == -1 or possessions[index] == unit_id
set index = index + 2
endloop
if add_unit then
if possessions[index] == -1 then
set possessions[index] = unit_id
set possessions[index + 1] = 1
set possessions[index + 2] = -1
call DisplayTextToPlayer(dbg, 0, 0, "Added new possessed unit type.")
else
set possessions[index + 1] = possessions[index + 1] + 1
call DisplayTextToPlayer(dbg, 0, 0, "Updated existing possessed unit type count.")
endif
call SuicideUnitOnBattlefield(unit_id)
elseif possessions[index] == unit_id then
if possessions[index + 1] > 0 then
set possessions[index + 1] = possessions[index + 1] - 1
call DisplayTextToPlayer(dbg, 0, 0, "Removed one possessed unit.")
endif
endif
endfunction
SetPossessedUnit is another function the AI script uses. It stores the possessed and charmed units. It won't store resurrected units, because they're from the AI anyways. I don't find that necessary.
Code:
function FormAssaultGroup takes real seconds, boolean check_hp, integer hp_perc returns boolean
local integer index
local integer count
local integer unit_id
local boolean captain_ready
if wave_prep_time < seconds or seconds <= 0 then
call DisplayTextToPlayer(dbg, 0, 0, "Group forming wait time is too high!")
set seconds = wave_prep_time
endif
if not check_hp then
set hp_perc = 0
endif
loop
set index = 0
set wave_prep_time = wave_prep_time - seconds
call Wait(seconds)
call InitAssault()
loop
exitwhen index == attack_count
set unit_id = attack_units[index]
set count = attack_units[index + 1]
call AddAssault(count, unit_id)
set index = index + 2
endloop
set index = 0
loop
exitwhen not do_possessions
exitwhen possessions[index] == -1
set unit_id = possessions[index]
set count = TownCountDone(unit_id)
if count > 0 and possessions[index + 1] > 0 then
if count > possessions[index + 1] then
set count = possessions[index + 1]
endif
call AddAssault(count, unit_id)
endif
set index = index + 2
endloop
call DisplayTextToPlayer(dbg, 0, 0, "Captain ready check...")
set captain_ready = CaptainIsFull() and CaptainReadiness() >= hp_perc
exitwhen captain_ready or wave_prep_time <= 0
call DisplayTextToPlayer(dbg, 0, 0, "Captain in combat check, or form group timeout...")
exitwhen abort
endloop
return captain_ready
endfunction
FormAssaultGroup is the custom function I use to create attack groups. It also includes the possessions that are stored in the possessions array that're not sent into combat yet. This happens for example when possessions occur when the attack captain isn't in combat on the battlefield. Most of the time this is caused by the defense captain combating attackers.
As for the GroupTimedLife, I never use it, because rarely, or sometimes, the AI ends up screwing around with their attack waves, and their attack timings rarely get messed up.
Well it's actually quite useful to set GroupTimedLife during the setup of your AI script. It ensures that the AI always includes timed units, like summons and parasites and such in attack waves. If you don't set this the AI doesn't make proper use of those units. For example if you have an attack wave with Meat wagons and Necromancers. The Necromancers raise skeletons from the corpses in the Meat wagons. This happens when the attack party is in combat. However when those skeletons are raised too far from the combat area they do nothing. If you set GroupTimedLife they will be included in the attack party and will automatically move into the combat zone. The same goes for summons from other races.
I just had to come up with something for this lol..
I don't know why, I just can't stand it when faced with a problem and a solution isn't available yet.
Well it's actually quite useful to set GroupTimedLife during the setup of your AI script. It ensures that the AI always includes timed units, like summons and parasites and such in attack waves. If you don't set this the AI doesn't make proper use of those units. For example if you have an attack wave with Meat wagons and Necromancers. The Necromancers raise skeletons from the corpses in the Meat wagons. This happens when the attack party is in combat. However when those skeletons are raised too far from the combat area they do nothing. If you set GroupTimedLife they will be included in the attack party and will automatically move into the combat zone. The same goes for summons from other races.
Yeah, I know the GroupTimedLife sounds useful, because I used it once before. Used until I spotted a terrible part, when they summon a unit in their main base and gets attacked, the already launched army (for having traveled so far) noticed that issue, and they've interrupted their traveling progress just to intercept to where the summoned unit was taking damage. That's why I have to disable the GroupTimedLife, sorry.
I just had to come up with something for this lol..
I don't know why, I just can't stand it when faced with a problem and a solution isn't available yet.
I bet that most of us have already tried that so many times. But unfortunately, that "secret" code is not visible in any of the JASS scripts we know. Where could it be hidden? Perhaps in some encrypted data in the deep core of the game?
What would the creator of the AMAI scripts do about the transport ships? Since he's too good with the AI scripts. Perhaps someone who's registered to WC3Campaigns.net should ask him...
I think the Blizzard Team should have programed that before releasing the TFT version. Should we beg the Blizzard Team to release a 1.22 patch which includes the fix? And also fixing the Firelord's Volcano ability (Because I don't see him casting that spell by the CPU players!), and the Alchemist's Chemical Rage ability (The CPU players should use that each time he attacks, not rarely!).
Yeah, I know the GroupTimedLife sounds useful, because I used it once before. Used until I spotted a terrible part, when they summon a unit in their main base and gets attacked, the already launched army (for having traveled so far) noticed that issue, and they've interrupted their traveling progress just to intercept to where the summoned unit was taking damage. That's why I have to disable the GroupTimedLife, sorry.
I bet that most of us have already tried that so many times. But unfortunately, that "secret" code is not visible in any of the JASS scripts we know. Where could it be hidden? Perhaps in some encrypted data in the deep core of the game?
What would the creator of the AMAI scripts do about the transport ships? Since he's too good with the AI scripts. Perhaps someone who's registered to WC3Campaigns.net should ask him...
I think the Blizzard Team should have programed that before releasing the TFT version. Should we beg the Blizzard Team to release a 1.22 patch which includes the fix? And also fixing the Firelord's Volcano ability (Because I don't see him casting that spell by the CPU players!), and the Alchemist's Chemical Rage ability (The CPU players should use that each time he attacks, not rarely!).
I bet that most of us have already tried that so many times. But unfortunately, that "secret" code is not visible in any of the JASS scripts we know. Where could it be hidden? Perhaps in some encrypted data in the deep core of the game?
What would the creator of the AMAI scripts do about the transport ships? Since he's too good with the AI scripts. Perhaps someone who's registered to WC3Campaigns.net should ask him...
I think the Blizzard Team should have programed that before releasing the TFT version. Should we beg the Blizzard Team to release a 1.22 patch which includes the fix? And also fixing the Firelord's Volcano ability (Because I don't see him casting that spell by the CPU players!), and the Alchemist's Chemical Rage ability (The CPU players should use that each time he attacks, not rarely!).
Transport issues are soooo complicated that even Strategy Master hasn't been able to "fix" them. If you analyze how the transport works in the standard AI, you will notice that improving this (or just trying to implement on transport ships) is really complicated, because it's completely hardcoded. Just to give an idea: the AI has a lame system that detects if a unit is stuck, if it's true, then the AI "paralyze" that unit, and order the Zeppelin to pick it up, then the AI has to find a better place to unload it so that unit can move properly... pretty difficult I must say.
Besides, in AMAI the flying transport is not used to move units from one place to other, in fact, Strategy Master developed one common strategy for all the races that use the Zeppelins to protect units with low health.
About a patch that fixes the AI behavior... I doubt seriously it will become into reality, it seems that it's the less important thing for Blizzard. Anyways, AMAI fills that gap in the best way possible IMO.
I've worked too much with this, and I think the best solution is to develop a full scripted AI system, now that vJASS has been implemented. We could create a system which offers a set of textmacros which we can use to manipulate an AI and, eventually, create "easy scripts". This, of course, implies a hard work implementing those macros and some functions that replace the functions GetUnitGoldCost, GetUnitLumberCost, etc...
If I'd have time, I will work with this, seriously.
Transport issues are soooo complicated that even Strategy Master hasn't been able to "fix" them. If you analyze how the transport works in the standard AI, you will notice that improving this (or just trying to implement on transport ships) is really complicated, because it's completely hardcoded. Just to give an idea: the AI has a lame system that detects if a unit is stuck, if it's true, then the AI "paralyze" that unit, and order the Zeppelin to pick it up, then the AI has to find a better place to unload it so that unit can move properly... pretty difficult I must say.
Besides, in AMAI the flying transport is not used to move units from one place to other, in fact, Strategy Master developed one common strategy for all the races that use the Zeppelins to protect units with low health.
I used to play many melee maps (with the AMAI scripts) for long time ago. And I still play sometimes because it's fun. When I tried to learn how he created those scripts, I quited learning, too confusing for my brains. And again, he's really good with the AI Scripts.
But when I mentioned him, I was just wondering if he knew about a solution for the naval transports. That's all.
And you're right, the transport issues are indeed soooo complicated...
About a patch that fixes the AI behavior... I doubt seriously it will become into reality, it seems that it's the less important thing for Blizzard. Anyways, AMAI fills that gap in the best way possible IMO.
I know the Blizzard Team are too busy with the WoW to mind about updating WC3. But those spells AI are just minor problems, I use the fake Death and Decay spell to simulate the Volcano spell, while I use triggers to trigger the Alchemist's Chemical Rage. But still, I'm up for that alternative solution.
I've worked too much with this, and I think the best solution is to develop a full scripted AI system, now that vJASS has been implemented. We could create a system which offers a set of textmacros which we can use to manipulate an AI and, eventually, create "easy scripts". This, of course, implies a hard work implementing those macros and some functions that replace the functions GetUnitGoldCost, GetUnitLumberCost, etc...
If I'd have time, I will work with this, seriously.
Uoh ! You don't have to work so hard because of this problem! Sorry, but I'd rather stick with the JASS only, it's the only programing language that I understand, sorry again.
Thanks for the replies, guys. Now, I think I have nothing else to ask about the AI, for now. So I'll be off for some time...
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.