Scripting tutorial?

SkelApe

Member
Elder
Joined
Nov 10, 2007
Messages
651
hello everyone. i was wondering, judging on the amount of questions asked about scripting etc that someone expirienced like 00din or Daxter would write a more in depth tutorial. im sure alot of us are confused about how it works and maybe this might help the budding scripters. it should include a list of errors like "parse error", "error near token "x" not defined" and others to do with arguements, i think it should also include lists of how they are solved. you could go into some aspects like how you compile a chl file from 1 file defining them all at the top, and you could mention how you compile from multiple files, all listed in the challenges file. maybe not so much on arravs etc just more on the common problems that people encounter. i hope its not just me that finds it really hard to start off.

thanks guys, only if you have the time
SkelApe
 
There is a bit of a tutorial in the Script Library. Usually if you clear up the first problem most of the rest of them will dissapear.

Your problem here appears to be on line 49 where AttackTest is declared. Post the code from about 10 lines on either side of it.
 
I seriously must have forgotten about those tutorials I posted in the Script Library, I guess I was just busy with OGaM. With these in mind, it should be simple enough to seperate each section into tutorials with a specific area for errors and what they mean and of course how to solve them.

EDIT: This is just something I just wrote, but it's a start.
Code:
Errors - Errors you might get when compiling a script for custom maps.

- Parse Errors
Command Parse Error: An error that basically occurs when a specific command or section of code is incorrect or can't be compiled.
  Solution: Simply put the only way to fix this is to compare the command 
	    you have used to that in the Challenge Language Documentation.

Text file Parse Error: Generally only a few people have a problem with this when they create their first script.
  Solution: A simple way to stop this happening is to create an empty text file and add it to the challenges.txt file list

- Script Arguments error
Description: This error occurs when a script contains arguments that do not exist where the script is defined or run.
  Solution: The best way to fix this is to make sure that e.g. "begin script AScript(Argument1, Argument2)" is the same as where
	    you have defined it and where you are running the script from.
 
EDIT: when i try to run GodAI as a background script, it says there is a parse error. can you suggest a solution? 

Code:
define script GodAI (1Town, 256, 22, 42, 1)
define script CentralScript

run script CentralScript

begin script CentralScript

oTown = get town with id 0
1Town = get town with id 1

start

disable load screen
set fade in time 1

run background script GodAI(1Town, 256, 22, 42, 1)

wait until 1 != 1

end script CentralScript

thanks
 
whilst we are on topic, i wondered if you could tell me where ive gone wrong here. orry for the long
script.  :D


Code:
define script AIStuff
define script RecruitArmy(nTown, nAttackSize, fDelay, fDelayVariation)
define script MoveToValidPosition(oObject, fLimit)
define script AttackTest(nTown)
define script DefendTest(nTown, nDefendSize)
define script TownManagement(nTown)
define script CreateTownArray
define script RunTownAIForAll

// Debug switch
define DEBUG = 0

// Platoon sizes.
define TINY = 10
define SMALL = 20
define MEDIUM = 80
define LARGE = 240
define LEGION = 5000

// Platoons will attack enemies within this distance.
define ATTACK_DISTANCE = 70.0

// Platoons will capture enemy towns within this distance once all enemies in area have been killed.
define CAPTURE_TOWN_DISTANCE = 60.0

// The actual number of towns on the map.
define NUMBER_OF_TOWNS = 2

// Max number of platoons in an army.
define MAX_NUMBER_OF_PLATOONS = 20
define MAX_NUMBER_OF_SIEGE_WEAPONS = 2 // Doesn't seem to work for some reason.

// The max size of the army compared to the size of the town.
define MAX_ARMY_SIZE = 30 // percent

// This array holds all town objects on the map.
global oTownArray[NUMBER_OF_TOWNS]

// MAX_NUMBER_OF_PLATOONS * NUMBER_OF_TOWNS
global oPlatoonArray[140]
global oArchersArray[140]
global oSiegeArray[140]

run script AIStuff
run script RecruitArmy(nTown, nAttackSize, fDelay, fDelayVariation)
run script MoveToValidPosition(oObject, fLimit)
run script AttackTest(nTown)
run script DefendTest(nTown, nDefendSize)
run script TownManagement(nTown)
run script CreateTownArray
run script RunTownAIForAll

begin script AIStuff
start
	run script CreateTownArray
	run background script RunTownAIForAll

end script AIStuff

begin script RecruitArmy(nTown, nAttackSize, fDelay, fDelayVariation)
	oTown = get town with id nTown

	nArmySize = 0
	nMaxArmySize = 0
	nTownSize = 0
	nRecruitSize = 0
	nDiff = 0
	nCount = 0

	nAttacker = 0
	nUnderAttack = 0

	nTownRangeMin = nTown * MAX_NUMBER_OF_PLATOONS
	nTownRangeMax = (nTown * MAX_NUMBER_OF_PLATOONS) + MAX_NUMBER_OF_PLATOONS
start
	begin loop
		nAttacker = 0
		nUnderAttack = 0
		force while nAttacker < 7
			if town oTown is under takeover from player nAttacker
				nUnderAttack = 1
			end if
			nAttacker++
		end while

		if get oTown player != 0 and nUnderAttack == 0
			begin loop
				nArmySize = get army size in town oTown
				nTownSize = adult size of oTown
				nTownSize -= nArmySize
				nMaxArmySize = (nTownSize/100) * nAttackSize

				nDiff = nMaxArmySize - nArmySize

				if nDiff >= LEGION
					nRecruitSize = LEGION
				elsif nDiff >= LARGE
					nRecruitSize = LARGE
				elsif nDiff >= MEDIUM
					nRecruitSize = MEDIUM
				elsif nDiff >= SMALL
					nRecruitSize = SMALL
				elsif nDiff >= TINY
					nRecruitSize = TINY
				else
					nRecruitSize = 0
				end if

				until nRecruitSize > 0
			end loop

			// Recruit army of nRecruitSize.
			nCount = nTownRangeMin
			force while nCount < nTownRangeMax
				if oPlatoonArray[nCount] not exists
					oPlatoonArray[nCount] = recruit ARMY_UNIT_TYPE_MELEE_1 town oTown platoon of size nRecruitSize

					if oArchersArray[nCount] not exists
						oArchersArray[nCount] = recruit ARMY_UNIT_TYPE_RANGED_1 town oTown platoon of size (nRecruitSize / 4)
					end if
					add action PLATOON_AGENDA_ACTION_LINK_TO_ARMY_MEMBER using oPlatoonArray[nCount] to oArchersArray[nCount] action queue
					nCount = nTownRangeMax
				end if
				nCount++
			end while

			fDelay = number from (fDelay - fDelayVariation) to (fDelay + fDelayVariation)
			wait fDelay seconds
		end if
	end loop

end script RecruitArmy

begin script MoveToValidPosition(oObject, fLimit)
	lTarget = 0
	lFocus = 0
	fDistance = 1.0
start
	force while fDistance <= fLimit
		if not oObject can navigate to {oObject}
			lFocus = marker at focus position of oObject
			lTarget = marker at get target from {lFocus} to {oObject} distance fDistance angle 180
			set oObject position to {lTarget}
		else
			fDistance = fLimit
		end if
		fDistance++
	end while

	// Delete object if it's still stuck.
	if not oObject can navigate to {oObject}
		delete oObject
	end if

end script MoveToValidPosition

begin script AttackTest(nTown)
	oTown = get town with id nTown
	oTownCentre = get building ABODE_NUMBER_TOWN_CENTRE in oTown min built 1.0
	nTownPlayer = 0
	nPlatoonPlayer = 0
	nPlayer = 0

	oEnemyTown = 0
	oEnemyTownCentre = 0
	oFriendlyTown = 0
	oFriendlyTownCentre = 0
	oTownMisc = 0
	oTownCentreMisc = 0

	oPlatoon = 0
	oSiegeWeapon = 0
	oEnemyPlatoon = 0
	oNextEnemyPlatoon = 0
	oEnemySiegeWeapon = 0
	oNextEnemySiegeWeapon = 0

	oWall = 0
	oGate = 0
        oGate2 = 0

	fNewDistance = 0
	fLastDistance = 0
	fFriendlyNewDistance = 0
	fFriendlyLastDistance = 0

	nTownRangeMin = nTown * MAX_NUMBER_OF_PLATOONS
	nTownRangeMax = (nTown * MAX_NUMBER_OF_PLATOONS) + MAX_NUMBER_OF_PLATOONS

	nCount = 0
	nCountMisc = 0
	nSiegeCount = 0
	nAttacker = 0
	nUnderAttack = 0
	nFriendlyTownUnderAttack = 0
	nIsCapturingTown = 0

	lPos = 0
	lTarget = 0

	eEffect = 0
start
	begin loop
		//increment tribute by 1
		nTownPlayer = get oTown player
		if nTownPlayer != 0

		// Get the nearest hostile and friendly towns.
		oEnemyTown = 0
		oFriendlyTown = 0
		nCount = 0
		force while nCount < NUMBER_OF_TOWNS
			oTownMisc = oTownArray[nCount]
			if get oTownMisc player != nTownPlayer
				if oEnemyTown not exists and not town oTownMisc is under takeover from player nTownPlayer
					oEnemyTown = oTownMisc
					fLastDistance = get distance from {oTown} to {oEnemyTown}
				else
					fNewDistance = get distance from {oTown} to {oTownMisc}
					if fNewDistance < fLastDistance and not town oTownMisc is under takeover from player nTownPlayer
						fLastDistance = fNewDistance
						oEnemyTown = oTownMisc
					end if
				end if
			elsif get oTownMisc player == nTownPlayer
				if oFriendlyTown not exists
					if oTownMisc != oTown
						oFriendlyTown = oTownMisc
						fFriendlyLastDistance = get distance from {oTown} to {oFriendlyTown}
					end if
				else
					fFriendlyNewDistance = get distance from {oTown} to {oTownMisc}
					if fFriendlyNewDistance < fFriendlyLastDistance
						fFriendlyLastDistance = fFriendlyNewDistance
						oFriendlyTown = oTownMisc
					end if
				end if
			end if
			nCount++
		end while

		nCount = nTownRangeMin
		force while nCount < nTownRangeMax
			oPlatoon = oPlatoonArray[nCount]
			nPlatoonPlayer = get oPlatoon player

			// Get if the platoon is currently capturing a town. Isn't there an easier way to do this?
			nIsCapturingTown = 0
			nCountMisc = 0
			force while nCountMisc < NUMBER_OF_TOWNS
				oTownMisc = get town with id nCountMisc
				oTownCentreMisc = get building ABODE_NUMBER_TOWN_CENTRE in oTownMisc min built 1.0
				if platoon oPlatoon current action is PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oTownCentreMisc
					nIsCapturingTown = 1
					nCountMisc = NUMBER_OF_TOWNS
				end if
				nCountMisc++
			end while

			// Get town gate. Needs improvement.
                        oGate = get building ABODE_NUMBER_GATEHOUSE in oTown min built 1.0
			if oGate not exists
			oGate = get building ABODE_NUMBER_GATEHOUSE_F in oTown min built 1.0
			end if

			if oEnemyTown exists and oPlatoon exists
				oEnemyTownCentre = get building ARTEFACT_ABODE_NUMBER_TOWN_CENTRE in oEnemyTown min built 1.0
				oFriendlyTownCentre = get building ARTEFACT_ABODE_NUMBER_TOWN_CENTRE in oFriendlyTown min built 1.0

				// Check if the platoon's town is under attack.
				nAttacker = 0
				nUnderAttack = 0
				force while nAttacker < 7
					if town oTown is under takeover from player nAttacker
						nUnderAttack = 1
					end if
					nAttacker++
				end while

				// Check if the nearest friendly town is under attack.
				nAttacker = 0
				nFriendlyTownUnderAttack = 0
				force while nAttacker < 7
					if town oFriendlyTown is under takeover from player nAttacker
						nFriendlyTownUnderAttack = 1
					end if
					nAttacker++
				end while

				// Get nearest hostile platoon and siege weapon.
				oEnemyPlatoon = 0
				nPlayer = 0
				force while nPlayer < 7
					if nPlayer != nPlatoonPlayer
						if oEnemyPlatoon not exists
							oEnemyPlatoon = get platoon of player nPlayer nearest {oPlatoon} radius ATTACK_DISTANCE
							fLastDistance = get distance from {oPlatoon} to {oEnemyPlatoon}
						else
							oNextEnemyPlatoon = get platoon of player nPlayer nearest {oPlatoon} radius ATTACK_DISTANCE
							fNewDistance = get distance from {oPlatoon} to {oNextEnemyPlatoon}
							if fNewDistance < fLastDistance
								oEnemyPlatoon = oNextEnemyPlatoon
								fLastDistance = fNewDistance
							end if
						end if
					end if
					nPlayer++
				end while
				oEnemySiegeWeapon = 0
				nPlayer = 0
				force while nPlayer < 7
					if nPlayer != nPlatoonPlayer
						if oEnemySiegeWeapon not exists
							oEnemySiegeWeapon = get siege weapon of player nPlayer nearest {oPlatoon} radius ATTACK_DISTANCE
							fLastDistance = get distance from {oPlatoon} to {oEnemySiegeWeapon}
						else
							oNextEnemySiegeWeapon = get siege weapon of player nPlayer nearest {oPlatoon} radius ATTACK_DISTANCE
							fNewDistance = get distance from {oPlatoon} to {oNextEnemySiegeWeapon}
							if fNewDistance < fLastDistance
								oEnemySiegeWeapon = oNextEnemySiegeWeapon
								fLastDistance = fNewDistance
							end if
						end if
					end if
					nPlayer++
				end while


				// This is a list of actions ordered after priority. First on the list gets the highest priority.

				// Clear action queue and attack oEnemyPlatoon if there's a hostile platoon within attacking distance.
				if oEnemyPlatoon exists
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_MELEE_ATTACK_PLATOON using oEnemyPlatoon
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_MELEE_ATTACK_PLATOON using oEnemyPlatoon to oPlatoon action queue
					end if
				// Clear action queue and attack oEnemySiegeWeapon if there's a hostile siege weapon within attacking distance.
				elsif oEnemySiegeWeapon exists
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_MELEE_ATTACK_MOVING_OBJECT using oEnemySiegeWeapon
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_MELEE_ATTACK_MOVING_OBJECT using oEnemySiegeWeapon to oPlatoon action queue
					end if
				// Capture hometown if it has been lost to enemy forces.
				elsif nTownPlayer != nPlatoonPlayer 
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oTownCentre
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oTownCentre to oPlatoon action queue
					end if
				// Protect hometown if it is under attack.
				elsif nUnderAttack == 1
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre to oPlatoon action queue
					end if
				// Protect nearest friendly town if it is under attack.
				elsif nFriendlyTownUnderAttack == 1
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oFriendlyTownCentre
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oFriendlyTownCentre to oPlatoon action queue
					end if
				// Clear action queue if the platoon is protecting its hometown without reason.
				elsif nTownPlayer == nPlatoonPlayer and platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre
					clear oPlatoon action queue
				// Hehehehe... This should be gooood.
				elsif nIsCapturingTown == 1
					// Do nothing! Didn't see that one coming, now did ye?
					// Note to self: Makes the platoon ignore towns that are already being captured... I think.
				// Move to nearest enemy town. Create siege weapons if target town is protected by walls.
				elsif get distance from {oPlatoon} to {oEnemyTown} > 60.0
					if oPlatoon can navigate to object oEnemyTownCentre
						if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_MOVE_TO_OBJECT using oEnemyTownCentre
							clear oPlatoon action queue
							add action PLATOON_AGENDA_ACTION_MOVE_TO_OBJECT using oEnemyTownCentre to oPlatoon action queue
						end if
					else
						if oGate exists
							add action PLATOON_AGENDA_ACTION_MOVE_TO_OBJECT using oGate to oPlatoon action queue
						else
							nSiegeCount = 0
							nCountMisc = nTownRangeMin
							force while nCountMisc < nTownRangeMax
								if oSiegeArray[nCountMisc] exists
									nSiegeCount++
								end if
								nCountMisc++
							end while

							oSiegeWeapon = oSiegeArray[nCount]
							if oSiegeWeapon not exists
								if nSiegeCount <= MAX_NUMBER_OF_SIEGE_WEAPONS
									oSiegeArray[nCount] = recruit SIEGE_BALANCE_TYPE_CATAPULT_LEVEL_1 town oTown siege weapon
								end if
							elsif oSiegeWeapon exists
								oSiegeWeapon = oSiegeArray[nCount]

								lTarget = marker at get target from {oTown} to {oEnemyTown} distance 200 angle 180
								if DEBUG == 1 eEffect = create visual effect VISUAL_EFFECT_MULTI_PICKUP at {lTarget} time -1 end if
								oWall = get wall segment nearest {lTarget} radius 400
								lTarget = marker at get target from {oSiegeWeapon} to {oWall} distance 10 angle 180

								if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oSiegeWeapon
									add action PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oSiegeWeapon to oPlatoon action queue
								elsif not {oWall} is in range of oSiegeWeapon
									if not siege weapon oSiegeWeapon current action is SIEGEWEAPON_AGENDA_ACTION_MOVE_TO_POS using {lTarget}
										//clear siege weapon oSiegeArray[nCount] action queue
										add action SIEGEWEAPON_AGENDA_ACTION_MOVE_TO_POS using {lTarget} to siege weapon oSiegeWeapon action queue
									end if
								elsif not siege weapon oSiegeWeapon current action is SIEGEWEAPON_AGENDA_ACTION_ATTACK_THING using oWall
									clear siege weapon oSiegeWeapon action queue
									add action SIEGEWEAPON_AGENDA_ACTION_ATTACK_THING using oWall to siege weapon oSiegeWeapon action queue
								end if
							end if
						end if
					end if
				// Attack enemy town if there is nothing else to do.
				elsif not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oEnemyTownCentre
					clear oPlatoon action queue
					add action PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oEnemyTownCentre to oPlatoon action queue
				end if
			else
				// Just go back and defend town centre if there are no enemy towns left.
				if nIsCapturingTown == 0 and not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre
					clear oPlatoon action queue
					add action PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre to oPlatoon action queue
				end if
			end if

			// We don't like platoons that get stuck.
			// EDIT: Lags the script and is generally more trouble than it's worth.
			// EDIT2: Activate by holding down the 'K' button.
			if key KB_K down
				if not oPlatoon can navigate to {oPlatoon}
					run script MoveToValidPosition(oPlatoon, 20.0)
				end if
			end if

			nCount++
		end while

		end if
	end loop

end script AttackTest


// Will be used for archers on walls and other town defenses.
begin script DefendTest(nTown, nDefendSize)
start
end script DefendTest

begin script TownManagement(nTown)
	oTown = get town with id nTown
	oStore = get building ABODE_NUMBER_STORAGE_PIT in oTown min built 1.0
	oGate = 0
	oPlatoon = 0
	nPlayer = 0
start
	begin loop
		nPlayer = get oTown player
		if nPlayer != 0
			oGate = get building ABODE_NUMBER_GATEHOUSE in oTown min built 1.0
			if oGate not exists
				oGate = get building ABODE_NUMBER_GATEHOUSE_F in oTown min built 1.0
			end if

			if oGate exists
				oPlatoon = get platoon of player nPlayer nearest {oGate} radius 50.0
				if oPlatoon exists
					set gate oGate open
				else
					set gate oGate close
				end if
			end if

			// Store management. Needs improvement.
			set oStore resource RESOURCE_TYPE_FOOD to 20000
			set oStore resource RESOURCE_TYPE_WOOD to 20000
			set oStore resource RESOURCE_TYPE_ORE to 20000
		end if
	end loop

end script TownManagement

begin script CreateTownArray
	oTown = 0
	nCount = 0
start
	// Creates a town object array.
	force while nCount < NUMBER_OF_TOWNS
		oTown = get town with id nCount
		if oTown exists
			oTownArray[nCount] = oTown
		else
			nCount = NUMBER_OF_TOWNS
		end if
		nCount++
	end while

end script CreateTownArray


// This function runs all the AI scripts for all towns on the map. There's checks in each individual script to make sure human controlled towns are ignored.
begin script RunTownAIForAll
	nAttackSize = 100
	nDefendSize = 0

	fDelay = 90.0
	fDelayVariation = 30.0

	nCount = 0
start
	nAttackSize = (MAX_ARMY_SIZE/100) * nAttackSize
	nDefendSize = (MAX_ARMY_SIZE/100) * (100 - nAttackSize)

	force while nCount < NUMBER_OF_TOWNS
		run background script RecruitArmy(nCount, nAttackSize, fDelay, fDelayVariation)
		run background script AttackTest(nCount)
		run background script DefendTest(nCount, nDefendSize)
		run background script TownManagement(nCount)
		nCount++
	end while

end script RunTownAIForAll
 
SkelApe said:
EDIT: when i try to run GodAI as a background script, it says there is a parse error. can you suggest a solution? 

Code:
define script GodAI (1Town, 256, 22, 42, 1)
define script CentralScript

run script CentralScript

begin script CentralScript

oTown = get town with id 0
1Town = get town with id 1

start

disable load screen
set fade in time 1

run background script GodAI(1Town, 256, 22, 42, 1)

wait until 1 != 1

end script CentralScript

thanks

From looking at this I can see what your problem is. The God is designed to be run from a seperate file and added to the challenges.txt file.

Just input into the challenge the path to the scriptm for example this is what I use as my path to the God AI. Where OGAM_1 is the name of the folder.
Code:
OGAM_1\Gods AI.txt

This is how I declare seperate files to be a part of the challenge file, it God AI script has already been defined in the script itself. The one part you have done right, is how you run the script.

Code:
run background script GodAI(1Town, 256, 22, 42, 1)

Also because you having already set the Central Script to run there is no need to define it, so scrap define script CentralScript.

But that should pretty much fix that. Your other problem, I will deal in my next post.
 
SkelApe said:
whilst we are on topic, i wondered if you could tell me where ive gone wrong here. orry for the long
script.  :D


Code:
define script AIStuff
define script RecruitArmy(nTown, nAttackSize, fDelay, fDelayVariation)
define script MoveToValidPosition(oObject, fLimit)
define script AttackTest(nTown)
define script DefendTest(nTown, nDefendSize)
define script TownManagement(nTown)
define script CreateTownArray
define script RunTownAIForAll

// Debug switch
define DEBUG = 0

// Platoon sizes.
define TINY = 10
define SMALL = 20
define MEDIUM = 80
define LARGE = 240
define LEGION = 5000

// Platoons will attack enemies within this distance.
define ATTACK_DISTANCE = 70.0

// Platoons will capture enemy towns within this distance once all enemies in area have been killed.
define CAPTURE_TOWN_DISTANCE = 60.0

// The actual number of towns on the map.
define NUMBER_OF_TOWNS = 2

// Max number of platoons in an army.
define MAX_NUMBER_OF_PLATOONS = 20
define MAX_NUMBER_OF_SIEGE_WEAPONS = 2 // Doesn't seem to work for some reason.

// The max size of the army compared to the size of the town.
define MAX_ARMY_SIZE = 30 // percent

// This array holds all town objects on the map.
global oTownArray[NUMBER_OF_TOWNS]

// MAX_NUMBER_OF_PLATOONS * NUMBER_OF_TOWNS
global oPlatoonArray[140]
global oArchersArray[140]
global oSiegeArray[140]

run script AIStuff
run script RecruitArmy(nTown, nAttackSize, fDelay, fDelayVariation)
run script MoveToValidPosition(oObject, fLimit)
run script AttackTest(nTown)
run script DefendTest(nTown, nDefendSize)
run script TownManagement(nTown)
run script CreateTownArray
run script RunTownAIForAll

begin script AIStuff
start
	run script CreateTownArray
	run background script RunTownAIForAll

end script AIStuff

begin script RecruitArmy(nTown, nAttackSize, fDelay, fDelayVariation)
	oTown = get town with id nTown

	nArmySize = 0
	nMaxArmySize = 0
	nTownSize = 0
	nRecruitSize = 0
	nDiff = 0
	nCount = 0

	nAttacker = 0
	nUnderAttack = 0

	nTownRangeMin = nTown * MAX_NUMBER_OF_PLATOONS
	nTownRangeMax = (nTown * MAX_NUMBER_OF_PLATOONS) + MAX_NUMBER_OF_PLATOONS
start
	begin loop
		nAttacker = 0
		nUnderAttack = 0
		force while nAttacker < 7
			if town oTown is under takeover from player nAttacker
				nUnderAttack = 1
			end if
			nAttacker++
		end while

		if get oTown player != 0 and nUnderAttack == 0
			begin loop
				nArmySize = get army size in town oTown
				nTownSize = adult size of oTown
				nTownSize -= nArmySize
				nMaxArmySize = (nTownSize/100) * nAttackSize

				nDiff = nMaxArmySize - nArmySize

				if nDiff >= LEGION
					nRecruitSize = LEGION
				elsif nDiff >= LARGE
					nRecruitSize = LARGE
				elsif nDiff >= MEDIUM
					nRecruitSize = MEDIUM
				elsif nDiff >= SMALL
					nRecruitSize = SMALL
				elsif nDiff >= TINY
					nRecruitSize = TINY
				else
					nRecruitSize = 0
				end if

				until nRecruitSize > 0
			end loop

			// Recruit army of nRecruitSize.
			nCount = nTownRangeMin
			force while nCount < nTownRangeMax
				if oPlatoonArray[nCount] not exists
					oPlatoonArray[nCount] = recruit ARMY_UNIT_TYPE_MELEE_1 town oTown platoon of size nRecruitSize

					if oArchersArray[nCount] not exists
						oArchersArray[nCount] = recruit ARMY_UNIT_TYPE_RANGED_1 town oTown platoon of size (nRecruitSize / 4)
					end if
					add action PLATOON_AGENDA_ACTION_LINK_TO_ARMY_MEMBER using oPlatoonArray[nCount] to oArchersArray[nCount] action queue
					nCount = nTownRangeMax
				end if
				nCount++
			end while

			fDelay = number from (fDelay - fDelayVariation) to (fDelay + fDelayVariation)
			wait fDelay seconds
		end if
	end loop

end script RecruitArmy

begin script MoveToValidPosition(oObject, fLimit)
	lTarget = 0
	lFocus = 0
	fDistance = 1.0
start
	force while fDistance <= fLimit
		if not oObject can navigate to {oObject}
			lFocus = marker at focus position of oObject
			lTarget = marker at get target from {lFocus} to {oObject} distance fDistance angle 180
			set oObject position to {lTarget}
		else
			fDistance = fLimit
		end if
		fDistance++
	end while

	// Delete object if it's still stuck.
	if not oObject can navigate to {oObject}
		delete oObject
	end if

end script MoveToValidPosition

begin script AttackTest(nTown)
	oTown = get town with id nTown
	oTownCentre = get building ABODE_NUMBER_TOWN_CENTRE in oTown min built 1.0
	nTownPlayer = 0
	nPlatoonPlayer = 0
	nPlayer = 0

	oEnemyTown = 0
	oEnemyTownCentre = 0
	oFriendlyTown = 0
	oFriendlyTownCentre = 0
	oTownMisc = 0
	oTownCentreMisc = 0

	oPlatoon = 0
	oSiegeWeapon = 0
	oEnemyPlatoon = 0
	oNextEnemyPlatoon = 0
	oEnemySiegeWeapon = 0
	oNextEnemySiegeWeapon = 0

	oWall = 0
	oGate = 0
        oGate2 = 0

	fNewDistance = 0
	fLastDistance = 0
	fFriendlyNewDistance = 0
	fFriendlyLastDistance = 0

	nTownRangeMin = nTown * MAX_NUMBER_OF_PLATOONS
	nTownRangeMax = (nTown * MAX_NUMBER_OF_PLATOONS) + MAX_NUMBER_OF_PLATOONS

	nCount = 0
	nCountMisc = 0
	nSiegeCount = 0
	nAttacker = 0
	nUnderAttack = 0
	nFriendlyTownUnderAttack = 0
	nIsCapturingTown = 0

	lPos = 0
	lTarget = 0

	eEffect = 0
start
	begin loop
		//increment tribute by 1
		nTownPlayer = get oTown player
		if nTownPlayer != 0

		// Get the nearest hostile and friendly towns.
		oEnemyTown = 0
		oFriendlyTown = 0
		nCount = 0
		force while nCount < NUMBER_OF_TOWNS
			oTownMisc = oTownArray[nCount]
			if get oTownMisc player != nTownPlayer
				if oEnemyTown not exists and not town oTownMisc is under takeover from player nTownPlayer
					oEnemyTown = oTownMisc
					fLastDistance = get distance from {oTown} to {oEnemyTown}
				else
					fNewDistance = get distance from {oTown} to {oTownMisc}
					if fNewDistance < fLastDistance and not town oTownMisc is under takeover from player nTownPlayer
						fLastDistance = fNewDistance
						oEnemyTown = oTownMisc
					end if
				end if
			elsif get oTownMisc player == nTownPlayer
				if oFriendlyTown not exists
					if oTownMisc != oTown
						oFriendlyTown = oTownMisc
						fFriendlyLastDistance = get distance from {oTown} to {oFriendlyTown}
					end if
				else
					fFriendlyNewDistance = get distance from {oTown} to {oTownMisc}
					if fFriendlyNewDistance < fFriendlyLastDistance
						fFriendlyLastDistance = fFriendlyNewDistance
						oFriendlyTown = oTownMisc
					end if
				end if
			end if
			nCount++
		end while

		nCount = nTownRangeMin
		force while nCount < nTownRangeMax
			oPlatoon = oPlatoonArray[nCount]
			nPlatoonPlayer = get oPlatoon player

			// Get if the platoon is currently capturing a town. Isn't there an easier way to do this?
			nIsCapturingTown = 0
			nCountMisc = 0
			force while nCountMisc < NUMBER_OF_TOWNS
				oTownMisc = get town with id nCountMisc
				oTownCentreMisc = get building ABODE_NUMBER_TOWN_CENTRE in oTownMisc min built 1.0
				if platoon oPlatoon current action is PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oTownCentreMisc
					nIsCapturingTown = 1
					nCountMisc = NUMBER_OF_TOWNS
				end if
				nCountMisc++
			end while

			// Get town gate. Needs improvement.
                        oGate = get building ABODE_NUMBER_GATEHOUSE in oTown min built 1.0
			if oGate not exists
			oGate = get building ABODE_NUMBER_GATEHOUSE_F in oTown min built 1.0
			end if

			if oEnemyTown exists and oPlatoon exists
				oEnemyTownCentre = get building ARTEFACT_ABODE_NUMBER_TOWN_CENTRE in oEnemyTown min built 1.0
				oFriendlyTownCentre = get building ARTEFACT_ABODE_NUMBER_TOWN_CENTRE in oFriendlyTown min built 1.0

				// Check if the platoon's town is under attack.
				nAttacker = 0
				nUnderAttack = 0
				force while nAttacker < 7
					if town oTown is under takeover from player nAttacker
						nUnderAttack = 1
					end if
					nAttacker++
				end while

				// Check if the nearest friendly town is under attack.
				nAttacker = 0
				nFriendlyTownUnderAttack = 0
				force while nAttacker < 7
					if town oFriendlyTown is under takeover from player nAttacker
						nFriendlyTownUnderAttack = 1
					end if
					nAttacker++
				end while

				// Get nearest hostile platoon and siege weapon.
				oEnemyPlatoon = 0
				nPlayer = 0
				force while nPlayer < 7
					if nPlayer != nPlatoonPlayer
						if oEnemyPlatoon not exists
							oEnemyPlatoon = get platoon of player nPlayer nearest {oPlatoon} radius ATTACK_DISTANCE
							fLastDistance = get distance from {oPlatoon} to {oEnemyPlatoon}
						else
							oNextEnemyPlatoon = get platoon of player nPlayer nearest {oPlatoon} radius ATTACK_DISTANCE
							fNewDistance = get distance from {oPlatoon} to {oNextEnemyPlatoon}
							if fNewDistance < fLastDistance
								oEnemyPlatoon = oNextEnemyPlatoon
								fLastDistance = fNewDistance
							end if
						end if
					end if
					nPlayer++
				end while
				oEnemySiegeWeapon = 0
				nPlayer = 0
				force while nPlayer < 7
					if nPlayer != nPlatoonPlayer
						if oEnemySiegeWeapon not exists
							oEnemySiegeWeapon = get siege weapon of player nPlayer nearest {oPlatoon} radius ATTACK_DISTANCE
							fLastDistance = get distance from {oPlatoon} to {oEnemySiegeWeapon}
						else
							oNextEnemySiegeWeapon = get siege weapon of player nPlayer nearest {oPlatoon} radius ATTACK_DISTANCE
							fNewDistance = get distance from {oPlatoon} to {oNextEnemySiegeWeapon}
							if fNewDistance < fLastDistance
								oEnemySiegeWeapon = oNextEnemySiegeWeapon
								fLastDistance = fNewDistance
							end if
						end if
					end if
					nPlayer++
				end while


				// This is a list of actions ordered after priority. First on the list gets the highest priority.

				// Clear action queue and attack oEnemyPlatoon if there's a hostile platoon within attacking distance.
				if oEnemyPlatoon exists
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_MELEE_ATTACK_PLATOON using oEnemyPlatoon
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_MELEE_ATTACK_PLATOON using oEnemyPlatoon to oPlatoon action queue
					end if
				// Clear action queue and attack oEnemySiegeWeapon if there's a hostile siege weapon within attacking distance.
				elsif oEnemySiegeWeapon exists
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_MELEE_ATTACK_MOVING_OBJECT using oEnemySiegeWeapon
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_MELEE_ATTACK_MOVING_OBJECT using oEnemySiegeWeapon to oPlatoon action queue
					end if
				// Capture hometown if it has been lost to enemy forces.
				elsif nTownPlayer != nPlatoonPlayer 
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oTownCentre
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oTownCentre to oPlatoon action queue
					end if
				// Protect hometown if it is under attack.
				elsif nUnderAttack == 1
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre to oPlatoon action queue
					end if
				// Protect nearest friendly town if it is under attack.
				elsif nFriendlyTownUnderAttack == 1
					if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oFriendlyTownCentre
						clear oPlatoon action queue
						add action PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oFriendlyTownCentre to oPlatoon action queue
					end if
				// Clear action queue if the platoon is protecting its hometown without reason.
				elsif nTownPlayer == nPlatoonPlayer and platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre
					clear oPlatoon action queue
				// Hehehehe... This should be gooood.
				elsif nIsCapturingTown == 1
					// Do nothing! Didn't see that one coming, now did ye?
					// Note to self: Makes the platoon ignore towns that are already being captured... I think.
				// Move to nearest enemy town. Create siege weapons if target town is protected by walls.
				elsif get distance from {oPlatoon} to {oEnemyTown} > 60.0
					if oPlatoon can navigate to object oEnemyTownCentre
						if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_MOVE_TO_OBJECT using oEnemyTownCentre
							clear oPlatoon action queue
							add action PLATOON_AGENDA_ACTION_MOVE_TO_OBJECT using oEnemyTownCentre to oPlatoon action queue
						end if
					else
						if oGate exists
							add action PLATOON_AGENDA_ACTION_MOVE_TO_OBJECT using oGate to oPlatoon action queue
						else
							nSiegeCount = 0
							nCountMisc = nTownRangeMin
							force while nCountMisc < nTownRangeMax
								if oSiegeArray[nCountMisc] exists
									nSiegeCount++
								end if
								nCountMisc++
							end while

							oSiegeWeapon = oSiegeArray[nCount]
							if oSiegeWeapon not exists
								if nSiegeCount <= MAX_NUMBER_OF_SIEGE_WEAPONS
									oSiegeArray[nCount] = recruit SIEGE_BALANCE_TYPE_CATAPULT_LEVEL_1 town oTown siege weapon
								end if
							elsif oSiegeWeapon exists
								oSiegeWeapon = oSiegeArray[nCount]

								lTarget = marker at get target from {oTown} to {oEnemyTown} distance 200 angle 180
								if DEBUG == 1 eEffect = create visual effect VISUAL_EFFECT_MULTI_PICKUP at {lTarget} time -1 end if
								oWall = get wall segment nearest {lTarget} radius 400
								lTarget = marker at get target from {oSiegeWeapon} to {oWall} distance 10 angle 180

								if not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oSiegeWeapon
									add action PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oSiegeWeapon to oPlatoon action queue
								elsif not {oWall} is in range of oSiegeWeapon
									if not siege weapon oSiegeWeapon current action is SIEGEWEAPON_AGENDA_ACTION_MOVE_TO_POS using {lTarget}
										//clear siege weapon oSiegeArray[nCount] action queue
										add action SIEGEWEAPON_AGENDA_ACTION_MOVE_TO_POS using {lTarget} to siege weapon oSiegeWeapon action queue
									end if
								elsif not siege weapon oSiegeWeapon current action is SIEGEWEAPON_AGENDA_ACTION_ATTACK_THING using oWall
									clear siege weapon oSiegeWeapon action queue
									add action SIEGEWEAPON_AGENDA_ACTION_ATTACK_THING using oWall to siege weapon oSiegeWeapon action queue
								end if
							end if
						end if
					end if
				// Attack enemy town if there is nothing else to do.
				elsif not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oEnemyTownCentre
					clear oPlatoon action queue
					add action PLATOON_AGENDA_ACTION_ATTACK_TOWN_CENTRE_FOR_TAKE_OVER using oEnemyTownCentre to oPlatoon action queue
				end if
			else
				// Just go back and defend town centre if there are no enemy towns left.
				if nIsCapturingTown == 0 and not platoon oPlatoon current action is PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre
					clear oPlatoon action queue
					add action PLATOON_AGENDA_ACTION_DEFEND_OBJECT using oTownCentre to oPlatoon action queue
				end if
			end if

			// We don't like platoons that get stuck.
			// EDIT: Lags the script and is generally more trouble than it's worth.
			// EDIT2: Activate by holding down the 'K' button.
			if key KB_K down
				if not oPlatoon can navigate to {oPlatoon}
					run script MoveToValidPosition(oPlatoon, 20.0)
				end if
			end if

			nCount++
		end while

		end if
	end loop

end script AttackTest


// Will be used for archers on walls and other town defenses.
begin script DefendTest(nTown, nDefendSize)
start
end script DefendTest

begin script TownManagement(nTown)
	oTown = get town with id nTown
	oStore = get building ABODE_NUMBER_STORAGE_PIT in oTown min built 1.0
	oGate = 0
	oPlatoon = 0
	nPlayer = 0
start
	begin loop
		nPlayer = get oTown player
		if nPlayer != 0
			oGate = get building ABODE_NUMBER_GATEHOUSE in oTown min built 1.0
			if oGate not exists
				oGate = get building ABODE_NUMBER_GATEHOUSE_F in oTown min built 1.0
			end if

			if oGate exists
				oPlatoon = get platoon of player nPlayer nearest {oGate} radius 50.0
				if oPlatoon exists
					set gate oGate open
				else
					set gate oGate close
				end if
			end if

			// Store management. Needs improvement.
			set oStore resource RESOURCE_TYPE_FOOD to 20000
			set oStore resource RESOURCE_TYPE_WOOD to 20000
			set oStore resource RESOURCE_TYPE_ORE to 20000
		end if
	end loop

end script TownManagement

begin script CreateTownArray
	oTown = 0
	nCount = 0
start
	// Creates a town object array.
	force while nCount < NUMBER_OF_TOWNS
		oTown = get town with id nCount
		if oTown exists
			oTownArray[nCount] = oTown
		else
			nCount = NUMBER_OF_TOWNS
		end if
		nCount++
	end while

end script CreateTownArray


// This function runs all the AI scripts for all towns on the map. There's checks in each individual script to make sure human controlled towns are ignored.
begin script RunTownAIForAll
	nAttackSize = 100
	nDefendSize = 0

	fDelay = 90.0
	fDelayVariation = 30.0

	nCount = 0
start
	nAttackSize = (MAX_ARMY_SIZE/100) * nAttackSize
	nDefendSize = (MAX_ARMY_SIZE/100) * (100 - nAttackSize)

	force while nCount < NUMBER_OF_TOWNS
		run background script RecruitArmy(nCount, nAttackSize, fDelay, fDelayVariation)
		run background script AttackTest(nCount)
		run background script DefendTest(nCount, nDefendSize)
		run background script TownManagement(nCount)
		nCount++
	end while

end script RunTownAIForAll

Now for the second problem, the compiler has indeed spit a correct error because on line 45 there starts a list of run script commands, to make this work just delete all the run script commands in the script and do what I mentioned before about adding the script file to challenges.txt , then add this line to your main script.

Code:
run background script AIStuff

Btw, make sure that when you add the files to the challenges.txt file to make sure that they are before the Main Script file.

Like what I have done for OGaM.

Code:
OGAM_1\GodsAI.txt
OGAM_1\OGAMLand1.txt

But change the folder to the name of the folder of where you have the scripts located and add the name you've given the AI script(e.g. AIScript.txt) before the Main Script inside that challenges.txt file.

I hope this helps.  :)

EDIT: Since I've got the net now, it'll be much easier to constantly update those tutorials I have in the script library, oh and thanks for bringing this up, it's given me motivation to do these tutorials again.
 
thanks for the help daxter. hey could you tell me, does a given script need to say "autoruns will run in multiplayer too!" to work?

PS: excellent work on OGaM! my support all the way on molyneux's help with the tools.

EDIT: does your advanced select script still work? its just it did before and when i used it after you updated it a load of errors came up. maybe just a stupid mistake though. does it require tweaking at all? (apart from co ordinates)
 
No, that little saying in the compiler is standard for a working script.

The Creature Selection should be fine, the only things to change are the co-ordinates and of course you don't need to run it from the main script, if you recall I left a note saying that it's self-running and all you need to do is add it to the challenges.txt file however, I think there are some abbrev. on the game constants for the creatures, so in this case, I will upload a script that contains all the abbrev. of the constants in the game that make all the scripter much easier with shorter versions of the constants instead of writing out the whole thing.

e.g. When you have these constants in a seperate file and added to the challenges.txt file before any of the scripts(so any more scripts that you add to the challenge file are to be after where the Constants.txt file is.

In one example instead of writing,

Code:
SCRIPT_OBJECT_TYPE_FEATURE

All you need to write is,

Code:
FEATURE

Because it has been abbrev. to allow the constant to be written in a script as FEATURE.

EDIT: Btw, in your post about the God AI you had this line.

Code:
run background script GodAI(1Town, 256, 22, 42, 1)

I guess I should tell you now that obviously this is the example given in the Script Library but you don't have to use that one, there are millions of colour combinations. You can find the RGB of a colour like in Microsoft Paint as part of Windows. Double-clicking on a colour will give the RGB.
 
hmm it says above the script that all i need to do is add it to the challenges file and change the coordinates and i did  ???
this was the outcome. any suggestions?
 
[quote author=Daxter]
I think there are some abbrev. on the game constants for the creatures, so in this case, I will upload a script that contains all the abbrev. of the constants in the game that make all the scripter much easier with shorter versions of the constants instead of writing out the whole thing.
[/quote]

In my previous post, I said this. In that case, If you want to fix any of those constant problems, then download a copy of the Constants that I have uploaded to Kayssplace and save them in a text file and add to the challenges.txt file.
 
thanks alot for that dax. ill have to try using them in my scripts
(im really bad at it though =D)
 
yeh i got the creature select to work. nice script btw! i think the constants helped with alot of my scripts.
 
Thought so. The constants script, I actually obtained from Lionhead some time back and ever since, its been very useful.
 
Back
Top