GameObjective
Actors of class GameObjective (or rather subclasses thereof) are part of UT2003's bot support.
While a GameObjective is "active", bots of one team seek it out, bots of the other try and defend it. When the attacking team reaches it, they "disable" it in some way – the various subclasses tell the bots that they need to do (can a coder confirm this bit?). This is used to implement CTF flags, Domination points, and so on.
Ways to disable:
- DestroyableObjective does it when the objective's Health reaches zero.
- KeyInventory in conjunction with a LockedObjective when a player bearing the key approaches the locked objective.
- TriggeredObjective when a player triggers the objective.
The GameObjective actor can be tied to defense points created with UnrealScriptedSequences, and routes to the objective are defined with AssaultPaths.
Coding with GameObjectives
Normally, a GameObjective will be added to a map manually by level designers, but it is possible to have game code spawn GameObjective objects (of subclasses where bStatic and bNoDelete are both set to False), but since they're not part of the navigation network bots won't find them. To facilitate that anyway, overwrite TellBotHowToDisable in your GameObjective subclass and direct the bot to a nearby regular actor (either a static NavigationPoint that has been pathed or an actor not derived from NavigationPoint at all).
You might also need to set the bCollideWhenPlacing property to False so that the spawn actually succeeds if you try to spawn it at the map origin. This is one reason why the code might work on some maps and not on others.
Another trap here is that GameObjective contains a built in linked list which can get corrupted into a circular list if you spawn GOs at runtime. (Depending on the order that AllActors passes the existing GOs). This will cause anything using the linked list to crash the game (infinite loop).
The problem is that GameObjective's PostBeginPlay assumes no more GameObjectives are spawned after the first's PostBeginPlay is called. The solution is to fix the list yourself with something like:
prevGO = none; foreach AllActors(class'GameObjective', GO) { //Clear NextObjective on all, since GameObjective code has got it wrong GO.NextObjective = none; if(prevGO != none) { prevGO.NextObjective = GO; GO.bFirstObjective = false; } else GO.bFirstObjective = true; prevGO = GO; }
Ideally do this in an override of GO.PostBeginPlay. Then you don't have to care what else (like TeamAI) might keep its own reference to the list, as that will happen later.
Properties
Main
- name Event
- Inherited from Actor. Event that is fired when this objective has been disabled.
- bool bTeamControlled
- Disabling this objective changes the objective's team rather than removing it. (Used for Domination control points.)
- bool bAccruePoints
- If set, the controlling team accrues points. (Can be used for Unreal Tournament-style Domination control points.)
- byte DefenderTeamIndex
- Team number of the team defending this objective : 0=red, 1=blue.
- byte DefensePriority
- Used to set objective order. Objectives that should be completed first should be given a higher DefensePriority. The last objective should have a DefensePriority of 0, and each previous objective should have its DefensePriority increased by one.
- int Score
- If the bAccruePoints property is set, score given to the team holding this objective every second. Otherwise, score given to player who completes/disables this objective.
Bot Support
- name DefenseScriptTags
- Tag of UnrealScriptedSequences used by bots that defend this objective.
- name AreaVolumeTag
- Optional tag of a Volume defining the base area around this objective. Used by the game to determine whether a bot is close to this objective.
- float BaseRadius
- Radius of a simple base area around this objective. Can be used instead of or in addition to AreaVolumeTag.
- float BaseExitTime
- Time (in seconds) it takes a bot to get entirely away from the base. In CTF, used by bots to make a guess whether an enemy has already left the base after taking the flag.
Localized
- string ObjectiveName (localized)
- Human-readable name of this objective.
- string DestructionMessage (localized)
- Message displayed when this objective has been destroyed.
- string LocationPrefix (localized)
- Text displayed before the human-readable objective name as a player's location in the scoreboard.
- string LocationPostfix (localized)
- (Text displayed after)
Hidden Properties
General
- bool bDisabled
- Set by DisableObjective when this objective has been disabled/destroyed.
- byte StartTeam
- Initial value of DefenderTeamIndex. Set by PostBeginPlay and used solely by the Reset function.
Bot Support
- UnrealScriptedSequence DefenseScripts
- First UnrealScriptedSequence in a linked list of defense scripts associated with this objective. PostBeginPlay looks for scripts whose Tag matches the objective's DefenseScriptTags property and initializes the DefenseScripts variable with a reference to the first script in the linked list.
- bool bHasShootSpots
- Used exclusively by [Bombing Run]? bot support and specifies whether a goal has associated ShootSpots from where the bomb can be shot through the hoop. Set by PostBeginPlay in xBombDelivery, used by BombingRunSquadAI.
- AssaultPath AlternatePaths
- References the first of a linked list of AssaultPaths associated with this GameObjective. All paths for a GameObjective are stored in a single list according to the order they are encountered by the AllActors iterator function ignoring any priority or path specifications.
- Volume MyBaseVolume
- Initialized with a reference to the volume specified by the AreaVolumeTag property (see above). Used by BotNearObjective.
Linked List
- bool bFirstObjective
- Used internally to link all objectives by their NextObjective property in PostBeginPlay. Set to True only for the first objective in the linked list.
- GameObjective NextObjective
- Links to the next objective in the linked objective list.
Functions
General
- PostBeginPlay()
- Performs several initialization tasks:
- Finds the first UnrealScriptedSequence in the linked list whose Tag matches the tag given by the DefenseScriptTags property and stores a reference to it in the DefenseScripts variable.
- Chains all GameObjective actors found in the map to a list linked by the NextObjective variable. The first GameObjective actor in the list has its bFirstObjective variable set to
True
. The SetObjectiveLists function in TeamAI (and other functions there) use this to find the start of the chain. - Initializes the AlternatePaths linked list of AssaultPath actors with a matching ObjectiveTag. Every AssaultPath added to the list will check, whether it is the first or last (known) node in each of its paths and correct the bFirstPath and bLastPath properties accordingly.
- Finds the Volume specified by the AreaVolumeTag property and stores a reference to it in the MyBaseVolume variable.
- If the bAccruePoints property is set, starts the timer with a one-second interval.
- Timer()
- If the bAccruePoints property is set, adds the number of points specified in the Score property to the total score of the team currently holding this objective.
- float GetDifficulty()
- Returns a generic "difficulty" value. Only implemented by the xBombDelivery subclass of GameObjective and used by function PreferShootScore in BombingRunSquadAI to make a decision whether a bot prefers shooting through the hoop or making a touchdown.
- function PlayAlarm()
- Can be overwritten in subclasses to play an alarm (for instance when a domination point or a flag is taken). Must be explicitely called.
- DisableObjective( Pawn Instigator )
- Called when this objective has been disabled. The default implementation fires the objective's Event, gives points to the attackers and changes the attacking bots' orders. Various other classes call DisableObjective:
- DestroyableObjective does it when the objective's Health reaches zero.
- KeyInventory in conjunction with a LockedObjective when a player bearing the key approaches the locked objective.
- TriggeredObjective when a player triggers the objective.
Bot Support
- bool BotNearObjective( Bot B )
- Returns whether the given Bot is "near" this objective. Uses the volume specified through the AreaVolumeTag property and the BaseRadius property to figure that out.
- bool OwnsDefenseScript( UnrealScriptedSequence S )
- Checks and returns whether the given UnrealScriptedSequence is in the list of defense scripts for this objective.
- bool TellBotHowToDisable( Bot B)
- Tells the given bot how to disable this objective; the default implementation simply shows the bot a path to it. Only returns True if valid and useable orders were given to the bot. Called by CheckSquadObjectives in SquadAI (which in turn is indirectly called by a Bot itself).
- int GetNumDefenders()
- Returns the number of players and bots currently defending this objective. Used by the GetLeastDefendedObjective and GetMostDefendedObjective functions in TeamAI (which in turn are used to make a decision about where to send bots for attack or defense).
Information
- string GetHumanReadableName() (simulated)
- Inherited from Actor. Returns a human-readable name for this objective. Used for logging.
- bool BetterObjectiveThan( GameObjective Best, byte DesiredTeamNum, byte RequesterTeamNum )
- Solely used to display WillowWhisp?s to show (human) players the path to the next objective.
Known Subclasses
GameObjective +- ASOBJ EnergyCore Spawn (UT2004 only) +- CTFBase +- DestroyableObjective | +- ONSPowerCore? | +- ONSPowerCoreBlue? | +- ONSPowerCoreRed? | +- ONSPowerNode? | +- ONSPowerNodeNeutral +- DominationPoint | +- xDomPoint | +- xDomPointA | +- xDomPointB +- LockedObjective (UT2003 only) +- ProximityObjective? (UT2004 only) | +- ASOBJ EnergyCore Delivery | +- HoldObjective | +- LockedObjective | +- UseObjective +- TouchableObjective (custom class) +- TriggeredObjective +- xBombDelivery +- xBombSpawn
Related Topics
Questions/Comments
MythOpus: I want to set my HoldObjective to start out with no team. Since 2,3 and 255 are completely ignored, how can I do this? Also, even when I have the bTeamControlled set to true and the red team completes the objective, the blue team is still left defending it and cannot retake control. Does anyone know how to make this possible?
Ironblayde: Is there some advantage to setting up an AreaVolumeTag? Under what circumstances would the game use this, and to what end? I didn't find any other pages on the Wiki that mention this property, so I'm curious as to whether anyone knows more about it.
SuperApe: Added subclass tree. Marked up propeties, functions.
IceCreamYou: Should DefenderTeamIndex be set to 0 or 1 for normal objectives? Also, I'm confused about DefensePriority: as I understand it, this field is for ordering your objectives, not setting which ones are more important as this page would currently imply.
SuperApe: To answer your question: That depends on which team the GameObjective is defended by. (0=red, 1=blue)
IceCreamYou: Numbering in Assault, unlike other gametypes, is relative. 0=attackers, 1=defenders (and even that doesn't apply when setting up playerstarts). However, after experimentation, I found that the number in DefenderTeamIndex has absolutely no effect on anything. I also changed the passage about DefensePriority to better reflect its usage.
SuperApe: Different gametypes will use that property as advertised, a few will not (as you found that AS is the odd duck in the group). But, on futher experimentation (say, in a CTF, BR or DDOM map), you'll find this property does what it's supposed to do.