| 08-27-2003, 12:15 AM | #1 |
Firstly, the War3X editor won't load on my computer. The Windows always says that my display driver is corrupted after loading War3X editor so I need another way to "embed" my A.I into the maps. And second, how to hire mercenaries and most importantly, merc heroes? |
| 08-27-2003, 07:40 AM | #2 |
You can try run the editor with OpenGL insted by running it from a shortcut with the "-opengl" commandline. |
| 08-27-2003, 08:56 AM | #3 |
Neutral Heroes cannot be easily bought with the AI. AMAI uses direct orders to buy them. AMAI version 1.6 which will be released soon will contain an even better buy function. Same problem with mercenaries and it is harder because you do not know which mercenaries are available unless you write an AI for a specific map. |
| 08-28-2003, 04:02 AM | #4 |
Get new video drivers if you haven't already. |
| 08-30-2003, 08:41 AM | #5 |
I tried all versions of nVidia video drivers, nothing works :nono: Yeah, even with the -opengl option on it still says my video driver is corrupted, and switches to 640x480x16 mode :nono: Next q : How many threads max we can start with StartThread? |
| 08-30-2003, 10:32 AM | #6 |
6 threads can be started inclusive all the threads started by common.ai . |
| 08-31-2003, 12:57 PM | #7 |
That means only one thread left :bgrun: I need a method for communication between A.I allies and A.I with human allies. Is there shared variables or string parsing? |
| 08-31-2003, 02:09 PM | #8 |
No shared variables and reading chat entries does not work from AI (because triggers do not work, they need callbacks). If you want to communicate with human allies you will have to do it like AMAI in the map script or Blizzard.j . Communication between AI allies works with AI commands and Alliance target. If you don't have enough threads you could use the timed job system used in AMAI 1.6 . It allows to time jobs executing them at the time specified. It uses a priority heap and is quite efficient. |
| 09-01-2003, 12:01 AM | #9 |
Ok, can you explain to me about AI commands for AI-to-AI communications? What functions/methods should I use? Does modifying blizzard.j safe for multiplayer use? |
| 09-01-2003, 02:04 AM | #10 |
Blizzard.j can be included in a map and it works fine (although it is not that small so if you only want it for a specific map rather put it in the map script). native CommandAI takes player num, integer command, integer data returns nothing With this native you can send a command consisting of a command number and an integer as data to an AI (you can interpret these numbers however you like). Origin does not matter so it can be used from both AI and trigger. The command is then put on a stack (there is one for each AI). native CommandsWaiting takes nothing returns integer native GetLastCommand takes nothing returns integer native GetLastData takes nothing returns integer native PopLastCommand takes nothing returns nothing With these natives you can then read the stack in the AI (mind that a stack means last in first out, which is relevant when you send multiple commands at the same time). CommandsWaiting returns the number of commands on the stack. GetLastCommand retrieves the command number of the command on the top of the stack. GetLastData returns the data number. PopLastCommand removes the topmost element of the stack. |
| 09-10-2003, 11:18 AM | #11 |
Ok thanks, that worked well :ggani: Now, how to send resources to a player using normal resource trading means (and this means the end game result shows how much resource is traded. If I just use a simple resource add/remove from players it won't show anything...) |
| 09-10-2003, 02:19 PM | #12 |
I don't think there is a way to do that. (I'd have used it in AMAI, if I knew of any way) Currently I think you have to use the resource add / remove. |
| 09-14-2003, 01:00 AM | #13 | |
Quote:
You know, you can actually do this : Code:
//--------------------------------------------------------------------
// Neutral Hireable Mercenaries
//--------------------------------------------------------------------
//--- Ashenvale
constant integer SATYR_SHADOWDANCER = 'nsts'
constant integer FURBOLG_SHAMAN = 'nfrs'
constant integer THUNDER_LIZARD = 'nthl'
//--- Barrens
constant integer CENTAUR_OUTRUNNER = 'ncen'
constant integer HARPY_ROGUE = 'nhrr'
constant integer RAZORMANE_MEDICINE_MAN = 'nrzm'
constant integer HARPY_WINDWITCH = 'nhrw'
//--- Black Citadel and Outland
constant integer FEL_BEAST = 'npfl'
constant integer DRAENEI_DISCIPLE = 'ndrm'
constant integer VOIDWALKER = 'nvdw'
constant integer DRAENEI_DARKSLAYER = 'ndrd'
//--- Cityscape, Dalaran, and Dalaran Ruins
constant integer ROGUE = 'nrog'
constant integer ASSASSIN = 'nass'
constant integer KOBOLD_GEOMANCER = 'nkog'
constant integer FOREST_TROLL_HIGH_PRIEST = 'nfsh'
//--- Dungeon and Underground
constant integer BURNING_ARCHER = 'nskf'
// constant integer KOBOLD_GEOMANCER = 'nkog'
constant integer WILDKIN = 'nowb' // owlbear
//--- Felwood
constant integer MURLOC_FLESHEATER = 'nmfs'
constant integer SLUDGE_FLINGER = 'nslf'
constant integer SATYR_SOULSTEALER = 'nstl'
//--- Icecrown Glacier
constant integer BARBED_ARACHNATHID = 'nanm'
constant integer BLUE_DRAGONSPAWN_MEDDLER = 'nbdm'
constant integer MAGNATAUR_WARRIOR = 'nmgw'
constant integer POLAR_FURBOLG_SHAMAN = 'nfps'
//--- Lordaeron Fall
constant integer GNOLL_BRUTE = 'ngnb'
constant integer GNOLL_WARDEN = 'ngnw'
constant integer OGRE_MAGI = 'nomg'
constant integer MUD_GOLEM = 'ngrk'
//--- Lordaeron Summer
constant integer FOREST_TROLL_BERSERKER = 'nftb'
constant integer FOREST_TROLL_SHADOW_PRIEST = 'nfsp'
constant integer OGRE_MAULER = 'nogm'
// constant integer MUD_GOLEM = 'ngrk'
//--- Lordaeron Winter
constant integer GNOLL_OVERSEER = 'ngnv'
constant integer ICE_TROLL_BERSERKER = 'nits'
constant integer ICE_TROLL_TRAPPER = 'nitt'
// constant integer MUD_GOLEM = 'ngrk'
//--- Northrend
constant integer NERUBIAN_WARRIOR = 'nnwa'
// constant integer ICE_TROLL_BERSERKER = 'nits'
constant integer FROST_REVENANT = 'nrvs'
constant integer NERUBIAN_WEBSPINNER = 'nnwl'
//--- Sunken Ruins
constant integer MURGUL_SNARECASTER = 'nmsn'
constant integer MAKRURA_SNAPPER = 'nlsn'
constant integer MAKRURA_DEEPSEER = 'nlds'
constant integer GIANT_SEA_TURTLE = 'ntrt'
//--- Village
constant integer KOBOLD = 'nkob'
constant integer MURLOC_HUNTSMAN = 'nmrr'
// constant integer ASSASSIN = 'nass'
// constant integer KOBOLD_GEOMANCER = 'nkog'
//--------------------------------------------------------------------
// Neutral Hireable Dragons
//--------------------------------------------------------------------
//--- Black
constant integer BLACK_DRAGON_1 = 'nbdr'
constant integer BLACK_DRAGON_2 = 'nbdk'
constant integer BLACK_DRAGON_3 = 'nbwm'
//--- Blue
constant integer BLUE_DRAGON_1 = 'nadw'
constant integer BLUE_DRAGON_2 = 'nadk'
constant integer BLUE_DRAGON_3 = 'nadr'
//--- Bronze
constant integer BRONZE_DRAGON_1 = 'nbzw'
constant integer BRONZE_DRAGON_2 = 'nbzk'
constant integer BRONZE_DRAGON_3 = 'nbzd'
//--- Green
constant integer GREEN_DRAGON_1 = 'ngrw'
constant integer GREEN_DRAGON_2 = 'ngdk'
constant integer GREEN_DRAGON_3 = 'ngrd'
//--- Nether
constant integer NETHER_DRAGON_1 = 'nnht'
constant integer NETHER_DRAGON_2 = 'nndk'
constant integer NETHER_DRAGON_3 = 'nndr'
//--- Red
constant integer RED_DRAGON_1 = 'nrdk'
constant integer RED_DRAGON_2 = 'nrdr'
constant integer RED_DRAGON_3 = 'nrwm'
//--------------------------------------------------------------------
constant integer M1 = 60
constant integer M2 = 2*60
constant integer M3 = 3*60
constant integer M4 = 4*60
constant integer M5 = 5*60
constant integer M6 = 6*60
constant integer M7 = 7*60
constant integer M8 = 8*60
constant integer M9 = 9*60
constant integer M10 = 10*60
constant integer M11 = 11*60
constant integer M12 = 12*60
constant integer M13 = 13*60
constant integer M14 = 14*60
constant integer M15 = 15*60
constant integer EASY = 1
constant integer NORMAL = 2
constant integer HARD = 3
constant integer INSANE = 4 // not used
constant integer MELEE_NEWBIE = 1
constant integer MELEE_NORMAL = 2
constant integer MELEE_INSANE = 3
constant integer ATTACK_CAPTAIN = 1
constant integer DEFENSE_CAPTAIN = 2
constant integer BOTH_CAPTAINS = 3
constant integer BUILD_UNIT = 1
constant integer BUILD_UPGRADE = 2
constant integer BUILD_EXPAND = 3
constant integer UPKEEP_TIER1 = 50
constant integer UPKEEP_TIER2 = 80Code:
//==========================================================================
// CheckDragon
//==========================================================================
function CheckDragon takes nothing returns nothing
local group g = CreateGroup()
local unit u = null
local string s = "dragonroost"
local string add = "black"
local integer i = 0
local boolean found = false
loop
exitwhen i >= 6 or found
set i = i + 1
if i == 1 then
set add = "black"
elseif i == 2 then
set add = "blue"
elseif i == 3 then
set add = "bronze"
elseif i == 4 then
set add = "green"
elseif i == 5 then
set add = "outland"
elseif i == 6 then
set add = "red"
endif
call GroupEnumUnitsOfType(g, add+s , null)
if FirstOfGroup(g) != null then
set dragon_available = true
set nearest_dragon_roost = GetNearestOfGroup(g, GetPlayerStartLocationLoc(Player(GetAiPlayer())))
set dragon_roost_guarded = GetLocationCreepStrength(GetUnitX(nearest_observatory), GetUnitY(nearest_observatory), 500) > 0
set found = true
if i == 1 then
set dragon_types[1] = BLACK_DRAGON_1
set dragon_types[2] = BLACK_DRAGON_2
set dragon_types[3] = BLACK_DRAGON_3
elseif i == 2 then
set dragon_types[1] = BLUE_DRAGON_1
set dragon_types[2] = BLUE_DRAGON_2
set dragon_types[3] = BLUE_DRAGON_3
elseif i == 3 then
set dragon_types[1] = BRONZE_DRAGON_1
set dragon_types[2] = BRONZE_DRAGON_2
set dragon_types[3] = BRONZE_DRAGON_3
elseif i == 4 then
set dragon_types[1] = GREEN_DRAGON_1
set dragon_types[2] = GREEN_DRAGON_2
set dragon_types[3] = GREEN_DRAGON_3
elseif i == 5 then
set dragon_types[1] = NETHER_DRAGON_1
set dragon_types[2] = NETHER_DRAGON_2
set dragon_types[3] = NETHER_DRAGON_3
elseif i == 6 then
set dragon_types[1] = RED_DRAGON_1
set dragon_types[2] = RED_DRAGON_2
set dragon_types[3] = RED_DRAGON_3
endif
endif
endloop
endfunction
//==========================================================================
// CheckMercenary
//==========================================================================
function CheckMercenary takes nothing returns nothing
local group g = CreateGroup()
local unit u = null
local string s = "mercenarycamp"
local string add = "a"
local integer i = 0
local boolean found = false
loop
exitwhen i >= 16 or found
set i = i + 1
if i == 1 then
set add = "a"
elseif i == 2 then
set add = "b"
elseif i == 3 then
set add = "k"
elseif i == 4 then
set add = "y"
elseif i == 5 then
set add = "x"
elseif i == 6 then
set add = "d"
elseif i == 7 then
set add = "c"
elseif i == 8 then
set add = "i"
elseif i == 9 then
set add = "f"
elseif i == 10 then
set add = "l"
elseif i == 11 then
set add = "w"
elseif i == 12 then
set add = "n"
elseif i == 13 then
set add = "o"
elseif i == 14 then
set add = "z"
elseif i == 15 then
set add = "g"
elseif i == 16 then
set add = "v"
endif
call GroupEnumUnitsOfType(g, s+add , null)
if FirstOfGroup(g) != null then
set mercenary_available = true
set nearest_merc_camp = GetNearestOfGroup(g, GetPlayerStartLocationLoc(Player(GetAiPlayer())))
set merc_camp_guarded = GetLocationCreepStrength(GetUnitX(nearest_observatory), GetUnitY(nearest_observatory), 500) > 0
set found = true
if i == 1 then
set merc_unit_types[1] = SATYR_SHADOWDANCER
set merc_unit_types[2] = FURBOLG_SHAMAN
set merc_unit_types[3] = THUNDER_LIZARD
set merc_types = 3
elseif i == 2 then
set merc_unit_types[1] = CENTAUR_OUTRUNNER
set merc_unit_types[2] = HARPY_ROGUE
set merc_unit_types[3] = RAZORMANE_MEDICINE_MAN
set merc_unit_types[4] = HARPY_WINDWITCH
set merc_types = 4
elseif i == 3 or i == 13 then
set merc_unit_types[1] = FEL_BEAST
set merc_unit_types[2] = DRAENEI_DISCIPLE
set merc_unit_types[3] = VOIDWALKER
set merc_unit_types[4] = DRAENEI_DARKSLAYER
set merc_types = 4
elseif i == 4 or i == 5 then
set merc_unit_types[1] = ROGUE
set merc_unit_types[2] = ASSASSIN
set merc_unit_types[3] = KOBOLD_GEOMANCER
set merc_unit_types[4] = FOREST_TROLL_HIGH_PRIEST
set merc_types = 4
elseif i == 6 or i == 15 then
set merc_unit_types[1] = BURNING_ARCHER
set merc_unit_types[2] = KOBOLD_GEOMANCER
set merc_unit_types[3] = WILDKIN
set merc_types = 3
elseif i == 7 then
set merc_unit_types[1] = MURLOC_FLESHEATER
set merc_unit_types[2] = SLUDGE_FLINGER
set merc_unit_types[3] = SATYR_SOULSTEALER
set merc_types = 3
elseif i == 8 then
set merc_unit_types[1] = BARBED_ARACHNATHID
set merc_unit_types[2] = BLUE_DRAGONSPAWN_MEDDLER
set merc_unit_types[3] = MAGNATAUR_WARRIOR
set merc_unit_types[4] = POLAR_FURBOLG_SHAMAN
set merc_types = 4
elseif i == 9 then
set merc_unit_types[1] = GNOLL_BRUTE
set merc_unit_types[2] = GNOLL_WARDEN
set merc_unit_types[3] = OGRE_MAGI
set merc_unit_types[4] = MUD_GOLEM
set merc_types = 4
elseif i == 10 then
set merc_unit_types[1] = FOREST_TROLL_BERSERKER
set merc_unit_types[2] = FOREST_TROLL_SHADOW_PRIEST
set merc_unit_types[3] = OGRE_MAULER
set merc_unit_types[4] = MUD_GOLEM
set merc_types = 4
elseif i == 11 then
set merc_unit_types[1] = GNOLL_OVERSEER
set merc_unit_types[2] = ICE_TROLL_BERSERKER
set merc_unit_types[3] = ICE_TROLL_TRAPPER
set merc_unit_types[4] = MUD_GOLEM
set merc_types = 4
elseif i == 12 then
set merc_unit_types[1] = NERUBIAN_WARRIOR
set merc_unit_types[2] = ICE_TROLL_BERSERKER
set merc_unit_types[3] = FROST_REVENANT
set merc_unit_types[4] = NERUBIAN_WEBSPINNER
set merc_types = 4
elseif i == 14 then
set merc_unit_types[1] = MURGUL_SNARECASTER
set merc_unit_types[2] = MAKRURA_SNAPPER
set merc_unit_types[3] = MAKRURA_DEEPSEER
set merc_unit_types[4] = GIANT_SEA_TURTLE
set merc_types = 4
elseif i == 16 then
set merc_unit_types[1] = KOBOLD
set merc_unit_types[2] = MURLOC_HUNTSMAN
set merc_unit_types[3] = ASSASSIN
set merc_unit_types[4] = KOBOLD_GEOMANCER
set merc_types = 4
endif
endif
endloop
set random_merc_type = GetRandomInt(1,merc_types)
endfunctionAnd it works fine!:ggani: |
| 09-14-2003, 10:39 AM | #14 |
:D Wow, nice code. I never knew that mercenary camps were actually different buildings. There is a small bug in the guarded check you do. You need to replace nearest_observatory there with the nearest_dragon_roost respective nearest_merc_camp . Now we just have to come up with some good way to determine when to buy them (best dividing them into different categories) and putting them in the unit information arrays with a new id and their available_time so they can be used with SetBuildUnit. Then they can be used in AMAI :gsmile: . Do you have an ICQ# ? |
| 09-14-2003, 01:12 PM | #15 |
0_o thx, I never knew that camp guarded bug lol :ggani: Anyway, for dragons, you better not buy them unless they're aren't guarded. Lv. 10 Dragons don't sleep ya know I uses 440 seconds game time as the minimal buy time, since if you take a look of their first available-to-hire times you'll notice that almost all of them has 440. For dragons, it depends only on their "size" (whelp, drake, mature dragons). Colour doesn't matter. Another problem I encountered is that sometimes different A.I players tries to get the same merc... --- If I'm not mistaken there is a formula of r creep buy respawn time... I heard of it somewhere... and I think it's based on the creeps' level. Edited because: Merc regeneration times are typically level/food cost of Merc * 50 sec. + 10 sec. from http://www.battle.net/war3/neutral/b...#mercenarycamp :D My ICQ# is 72579615... but I don't use ICQ often. If you can use MSN instead... my id is [email protected] . |
