• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Mysterious Crash

Status
Not open for further replies.
==============================================================================
Warcraft III (build 6387)

Exe: l:\program files\warcraft iii\war3.exe
Time: Aug 30, 2010 3:20:02.788 PM
User: ----
Computer: UBEL
------------------------------------------------------------------------------

This application has encountered a critical error:

FATAL ERROR!

Program: l:\program files\warcraft iii\war3.exe
Exception: 0xC0000005 (ACCESS_VIOLATION) at 001B:01699BD1

The instruction at '0x01699BD1' referenced memory at '0x0000000C'.
The memory could not be 'read'.


War3Build: 1.24.4.6387
Played Maps\Test\BtT SF - Paradise.w3x
Player 0 Ubel Race Orc StartLoc 0
Player 1 Pure Brotherhood Race Human StartLoc 3
Player 2 <Unused> Race Orc StartLoc -1
Player 3 <Unused> Race Human StartLoc -1
Player 4 Black Tooth Guard Race Orc StartLoc 2
Player 5 <Unused> Race Human StartLoc -1
Player 6 Icecrown Survivors Race Human StartLoc 1
Player 7 <Unused> Race Orc StartLoc -1
Player 8 <Unused> Race Undead StartLoc -1
Player 9 <Unused> Race Human StartLoc -1
Player 10 <Unused> Race Undead StartLoc -1
Player 11 <Unused> Race Undead StartLoc -1
------------------------------------------------------------------------------

----------------------------------------
x86 Registers
----------------------------------------

EAX=0013EAD8 EBX=FFFFFFFF ECX=00000000 EDX=0013EAD8 ESI=1B5A8D0C
EDI=0013EB4C EBP=0013EBA0 ESP=0013EAC8 EIP=01699BD1 FLG=00010246
CS =001B DS =0023 ES =0023 SS =0023 FS =003B GS =0000


----------------------------------------
Stack Trace (Manual)
----------------------------------------

Address Frame Logical addr Module

01699BD1 0013EBA0 0001:00478BD1 l:\program files\warcraft iii\Game.dll

----------------------------------------
Stack Trace (Using DBGHELP.DLL)
----------------------------------------

01699BD1 Game.dll <unknown symbol>+0 (0x0BE0CF60,0xBD343631,0x00000000,0x0C041D58)
0167FABE Game.dll <unknown symbol>+0 (0x00000000,0x00000000,0x00000000,0x00000000)


----------------------------------------
Loaded Modules
----------------------------------------

0x00400000 - 0x0047D000 war3.exe
0x01220000 - 0x01DF4000 Game.dll
0x02610000 - 0x028D5000 xpsp2res.dll
0x0FFD0000 - 0x0FFF8000 rsaenh.dll
0x10000000 - 0x10024000 mumble_ol.dll
0x15000000 - 0x15061000 Storm.dll
0x21100000 - 0x2115F000 mss32.dll
0x22600000 - 0x22616000 Mssfast.m3d
0x22700000 - 0x22717000 Mssdolby.m3d
0x22C00000 - 0x22C18000 Msseax2.m3d
0x24600000 - 0x24611000 Reverb3.flt
0x26F00000 - 0x26F2A000 Mp3dec.asi
0x4D4F0000 - 0x4D548000 WINHTTP.dll
0x59A60000 - 0x59B01000 dbghelp.dll
0x5AD70000 - 0x5ADA8000 UxTheme.dll
0x5B860000 - 0x5B8B5000 netapi32.dll
0x5CB70000 - 0x5CB96000 ShimEng.dll
0x5D090000 - 0x5D12A000 COMCTL32.dll
0x5ED00000 - 0x5EDCC000 OPENGL32.dll
0x60000000 - 0x6005D000 ijl15.dll
0x68B20000 - 0x68B40000 GLU32.dll
0x6D990000 - 0x6D996000 d3d8thk.dll
0x6D9A0000 - 0x6DAC8000 d3d8.dll
0x6F880000 - 0x6FA4A000 AcGenral.DLL
0x71A50000 - 0x71A8F000 mswsock.dll
0x71AA0000 - 0x71AA8000 WS2HELP.dll
0x71AB0000 - 0x71AC7000 WS2_32.dll
0x71AD0000 - 0x71AD9000 WSOCK32.dll
0x71BF0000 - 0x71C03000 SAMLIB.dll
0x722B0000 - 0x722B5000 SensApi.dll
0x72D10000 - 0x72D18000 msacm32.drv
0x72D20000 - 0x72D29000 wdmaud.drv
0x73760000 - 0x737AB000 DDRAW.dll
0x73BC0000 - 0x73BC6000 DCIMAN32.dll
0x73EE0000 - 0x73EE4000 KsUser.dll
0x73F10000 - 0x73F6C000 DSOUND.DLL
0x74720000 - 0x7476C000 MSCTF.dll
0x75E60000 - 0x75E73000 cryptnet.dll
0x76390000 - 0x763AD000 IMM32.dll
0x763B0000 - 0x763F9000 comdlg32.dll
0x769C0000 - 0x76A73000 USERENV.dll
0x76B40000 - 0x76B6D000 WINMM.dll
0x76BF0000 - 0x76BFB000 PSAPI.DLL
0x76C30000 - 0x76C5E000 WINTRUST.dll
0x76C90000 - 0x76CB8000 IMAGEHLP.dll
0x76F60000 - 0x76F8C000 WLDAP32.dll
0x76FD0000 - 0x7704F000 CLBCATQ.DLL
0x77050000 - 0x77115000 COMRes.dll
0x77120000 - 0x771AB000 OLEAUT32.dll
0x771B0000 - 0x77256000 WININET.dll
0x773D0000 - 0x774D3000 comctl32.dll
0x774E0000 - 0x7761D000 ole32.dll
0x77690000 - 0x776B1000 NTMARTA.DLL
0x77A80000 - 0x77B14000 CRYPT32.dll
0x77B20000 - 0x77B32000 MSASN1.dll
0x77BD0000 - 0x77BD7000 midimap.dll
0x77BE0000 - 0x77BF5000 MSACM32.dll
0x77C00000 - 0x77C08000 VERSION.dll
0x77C10000 - 0x77C68000 msvcrt.dll
0x77DD0000 - 0x77E6B000 ADVAPI32.dll
0x77E70000 - 0x77F02000 RPCRT4.dll
0x77F10000 - 0x77F57000 GDI32.dll
0x77F60000 - 0x77FD6000 SHLWAPI.dll
0x77FE0000 - 0x77FF1000 Secur32.dll
0x78130000 - 0x781CB000 MSVCR80.dll
0x7C800000 - 0x7C8F6000 kernel32.dll
0x7C900000 - 0x7C9AF000 ntdll.dll
0x7C9C0000 - 0x7D1D6000 SHELL32.dll
0x7E410000 - 0x7E4A0000 USER32.dll


----------------------------------------
Memory Dump
----------------------------------------

Code: 16 bytes starting at (EIP = 01699BD1)

01699BD1: 8B 51 0C 8B 49 08 56 57 E8 92 6B BC FF 8B 7C 24 .Q..I.VW..k...|$


Stack: 1024 bytes starting at (ESP = 0013EAC8)

* = addr ** *
0013EAC0: 00 00 00 00 00 F0 FD 7F 00 00 00 00 CF 3E 26 01 .............>&.
0013EAD0: D8 EA 13 00 0C 8D 5A 1B 00 00 61 44 E0 7C 5E 01 ......Z...aD.|^.
0013EAE0: D4 A4 B7 01 C8 DC 67 01 CF 09 10 00 37 34 30 41 ......g.....740A
0013EAF0: 60 CF E0 0B 37 34 30 41 AC DC 67 01 60 CF E0 0B `...740A..g.`...
0013EB00: 58 1D 04 0C 08 00 00 00 74 40 C1 0E 67 40 C1 0E [email protected]@..
0013EB10: 14 20 B5 09 88 00 A7 04 64 63 73 77 E6 C2 67 01 . ......dcsw..g.
0013EB20: 58 1D 04 0C 54 EB 13 00 A3 AB 67 01 B1 36 34 BD X...T.....g..64.
0013EB30: 00 00 00 00 54 EB 13 00 7C EB 13 00 C8 0E A6 01 ....T...|.......
0013EB40: 00 00 00 00 CF 09 10 00 37 34 30 41 18 39 67 01 ........740A.9g.
0013EB50: 00 00 00 00 68 59 CB 01 FE FF FF FF 02 00 00 00 ....hY..........
0013EB60: E0 1C 00 0B 28 32 DD 0B 8E E3 D6 FD 07 4D 67 01 ....(2.......Mg.
0013EB70: 38 B2 0E 0B 00 00 00 00 8B A2 67 01 00 00 00 00 8.........g.....
0013EB80: 08 00 00 00 44 EB 13 00 88 7E 0D 01 50 1C 00 0B ....D....~..P...
0013EB90: FE FF FF FF 01 00 00 00 70 7C 5E 01 21 36 34 BD ........p|^.!64.
0013EBA0: 04 00 00 00 BE FA 67 01 60 CF E0 0B 31 36 34 BD ......g.`...164.
0013EBB0: 00 00 00 00 58 1D 04 0C 00 00 00 00 7C 1D 04 0C ....X.......|...
0013EBC0: 00 00 3E 0A 00 04 00 00 20 EC 13 00 08 04 00 00 ..>..... .......
0013EBD0: B9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0013EBE0: 48 5D 02 15 00 04 00 00 E2 5D 02 15 FE FF FF FF H].......]......
0013EBF0: E6 C2 67 01 58 1D 04 0C 28 EC 13 00 A3 AB 67 01 ..g.X...(.....g.
0013EC00: 85 31 34 BD 00 00 00 00 28 EC 13 00 50 EC 13 00 .14.....(...P...
0013EC10: C8 0E A6 01 00 00 00 00 42 F3 67 01 A1 31 34 BD ........B.g..14.
0013EC20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0013EC30: 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 ................
0013EC40: 5E 9B 02 00 00 00 00 00 74 ED 13 00 48 11 A6 01 ^.......t...H...
0013EC50: FF FF FF FF 13 07 68 01 20 6C C5 0B 00 ED 13 00 ......h. l......
0013EC60: E0 93 04 00 00 00 00 00 DF 00 00 00 58 1D 04 0C ............X...
0013EC70: CC 00 F9 09 C0 00 F9 09 E4 C1 66 01 20 6C C5 0B ..........f. l..
0013EC80: 00 00 00 00 00 ED 13 00 E0 93 04 00 00 00 00 00 ................
0013EC90: 00 00 00 00 00 ED 13 00 CC 00 62 1B D6 8E 5C 01 ..........b...\.
0013ECA0: 00 00 00 00 00 ED 13 00 E0 93 04 00 00 00 00 00 ................
0013ECB0: 00 00 00 00 00 00 00 00 9C 23 FA 09 00 00 00 00 .........#......
0013ECC0: 6C 15 FE 09 04 B4 5D 01 DF 00 00 00 00 ED 13 00 l.....].........
0013ECD0: CC 00 62 1B 00 00 00 00 00 00 00 00 7C 00 62 1B ..b.........|.b.
0013ECE0: 65 63 66 01 00 ED 13 00 CC 00 62 1B 00 00 00 00 ecf.......b.....
0013ECF0: 00 00 00 00 7C 00 62 1B CC 00 62 1B 7C 00 62 1B ....|.b...b.|.b.
0013ED00: 00 00 00 00 06 7F 66 01 CC 00 62 1B 00 00 00 00 ......f...b.....
0013ED10: 7C 00 62 1B 7C 00 62 1B 20 19 FC 13 A0 00 62 1B |.b.|.b. .....b.
0013ED20: 00 00 00 00 20 19 FC 13 A0 00 62 1B 7C 00 62 1B .... .....b.|.b.
0013ED30: 27 FF 9D E4 43 5B 66 01 82 5B 66 01 00 00 00 00 '...C[f..[f.....
0013ED40: 7C 00 62 1B A0 00 62 1B 20 19 FC 13 92 8A 66 01 |.b...b. .....f.
0013ED50: D5 30 34 BD FF FF FF FF C0 42 FD 09 CC 58 C7 09 .04......B...X..
0013ED60: 88 00 A7 04 84 42 FD 09 CC 58 C7 09 88 00 A7 04 .....B...X......
0013ED70: 7C 00 62 1B D4 ED 13 00 F1 06 A6 01 FF FF FF FF |.b.............
0013ED80: 74 8D 66 01 C0 42 FD 09 3B BD 02 F6 00 00 00 00 t.f..B..;.......
0013ED90: 15 30 34 BD 84 42 FD 09 84 42 FD 09 88 03 02 0A .04..B...B......
0013EDA0: 7C 00 62 1B 78 65 74 2B 6C 67 61 2B 78 65 74 2B |.b.xet+lga+xet+
0013EDB0: 00 00 00 00 9C E2 BD 09 64 E0 CE 01 00 00 00 00 ........d.......
0013EDC0: 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF ................
0013EDD0: FF FF FF FF 40 EE 13 00 48 07 A6 01 00 00 00 00 [email protected].......
0013EDE0: DB 8D 66 01 00 00 00 00 B4 27 C4 09 46 8F 66 01 ..f......'..F.f.
0013EDF0: D4 26 C7 15 D4 26 C7 15 3C 8C 71 06 AC 2F F5 13 .&...&..<.q../..
0013EE00: 9D AE 84 01 B0 00 66 20 8D 33 34 BD 88 03 02 0A ......f .34.....
0013EE10: CC 58 C7 09 B0 00 66 20 CC 58 C7 09 00 00 00 00 .X....f .X......
0013EE20: 02 00 00 00 AC 2F F5 13 30 EE 13 00 D4 26 C7 15 ...../..0....&..
0013EE30: D4 26 C7 15 04 B4 5D 01 00 00 00 00 F0 00 00 00 .&....].........
0013EE40: D4 EE 13 00 08 33 A7 01 00 00 00 00 70 AF 84 01 .....3......p...
0013EE50: 14 02 08 00 B0 00 66 20 88 03 02 0A DC 1F B8 01 ......f ........
0013EE60: 41 A2 84 01 14 02 08 00 B0 00 66 20 CC 66 C4 09 A.........f .f..
0013EE70: 3D 7D 65 01 B0 00 66 20 3C 24 72 06 C4 26 C7 15 =}e...f <$r..&..
0013EE80: C4 26 C7 15 74 02 71 06 B4 27 C4 09 01 00 00 00 .&..t.q..'......
0013EE90: B4 CC E6 09 9D AE 84 01 B0 00 66 20 21 33 34 BD ..........f !34.
0013EEA0: B4 27 C4 09 CC 66 C4 09 88 03 02 0A CC 66 C4 09 .'...f.......f..
0013EEB0: 01 00 00 00 18 00 00 00 3C 24 72 06 F4 22 C7 15 ........<$r.."..
0013EEC0: 74 0B 73 06 74 0B 73 06 CF 23 69 01 00 00 00 00 t.s.t.s..#i.....


------------------------------------------------------------------------------
 
I ran leak checker and it still happened:

==============================================================================
Warcraft III (build 6387)

Exe: l:\program files\warcraft iii\war3.exe
Time: Aug 31, 2010 4:33:23.671 PM
User: ----
Computer: UBEL
------------------------------------------------------------------------------

This application has encountered a critical error:

FATAL ERROR!

Program: l:\program files\warcraft iii\war3.exe
Exception: 0xC0000005 (ACCESS_VIOLATION) at 001B:01699BD1

The instruction at '0x01699BD1' referenced memory at '0x0000000C'.
The memory could not be 'read'.


War3Build: 1.24.4.6387
Played Maps\Test\BtT SF - Paradise.w3x
Player 0 Ubel Race Human StartLoc 0
Player 1 Pure Brotherhood Race Human StartLoc 0
Player 2 Stormreaver Cult Race Orc StartLoc 2
Player 3 Race Orc StartLoc -1
Player 4 Race NightElf StartLoc 2
Player 5 Race Human StartLoc -1
Player 6 Race Undead StartLoc 3
Player 7 Race Undead StartLoc -1
Player 8 Shining Sword Race Human StartLoc 1
Player 9 Race Human StartLoc -1
Player 10 Race Undead StartLoc -1
Player 11 Twilight Oblivion Race Orc StartLoc 3
------------------------------------------------------------------------------

----------------------------------------
x86 Registers
----------------------------------------

EAX=0013ED28 EBX=FFFFFFFF ECX=00000000 EDX=0013ED28 ESI=17CD38AC
EDI=0013EDA0 EBP=0013EDF4 ESP=0013ED18 EIP=01699BD1 FLG=00010246
CS =001B DS =0023 ES =0023 SS =0023 FS =003B GS =0000


----------------------------------------
Stack Trace (Manual)
----------------------------------------

Address Frame Logical addr Module

01699BD1 0013EDF4 0001:00478BD1 l:\program files\warcraft iii\Game.dll

----------------------------------------
Stack Trace (Using DBGHELP.DLL)
----------------------------------------

01699BD1 Game.dll <unknown symbol>+0 (0x0C48E7D0,0xE6A60C7C,0x00000000,0x226A0088)
0167FABE Game.dll <unknown symbol>+0 (0x00000000,0x00000000,0x00000000,0x00000000)


----------------------------------------
Loaded Modules
----------------------------------------

0x00400000 - 0x0047D000 war3.exe
0x01220000 - 0x01DF4000 Game.dll
0x02610000 - 0x028D5000 xpsp2res.dll
0x0FFD0000 - 0x0FFF8000 rsaenh.dll
0x10000000 - 0x10024000 mumble_ol.dll
0x15000000 - 0x15061000 Storm.dll
0x21100000 - 0x2115F000 mss32.dll
0x22600000 - 0x22616000 Mssfast.m3d
0x22700000 - 0x22717000 Mssdolby.m3d
0x22C00000 - 0x22C18000 Msseax2.m3d
0x24600000 - 0x24611000 Reverb3.flt
0x26F00000 - 0x26F2A000 Mp3dec.asi
0x4D4F0000 - 0x4D548000 WINHTTP.dll
0x59A60000 - 0x59B01000 dbghelp.dll
0x5AD70000 - 0x5ADA8000 UxTheme.dll
0x5B860000 - 0x5B8B5000 netapi32.dll
0x5CB70000 - 0x5CB96000 ShimEng.dll
0x5D090000 - 0x5D12A000 COMCTL32.dll
0x5ED00000 - 0x5EDCC000 OPENGL32.dll
0x60000000 - 0x6005D000 ijl15.dll
0x662B0000 - 0x66308000 hnetcfg.dll
0x68B20000 - 0x68B40000 GLU32.dll
0x6D990000 - 0x6D996000 d3d8thk.dll
0x6D9A0000 - 0x6DAC8000 d3d8.dll
0x6F880000 - 0x6FA4A000 AcGenral.DLL
0x71A50000 - 0x71A8F000 mswsock.dll
0x71A90000 - 0x71A98000 wshtcpip.dll
0x71AA0000 - 0x71AA8000 WS2HELP.dll
0x71AB0000 - 0x71AC7000 WS2_32.dll
0x71AD0000 - 0x71AD9000 WSOCK32.dll
0x71BF0000 - 0x71C03000 SAMLIB.dll
0x722B0000 - 0x722B5000 SensApi.dll
0x72D10000 - 0x72D18000 msacm32.drv
0x72D20000 - 0x72D29000 wdmaud.drv
0x73760000 - 0x737AB000 DDRAW.dll
0x73BC0000 - 0x73BC6000 DCIMAN32.dll
0x73EE0000 - 0x73EE4000 KsUser.dll
0x73F10000 - 0x73F6C000 DSOUND.DLL
0x74720000 - 0x7476C000 MSCTF.dll
0x75E60000 - 0x75E73000 cryptnet.dll
0x76390000 - 0x763AD000 IMM32.dll
0x763B0000 - 0x763F9000 comdlg32.dll
0x769C0000 - 0x76A73000 USERENV.dll
0x76B40000 - 0x76B6D000 WINMM.dll
0x76BF0000 - 0x76BFB000 PSAPI.DLL
0x76C30000 - 0x76C5E000 WINTRUST.dll
0x76C90000 - 0x76CB8000 IMAGEHLP.dll
0x76F60000 - 0x76F8C000 WLDAP32.dll
0x76FD0000 - 0x7704F000 CLBCATQ.DLL
0x77050000 - 0x77115000 COMRes.dll
0x77120000 - 0x771AB000 OLEAUT32.dll
0x771B0000 - 0x77256000 WININET.dll
0x773D0000 - 0x774D3000 comctl32.dll
0x774E0000 - 0x7761D000 ole32.dll
0x77690000 - 0x776B1000 NTMARTA.DLL
0x77A80000 - 0x77B14000 CRYPT32.dll
0x77B20000 - 0x77B32000 MSASN1.dll
0x77BD0000 - 0x77BD7000 midimap.dll
0x77BE0000 - 0x77BF5000 MSACM32.dll
0x77C00000 - 0x77C08000 VERSION.dll
0x77C10000 - 0x77C68000 msvcrt.dll
0x77DD0000 - 0x77E6B000 ADVAPI32.dll
0x77E70000 - 0x77F02000 RPCRT4.dll
0x77F10000 - 0x77F57000 GDI32.dll
0x77F60000 - 0x77FD6000 SHLWAPI.dll
0x77FE0000 - 0x77FF1000 Secur32.dll
0x78130000 - 0x781CB000 MSVCR80.dll
0x7C800000 - 0x7C8F6000 kernel32.dll
0x7C900000 - 0x7C9AF000 ntdll.dll
0x7C9C0000 - 0x7D1D6000 SHELL32.dll
0x7E410000 - 0x7E4A0000 USER32.dll


----------------------------------------
Memory Dump
----------------------------------------

Code: 16 bytes starting at (EIP = 01699BD1)

01699BD1: 8B 51 0C 8B 49 08 56 57 E8 92 6B BC FF 8B 7C 24 .Q..I.VW..k...|$


Stack: 1024 bytes starting at (ESP = 0013ED18)

* = addr ** *
0013ED10: 00 00 00 00 00 F0 FD 7F 00 00 00 00 CF 3E 26 01 .............>&.
0013ED20: 28 ED 13 00 AC 38 CD 17 00 00 61 44 E0 7C 5E 01 (....8....aD.|^.
0013ED30: D4 A4 B7 01 C8 DC 67 01 DB 1C 10 00 31 34 30 41 ......g.....140A
0013ED40: 26 F5 66 01 D0 E7 48 0C 31 34 30 41 AC DC 67 01 &.f...H.140A..g.
0013ED50: D0 E7 48 0C 88 00 6A 22 08 00 00 00 4D 41 58 48 ..H...j"....MAXH
0013ED60: 14 20 D1 09 88 00 A7 04 64 63 73 77 CF 23 69 01 . ......dcsw.#i.
0013ED70: E6 C2 67 01 88 00 6A 22 A8 ED 13 00 A3 AB 67 01 ..g...j"......g.
0013ED80: FC 0F A6 E6 00 00 00 00 A8 ED 13 00 D0 ED 13 00 ................
0013ED90: C8 0E A6 01 00 00 00 00 DB 1C 10 00 31 34 30 41 ............140A
0013EDA0: 18 39 67 01 00 00 00 00 68 59 CB 01 FE FF FF FF .9g.....hY......
0013EDB0: 02 00 00 00 20 25 74 0B B0 CA 49 0C 8E E3 D6 FD .... %t...I.....
0013EDC0: 07 4D 67 01 A0 9C 75 0B 00 00 00 00 8B A2 67 01 .Mg...u.......g.
0013EDD0: 00 00 00 00 08 00 00 00 98 ED 13 00 88 7E 93 04 .............~..
0013EDE0: 90 24 74 0B FE FF FF FF 01 00 00 00 70 7C 5E 01 .$t.........p|^.
0013EDF0: 8C 0F A6 E6 04 00 00 00 BE FA 67 01 D0 E7 48 0C ..........g...H.
0013EE00: 7C 0C A6 E6 00 00 00 00 88 00 6A 22 00 00 00 00 |.........j"....
0013EE10: AC 00 6A 22 00 00 08 0B 00 04 00 00 74 EE 13 00 ..j"........t...
0013EE20: 08 04 00 00 45 00 00 00 00 00 00 00 00 00 00 00 ....E...........
0013EE30: 00 00 00 00 48 5D 02 15 00 04 00 00 E2 5D 02 15 ....H].......]..
0013EE40: FE FF FF FF E6 C2 67 01 88 00 6A 22 7C EE 13 00 ......g...j"|...
0013EE50: A3 AB 67 01 20 0C A6 E6 00 00 00 00 7C EE 13 00 ..g. .......|...
0013EE60: A4 EE 13 00 C8 0E A6 01 00 00 00 00 42 F3 67 01 ............B.g.
0013EE70: 0C 0C A6 E6 00 00 00 00 00 00 00 00 00 00 00 00 ................
0013EE80: 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ................
0013EE90: 01 00 00 00 72 9B 02 00 00 00 00 00 C8 EF 13 00 ....r...........
0013EEA0: 48 11 A6 01 FF FF FF FF 13 07 68 01 B0 6D 23 0C H.........h..m#.
0013EEB0: 54 EF 13 00 E0 93 04 00 00 00 00 00 DF 00 00 00 T...............
0013EEC0: 88 00 6A 22 CC 00 15 0A C0 00 15 0A E4 C1 66 01 ..j"..........f.
0013EED0: B0 6D 23 0C 00 00 00 00 54 EF 13 00 E0 93 04 00 .m#.....T.......
0013EEE0: 00 00 00 00 00 00 00 00 54 EF 13 00 94 73 99 19 ........T....s..
0013EEF0: D6 8E 5C 01 00 00 00 00 54 EF 13 00 E0 93 04 00 ..\.....T.......
0013EF00: 00 00 00 00 00 00 00 00 00 00 00 00 9C 23 16 0A .............#..
0013EF10: 00 00 00 00 6C 15 1A 0A 04 B4 5D 01 DF 00 00 00 ....l.....].....
0013EF20: 54 EF 13 00 94 73 99 19 00 00 00 00 00 00 00 00 T....s..........
0013EF30: 44 73 99 19 65 63 66 01 54 EF 13 00 94 73 99 19 Ds..ecf.T....s..
0013EF40: 00 00 00 00 00 00 00 00 44 73 99 19 94 73 99 19 ........Ds...s..
0013EF50: 44 73 99 19 00 00 00 00 06 7F 66 01 94 73 99 19 Ds........f..s..
0013EF60: 00 00 00 00 44 73 99 19 44 73 99 19 F0 18 7F 14 ....Ds..Ds......
0013EF70: 68 73 99 19 00 00 00 00 F0 18 7F 14 68 73 99 19 hs..........hs..
0013EF80: 44 73 99 19 5F 8C 66 E6 43 5B 66 01 82 5B 66 01 Ds.._.f.C[f..[f.
0013EF90: 00 00 00 00 44 73 99 19 68 73 99 19 F0 18 7F 14 ....Ds..hs......
0013EFA0: 92 8A 66 01 D0 0D A6 E6 FF FF FF FF C0 42 19 0A ..f..........B..
0013EFB0: BC 6A E3 09 88 00 A7 04 84 42 19 0A BC 6A E3 09 .j.......B...j..
0013EFC0: 88 00 A7 04 44 73 99 19 28 F0 13 00 F1 06 A6 01 ....Ds..(.......
0013EFD0: FF FF FF FF 74 8D 66 01 C0 42 19 0A 3B BD E6 F5 ....t.f..B..;...
0013EFE0: 00 00 00 00 90 0D A6 E6 84 42 19 0A 84 42 19 0A .........B...B..
0013EFF0: F0 01 1E 0A 44 73 99 19 78 65 74 2B 6C 67 61 2B ....Ds..xet+lga+
0013F000: 78 65 74 2B 00 00 00 00 9C E2 D9 09 64 E0 CE 01 xet+........d...
0013F010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0013F020: FF FF FF FF FF FF FF FF 94 F0 13 00 48 07 A6 01 ............H...
0013F030: 00 00 00 00 DB 8D 66 01 00 00 00 00 B4 27 E0 09 ......f......'..
0013F040: 46 8F 66 01 94 29 BF 15 94 29 BF 15 CC 8C 71 06 F.f..)...)....q.
0013F050: CC 30 79 14 9D AE 84 01 90 00 3A 16 18 12 A6 E6 .0y.......:.....
0013F060: F0 01 1E 0A BC 6A E3 09 90 00 3A 16 BC 6A E3 09 .....j....:..j..
0013F070: 00 00 00 00 02 00 00 00 CC 30 79 14 84 F0 13 00 .........0y.....
0013F080: 94 29 BF 15 94 29 BF 15 04 B4 5D 01 00 00 00 00 .)...)....].....
0013F090: 40 01 00 00 28 F1 13 00 08 33 A7 01 00 00 00 00 @...(....3......
0013F0A0: 70 AF 84 01 14 02 08 00 90 00 3A 16 F0 01 1E 0A p.........:.....
0013F0B0: DC 1F B8 01 41 A2 84 01 14 02 08 00 90 00 3A 16 ....A.........:.
0013F0C0: 2C 6F E0 09 3D 7D 65 01 90 00 3A 16 7C 24 72 06 ,o..=}e...:.|$r.
0013F0D0: 84 29 BF 15 84 29 BF 15 3C 56 71 06 B4 27 E0 09 .)...)..<Vq..'..
0013F0E0: 01 00 00 00 94 3E CD 1F 9D AE 84 01 90 00 3A 16 .....>........:.
0013F0F0: 8C 12 A6 E6 B4 27 E0 09 2C 6F E0 09 F0 01 1E 0A .....'..,o......
0013F100: 2C 6F E0 09 01 00 00 00 18 00 00 00 7C 24 72 06 ,o..........|$r.
0013F110: B4 25 BF 15 E4 8C 73 14 E4 8C 73 14 CF 23 69 01 .%....s...s..#i.


------------------------------------------------------------------------------
 
I've worked out that it's the Orc AI causing the crashes, I've attached it here and if anyone sees anything that would be a problem please let me know.


JASS:
//===========================================================================
// 
// Beyond The Throne: Tides Of Darkness Standing Final (Kam™) Horde Melee AI
// by Michael Peppers
// 
//===========================================================================

//***************************************************************************
//*
//*  Global Variables
//*
//***************************************************************************

globals

    // Standard AI globals, DON'T TOUCH!!
    integer attackWave = 1
    integer nextDelay = 0

    // Town Hall
    constant integer Hall = 'ogre' //20 food
    constant integer Mine = 'ogre' //Only with mines that have to be built (UD), in any other case = Hall
    constant integer HallTier2 = 'ostr'
    constant integer HallTier3 = 'ofrt'

    // Workers
    constant integer GoldHarvester = 'opeo'
    constant integer WoodHarvester = 'o003' //In most AIs = GoldHarvester

// Highly volatile globals section

    // Buildings
    constant integer House = 'otrb' //12 food
    constant integer Altar = 'oalt'
    constant integer Barracks = 'obar'
    constant integer Blacksmith = 'o00A'
    constant integer LumberMill = 'o001' //In most AIs = Blacksmith
    constant integer CasterBarracks = 'u000'
    constant integer Tower = 'owtw'
    constant integer SpecializedBarracks = 'n00B' //Workshop/Beastiary/AncientOfWind/SlaughterHouse etc.
    constant integer FlyingBarracks = 'ndrb'
    // Buildings: BTT custom categories
    constant integer TowerUpg = 'o000'
    constant integer Tower2 = 'n009'
    constant integer AltarOfBlood = 'o002'
    constant integer Shipyard = 'o004'
    constant integer NavalBlacksmith = 'o007' //(Requires ^)
    constant integer Brazier = 'o00I'
    constant integer UltimateBarracks = 'obea'
		
    // Units
    constant integer BasicMelee = 'ogru'
    constant integer BasicRanged = 'o005' //I hope for my AI's sanity that BasicMelee + BasicRanged >= 5 food. =P
    constant integer MainCaster = 'owar' //Ala Sorceress
    constant integer SupportCaster = 'o006' //Ala Priest
    constant integer OwnageMelee = 'nogm' //Ala Knight/Tauren/Abo etc.
    constant integer AirAir = 'otbr' //ala Gargoyle
    constant integer AirGround = 'nrwm' //ala Gryphon //6 food
    constant integer SiegeRanged = 'o00B'
    constant integer MiscUnit1 = 'n00A' //Sappers (Unused)
    constant integer MiscUnit2 = 'n002' //Zeppelin (can only scout so AIs can't use it effectively)
    // Units: BTT custom categories
    constant integer DurnholdeGuy = 'o008'
    constant integer OwnageMeleeUpg = 'n000'
    constant integer SiegeRangedUpg = 'h005'
    constant integer Destroyer = 'odes' //3 food
    constant integer Submarine = 'n004' //3 food (Requires SpecializedBarracks)
    constant integer HeavyShip = 'ojgn' //4 food (Requires Castle, NavalBlacksmith)
    constant integer SuperUnit = 'o00H' //trainable only once, 5 food
    constant integer CasterFlyer = 'u008'
    constant integer AssaultFlyer = 'n00E'
	
    // Upgrades
    constant integer AttackUpgrade1 = 'R00Z' //2 Levels
    constant integer AttackUpgrade2 = 'R010' //2 Levels
    constant integer DefenseUpgrade1 = 'R00Y' //2 Levels
    constant integer DefenseUpgrade2 = 0 //Unused
    constant integer BasicMeleeUpgrade = 'Robs' //Requires Keep
    constant integer BasicRangedUpgrade = 'Rotr' //Requires Keep
    constant integer MainCasterUpgrade = 'R005' //Raise Dead
    constant integer SupportCasterUpgrade = 'R007' //1 Level
    constant integer LumberHarvestUpgrade = 'R004' //2 Levels
    constant integer BuildingDefenseUpgrade = 'R00X' //2 Levels
    constant integer MiscUpgrade1 = 'Robs' //Berserker Strength
    constant integer MiscUpgrade2 = 'R00S' //Death Knight: Sleep (Requires Keep)
    constant integer MiscUpgrade3 = 'R00J' //Ogre Magi upgrade (Requires Castle 'n' shit)
    constant integer MiscUpgrade4 = 'R00K' //Bloodlust (Requires ^)
    constant integer MiscUpgrade5 = 'R00U' //Runes (Requires ^)
    constant integer MiscUpgrade6 = 'R00G' //Death Knight: Death and Decay (Requires Castle)
    constant integer MiscUpgrade7 = 'R00R' //Death Knight: Void (Requires Castle)
    constant integer MiscUpgrade8 = 'Ropg' //Pillage
    constant integer MiscUpgrade9 = 'R01D' //Blaster Upgrade
    constant integer MiscUpgrade10 = 'R008' //Scattershot (Requires ^)
    constant integer MiscUpgrade11 = 'R002' //Armor Piercing Shells (Requires ^)
    constant integer MiscUpgrade12 = 'R37L'
    // Upgrades: BTT custom categories
    constant integer NavalAttackUpgrade = 'R00D' //2 Levels (2nd requires Castle)
    constant integer NavalDefenseUpgrade = 'R00B' //2 Levels (2nd requires Castle)

//End of highly volatile globals =P
	
    // Heroes
    constant integer Heroes = 3 //Number of heroes in the racial altar
    constant integer H1 = 'Oshd'
    constant integer H2 = 'O00D' //Set to 0 if it doesn't exists, shouldn't cause problems, though
    constant integer H3 = 'O00E' //Read above
    constant integer H4 = 0 //Idem

    // Hero Skills
    
    // First Hero = Shadow Mistress
    constant integer H1A1 = 'A019'
    constant integer H1A2 = 'A02N'
    constant integer H1A3 = 'A01J'
    constant integer H1U = 'A02G'
    
    // Second Hero = Magnate
    constant integer H2A1 = 'A02A'
    constant integer H2A2 = 'A01W'
    constant integer H2A3 = 'A02S'
    constant integer H2U = 'A01P'

    // Third Hero = Technician
    constant integer H3A1 = 'A02Q'
    constant integer H3A2 = 'A01Q'
    constant integer H3A3 = 'A033'
    constant integer H3U = 'A00K'
    
    // Fourth Hero (yes, the AI supports 4 racial heroes =D)
    constant integer H4A1 = 0
    constant integer H4A2 = 0
    constant integer H4A3 = 0
    constant integer H4U = 0

    // Food Conditions for assaults
    constant integer Food4Attack = 80 //Food usage needed for assaulting Main Bases
    constant integer Food4Exp = 42 //Food usage needed for creating Expansions
    
    // Harvest priorities
    constant integer GoldGuys1 = 5 //How many people will gather gold at the 1st mine
    constant integer WoodGuys1 = 5 //How many people will gather wood at the base
    constant integer GoldGuys2 = 5 //How many people will gather gold at the 2nd mine, 0 to disable
    constant integer WoodGuys2 = 2 //How many other people will gather wood at the base, 0 to disable
    
    // Misc stuff
    constant boolean WantName = false
    constant string Name = "Horde Test"
    constant boolean IsAmphibious = false //Naga-like race?
    constant boolean WannaKeepBasicMelee = true //Self-explainatory, I hope =)
    constant integer KeepBasicMeleeFoodCap = 170 //As soon as the AI surpasses this food cap it will stop training basic melee units
    constant integer MinimumForceBasicMelee = 3 //Use wisely: 2 food each = 4, 3 food each = 3
    constant integer MinimumForceBasicRanged = 4 //Use wisely: 2 food each = 4, 3 food each = 3
    constant integer MinimumForceOwnageMelee = 3
    constant integer AIHasOwnageMelee = 42 //When this food cap is reached, the AI will use OwnageMelee too in Minimum Attack

    // Difficulty-dependant variables (to change them, look in "main")
    integer MinesToOwn = 0 //(2 for Newb AI, 3 for Normal, 4 for Insane)

    // Conditions (Do not touch!!! These are changed by "UpdateConditions" anyway...)
    boolean KeepBasicMelee = true
    boolean CanAttack = false //Has enough units to help allies/launch small attacks?

    // Misc
    boolean SuperNotDone = true

endglobals

//***************************************************************************
//*
//*  Utility Functions
//*
//***************************************************************************

//HallCount Replicates common.ai's TownCountEx function, with minor functionality, to make it work with custom halls =D
function HallCount takes integer unitid returns integer
    local integer have_qty = GetUnitCount(unitid)
    if unitid == Hall then
        set have_qty = have_qty + GetUnitCount(HallTier2) + GetUnitCount(HallTier3)
    elseif unitid == HallTier2 then
        set have_qty = have_qty  + GetUnitCount(HallTier3)
    endif
return have_qty		
endfunction

//===========================================================================
function CheckLastCommand takes boolean pop returns integer
    local integer cmd = GetLastCommand()
    if (pop) then
        call PopLastCommand()
    endif
    return cmd
endfunction

//===========================================================================
function CheckLastCommandData takes boolean pop returns integer
    local integer data = GetLastData()
    if (pop) then
        call PopLastCommand()
    endif
    return data
endfunction

//===========================================================================
function BuildExpansion takes boolean build_it returns nothing
    if build_it and HallsCompleted(Hall) then
        call SetBuildExpa(HallCount(Hall) + 1, Hall)
    endif
endfunction

//***************************************************************************
//*
//*  Basic Options
//*
//***************************************************************************

//===========================================================================
function InitOptions takes nothing returns nothing
    call SetMeleeAI()
    call SetDefendPlayer(true)
    call SetRandomPaths(false)
    call SetTargetHeroes(true)
    call SetPeonsRepair(true)
    call SetHeroesFlee(false)
    call SetHeroesBuyItems(true)
    call SetUnitsFlee(false)
    call SetGroupsFlee(false)
    call SetWatchMegaTargets(true)
    call SetIgnoreInjured(true)
    call SetHeroesTakeItems(true)
    call SetSlowChopping(false)
    call SetCaptainChanges(true)
    call SetSmartArtillery(true)
endfunction

//***************************************************************************
//*
//*  Conditions
//*
//***************************************************************************

//===========================================================================
// Updates the values of all preset conditions
//===========================================================================
function UpdateConditions takes nothing returns nothing
	local integer x = GetUnitCountDone(BasicMelee) + GetUnitCountDone(DurnholdeGuy)
	local integer y = GetUnitCountDone(OwnageMelee) + GetUnitCountDone(OwnageMeleeUpg)
    if (not WannaKeepBasicMelee) then
        set KeepBasicMelee = (FoodCap() < KeepBasicMeleeFoodCap)
    endif
    set CanAttack = (x >= MinimumForceBasicMelee or y >= MinimumForceOwnageMelee) and GetUnitCountDone(BasicRanged) >= MinimumForceBasicRanged
endfunction

//***************************************************************************
//*
//*  Heroes
//*
//***************************************************************************

function SetSkills takes nothing returns nothing

    set skill[ 1] = H1A1
    set skill[ 2] = H1A2
    set skill[ 3] = H1A3
    set skill[ 4] = H1A1
    set skill[ 5] = H1A2
    set skill[ 6] = H1U
    set skill[ 7] = H1A3
    set skill[ 8] = H1A1
    set skill[ 9] = H1A2
    set skill[10] = H1A3

if hero_id == H1 then
    call SetSkillArray(1, H1)
elseif hero_id2 == H1 then
    call SetSkillArray(2, H1)
elseif hero_id3 == H1 then
    call SetSkillArray(3, H1)
endif

if Heroes > 1 then
    set skill[ 1] = H2A1
    set skill[ 2] = H2A2
    set skill[ 3] = H2A3
    set skill[ 4] = H2A1
    set skill[ 5] = H2A2
    set skill[ 6] = H2U
    set skill[ 7] = H2A3
    set skill[ 8] = H2A1
    set skill[ 9] = H2A2
    set skill[10] = H2A3

    if hero_id == H2 then
        call SetSkillArray(1, H2)
    elseif hero_id2 == H2 then
        call SetSkillArray(2, H2)
    elseif hero_id3 == H2 then
        call SetSkillArray(3, H2)
    endif
endif

if Heroes > 2 then
    set skill[ 1] = H3A1
    set skill[ 2] = H3A2
    set skill[ 3] = H3A3
    set skill[ 4] = H3A1
    set skill[ 5] = H3A2
    set skill[ 6] = H3U
    set skill[ 7] = H3A3
    set skill[ 8] = H3A1
    set skill[ 9] = H3A2
    set skill[10] = H3A3

    if hero_id == H3 then
        call SetSkillArray(1, H3)
    elseif hero_id2 == H3 then
        call SetSkillArray(2, H3)
    elseif hero_id3 == H3 then
        call SetSkillArray(3, H3)
    endif
endif

if Heroes > 3 then
    set skill[ 1] = H4A1
    set skill[ 2] = H4A2
    set skill[ 3] = H4A3
    set skill[ 4] = H4A1
    set skill[ 5] = H4A2
    set skill[ 6] = H4U
    set skill[ 7] = H4A3
    set skill[ 8] = H4A1
    set skill[ 9] = H4A2
    set skill[10] = H4A3

    if hero_id == H4 then
        call SetSkillArray(1, H4)
    elseif hero_id2 == H4 then
        call SetSkillArray(2, H4)
    elseif hero_id3 == H4 then
        call SetSkillArray(3, H4)
    endif
endif

endfunction

function PickRacialHero takes nothing returns nothing
    local integer first
    local integer second
    local integer third
    local integer last
    local integer array heroes

        set heroes[1] = H1
        set heroes[2] = H2
        set heroes[3] = H3
        set heroes[4] = H4
    if Heroes > 3 then
        if VersionCompatible(VERSION_FROZEN_THRONE) then
            set last = 4
        else
            set last = 3
        endif
    else
        set last = Heroes
    endif

    if last >= 1 then
        set first  = GetRandomInt(1,last)
        if last >= 2 then
            set second = GetRandomInt(1,last-1)
            if last >= 3 then
               set third  = GetRandomInt(1,last-2)
            else
               set third = 3
            endif
        else
            set second = 2
        endif
    endif

    set hero_id        = heroes[first]
    set heroes[first]  = heroes[last]
    set hero_id2       = heroes[second]
    set heroes[second] = heroes[last-1]
    set hero_id3       = heroes[third]
endfunction

//***************************************************************************
//*
//*  Building and Harvesting
//*
//***************************************************************************

//===========================================================================
// Specifies building priorities for workers
//===========================================================================
function BuildPriorities takes nothing returns nothing
    local integer mine = TownWithMine()
    call InitBuildArray()

    call MeleeTownHall(0, Hall)
    call MeleeTownHall(1, Hall)
    if Hall != Mine and GetGold() < 1500 then //In case of a custom mine
        call SecondaryTown(mine, 1, Mine)
    endif
    call SetBuildUnit(5, GoldHarvester)
    call SetBuildUnit(2, WoodHarvester)
    call SetBuildUnit(1, House)
    call SetBuildUnit(7, GoldHarvester)
    call SetBuildUnit(1, Altar)
    call SetBuildUnit(1, Barracks)
    call SetBuildUnit(8, GoldHarvester)
    call SetBuildUnit(1, hero_id)
    if KeepBasicMelee then
        call SetBuildUnit(1, BasicMelee)
    endif
    call SetBuildUnit(2, House)
    if KeepBasicMelee then
        call SetBuildUnit(2, BasicMelee)
    endif                              
    call SetBuildUnit(2, Barracks)
    call SetBuildUnit(1, Blacksmith)
    call SetBuildUnit(2, BasicRanged)
    if Blacksmith != LumberMill then
        call SetBuildUnit(1, LumberMill)
    endif
    call SetBuildUnit(3, BasicRanged)
    call SetBuildUnit(3, House)
    if KeepBasicMelee then
        if GetUnitCountDone(Barracks) > 0 then
            call SetBuildUnit(2, BasicRanged)
        else
            call SetBuildUnit(4, BasicMelee)
        endif
    endif
    call SetBuildUnit(5, BasicRanged)
    call SetBuildUpgr(1, BasicMeleeUpgrade)
    call SetBuildUpgr(1, AttackUpgrade1)
    call SetBuildUpgr(1, AttackUpgrade2)
    call SetBuildUpgr(1, DefenseUpgrade1)
    call SetBuildUnit(1, HallTier2)
    call SetBuildUnit(10, GoldHarvester)
    call BuildExpansion(GetMinesOwned() < MinesToOwn)
    call SetBuildUpgr(1, BasicRangedUpgrade)
    call SetBuildUpgr(1, LumberHarvestUpgrade)
    call SetBuildUnit(1, Brazier)
    call SetBuildUnit(1, SpecializedBarracks)
    if GetUnitCountDone(Shipyard) > 0 then
        call SetBuildUnit(2, AssaultFlyer)
    endif
    if MeleeDifficulty() != MELEE_NEWBIE and Heroes > 1 then //2 heroes? kthxbai
        call SetBuildUnit(1, hero_id2)
    else //Adding some cannon fodder, >= 5 food in total, I hope...
        if KeepBasicMelee then
            if GetUnitCountDone(Barracks) > 0 then
                call SetBuildUnit(5, BasicRanged)
            else
                call SetBuildUnit(5, BasicMelee)
            endif
        else
            if GetUnitCountDone(Barracks) > 0 then
                call SetBuildUnit(2, BasicMelee)
            else
                call SetBuildUnit(1, BasicMelee)
            endif
        endif
        call SetBuildUnit(6, BasicRanged)
    endif
    call SetBuildUnit(6, House)
    if GetUpgradeLevel(MiscUpgrade3) == 0 then
        call SetBuildUnit(4, OwnageMelee)
    else
        call SetBuildUnit(4, OwnageMeleeUpg)
    endif
    call SetBuildUnit(1, CasterBarracks)
    call SetBuildUnit(3, CasterFlyer)
    call SetBuildUpgr(1, MiscUpgrade1)
    call SetBuildUnit(9, House)
    if GetUpgradeLevel(MiscUpgrade3) == 0 then
        call SetBuildUnit(6, OwnageMelee)
    else
        call SetBuildUnit(6, OwnageMeleeUpg)
    endif
    call SetBuildUpgr(1, MiscUpgrade1)
    call SetBuildUnit(1, HallTier3)
    call SetBuildUnit(2, Tower)
    call SetBuildUnit(1, TowerUpg)
    call SetBuildUnit(3, Tower)
    call SetBuildUpgr(1, MiscUpgrade2)
    call SetBuildUnit(1, SupportCaster)
    call SetBuildUnit(3, TowerUpg)
    call SetBuildUnit(1, UltimateBarracks)
    call SetBuildUnit(1, MainCaster)
    call SetBuildUnit(2, SpecializedBarracks)
    call SetBuildUpgr(1, MainCasterUpgrade)
    call SetBuildUpgr(1, SupportCasterUpgrade)
    if SuperNotDone then
        if GetUnitCountDone(SuperUnit) > 0 then
            set SuperNotDone = false
        else
            call SetBuildUnit(1, SuperUnit)
        endif
    endif
    if GetUnitCountDone(Shipyard) > 0 then
        call SetBuildUnit(3, Destroyer)
    endif
    if GetUnitCountDone(NavalBlacksmith) > 0 then
        call SetBuildUpgr(1, NavalAttackUpgrade)
        call SetBuildUpgr(1, NavalDefenseUpgrade)
    endif
   if GetUnitCountDone(Shipyard) > 0 and GetUnitCountDone(AssaultFlyer) < 2 then
    call SetBuildUnit(2, AssaultFlyer)
    endif
    if GetUpgradeLevel(MiscUpgrade9) == 0 then
        call SetBuildUnit(2, SiegeRanged)
    else
        call SetBuildUnit(2, SiegeRangedUpg)
    endif
    if GetMinesOwned() > 1 then
        call SetBuildUnit(15, GoldHarvester)
    endif
    call SetBuildUpgr(2, LumberHarvestUpgrade)
    if MeleeDifficulty() == MELEE_INSANE and Heroes > 2 then //3 heroes? 1337sauce
        call SetBuildUnit(1, hero_id3)
    else
        if GetUpgradeLevel(MiscUpgrade3) == 0 then
            call SetBuildUnit(7, OwnageMelee)
        else
            call SetBuildUnit(7, OwnageMeleeUpg)
        endif
    endif
    call SetBuildUnit(1, AltarOfBlood)
    call SetBuildUpgr(1, MiscUpgrade3)
    if MeleeDifficulty() != MELEE_NEWBIE then
        call SecondaryTown(mine, 3, Tower)
        call SecondaryTown(mine, 3, TowerUpg)
    endif
    call SetBuildUpgr(2, AttackUpgrade1)
    call SetBuildUpgr(2, AttackUpgrade2)
    call SetBuildUpgr(2, DefenseUpgrade1)
    call SetBuildUnit(11, House)
    if GetUnitCount(SuperUnit) == 0 then
        if MeleeDifficulty() == MELEE_INSANE and Heroes > 2 then
            if GetUpgradeLevel(MiscUpgrade3) == 0 then
                call SetBuildUnit(8, OwnageMelee)
            else
                call SetBuildUnit(8, OwnageMeleeUpg)
            endif
        else
            if GetUpgradeLevel(MiscUpgrade3) == 0 then
                call SetBuildUnit(9, OwnageMelee)
            else
                call SetBuildUnit(9, OwnageMeleeUpg)
            endif
        endif
    endif
    if GetUnitCountDone(Shipyard) > 0 then
        call SetBuildUnit(3, Submarine)
        call SetBuildUnit(5, Destroyer)
        call SetBuildUnit(5, Submarine)
    endif
    call SetBuildUnit(1, FlyingBarracks)
    call SetBuildUnit(3, AirGround)
    call SetBuildUpgr(1, MiscUpgrade4)
    call SetBuildUpgr(1, MiscUpgrade5)
    call SetBuildUnit(3, AirAir)
    call SetBuildUnit(2, DurnholdeGuy)
    call SetBuildUnit(2, SupportCaster)
    call SetBuildUpgr(1, BuildingDefenseUpgrade)
    if GetUnitCountDone(NavalBlacksmith) > 0 then
        call SetBuildUpgr(2, NavalAttackUpgrade)
        call SetBuildUpgr(2, NavalDefenseUpgrade)
    endif
    if GetUnitCountDone(Shipyard) > 0 and GetUnitCountDone(NavalBlacksmith) > 0 then
        call SetBuildUnit(2, HeavyShip)
    endif
    call SetBuildUpgr(2, BuildingDefenseUpgrade)
    call SetBuildUpgr(1, MiscUpgrade6)
    call SetBuildUpgr(1, MiscUpgrade7)
    call SetBuildUpgr(1, MiscUpgrade8)
    call SetBuildUpgr(1, MiscUpgrade9)
    call SetBuildUpgr(1, MiscUpgrade10)
    call SetBuildUpgr(1, MiscUpgrade11)
    call SetBuildUpgr(1, MiscUpgrade12)
    if MeleeDifficulty() == MELEE_INSANE then
        call SetBuildUnit(6, Tower2)
    endif
endfunction

function GuysAtWork takes nothing returns nothing
    local integer mine
    loop
        call UpdateConditions()
        call ClearHarvestAI()
        set mine = TownWithMine()
        call HarvestGold(mine + 0, GoldGuys1)
        call HarvestWood(0, WoodGuys1)
        if GoldGuys2 != 0 and GetMinesOwned() >= 2 then
            call HarvestGold(mine + 1, GoldGuys2)
        endif
        if WoodGuys2 != 0 then
            call HarvestWood(0, WoodGuys2)
        endif
        call BuildPriorities()
        call Sleep(2)
    endloop
endfunction

//***************************************************************************
//*
//*  Attacking
//*
//***************************************************************************

//===========================================================================
// Returns true if the minimum forces for an attack exist
//===========================================================================
function HaveMinimumAttackers takes nothing returns boolean

    // Check for attack wave limit
    if attackWave > 3 or (GetUnitCountDone(Shipyard) == 0 and attackWave > 2) then
        return false
    endif

    return CanAttack
endfunction

//===========================================================================
// Assigns units to attack based on the given attack group
//===========================================================================
function PrepareAttackGroup takes integer groupID returns nothing

    // Attack Group #1: Minimum Attack
    if (groupID == 1) then
        call SetAssaultGroup(GetUnitCountDone(hero_id), -1, hero_id)
        call SetAssaultGroup(GetUnitCountDone(BasicRanged), -1, BasicRanged)
        call SetAssaultGroup(GetUnitCountDone(BasicMelee), -1, BasicMelee)
        call SetAssaultGroup(GetUnitCountDone(DurnholdeGuy), -1, DurnholdeGuy)
        if (FoodCap() >= AIHasOwnageMelee) then
            call SetAssaultGroup(GetUnitCountDone(OwnageMelee), -1, OwnageMelee)
            call SetAssaultGroup(GetUnitCountDone(OwnageMeleeUpg), -1, OwnageMeleeUpg)
        endif

    // Attack Group #2: Main Units
    elseif (groupID == 2) then
        call SetAssaultGroup(GetUnitCountDone(hero_id), -1, hero_id)
        if Heroes > 1 then //Just in case =)
            call SetAssaultGroup(GetUnitCountDone(hero_id2), -1, hero_id2)
            if Heroes > 2 then
                call SetAssaultGroup(GetUnitCountDone(hero_id3), -1, hero_id3)
            endif
        endif
        call SetAssaultGroup(GetUnitCountDone(BasicRanged), -1, BasicRanged)
        call SetAssaultGroup(GetUnitCountDone(BasicMelee), -1, BasicMelee)
        call SetAssaultGroup(GetUnitCountDone(DurnholdeGuy), -1, DurnholdeGuy)
        call SetAssaultGroup(GetUnitCountDone(OwnageMelee), -1, OwnageMelee)
        call SetAssaultGroup(GetUnitCountDone(OwnageMeleeUpg), -1, OwnageMelee)
        call SetAssaultGroup(GetUnitCountDone(SupportCaster), -1, SupportCaster)
        call SetAssaultGroup(GetUnitCountDone(SuperUnit), -1, SuperUnit)
        call SetAssaultGroup(GetUnitCountDone(MainCaster), -1, MainCaster)
        call SetAssaultGroup(GetUnitCountDone(AirGround), -1, AirGround)
        call SetAssaultGroup(GetUnitCountDone(AirAir), -1, AirAir)
        call SetAssaultGroup(GetUnitCountDone(SiegeRanged), -1, SiegeRanged)
        call SetAssaultGroup(GetUnitCountDone(SiegeRangedUpg), -1, SiegeRangedUpg)
        call SetAssaultGroup(GetUnitCountDone(MiscUnit1), -1, MiscUnit1)
        call SetAssaultGroup(GetUnitCountDone(MiscUnit2), -1, MiscUnit2)
        call SetAssaultGroup(GetUnitCountDone(AssaultFlyer), -1, AssaultFlyer)
        call SetAssaultGroup(GetUnitCountDone(CasterFlyer), -1, CasterFlyer)

    // Attack Group #3: Naval Units
    elseif (groupID == 3) then
        call InitAssaultGroup()
        call SetAssaultGroup(GetUnitCountDone(Destroyer), -1, Destroyer)
        call SetAssaultGroup(GetUnitCountDone(Submarine), -1, Submarine)
        call SetAssaultGroup(GetUnitCountDone(HeavyShip), -1, HeavyShip)
    endif
endfunction

//===========================================================================
// Prepares an attack group based on the current attack wave
//===========================================================================
function PrepareForces takes nothing returns nothing
    if attackWave == 1 then
        call PrepareAttackGroup(1)
    elseif attackWave == 2 then
        call PrepareAttackGroup(2)
    elseif attackWave == 3 then
        call PrepareAttackGroup(3)
    endif
endfunction

//===========================================================================
// Sleep delays for each attack wave
//===========================================================================
function AttackWaveDelay takes integer inWave returns nothing
    if inWave < nextDelay then
        return
    endif

    if inWave == 1 then
        call Sleep(2)
    endif

    set nextDelay = inWave + 1
endfunction

//===========================================================================
// Advances attack wave counter
//===========================================================================
function AttackWaveUpdate takes nothing returns nothing
    call AttackWaveDelay(attackWave)
    set attackWave = attackWave + 1
    if attackWave > 3 or (GetUnitCountDone(Shipyard) == 0 and attackWave > 2) then
        set attackWave = 2
        set nextDelay = attackWave + 1
    endif
endfunction

//===========================================================================
// Basic attack functionality
//===========================================================================
function AttackTarget takes unit target, boolean addAlliance returns nothing
    if target == null then
        return
    endif
    if addAlliance then
        call SetAllianceTarget(target)
    endif
    call FormGroup(3, true)
    call AttackMoveKillA(target)
    if (not addAlliance) then
        call SetAllianceTarget(null)
    endif
endfunction

//===========================================================================
// Initiates an attack based on target priorities
//===========================================================================
function LaunchAttack takes nothing returns nothing
    local unit target = null
    local boolean setAlly = true

    // Don't launch any attack while town is threatened
    if TownThreatened() then
        call Sleep(2)
        return
    endif

    // Target Priority #1 = Helping an ally Assault/Defence
    if (target == null) then
        set target = GetAllianceTarget()
        if (target != null) then
            set setAlly = false
        endif
    endif

    // Target Priority #2 = Preparing an expansion
    if FoodUsed() >= Food4Exp then
        if ((GetUnitCountDone(OwnageMelee) + GetUnitCountDone(OwnageMeleeUpg)) >= MinimumForceOwnageMelee) then //Ogres or gtfo
            if (target == null) then
                set target = GetExpansionFoe()
            endif
        endif
    endif

    // Target Priority #3 = Woot, MegaTarget? (MegaTarget is the enemy's main)
    if FoodUsed() >= Food4Attack then
        if (target == null) then
            set target = GetMegaTarget()
        endif

    // Target Priority #4 = Either enemy expansions or an enemy base
        if (target == null) then
            set target = GetEnemyExpansion()
            if (target == null) then
                call StartGetEnemyBase()
                loop
                    exitwhen (not WaitGetEnemyBase())
                    call SuicideSleep(1)
                endloop
                set target = GetEnemyBase()
            endif
        endif
    endif

    // Target Priority #5 = Small creep camps
    if FoodUsed() < Food4Attack then
        if target == null then
            set target = GetCreepCamp(0, 9, false)
        endif
    endif

    // Target Priority #6 = Huge creep camps
    if FoodUsed() >= Food4Attack then
        if (target == null) then
            set target = GetCreepCamp(10, 100, true)
        endif
    endif

    // Target Priority #7 = Goblin Zeppelin
    if (GetUnitCount('nzep') < 1) then
        if (target == null) then
            call PurchaseZeppelin()
            return
        endif
    endif

    // Attack the target and increment attack wave
    if (target != null) then
        call AttackTarget(target, setAlly)
        call AttackWaveUpdate()
    else
        // If no target was found, sleep a bit before trying again
        call Sleep(20)
    endif
endfunction

//===========================================================================
// Determines all attacking assignments
//===========================================================================
function AttackAssignment takes nothing returns nothing
local integer n = 0
    call StaggerSleep(0, 2)
    if (attackWave == 1) then
        call AttackWaveDelay(0)
    endif
    loop
        call UpdateConditions()
        if (HaveMinimumAttackers() and not CaptainRetreating()) then
            if n == 2 then
                call Sleep(2)
                set n = 0
            else
                set n = n + 1
                call RemoveInjuries()
                call InitAssaultGroup()
                call PrepareForces()
                call LaunchAttack()
            endif
        else
            call Sleep(2)
        endif
    endloop
endfunction

//***************************************************************************
//*
//*  Main Entry Point
//*
//***************************************************************************

//===========================================================================
function main takes nothing returns nothing
    set ai_player = Player(GetAiPlayer())
    set MinesToOwn = 1 + MeleeDifficulty()
    if WantName then
        call SetPlayerName(ai_player, Name)
    endif
    call InitOptions()
    call PickRacialHero()
    call SetSkills()
    call CreateCaptains()
    call StandardAI(function SkillArrays, function GuysAtWork, function AttackAssignment)
    if IsAmphibious then
        call SetAmphibious()
    endif
    call PlayGame()
endfunction


EDIT:eek:k, it's apparently an issue with both AI's.


JASS:
//===========================================================================
// 
// Beyond The Throne: Tides Of Darkness Standing Final (Kam™) Alliance Melee AI
// by Michael Peppers
// 
//===========================================================================

//***************************************************************************
//*
//*  Global Variables
//*
//***************************************************************************

globals

    // Standard AI globals, DON'T TOUCH!!
    integer attackWave = 1
    integer nextDelay = 0

    // Town Hall
    constant integer Hall = 'htow' //22 food
    constant integer Mine = 'htow' //Only with mines that have to be built (UD), in any other case = Hall
    constant integer HallTier2 = 'hkee'
    constant integer HallTier3 = 'hcas'

    // Workers
    constant integer GoldHarvester = 'hpea'
    constant integer WoodHarvester = 'h000' //In most AIs = GoldHarvester

// Highly volatile globals section

    // Buildings
    constant integer House = 'hhou' //8 food
    constant integer Altar = 'halt'
    constant integer Barracks = 'hbar'
    constant integer Blacksmith = 'hbla'
    constant integer LumberMill = 'hlum' //In most AIs = Blacksmith
    constant integer CasterBarracks = 'nheb'
    constant integer Tower = 'hwtw'
    constant integer SpecializedBarracks = 'h00C' //Workshop/Beastiary/AncientOfWind/SlaughterHouse etc.
    constant integer FlyingBarracks = 'hgra'
    // Buildings: BTT custom categories
    constant integer TowerUpg1 = 'hgtw'
    constant integer TowerUpg2 = 'hctw'
    constant integer Tower2 = 'n00C'
    constant integer Church = 'h00B'
    constant integer Spire = 'h004'
    constant integer Shipyard = 'h00A'
    constant integer NavalBlacksmith = 'h009' //(Requires ^)
    constant integer UltimateBarracks = 'hars'
		
    // Units
    constant integer BasicMelee = 'hfoo'
    constant integer BasicRanged = 'n008' //I hope for my AI's sanity that BasicMelee + BasicRanged >= 5 food. =P
    constant integer MainCaster = 'n00H' //Ala Sorceress
    constant integer SupportCaster = 'n00D' //Ala Priest
    constant integer OwnageMelee = 'hkni' //Ala Knight/Tauren/Abo etc.
    constant integer AirAir = 'e001' //ala Gargoyle
    constant integer AirGround = 'hgry' //ala Gryphon
    constant integer SiegeRanged = 'e002'
    constant integer MiscUnit1 = 'n00T' //Demolition Squad (Unused)
    constant integer MiscUnit2 = 'hgyr' //Gyrocopter (can only scout so AIs can't use it effectively)
    // Units: BTT custom categories
    constant integer BasicMeleeUpg = 'h002'
    constant integer OwnageMeleeUpg = 'n00S'
    constant integer SiegeRangedUpg = 'hmtt'
    constant integer ResurrectionWagon = 'h014'
    constant integer Destroyer = 'hdes' //3 food
    constant integer Submarine = 'n00O' //2 food (Requires SpecializedBarracks)
    constant integer HeavyShip = 'hbsh' //4 food (Requires Castle, NavalBlacksmith)
    constant integer Purifier = 'h00O' //Purifier (trainable only once), 5 food
    constant integer CasterFlyer = 'e005'
    constant integer AssaultFlyer = 'h015'
	
    // Upgrades
    constant integer AttackUpgrade1 = 'R00F' //2 Levels
    constant integer AttackUpgrade2 = 'R003' //2 Levels
    constant integer DefenseUpgrade1 = 'R00E' //2 Levels
    constant integer DefenseUpgrade2 = 0 //Unused
    constant integer BasicMeleeUpgrade = 'Rhde' //It's always defend someway =)
    constant integer BasicRangedUpgrade = 'R000' //Requires Keep
    constant integer MainCasterUpgrade = 'R00P' //Polymorph
    constant integer SupportCasterUpgrade = 'R006' //1 Level
    constant integer LumberHarvestUpgrade = 'Rhlh' //2 Levels
    constant integer BuildingDefenseUpgrade = 'R00W' //2 Levels
    constant integer MiscUpgrade1 = 'R00H' //Mage: Cleansing Fire (Requires Keep)
    constant integer MiscUpgrade2 = 'R00L' //Paladin upgrade (Requires Castle 'n' shit)
    constant integer MiscUpgrade3 = 'R00V' //Healing (Requires ^)
    constant integer MiscUpgrade4 = 'R00I' //Mage: Blizzard (Requires Castle)
    constant integer MiscUpgrade5 = 'R00O' //Mage: Hammer Of Thor (Requires Castle)
    constant integer MiscUpgrade6 = 'R009' //Swordsman Upgrade (Requires Castle 'n' shit)
    constant integer MiscUpgrade7 = 'R001' //Marksmanship
    constant integer MiscUpgrade8 = 'Rhan' //Animal War Training
    constant integer MiscUpgrade9 = 'R00M' //Combat Assistance
    constant integer MiscUpgrade10 = 'Rhhb' //Storm Hammer
    constant integer MiscUpgrade11 = 'R01A' //Siege Engine Replacement (doesn't upgrade existing Ballistas, remember)
    constant integer MiscUpgrade12 = 'Rhrt' //Scatter Rockets (Requires ^)
    // Upgrades: BTT custom categories
    constant integer NavalAttackUpgrade = 'R00C' //2 Levels (2nd requires Castle)
    constant integer NavalDefenseUpgrade = 'R00A' //2 Levels (2nd requires Castle)

//End of highly volatile globals =P
	
    // Heroes
    constant integer Heroes = 3 //Number of heroes in the racial altar
    constant integer H1 = 'H00K'
    constant integer H2 = 'H00G' //Set to 0 if it doesn't exists, shouldn't cause problems, though
    constant integer H3 = 'H007' //Read above
    constant integer H4 = 0 //Idem

    // Hero Skills
    
    // First Hero = Astral Mage
    constant integer H1A1 = 'A01U'
    constant integer H1A2 = 'A024'
    constant integer H1A3 = 'AHab'
    constant integer H1U = 'A01F'
    
    // Second Hero = Bowmaster
    constant integer H2A1 = 'A01Y'
    constant integer H2A2 = 'A02L'
    constant integer H2A3 = 'AEar'
    constant integer H2U = 'AEsf'

    // Third Hero = Lord (Garithos's a wuss)
    constant integer H3A1 = 'A01H'
    constant integer H3A2 = 'A01L'
    constant integer H3A3 = 'A01E'
    constant integer H3U = 'AHre'
    
    // Fourth Hero (yes, the AI supports 4 racial heroes =D)
    constant integer H4A1 = 0
    constant integer H4A2 = 0
    constant integer H4A3 = 0
    constant integer H4U = 0

    // Food Conditions for assaults
    constant integer Food4Attack = 80 //Food usage needed for assaulting Main Bases
    constant integer Food4Exp = 42 //Food usage needed for creating Expansions
    
    // Harvest priorities
    constant integer GoldGuys1 = 5 //How many people will gather gold at the 1st mine
    constant integer WoodGuys1 = 5 //How many people will gather wood at the base
    constant integer GoldGuys2 = 5 //How many people will gather gold at the 2nd mine, 0 to disable
    constant integer WoodGuys2 = 2 //How many other people will gather wood at the base, 0 to disable
    
    // Misc stuff
    constant boolean WantName = false
    constant string Name = "Alliance Test"
    constant boolean IsAmphibious = false //Naga-like race?
    constant boolean WannaKeepBasicMelee = true //Self-explainatory, I hope =)
    constant integer KeepBasicMeleeFoodCap = 170 //As soon as the AI surpasses this food cap it will stop training basic melee units
    constant integer MinimumForceBasicMelee = 4 //Use wisely: 2 food each = 4, 3 food each = 3
    constant integer MinimumForceBasicRanged = 4 //Use wisely: 2 food each = 4, 3 food each = 3
    constant integer MinimumForceOwnageMelee = 3
    constant integer AIHasOwnageMelee = 42 //When this food cap is reached, the AI will use OwnageMelee too in Minimum Attack

    // Difficulty-dependant variables (to change them, look in "main")
    integer MinesToOwn = 0 //(2 for Newb AI, 3 for Normal, 4 for Insane)

    // Conditions (Do not touch!!! These are changed by "UpdateConditions" anyway...)
    boolean KeepBasicMelee = true
    boolean CanAttack = false //Has enough units to help allies/launch small attacks?

    // Misc
    boolean PurifierNotDone = true
endglobals

//***************************************************************************
//*
//*  Utility Functions
//*
//***************************************************************************

//HallCount Replicates common.ai's TownCountEx function, with minor functionality, to make it work with custom halls =D
function HallCount takes integer unitid returns integer
    local integer have_qty = GetUnitCount(unitid)
    if unitid == Hall then
        set have_qty = have_qty + GetUnitCount(HallTier2) + GetUnitCount(HallTier3)
    elseif unitid == HallTier2 then
        set have_qty = have_qty  + GetUnitCount(HallTier3)
    endif
return have_qty		
endfunction

//===========================================================================
function CheckLastCommand takes boolean pop returns integer
    local integer cmd = GetLastCommand()
    if (pop) then
        call PopLastCommand()
    endif
    return cmd
endfunction

//===========================================================================
function CheckLastCommandData takes boolean pop returns integer
    local integer data = GetLastData()
    if (pop) then
        call PopLastCommand()
    endif
    return data
endfunction

//===========================================================================
function BuildExpansion takes boolean build_it returns nothing
    if build_it and HallsCompleted(Hall) then
        call SetBuildExpa(HallCount(Hall) + 1, Hall)
    endif
endfunction

//***************************************************************************
//*
//*  Basic Options
//*
//***************************************************************************

//===========================================================================
function InitOptions takes nothing returns nothing
    call SetMeleeAI()
    call SetDefendPlayer(true)
    call SetRandomPaths(false)
    call SetTargetHeroes(true)
    call SetPeonsRepair(true)
    call SetHeroesFlee(false)
    call SetHeroesBuyItems(true)
    call SetUnitsFlee(false)
    call SetGroupsFlee(false)
    call SetWatchMegaTargets(true)
    call SetIgnoreInjured(true)
    call SetHeroesTakeItems(true)
    call SetSlowChopping(false)
    call SetCaptainChanges(true)
    call SetSmartArtillery(true)
endfunction

//***************************************************************************
//*
//*  Conditions
//*
//***************************************************************************

//===========================================================================
// Updates the values of all preset conditions
//===========================================================================
function UpdateConditions takes nothing returns nothing
	local integer x = GetUnitCountDone(BasicMelee) + GetUnitCountDone(BasicMeleeUpg)
	local integer y = GetUnitCountDone(OwnageMelee) + GetUnitCountDone(OwnageMeleeUpg)
    if (not WannaKeepBasicMelee) then
        set KeepBasicMelee = (FoodCap() < KeepBasicMeleeFoodCap)
    endif
    set CanAttack = (x >= MinimumForceBasicMelee or y >= MinimumForceOwnageMelee) and GetUnitCountDone(BasicRanged) >= MinimumForceBasicRanged
endfunction

//***************************************************************************
//*
//*  Heroes
//*
//***************************************************************************

function SetSkills takes nothing returns nothing

    set skill[ 1] = H1A1
    set skill[ 2] = H1A2
    set skill[ 3] = H1A3
    set skill[ 4] = H1A1
    set skill[ 5] = H1A2
    set skill[ 6] = H1U
    set skill[ 7] = H1A3
    set skill[ 8] = H1A1
    set skill[ 9] = H1A2
    set skill[10] = H1A3

if hero_id == H1 then
    call SetSkillArray(1, H1)
elseif hero_id2 == H1 then
    call SetSkillArray(2, H1)
elseif hero_id3 == H1 then
    call SetSkillArray(3, H1)
endif

if Heroes > 1 then
    set skill[ 1] = H2A1
    set skill[ 2] = H2A2
    set skill[ 3] = H2A3
    set skill[ 4] = H2A1
    set skill[ 5] = H2A2
    set skill[ 6] = H2U
    set skill[ 7] = H2A3
    set skill[ 8] = H2A1
    set skill[ 9] = H2A2
    set skill[10] = H2A3

    if hero_id == H2 then
        call SetSkillArray(1, H2)
    elseif hero_id2 == H2 then
        call SetSkillArray(2, H2)
    elseif hero_id3 == H2 then
        call SetSkillArray(3, H2)
    endif
endif

if Heroes > 2 then
    set skill[ 1] = H3A1
    set skill[ 2] = H3A2
    set skill[ 3] = H3A3
    set skill[ 4] = H3A1
    set skill[ 5] = H3A2
    set skill[ 6] = H3U
    set skill[ 7] = H3A3
    set skill[ 8] = H3A1
    set skill[ 9] = H3A2
    set skill[10] = H3A3

    if hero_id == H3 then
        call SetSkillArray(1, H3)
    elseif hero_id2 == H3 then
        call SetSkillArray(2, H3)
    elseif hero_id3 == H3 then
        call SetSkillArray(3, H3)
    endif
endif

if Heroes > 3 then
    set skill[ 1] = H4A1
    set skill[ 2] = H4A2
    set skill[ 3] = H4A3
    set skill[ 4] = H4A1
    set skill[ 5] = H4A2
    set skill[ 6] = H4U
    set skill[ 7] = H4A3
    set skill[ 8] = H4A1
    set skill[ 9] = H4A2
    set skill[10] = H4A3

    if hero_id == H4 then
        call SetSkillArray(1, H4)
    elseif hero_id2 == H4 then
        call SetSkillArray(2, H4)
    elseif hero_id3 == H4 then
        call SetSkillArray(3, H4)
    endif
endif

endfunction

function PickRacialHero takes nothing returns nothing
    local integer first
    local integer second
    local integer third
    local integer last
    local integer array heroes

        set heroes[1] = H1
        set heroes[2] = H2
        set heroes[3] = H3
        set heroes[4] = H4
    if Heroes > 3 then
        if VersionCompatible(VERSION_FROZEN_THRONE) then
            set last = 4
        else
            set last = 3
        endif
    else
        set last = Heroes
    endif

    if last >= 1 then
        set first  = GetRandomInt(1,last)
        if last >= 2 then
            set second = GetRandomInt(1,last-1)
            if last >= 3 then
               set third  = GetRandomInt(1,last-2)
            else
               set third = 3
            endif
        else
            set second = 2
        endif
    endif

    set hero_id        = heroes[first]
    set heroes[first]  = heroes[last]
    set hero_id2       = heroes[second]
    set heroes[second] = heroes[last-1]
    set hero_id3       = heroes[third]
endfunction

//***************************************************************************
//*
//*  Building and Harvesting
//*
//***************************************************************************

//===========================================================================
// Specifies building priorities for workers
//===========================================================================
function BuildPriorities takes nothing returns nothing
    local integer mine = TownWithMine()
    call InitBuildArray()

    call MeleeTownHall(0, Hall)
    call MeleeTownHall(1, Hall)
    if Hall != Mine and GetGold() < 1500 then //In case of a custom mine
        call SecondaryTown(mine, 1, Mine)
    endif
    call SetBuildUnit(5, GoldHarvester)
    call SetBuildUnit(2, WoodHarvester)
    call SetBuildUnit(1, House)
    call SetBuildUnit(7, GoldHarvester)
    call SetBuildUnit(1, Altar)
    call SetBuildUnit(1, Barracks)
    call SetBuildUnit(8, GoldHarvester)
    call SetBuildUnit(1, hero_id)
    if KeepBasicMelee then
        if GetUpgradeLevel(MiscUpgrade6) == 0 then
            call SetBuildUnit(1, BasicMelee)
        else
            call SetBuildUnit(1, BasicMeleeUpg)
        endif
    endif
    call SetBuildUnit(2, House)
    if KeepBasicMelee then
        if GetUpgradeLevel(MiscUpgrade6) == 0 then
            call SetBuildUnit(3, BasicMelee)
        else
            call SetBuildUnit(3, BasicMeleeUpg)
        endif
    endif                        
    call SetBuildUnit(2, Barracks)
    call SetBuildUnit(1, Blacksmith)
    call SetBuildUnit(2, BasicRanged)
    if Blacksmith != LumberMill then
        call SetBuildUnit(1, LumberMill)
    endif
    call SetBuildUnit(3, BasicRanged)
    call SetBuildUnit(3, House)
    if KeepBasicMelee then
        if GetUpgradeLevel(MiscUpgrade6) == 0 then
            call SetBuildUnit(5, BasicMelee)
        else
            call SetBuildUnit(5, BasicMeleeUpg)
        endif
    endif
    call SetBuildUnit(5, BasicRanged)
    call SetBuildUpgr(1, BasicMeleeUpgrade)
    call SetBuildUpgr(1, AttackUpgrade1)
    call SetBuildUpgr(1, AttackUpgrade2)
    call SetBuildUpgr(1, DefenseUpgrade1)
    call SetBuildUnit(1, HallTier2)
    call SetBuildUnit(10, GoldHarvester)
    call BuildExpansion(GetMinesOwned() < MinesToOwn)
    call SetBuildUpgr(1, BasicRangedUpgrade)
    call SetBuildUpgr(1, LumberHarvestUpgrade)
    call SetBuildUnit(1, Spire)
    call SetBuildUnit(1, SpecializedBarracks)
    if GetUnitCountDone(Shipyard) > 0 then
        call SetBuildUnit(2, AssaultFlyer)
    endif
    if MeleeDifficulty() != MELEE_NEWBIE and Heroes > 1 then //2 heroes? kthxbai
        call SetBuildUnit(1, hero_id2)
    else //Adding some cannon fodder, >= 5 food in total, I hope...
        if KeepBasicMelee then
            if GetUpgradeLevel(MiscUpgrade6) == 0 then
                call SetBuildUnit(6, BasicMelee)
            else
                call SetBuildUnit(6, BasicMeleeUpg)
            endif
        else
            if GetUpgradeLevel(MiscUpgrade6) == 0 then
                call SetBuildUnit(1, BasicMelee)
            else
                call SetBuildUnit(1, BasicMeleeUpg)
            endif
        endif
        call SetBuildUnit(6, BasicRanged)
    endif
    call SetBuildUnit(6, House)
    if GetUpgradeLevel(MiscUpgrade2) == 0 then
        call SetBuildUnit(4, OwnageMelee)
    else
        call SetBuildUnit(4, OwnageMeleeUpg)
    endif
    call SetBuildUnit(1, CasterBarracks)
    call SetBuildUnit(3, CasterFlyer)
    call SetBuildUpgr(1, MiscUpgrade1)
    call SetBuildUnit(9, House)
    if GetUpgradeLevel(MiscUpgrade2) == 0 then
        call SetBuildUnit(6, OwnageMelee)
    else
        call SetBuildUnit(6, OwnageMeleeUpg)
    endif
    call SetBuildUnit(1, HallTier3)
    call SetBuildUnit(2, Tower)
    call SetBuildUnit(1, TowerUpg1)
    call SetBuildUnit(3, Tower)
    call SetBuildUpgr(1, MiscUpgrade1)
    call SetBuildUnit(1, SupportCaster)
    call SetBuildUnit(2, TowerUpg1)
    call SetBuildUnit(1, MainCaster)
    call SetBuildUnit(1, UltimateBarracks)
    call SetBuildUnit(2, SpecializedBarracks)
    call SetBuildUnit(10, House)
    call SetBuildUpgr(1, MainCasterUpgrade)
    call SetBuildUpgr(1, SupportCasterUpgrade)
    if PurifierNotDone then
        if GetUnitCountDone(Purifier) > 0 then
            set PurifierNotDone = false
        else
            call SetBuildUnit(1, Purifier)
        endif
    endif
    if GetUnitCountDone(Shipyard) > 0 then
        call SetBuildUnit(3, Destroyer)
    endif
    if GetUnitCountDone(NavalBlacksmith) > 0 then
        call SetBuildUpgr(1, NavalAttackUpgrade)
        call SetBuildUpgr(1, NavalDefenseUpgrade)
    endif
   if GetUnitCountDone(Shipyard) > 0 and GetUnitCountDone(AssaultFlyer) < 2 then
    call SetBuildUnit(2, AssaultFlyer)
    endif
    call SetBuildUnit(1, TowerUpg2)
    if GetUpgradeLevel(MiscUpgrade11) == 0 then
        call SetBuildUnit(2, SiegeRanged)
    else
        call SetBuildUnit(2, SiegeRangedUpg)
    endif
    if GetMinesOwned() > 1 then
        call SetBuildUnit(15, GoldHarvester)
    endif
    call SetBuildUpgr(2, LumberHarvestUpgrade)
    if MeleeDifficulty() == MELEE_INSANE and Heroes > 2 then //3 heroes? 1337sauce
        call SetBuildUnit(1, hero_id3)
    else
        if GetUpgradeLevel(MiscUpgrade3) == 0 then
            call SetBuildUnit(7, OwnageMelee)
        else
            call SetBuildUnit(7, OwnageMeleeUpg)
        endif
    endif
    call SetBuildUnit(1, Church)
    call SetBuildUpgr(1, MiscUpgrade2)
    call SetBuildUpgr(1, MiscUpgrade3)
    if MeleeDifficulty() != MELEE_NEWBIE then
        call SecondaryTown(mine, 3, Tower)
        call SecondaryTown(mine, 2, TowerUpg1)
        call SecondaryTown(mine, 1, TowerUpg2)
    endif
    call SetBuildUpgr(2, AttackUpgrade1)
    call SetBuildUpgr(2, AttackUpgrade2)
    call SetBuildUpgr(2, DefenseUpgrade1)
    call SetBuildUnit(12, House)
    if GetUnitCount(Purifier) == 0 then
        if MeleeDifficulty() == MELEE_INSANE and Heroes > 2 then
            if GetUpgradeLevel(MiscUpgrade3) == 0 then
                call SetBuildUnit(7, OwnageMelee)
            else
                call SetBuildUnit(7, OwnageMeleeUpg)
            endif
        else
            if GetUpgradeLevel(MiscUpgrade3) == 0 then
                call SetBuildUnit(8, OwnageMelee)
            else
                call SetBuildUnit(8, OwnageMeleeUpg)
            endif
        endif
    endif
    if GetUnitCountDone(Shipyard) > 0 then
        call SetBuildUnit(3, Submarine)
        call SetBuildUnit(5, Destroyer)
        call SetBuildUnit(5, Submarine)
    endif

    call SetBuildUnit(1, FlyingBarracks)
    call SetBuildUnit(3, AirGround)
    call SetBuildUpgr(1, MiscUpgrade4)
    call SetBuildUpgr(1, MiscUpgrade5)
    call SetBuildUnit(2, ResurrectionWagon)
    call SetBuildUnit(2, AirAir)
    call SetBuildUpgr(1, BuildingDefenseUpgrade)
    if GetUnitCountDone(NavalBlacksmith) > 0 then
        call SetBuildUpgr(2, NavalAttackUpgrade)
        call SetBuildUpgr(2, NavalDefenseUpgrade)
    endif
    call SetBuildUnit(13, House)
    if GetUnitCountDone(Shipyard) > 0 and GetUnitCountDone(NavalBlacksmith) > 0 then
        call SetBuildUnit(2, HeavyShip)
    endif
    call SetBuildUpgr(2, BuildingDefenseUpgrade)
    call SetBuildUpgr(1, MiscUpgrade6)
    call SetBuildUpgr(1, MiscUpgrade7)
    call SetBuildUpgr(1, MiscUpgrade8)
    call SetBuildUpgr(1, MiscUpgrade9)
    call SetBuildUpgr(1, MiscUpgrade10)
    call SetBuildUpgr(1, MiscUpgrade11)
    call SetBuildUpgr(1, MiscUpgrade12)
    if MeleeDifficulty() == MELEE_INSANE then
        call SetBuildUnit(6, Tower2)
    endif
endfunction

function GuysAtWork takes nothing returns nothing
    local integer mine
    loop
        call UpdateConditions()
        call ClearHarvestAI()
        set mine = TownWithMine()
        call HarvestGold(mine + 0, GoldGuys1)
        call HarvestWood(0, WoodGuys1)
        if GoldGuys2 != 0 and GetMinesOwned() >= 2 then
            call HarvestGold(mine + 1, GoldGuys2)
        endif
        if WoodGuys2 != 0 then
            call HarvestWood(0, WoodGuys2)
        endif
        call BuildPriorities()
        call Sleep(2)
    endloop
endfunction

//***************************************************************************
//*
//*  Attacking
//*
//***************************************************************************

//===========================================================================
// Returns true if the minimum forces for an attack exist
//===========================================================================
function HaveMinimumAttackers takes nothing returns boolean

    // Check for attack wave limit
    if attackWave > 3 or (GetUnitCountDone(Shipyard) == 0 and attackWave > 2) then
        return false
    endif

    return CanAttack
endfunction

//===========================================================================
// Assigns units to attack based on the given attack group
//===========================================================================
function PrepareAttackGroup takes integer groupID returns nothing

    // Attack Group #1: Minimum Attack
    if (groupID == 1) then
        call SetAssaultGroup(GetUnitCountDone(hero_id), -1, hero_id)
        call SetAssaultGroup(GetUnitCountDone(BasicRanged), -1, BasicRanged)
        call SetAssaultGroup(GetUnitCountDone(BasicMelee), -1, BasicMelee)
        call SetAssaultGroup(GetUnitCountDone(BasicMeleeUpg), -1, BasicMeleeUpg)
        if (FoodCap() >= AIHasOwnageMelee) then
            call SetAssaultGroup(GetUnitCountDone(OwnageMelee), -1, OwnageMelee)
            call SetAssaultGroup(GetUnitCountDone(OwnageMeleeUpg), -1, OwnageMeleeUpg)
        endif

    // Attack Group #2: Main Units
    elseif (groupID == 2) then
        call SetAssaultGroup(GetUnitCountDone(hero_id), -1, hero_id)
        if Heroes > 1 then //Just in case =)
            call SetAssaultGroup(GetUnitCountDone(hero_id2), -1, hero_id2)
            if Heroes > 2 then
                call SetAssaultGroup(GetUnitCountDone(hero_id3), -1, hero_id3)
            endif
        endif
        call SetAssaultGroup(GetUnitCountDone(BasicRanged), -1, BasicRanged)
        call SetAssaultGroup(GetUnitCountDone(BasicMelee), -1, BasicMelee)
        call SetAssaultGroup(GetUnitCountDone(BasicMeleeUpg), -1, BasicMeleeUpg)
        call SetAssaultGroup(GetUnitCountDone(OwnageMelee), -1, OwnageMelee)
        call SetAssaultGroup(GetUnitCountDone(OwnageMeleeUpg), -1, OwnageMelee)
        call SetAssaultGroup(GetUnitCountDone(SupportCaster), -1, SupportCaster)
        call SetAssaultGroup(GetUnitCountDone(MainCaster), -1, MainCaster)
        call SetAssaultGroup(GetUnitCountDone(AirGround), -1, AirGround)
        call SetAssaultGroup(GetUnitCountDone(AirAir), -1, AirAir)
        call SetAssaultGroup(GetUnitCountDone(SiegeRanged), -1, SiegeRanged)
        call SetAssaultGroup(GetUnitCountDone(SiegeRangedUpg), -1, SiegeRangedUpg)
        call SetAssaultGroup(GetUnitCountDone(Purifier), -1, Purifier)
        call SetAssaultGroup(GetUnitCountDone(ResurrectionWagon), -1, ResurrectionWagon)
        call SetAssaultGroup(GetUnitCountDone(MiscUnit1), -1, MiscUnit1)
        call SetAssaultGroup(GetUnitCountDone(MiscUnit2), -1, MiscUnit2)
        call SetAssaultGroup(GetUnitCountDone(AssaultFlyer), -1, AssaultFlyer)
        call SetAssaultGroup(GetUnitCountDone(CasterFlyer), -1, CasterFlyer)

    // Attack Group #3: Naval Units
    elseif (groupID == 3) then
        call InitAssaultGroup()
        call SetAssaultGroup(GetUnitCountDone(Destroyer), -1, Destroyer)
        call SetAssaultGroup(GetUnitCountDone(Submarine), -1, Submarine)
        call SetAssaultGroup(GetUnitCountDone(HeavyShip), -1, HeavyShip)
    endif
endfunction

//===========================================================================
// Prepares an attack group based on the current attack wave
//===========================================================================
function PrepareForces takes nothing returns nothing
    if attackWave == 1 then
        call PrepareAttackGroup(1)
    elseif attackWave == 2 then
        call PrepareAttackGroup(2)
    elseif attackWave == 3 then
        call PrepareAttackGroup(3)
    endif
endfunction

//===========================================================================
// Sleep delays for each attack wave
//===========================================================================
function AttackWaveDelay takes integer inWave returns nothing
    if inWave < nextDelay then
        return
    endif

    if inWave == 1 then
        call Sleep(2)
    endif

    set nextDelay = inWave + 1
endfunction

//===========================================================================
// Advances attack wave counter
//===========================================================================
function AttackWaveUpdate takes nothing returns nothing
    call AttackWaveDelay(attackWave)
    set attackWave = attackWave + 1
    if attackWave > 3 or (GetUnitCountDone(Shipyard) == 0 and attackWave > 2) then
        set attackWave = 2
        set nextDelay = attackWave + 1
    endif
endfunction

//===========================================================================
// Basic attack functionality
//===========================================================================
function AttackTarget takes unit target, boolean addAlliance returns nothing
    if target == null then
        return
    endif
    if addAlliance then
        call SetAllianceTarget(target)
    endif
    call FormGroup(3, true)
    call AttackMoveKillA(target)
    if (not addAlliance) then
        call SetAllianceTarget(null)
    endif
endfunction

//===========================================================================
// Initiates an attack based on target priorities
//===========================================================================
function LaunchAttack takes nothing returns nothing
    local unit target = null
    local boolean setAlly = true

    // Don't launch any attack while town is threatened
    if TownThreatened() then
        call Sleep(2)
        return
    endif

    // Target Priority #1 = Helping an ally Assault/Defence
    if (target == null) then
        set target = GetAllianceTarget()
        if (target != null) then
            set setAlly = false
        endif
    endif

    // Target Priority #2 = Preparing an expansion
    if FoodUsed() >= Food4Exp then
        if ((GetUnitCountDone(OwnageMelee) + GetUnitCountDone(OwnageMeleeUpg)) >= MinimumForceOwnageMelee) then //Knights or gtfo
            if (target == null) then
                set target = GetExpansionFoe()
            endif
        endif
    endif

    // Target Priority #3 = Woot, MegaTarget? (MegaTarget is the enemy's main)
    if FoodUsed() >= Food4Attack then
        if (target == null) then
            set target = GetMegaTarget()
        endif

    // Target Priority #4 = Either enemy expansions or an enemy base
        if (target == null) then
            set target = GetEnemyExpansion()
            if (target == null) then
                call StartGetEnemyBase()
                loop
                    exitwhen (not WaitGetEnemyBase())
                    call SuicideSleep(1)
                endloop
                set target = GetEnemyBase()
            endif
        endif
    endif

    // Target Priority #5 = Small creep camps
    if FoodUsed() < Food4Attack then
        if target == null then
            set target = GetCreepCamp(0, 9, false)
        endif
    endif

    // Target Priority #6 = Huge creep camps
    if FoodUsed() >= Food4Attack then
        if (target == null) then
            set target = GetCreepCamp(10, 100, true)
        endif
    endif

    // Target Priority #7 = Goblin Zeppelin
    if (GetUnitCount('nzep') < 1) then
        if (target == null) then
            call PurchaseZeppelin()
            return
        endif
    endif

    // Attack the target and increment attack wave
    if (target != null) then
        call AttackTarget(target, setAlly)
        call AttackWaveUpdate()
    else
        // If no target was found, sleep a bit before trying again
        call Sleep(20)
    endif
endfunction

//===========================================================================
// Determines all attacking assignments
//===========================================================================
function AttackAssignment takes nothing returns nothing
local integer n = 0
    call StaggerSleep(0, 2)
    if (attackWave == 1) then
        call AttackWaveDelay(0)
    endif
    loop
        call UpdateConditions()
        if (HaveMinimumAttackers() and not CaptainRetreating()) then
            if n == 2 then
                call Sleep(2)
                set n = 0
            else
                set n = n + 1
                call RemoveInjuries()
                call InitAssaultGroup()
                call PrepareForces()
                call LaunchAttack()
            endif
        else
            call Sleep(2)
        endif
    endloop
endfunction

//***************************************************************************
//*
//*  Main Entry Point
//*
//***************************************************************************

//===========================================================================
function main takes nothing returns nothing
    set ai_player = Player(GetAiPlayer())
    set MinesToOwn = 1 + MeleeDifficulty()
    if WantName then
        call SetPlayerName(ai_player, Name)
    endif
    call InitOptions()
    call PickRacialHero()
    call SetSkills()
    call CreateCaptains()
    call StandardAI(function SkillArrays, function GuysAtWork, function AttackAssignment)
    if IsAmphibious then
        call SetAmphibious()
    endif
    call PlayGame()
endfunction



JASS:
library AIForcer initializer Init requires TimerUtils, CSCache

globals
    private constant real    dt              = 0.8 // sets the timer period
    private constant real    range           = 5000. // sets the max range that units will move before building the build :P
    
    private          integer DataIndex = 0
    private          integer array DataIndexes
    
    private          integer DatabaseCounter = 0
    private          integer array DataBaseindexes
    
    private          group    G = CreateGroup()
    private          boolexpr Cnd1 //conditional used to get free unit builders
endglobals

// FILTERS
private function GetUnit takes nothing returns boolean
    // gets avaliable units...
    return GetUnitTypeId(GetFilterUnit()) == bj_groupEnumTypeId and GetUnitCurrentOrder(GetFilterUnit()) == OrderId("harvest") and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction
// END FILTERS

private struct Data
    unit builder
    integer build
    player p
    real px
    real py
    real a
    
    static method create takes unit c, integer id returns Data
        local Data D = Data.allocate()
        set D.builder = c
        set D.build = id
        set D.p = GetOwningPlayer(c)
        set D.px = GetPlayerStartLocationX(D.p)
        set D.py = GetPlayerStartLocationY(D.p)
        set D.a = GetRandomReal(0, 2*bj_PI)
        set DataIndex = DataIndex + 1
        set DataIndexes[DataIndex] = integer(D)
        return D
    endmethod
    
    private method RemoveIndex takes nothing returns nothing
        local integer p = integer(this)
        local integer i = 1
        loop
            exitwhen DataIndexes[i] == p or i > DataIndex
            set i = i + 1
        endloop
        if i < DataIndex then
            loop
                exitwhen i == DataIndex
                set DataIndexes[i] = DataIndexes[i+1]
                set i = i + 1
            endloop
        endif
        set DataIndex = DataIndex - 1
    endmethod
    
    method onDestroy takes nothing returns nothing
        call this.RemoveIndex()
    endmethod
    
    static method IsQueued takes integer id, player p returns boolean
        local integer i = 1
        local Data D 
        loop
            exitwhen i > DataIndex
            set D = Data( DataIndexes[i] )
            exitwhen D.build == id and D.p == p
            set i = i + 1
        endloop
        return i <= DataIndex
    endmethod
endstruct

struct BuildUnit
    integer id
    integer goldcost
    integer lumbercost
    integer builder
    integer array req [3]
    
    private static method HasReq takes integer id, player p returns boolean
        local BuildUnit BU
        local integer i = 1
        local boolean b
        loop
            exitwhen i > DatabaseCounter
            set BU = BuildUnit(DataBaseindexes[i])
            exitwhen BU.id == id
            set i = i + 1
        endloop
        if i <= DatabaseCounter then
            set b = (GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) >= BU.goldcost) and (GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) >= BU.lumbercost) and (CountLivingPlayerUnitsOfTypeId(BU.builder, p) > 0)
            if BU.req[0] != 0 then
                set b = b and (CountLivingPlayerUnitsOfTypeId(BU.req[0], p) > 0)
            endif
            if BU.req[1] != 0 then
                set b = b and (CountLivingPlayerUnitsOfTypeId(BU.req[1], p) > 0)
            endif
            if BU.req[2] != 0 then
                set b = b and (CountLivingPlayerUnitsOfTypeId(BU.req[2], p) > 0)
            endif
            return b
        else
            return false
        endif
    endmethod
    
    private static method GetBuilderID takes integer id returns integer 
        local BuildUnit BU
        local integer i = 1
        local boolean b
        loop
            exitwhen i > DatabaseCounter
            set BU = BuildUnit(DataBaseindexes[i])
            exitwhen BU.id == id
            set i = i + 1
        endloop
        if i <= DatabaseCounter then
            return BU.builder
        else
            return 0
        endif
    endmethod
    
    private static method GetBuilder takes player p, integer build returns unit 
        local unit u
        set bj_groupEnumTypeId = BuildUnit.GetBuilderID(build)
        call GroupEnumUnitsOfPlayer(G, p, Cnd1)
        set u = FirstOfGroup(G)
        call GroupClear(G)
        return u
    endmethod
    
    private static method Loop takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local Data D = Data( GetAttachedInt(t, "Data") )
        local timer t2 = NewTimer()
        if IssueBuildOrderById(D.builder, D.build, GetUnitX(D.builder), GetUnitY(D.builder)) or GetWidgetLife(D.builder) < 0.405 then
            call D.destroy()
            call CleanAttachedVars(t)
            call ReleaseTimer(t)
        else
            call IssuePointOrder(D.builder, "move", D.px + range * Cos(D.a), D.py + range * Sin(D.a))
            set D.a = D.a + GetRandomReal(0., bj_PI * dt / 40.)
        endif
        set t = null
    endmethod
    
    static method AddUnitData takes integer id, integer gold, integer lumber, integer b, integer req1, integer req2, integer req3 returns BuildUnit
        local BuildUnit BU = BuildUnit.allocate()
        set BU.id = id
        set BU.goldcost = gold
        set BU.lumbercost = lumber
        set BU.builder = b
        set BU.req[0] = req1
        set BU.req[1] = req2
        set BU.req[2] = req3
        set DatabaseCounter = DatabaseCounter + 1
        set DataBaseindexes[DatabaseCounter] = integer(BU)
        return BU
    endmethod
    
    static method Build takes player p, integer build, integer amount returns nothing
        local unit u = BuildUnit.GetBuilder(p, build)
        local timer t
        local Data D
        if CountLivingPlayerUnitsOfTypeId(build, p) < amount and u != null and BuildUnit.HasReq(build, p) and not Data.IsQueued(build, p) then
            set t = NewTimer()
            set D = Data.create(u, build)
            call AttachInt(t, "Data", integer(D))
            call TimerStart(t, dt, true, function BuildUnit.Loop)
        endif
        set t = null
    endmethod
endstruct

private function Init takes nothing returns nothing
    set Cnd1 = Condition(function GetUnit)
endfunction

endlibrary



JASS:
library AISetup requires AIForcer

globals
    private constant real  dt = 1.
    private          force F  = CreateForce()
    private          integer array Names
    private          integer Nindex = 0
endglobals

private struct AINames
    string n = ""
    
    static method add takes string s returns AINames
        local AINames AN = AINames.allocate()
        set AN.n = s
        set Nindex = Nindex + 1
        set Names[Nindex] = integer(AN)
        return AN
    endmethod
    
    private method RemoveIndex takes nothing returns nothing
        local integer p = integer(this)
        local integer i = 1
        loop
            exitwhen Names[i] == p or i > Nindex
            set i = i + 1
        endloop
        if i < Nindex then
            loop
                exitwhen i == Nindex
                set Names[i] = Names[i+1]
                set i = i + 1
            endloop
        endif
        set Nindex = Nindex - 1
    endmethod
    
    method onDestroy takes nothing returns nothing
        call this.RemoveIndex()
    endmethod
    
    static method GetRandomName takes integer low, integer high returns string 
        local integer i = GetRandomInt(low, high)
        local AINames AN = AINames(Names[i])
        local string s = AN.n
        call AN.destroy()
        return s
    endmethod
endstruct

//=========================================================
//||        FUNCTIONS THAT YOU CAN EDIT KAM!!!           ||
//=========================================================
private function FillDatabase takes nothing returns nothing
    // Use this function to add and update the info about the buildings that normally the AI can't build by itself
    //                         BUILD   GOLD LUM  BUIDER   REQ1    REQ2   REQ3
    call BuildUnit.AddUnitData('h00A', 160, 100, 'h000',      0,      0,      0) // Human Shipyard
    call BuildUnit.AddUnitData('h009', 250, 120, 'h000', 'h00A',      0,      0) // Human Foundry
    call BuildUnit.AddUnitData('o004', 180, 100, 'o003',      0,      0,      0) // Orc Shipyard
    call BuildUnit.AddUnitData('o007', 250, 100, 'o003', 'o004',      0,      0) // Orc Foundry
    // AI NAMES (Disabled, names are given by the "AI Name" trigger)
    call AINames.add("BlackHand") //Orc names
    call AINames.add("Ogrim")
    call AINames.add("Rockhan")
    call AINames.add("Misha")
    call AINames.add("Khadgar") //Human Names
    call AINames.add("Aegwynn")
    call AINames.add("Halahk")
    call AINames.add("Jaina")
endfunction

private function ForceBuild takes nothing returns nothing
    // You can edit the order and priority changing the value and the functions
    if GetPlayerRace(GetEnumPlayer()) == RACE_HUMAN then
        call BuildUnit.Build(GetEnumPlayer(), 'h00A', 1)
        call BuildUnit.Build(GetEnumPlayer(), 'h009', 1)
    else
       if GetPlayerRace(GetEnumPlayer()) == RACE_NIGHTELF then
        call BuildUnit.Build(GetEnumPlayer(), 'h00A', 1)
        call BuildUnit.Build(GetEnumPlayer(), 'h009', 1)
    else
       if GetPlayerRace(GetEnumPlayer()) == RACE_ORC then
        call BuildUnit.Build(GetEnumPlayer(), 'o004', 1)
        call BuildUnit.Build(GetEnumPlayer(), 'o007', 1)
    else
       if GetPlayerRace(GetEnumPlayer()) == RACE_UNDEAD then
        call BuildUnit.Build(GetEnumPlayer(), 'o004', 1)
        call BuildUnit.Build(GetEnumPlayer(), 'o007', 1)
    endif
    endif
    endif
    endif
endfunction
//=========================================================
//||      END FUNCTIONS THAT YOU CAN EDIT KAM!!!         ||
//=========================================================


private function Loop takes nothing returns boolean
    call ForForce(F, function ForceBuild)
    return true
endfunction 

function InitTrig_AI_Setup takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    local player p
    call FillDatabase()
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        set p = Player(i)
        if GetPlayerController(p) == MAP_CONTROL_COMPUTER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
            call ForceAddPlayer(F, p)
            if GetPlayerRace(p) == RACE_HUMAN then
                call PickMeleeAI(p, "Alliance.ai", null, null)
//                call SetPlayerName(p, AINames.GetRandomName(1, 4))
            else
            if GetPlayerRace(p) == RACE_NIGHTELF then
                call PickMeleeAI(p, "Alliance.ai", null, null)
//                call SetPlayerName(p, AINames.GetRandomName(1, 4))
            else
           if GetPlayerRace(p) == RACE_ORC then
                call PickMeleeAI(p, "Horde.ai", null, null)
//                call SetPlayerName(p, AINames.GetRandomName(5, Nindex))
            else
           if GetPlayerRace(p) == RACE_UNDEAD then
                call PickMeleeAI(p, "Horde.ai", null, null)
//                call SetPlayerName(p, AINames.GetRandomName(5, Nindex))
            endif    
        endif
        endif
        endif
        endif
        set i = i + 1
    endloop
    call TriggerRegisterTimerEvent(t, 450, true) //Will build after 7 and a half minutes
    call TriggerAddCondition(t, Condition(function Loop))
    call TriggerExecute(gg_trg_AI_Name) //Starts "AI Name" trigger
endfunction

endlibrary
 
Last edited:
Level 18
Joined
Jan 21, 2006
Messages
2,552
Okay well first of all you're going to have to post the code using
JASS:
 tags; I can't really read code like this without indentation or formatting in any way. Just surround what you've posted in [code=jass] tags within the [HIDDEN] tags.

[code=jass]function Example takes nothing returns nothing
    local integer i = 0
        loop
            exitwhen i == 3
            set i = i + 1
        endloop
endfunction
 
AI scripts, barf.

The problem could very well be in an AI native function call, and I can assure you that some of the AI natives can cause crashes.

I deliberately avoid AI scripts because Blizzard's AI had problems just from my experiences with single-player missions. And it lacks a LOT of features. I program everything myself and avoid ambiguous natives.
 
Well it just started recently, so I'm not sure. I'd appreciate it if you could look through each script as I'm really just wanting to finish my project and this is all that's left.

The significant changes recently were to identify all four races in the AI scripts (Orc and Undead, and Human and Nightelf) so people could choose their race. There is also a structure that has four building requirements now.
 
I found a definite cause for a crash in Naval AI Forcer. The "Loop" method in the BuildUnit struct was calling NewTimer for a local timer called t2, and that timer was never being used, recycled or anything, so after some time into the game, TimerUtils hits its limit and the timers no longer work properly ;)

I eliminated the requirement for CSCache as TimerUtils does not need it in its current version (http://www.wc3c.net/showthread.php?t=101322).

Hopefully this solves the problem.

JASS:
library AIForcer requires TimerUtils

globals
    private constant real    dt              = 0.8 // sets the timer period
    private constant real    range           = 5000. // sets the max range that units will move before building the build :P
    
    private          integer DataIndex = 0
    private          integer array DataIndexes
    
    private          integer DatabaseCounter = 0
    private          integer array DataBaseindexes
    
    private          group    G = CreateGroup()
endglobals
    
    native UnitAlive takes unit id returns boolean
    
// FILTERS
private function GetUnit takes nothing returns boolean
    // gets avaliable units...
    return GetUnitTypeId(GetFilterUnit()) == bj_groupEnumTypeId and GetUnitCurrentOrder(GetFilterUnit()) == OrderId("harvest") and UnitAlive(GetFilterUnit())
endfunction
// END FILTERS

private struct data
    unit builder
    integer build
    player p
    real px
    real py
    real a
    
    static method create takes unit c, integer id returns thistype
        local thistype dat = thistype.allocate()
        set dat.builder = c
        set dat.build = id
        set dat.p = GetOwningPlayer(c)
        set dat.px = GetPlayerStartLocationX(dat.p)
        set dat.py = GetPlayerStartLocationY(dat.p)
        set dat.a = GetRandomReal(0, 2*bj_PI)
        set DataIndex = DataIndex + 1
        set DataIndexes[DataIndex] = integer(dat)
        return dat
    endmethod
    
    private method RemoveIndex takes nothing returns nothing
        local integer p = integer(this)
        local integer i = 1
        loop
            exitwhen DataIndexes[i] == p or i > DataIndex
            set i = i + 1
        endloop
        if i < DataIndex then
            loop
                exitwhen i == DataIndex
                set DataIndexes[i] = DataIndexes[i+1]
                set i = i + 1
            endloop
        endif
        set DataIndex = DataIndex - 1
    endmethod
    
    method onDestroy takes nothing returns nothing
        call this.RemoveIndex()
    endmethod
    
    static method IsQueued takes integer id, player p returns boolean
        local integer i = 1
        local thistype dat 
        loop
            exitwhen i > DataIndex
            set dat = thistype( DataIndexes[i] )
            exitwhen dat.build == id and dat.p == p
            set i = i + 1
        endloop
        return i <= DataIndex
    endmethod
endstruct

struct BuildUnit
    integer id
    integer goldcost
    integer lumbercost
    integer builder
    integer array req [3]
    
    private static method HasReq takes integer id, player p returns boolean
        local thistype bu
        local integer i = 1
        local boolean b
        loop
            exitwhen i > DatabaseCounter
            set bu = thistype(DataBaseindexes[i])
            exitwhen bu.id == id
            set i = i + 1
        endloop
        if i <= DatabaseCounter then
            set b = (GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) >= bu.goldcost) and (GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) >= bu.lumbercost) and (CountLivingPlayerUnitsOfTypeId(bu.builder, p) > 0)
            if bu.req[0] != 0 then
                set b = b and (CountLivingPlayerUnitsOfTypeId(bu.req[0], p) > 0)
            endif
            if bu.req[1] != 0 then
                set b = b and (CountLivingPlayerUnitsOfTypeId(bu.req[1], p) > 0)
            endif
            if bu.req[2] != 0 then
                set b = b and (CountLivingPlayerUnitsOfTypeId(bu.req[2], p) > 0)
            endif
            return b
        else
            return false
        endif
    endmethod
    
    private static method GetBuilderID takes integer id returns integer 
        local thistype bu
        local integer i = 1
        local boolean b
        loop
            exitwhen i > DatabaseCounter
            set bu = thistype(DataBaseindexes[i])
            exitwhen bu.id == id
            set i = i + 1
        endloop
        if i <= DatabaseCounter then
            return bu.builder
        else
            return 0
        endif
    endmethod
    
    private static method GetBuilder takes player p, integer build returns unit 
        set bj_groupEnumTypeId = thistype.GetBuilderID(build)
        call GroupEnumUnitsOfPlayer(G, p, Filter(function GetUnit)) // Filter used to get free unit builders
        return FirstOfGroup(G)
    endmethod
    
    private static method Loop takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local data dat = data(GetTimerData(t))
        if IssueBuildOrderById(dat.builder, dat.build, GetUnitX(dat.builder), GetUnitY(dat.builder)) or not UnitAlive(dat.builder) then
            call dat.destroy()
            call ReleaseTimer(t)
        else
            call IssuePointOrder(dat.builder, "move", dat.px + range * Cos(dat.a), dat.py + range * Sin(dat.a))
            set dat.a = dat.a + GetRandomReal(0.0, bj_PI * dt / 40.0)
        endif
    endmethod
    
    static method AddUnitData takes integer id, integer gold, integer lumber, integer b, integer req1, integer req2, integer req3 returns thistype
        local thistype bu = thistype.allocate()
        set bu.id = id
        set bu.goldcost = gold
        set bu.lumbercost = lumber
        set bu.builder = b
        set bu.req[0] = req1
        set bu.req[1] = req2
        set bu.req[2] = req3
        set DatabaseCounter = DatabaseCounter + 1
        set DataBaseindexes[DatabaseCounter] = integer(bu)
        return bu
    endmethod
    
    static method Build takes player p, integer build, integer amount returns nothing
        local unit u = thistype.GetBuilder(p, build)
        local timer t
        local data dat
        if CountLivingPlayerUnitsOfTypeId(build, p) < amount and u != null and thistype.HasReq(build, p) and not data.IsQueued(build, p) then
            set t = NewTimer()
            set dat = data.create(u, build)
            call SetTimerData(t, integer(dat))
            call TimerStart(t, dt, true, function thistype.Loop)
        endif
        set t = null
    endmethod
endstruct

endlibrary

I optimized the AISetup library and got rid of the AINames struct that didn't do anything, which saves on array space in your map as well.

JASS:
library AISetup initializer init requires AIForcer

    globals
        private force  ComputerForce = CreateForce()
        private player TempPlayer
        private race   TempRace
    endglobals

    //====================================
    //||        Configurables           ||
    //====================================

    private function FillDatabase takes nothing returns nothing
        // Use this function to add and update buildings which the AI doesn't build natively
        //                         BUILD  GOLD LMBR  BUIDER    REQ1    REQ2    REQ3
        call BuildUnit.AddUnitData('h00A', 160, 100, 'h000',      0,      0,      0) // Human Shipyard
        call BuildUnit.AddUnitData('h009', 250, 120, 'h000', 'h00A',      0,      0) // Human Foundry
        call BuildUnit.AddUnitData('o004', 180, 100, 'o003',      0,      0,      0) // Orc Shipyard
        call BuildUnit.AddUnitData('o007', 250, 100, 'o003', 'o004',      0,      0) // Orc Foundry
    endfunction

    private function ForceBuild takes nothing returns nothing
        set TempPlayer = GetEnumPlayer()
        set TempRace = GetPlayerRace(TempPlayer)
        
        // You can edit the order and priority changing the value and the functions
        
        if TempRace == RACE_HUMAN then
            call BuildUnit.Build(TempPlayer, 'h00A', 1)
            call BuildUnit.Build(TempPlayer, 'h009', 1)
            
        elseif TempRace == RACE_NIGHTELF then
            call BuildUnit.Build(TempPlayer, 'h00A', 1)
            call BuildUnit.Build(TempPlayer, 'h009', 1)
            
        elseif TempRace == RACE_ORC then
            call BuildUnit.Build(TempPlayer, 'o004', 1)
            call BuildUnit.Build(TempPlayer, 'o007', 1)
            
        elseif TempRace == RACE_UNDEAD then
            call BuildUnit.Build(TempPlayer, 'o004', 1)
            call BuildUnit.Build(TempPlayer, 'o007', 1)
        endif
    endfunction

    //====================================
    //||      End Configurables         ||
    //====================================


    private function Loop takes nothing returns nothing
        call ForForce(ComputerForce, function ForceBuild)
    endfunction 

    private function init takes nothing returns nothing
        local integer i = 0
        call FillDatabase()
        loop
            set TempPlayer = Player(i)
            set TempRace = GetPlayerRace(TempPlayer)
            if GetPlayerController(TempPlayer) == MAP_CONTROL_COMPUTER and GetPlayerSlotState(TempPlayer) == PLAYER_SLOT_STATE_PLAYING then
                call ForceAddPlayer(ComputerForce, TempPlayer)
                
                if TempRace == RACE_HUMAN then
                    call PickMeleeAI(TempPlayer, "Alliance.ai", null, null)

                elseif TempRace == RACE_NIGHTELF then
                    call PickMeleeAI(TempPlayer, "Alliance.ai", null, null)

                elseif TempRace == RACE_ORC then
                    call PickMeleeAI(TempPlayer, "Horde.ai", null, null)

                elseif TempRace == RACE_UNDEAD then
                    call PickMeleeAI(TempPlayer, "Horde.ai", null, null)
                endif    
            endif
            exitwhen i == 15
            set i = i + 1
        endloop
        call TimerStart(CreateTimer(), 450.0, true, function Loop) //Will build after 7 and a half minutes
        call TriggerExecute(gg_trg_AI_Name) //Starts "AI Name" trigger
    endfunction

endlibrary
 
Last edited:
  • Like
Reactions: Kam
Level 2
Joined
Mar 15, 2009
Messages
19
This happens when I train a tower in some of my TD maps. What I do is just use a Watch Tower and then change its models to whatever and it seems to work. I don't know why it does it, I just know how to get around it.
 
Level 2
Joined
Mar 15, 2009
Messages
19
Yeah, it first happened about a year ago when I tried to upgrade to a Berserker with the "Is a building" ticked. I remade the tower using a different base custom and it worked.

And recently it has happened when using a Kodo beast as a tower and a Tauren as a tower, however when I use a Watch Tower as base and then change the object stats to the same as what I had for the Kodo tower, it works.
 
Status
Not open for further replies.
Top