Entries in ai (3)

Thursday
Dec162010

Game difficulty dictionary, part 2: real-world skill development (featuring Dance Central and Fighters Uncaged)

Following on from last week’s post on using differing opponent tactics to provide a more or less difficult experience for the player, this week we’ll be looking at something ostensibly more straight forward: making games harder by forcing the player to improve their real-world skills.

This also seemed to be an opportune time to explore the Kinect – our resident artist (in both the game art and martial sense) tried his hand (and foot, as it were) at both Dance Central and Fighters Uncaged.

Getting it wrong: Fighters Uncaged

Resident martial artist, Goose:

Fighters Uncaged has no set difficulty level; as the game progresses the characters you fight are supposed to be more difficult to defeat.

The interesting thing here though is that by the time you reach the latter stage opponents you have had ample chance (in some cases more than enough) to get your head around a method that works for you. So long as you stick to your method you won't go far wrong.

A prime example of this is when you are trying to graduate up to the next league. The hardest part isn't winning fights (that’s incredibly simple to do) it's trying to win within an imposed time limit with as much life left as possible so you can collect points. Points are what you need to advance up a level.

The main problem with this system is that you will end up fighting the same people over and over again to try and shave bits off your time. This gets very old very quickly.

Early on I discovered that simply dodging any blow and then following it up with an elbow to the same side that the blow came from was incredibly effective. After figuring this out and graduating up a level, I went straight for the toughest fighter in the class and wiped the floor with him with very little effort.

There is an almost complete disconnect between real world skill and your ability to perform well in the game. Personally, this was a massive let down especially as Dance Central heighted that this isn't due to the technology not being able to keep up with the finer points of the player's movements. Having studied several martial arts throughout my childhood and adult life, I’d made the presumption that I may have the edge over less “skilled” players.

As it turned out, I found I was constantly having to hold back and understate my movements: if I neglected to do so then my character had a tendency to behave unpredictably – lunging forward into a high kick I’d made a simple right hook. The point was rubbed in further still when my girlfriend and her sister (with no fighting experience whatsoever) experienced no difficulty at all in "wind-milling” through opponents.

Success in Fighters Uncaged seems to come primarily from figuring out the weaknesses in the game: presumably, the neat trick of an elbow to the side doesn’t work quite so reliably in a real-world scenario. As the came gets harder, you are more reliant on your understanding of the user interface of the game, not of what the game’s telling you should be good at: fighting.

Getting it right: Dance Central

Resident martial artist (and soon-to-be dancer), Goose:

Difficulty in Dance Central can be set manually, from a choice of easy, medium, hard and expert. Players are rated based on their performance in each song.

Increasing the difficulty increases the expectation put upon the player by requiring more moves per sequence. It also requires the player to execute moves more accurately.

Because each level of difficulty builds upon the last, the player is rewarded for their performance at one level by equipping them with the framework for the next. Presumably this isn’t dissimilar from how one might learn to dance in the real world.

It’s clear that the player’s ability to dance drastically improves their chances of success in this game. I also believe that with sufficient (game) play and practice, the player will become a better dancer.

The accuracy of the Kinect’s sensors shines in Dance Central – there’s no frustration over incorrectly tracked movements and there’s plenty of feedback – if one of your legs is trailing or your arm isn't hitting the right area the on-screen representation of it is highlighted.

For those familiar with Guitar Hero and Rock Band, the way increased difficulty is manifested in Dance Central is pretty familiar. Only difference here is that there’s a couple of layers of abstraction removed: the Kinect is using the player’s dance movements as an interface to, well, dance movements. It’s effectively assessing real-world skills, whereas Guitar Hero and Rock Band assess game-world skills using real word inputs, and to some extent, outputs (more on Rock Band 3’s Pro mode in a future post – that’s a whole different ball game).

The unsatisfying experience of Fighters Uncaged is now apparent – it can’t possibly be assessing the player’s ability to fight because they’re not fighting – they’re stood in the middle of a room throwing shapes at a television screen whilst the game itself simulates fighting. In Dance Central, this doesn’t matter; there’s very little difference between watching (and emulating) other dancers on screen and  watching (and also emulating) other dancers in a real-world, sticky-floors-and-everything, club.

It's entirely possible to rely on real-world skill development (other than video game playing skills) to provide a progressive, adaptive or explicit experience for the player -- but if you're going to attempt do this without some level of abstraction you need to be very careful that you're assessing the right skills. This is particularly evident when the skills required are physical (we're in the very early stages of human interfaces) and when they're the primary skill required to play the game (there are plenty of examples of secondary skills drawing on real-world experience - such as the example of Modern Warfare 2 drawing on a understanding of basic military tactics in its harder difficulty modes).

Wednesday
Dec082010

Game difficulty dictionary, part 1: opponent tactics (case studies from Strategery and Modern Warfare 2)

Game difficulty: not an easy one to pin down. In this, the first of a series of posts on the subject, we're going to look at one method of providing a more "difficult" experience for those players who want one: opponent tactics.

We've explored this by example - mainly because it's more fun to read that way, but also because it's useful for those not familiar with the genres used or for those who haven't tried the different difficulty settings available.

I'm sure most have you have played MW2 (note that other Call of Duty titles aren't necessarily appicable - we'll perhaps write about the apparent lack of considered difficulty settings in Black Ops at another point). The other example, Strategery, is available as a universal app for iPhone/iPod and iPad. For the purpose of the example, it makes no difference which device you're looking at.

The key thing to note here is that on the easier settings, the opponent AI in both games plays without tactics - they are equipped with basic responses and impulses, but no real tactical knowledge. On harder settings the opponent player/AI is equipped with tactical knowledge which it employs it to reach its objectives.

Through the provision of different difficulty settings these games manage to provide two distinctly different experiences: a visceral experience that provides no challenge, and; an intellectual challenge that requires the player to apply and develop skills (with the visceral elements rewarding and encouraging them along the way).

Case Study: Strategery

(above: key points in a vs AI game on "Easy" difficulty setting - human player is blue)

Strategery is a domination-style game in which several players (in this case one human player and the others all AI players) take turns to make advances across the board, with the winning objective being to conquer all of the available regions. There are some subtle nuances to how play progresses - namely that with the standard rule set new playing pieces are first divided between your border regions and then your other (less vulnerable) regions. Each player is rewarded with new pieces at the end of their turn equivalent to the number of regions in the largest contiguous area they occupy.

On the Easy difficulty setting, the AI players:

  • focus on expansion;
  • attack "soft" targets (those with fewer pieces);
  • end up hugging the edges of the playing area as it looks to expand in every direction, and, most importantly;
  • are oblivious to other players' movements.

Note: there also seems to be an element of "cheating" in the random (dice roll) element of play on Easy - whilst rolls in even scenarios on Brutal seemed to be 50/50, on the Easy setting they seemed to average 70/30 in favour of the player.

(above: key points in a vs AI game on "Brutal" difficulty setting - human player is blue)

On the Brutal difficulty setting, the AI players:

  • concentrate on constricting other players;
  • will attempt to "cut through" large areas occupied by their opponents, and;
  • try to minimise the number of "border" regions they have in play (in order to concentrate newly awarded playing pieces to those borders).

It doesn't take long playing the game to realise that the Brutal AI plays very much like a mindful human player who is adopting Blitzkrieg-like tactics.

Case Study: Call of Duty: Modern Warfare 2

On the Recruit (easy) setting, Modern Warfare 2 is straight forward to play - it's pretty difficult to get yourself killed. The experience is very much like watching a gripping action film in the same genre, the player is taken along for, and "shown", the ride. 

The Regular diffculty setting only changes the experience by adding a few more opponent forces and by making them a little more able to aim accurately. If it were not for the back drop you'd be forgiven for feeling like Master Chief wading through hordes of the Covenant.

In these two easiest modes the player is pretty much denied the opportunity to think tactically and it's difficult to become immersed in the full mise en scène of the respective levels' design.

When first jumping in to the harder difficulty settings (Hardened and Veteran) it can, at first, seem a little frustrating: there is a noticeable change in how hard it is to accomplish objectives. The game doesn't get harder simply because the opponent's bullets do more damage or because their aim is so much better, it gets harder because the enemy forces are actually employing a tactical method in trying to kill you. Amongst other things, they'll plan ways to get around your "wall of fire" and they'll keep their heads down to avoid getting shot wherever possible.

This is where things get interesting: you quickly abandon your run-and-gun approach and end up having to completely immerse yourself in the environment in order to develop your own tactics. Instead of following a linear path from one check point to the next, the player has to evaluate each immediate objective. By thinking laterally and adopting a more military (realistic) mindset each stage is completed with relative ease. By flitting from cover to cover and only taking shots that are available survival is prolonged. The changes in enemy behaviour and consequential planned tactics employed by the player enhance the sense of danger and realism. 

The diagrams above illustrate the analysis below for the extremes of difficulty in the Market Square section of the "Hornet's Nest" level - set in the favellas of Rio de Janeiro.

If you've not seen it before, check out YouTube-hosted walkthroughs of Hornet's Nest on Recruit (easiest) difficulty and Hornet's Nest on Veteran (hardest) difficulty.

On the Recruit (easiest) setting: 

  • The player has essentially free reign on the route they want to take.
  • The player can head straight for the raised area around the central building and:
    • see all the enemy forces
    • wait for the enemy to enter the map from the main spawn point (green arrow in diagram) or the building tops
    • wait for the enemy to filter through towards areas A, B & C
    • pick off enemy targets as they expose themselves between those areas
    • watch (and pick off) a steady pattern of enemies moving from roof #1 to building #3 and on to #6 and #7
    • ignore building #7 once it has been cleared (it generally isn't re-occupied by the enemy)
    • do likewise for enemies moving into buildings #5 and #8
  • The enemy player's basic tactic of holding positions and occasionally taking shots when available makes overpowering them very easy: the player can get a good view of where enemies are and can deal with them one by one by standing behind cover and surveying the map as the other non-player-controlled members of the team keep the enemy suppressed in cover.

On the Veteran (hardest) setting:

  • Enemy soldiers still spawn in the same areas, however it's rare that they move across open ground.
  • Instead of simply reaching A, B, or C, the enemy soldiers will, if possible, push on to reach area D and ultimately will attempt to take control of the central raised area.
  • The enemy soldiers that spawn on the roof of building #1 still filter through #3, #6 and #7 but if and when the occupants of building #7 are eliminated, remaining soldiers will move around in order to occupy the more advantageous #7 building.
  • Similarly, the troops around area C and those spawning from #2 will continuously try to occupy buildings #5 and #8.
  • Combined with the continuous suppression of the player's team members, the above enemy tactics force the player into making their own tactical choices.
  • The obvious route - to the central area - gets the player killed quickly. If the player heads up towards the raised part of the central building they are quickly overwhelmed: they are flanked from two sides and the enemy will actively move in on the player. As the enemy soldiers have a better aim (than on easier settings), both the player and their team mates are regularly forced into cover, allowing the enemy free (and largely invisible to the player) movement of the battlefield.
  • The player will need to choose a flank on which they wish to counter attack and attempt to clear a path up one side of the map with the aim of getting around the rear of the enemy forces (note that doing this also rewards the player with "hidden intel" - an artificial reward/achievement).
  • Once occupying a position to the rear of the enemy, the enemy soldiers fall back allowing the player's team mates to advance - pushing the enemy back yet further.
Friday
Sep242010

Draft AI design/spec for Chaos-like turn-based tactical game

Earlier this year we were briefly involved in the design and early production of a Chaos-like game, inspired directly by Julian Gollop's popular original Chaos: The Battle of Wizards.

If you're not familiar with the original check out the many resources linked from the above wikipedia article and the original game rules.

Before the project was cancelled, we produced a version 1 AI design - which, unfortunately, never got used (or reviewed for that matter). So, in all it's unedited, incomplete glory, here is a design document for a Chaos AI. Apologies for the variable formatting - it's come via Google Docs > HTML > embedded CSS to this post.

Use it for what you like - and if you do fancy reviewing, editing or improving on it, do so and let us know in the comments and we'll keep it up to date.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License

AI Design for a Chaos-like game

Notes

This assumes game rules are enshrined in the interface functions provided to the AI player/code, but is written in such a way that it should behave in legally.

This is (should be) modular such that individual methods and calculations can be adjusted independently.

It assumes a set of constants that can be adjusted (and managed separately) for each AI player to produce a set of differently-behaving AIs. See AI Type and the Constants section for more information.

The design is set up to take positive actions based on the queries it makes to game state. As such, it can be incomplete (insofar as it may not recognise creature, spell or player characteristics or behaviors) but still functional (i.e. will still play turns).

In order to remain performant relatively easily manipulated through data (constant) changes, it performs single turn analysis in two broad stages (tactical and local/per creature). Long running actions (such as multi-turn moves to a target) are managed by creating predictable (within the given set of constants) behaviours that are also affected by previous actions (in the form of last-turn decision memory) that is affected by a weighting constant (see RankTargets and RankTargetsLocally). This allows for one AI player to be very responsive to new circumstances (a nearby threat mid long-running move) whilst another AI player may show determinism to follow through on long-running actions.

Discussion points / things to complete:

1. Should all creatures know ranged attack range of all other creatures? i.e. for inbound proximity (Ranged Defense Proximity, Melee Defense Proximity). A good human player might - but it's not realistic to expect that they always would.

2. How to handle infinite values (i.e. a creature that's not reachable - i.e. in water), significant for the purposes of calculation and multiplication. Options are:

2.1. Use 0 - will nullify any multiplying factor in relevant calculations
2.2. Use fixed representation of infinity (e.g. 9999) - will balloon factors in multiplying calculations

The real impact of the above is if a value that could be infinity (any of the proximities potentially) is used in a multiplication (which they are in RankTargetsLocally()), states that return the infinite value will result in either a 0 value or a higher value than anything else (other than other infinities).

One or the other will likely be desirable but a consistent use of potentially infinite values is preferable. If necessary, the logic could always be switched with (e.g. value==0 in the case of using infinity==0).

EDIT - this is largely irrelevant now - 2.1 isn't a valid option as it's possible to be adjacent to a target and have a proximity query return 0.


3. Handling of non-creature spells not factored into tactical or local decision making (i.e. avoidance of sticky blobs, movement toward citadels etc etc). Casting of these spells also isn't considered (but its not being considered is covered in the current non-specification of SelectAndCastSpell()).

4. How would/should a creature move away from a threat? This is potentially covered in MoveToTarget, option 2 in circumstances that include the creature ranking a very threatening creature as the current target and then acting "scared". This does not cover movement away from a creature/threat that is not the targeted creature, however (i.e. a creature may melee attack creature 1, ranged attack creature 2 but still want to move away from creature 3 or another threat (blob, fire etc).

5. Ranged proximity calculations are not accurate (and could be unpredictably very inaccurate) as they rely on a movement pathfind - obvious alternatives would be computationally expensive.

6. MoveToTarget() needs expansion - both in a tactical sense (making smarter movement decisions) and a practical one (how to accomplish path finding and boundary decisions). See description for more information.

7. How do wizards (and to some extent creatures) stay put / run away (different rank local for wizards?). Affected also by special spells and feature (towers, citadel etc). Separate decision for keeping wizards safe, then weighted against immediate threats (i.e. if it can't move out of range then eval RankTargetsLocally)?


8. How/should creatures make decisions about the threat of a wizard's potential spell casts (i.e. because they can't be evalutated as a simple threat calculation).

Legend

Stub methods / procedures
    - written in style MethodName(Argument 1, Argument 2)

    - only information relevant at point of mention is included in arguments list

Concepts


DATA

CONSTANTS


META - stuff not done, reminders and suchlike.

AI Player's move - outline steps


  1. RankPOPs(): Rank Points of Presence (POPs) - Player's Wizard and Creatures

  2. IdentifyTargets(): Identify Targets (up to MAX_TARGETS)

  3. RankTargets(): Rank Targets

  4. SelectAndCastSpell(): Select & cast spell appropriate spell, insert created creature (if any) into RankedPOPs (no position mechanic as yet - suspect first or last will work best, re-rank is feasible)

  5. (optional) IdentifyTargets() as a new creature may affect proximity-based calculations (see IdentifyTargets for options)

  6. (if spell cast sucessful) PurgeTargets(): Remove destroyed creatures / wizards

  7. (if spell cast sucessful) RankTargets(): Update rankings based on presence of new creature

  8. Step creatures (in order of RankedPOPs, but with Wizard moved to last place), and:
    1. TestEngagement(): check if creature is being engaged
    2. RankTargetsLocally(): sort RankedTargets for applicability to this creature
    3. Set CurrentTarget to position 1 on RankedLocalTargets
    4. MoveToTarget()
    5. MeleeAttack()
    6. If CurrentTarget no longer exists, select a new CurrentTarget (position #2 on RankedLocalTargets)
    7. RangedAttack()
    8. If CurrentTarget has not been destroyed, set this creature's LastTarget to CurrentTarget
    9. (if any attack was successful) PurgeTargets()
    10. (if any attack was successful) RankTargets()


Method descriptions

RankPOPs

Create sorted list of wizard and creatures (RankedPOPs) for the AI player, with Wizard always first and each creature listed in descending order of Relative Value.

Also needs to factor likelihood of engagement, so rank value should be:
Relative Value - (Number of Adjacent Creatures * ENGAGEMENT_PARANOIA)

IdentifyTargets

Scan entire visible map, then for each found wizard or creature calculate:

Perceived Value * SUM(Simple Distance to POPx from creature * Relative Value of POPx)

Note: the SUM part is evaluated for each of the AI Player's POPs.

Sort this list descending and store top MAX_TARGETS in Targets
 
Note - actual ranking is done in the RankTargets stage - the approximate calculation of importance shown above exists solely to create a sorted list (such that the top x creatures can be properly considered in RankTargets).

Potential simplification
: if it is possible to consider all targets in RankTargets (i.e. for a performance perspective), this step can likely be removed (a simple map scan would suffice).

ALTERNATIVE - work out from POPs (in descending order of importance), going 1 extra hex in radius for each iteration of the POPs list until reaching MAX_TARGETS. Note:
 - would need to ignore duplicates
 - doesn't necessarily hit all wizards
 - no assessment of value / threat / risk imposed by creatures discovered, only considers proximity to important targets

RankTargets

Prepares a ranked list of targets (in order of tactical importance), which can then be sorted locally for each controlled creature, and used for spell casting and wizard movement decisions.

See RankTargetsLocally for usage on a creature level.

Obtain rank for each creature(x) by:
RANK =
  (1 / Position in targets list) * TARGET_NEARBY_CREATURES
+ Threat(x, wizard) * WIZARD_PROTECTION
+ SUM(Threat(x, each creature)) * COMPANION_PROTECTION
+ Previous rank (rank score, not position) on RankedTargets list * PARTY_DETERMINATION
+ (1 / Turn Age of x) * ATTENTION_TO_NEW_CREATURES
+ Attention from Opponent * FOCUS_ON_AGRESSORS

Rank should also incorporate target affinity (i.e. targeting creatures belonging to the same wizard), this could be done as a simple distribution, e.g.:

+ (# Affiliated Targets / # Targets) * FOCUS_ON_SINGLE_OPPONENTS (not yet defined)


However, it would be more useful to balance it as attention on powerful opponents (based on the actual ranking value of all of each opponents creatures), so alternatively the entire RANK sum for an individual creature could then be:

* (# Affiliated Targets / # Targets) * FOCUS_ON_SINGLE_OPPONENTS (not yet defined)

Incorporate "rescue" like behavior for companions who are potentially engaged - with a factoring on ATTENTION_TO_ENGAGED_COMPANIONS. This was lost somewhere along the way - behavior may be emergent from other characteristics.

Note: see "Constants" section for description (and effect) of each constant.

RankTargetsLocally()

This will be a re-sort (by adding a local rank score to the existing rank and re-sorting - i.e. if the creature in position 1's rank score is orders of magnitude in score above position 2+, little will prevent all creatures from attacking (locally ranking at #1) that target.

Targets are re-ranked locally to obtain a target to attack (or to move to attack if out of range).

As per step 8. in the AI Player's move, this is done for every creature (AI Creature) for each target creature (Target Creature) in the RankedTargets list.

Local Rank for creature x =
(Rank
 + IsEngaged * (Move Proximity == 0) * FOCUS_ON_ENGAGING_TARGETS
 + Threat(Target Creature, AI Creature) * CREATURE_SELFISHNESS
 + Threat(AI Creature, Target Creature) * DESIRE_TO_KILL
 + (Target == Last Target) * CREATURE_DETERMINATION
 + (1 / Team Compatibility) * ATTENTION_TO_DIFFICULT_TARGETS
) * Compatibility

The Compatibility multiplier essentially forces unattackable targets to the bottom of the list when Compatibility is 0 and as a consequence of wizards being prone to attacks from all creatures (and therefore higher in the list) mean a creature should never attack an incompatible target.

Must include significant weighting for any immediately threatening creatures (i.e. ignoring tactics in favor of self defense) - NOTE: this replaces the old AssessThreatsToCreature() method and associated break-out loop from inner list of step creatures.

SelectAndCastSpell

Expand, considering:
- value ranking (against ranked targets)
- relative value of subsequent creature
- tactical (group wise) value
- likelihood of success (factored against constant)
- forward value (i.e. spell tactics)
- likelihood of illusion present (to cast disbelieve) (simple decision tree?)
- decision on casting an illusion (simple decision tree?)
- casting creatures that will be incompatible (undead etc)
- decision on non-creature spells and buffs, inc blobs, fires, citadels, turmoil, subversion, vortex, shadow form, teleport (embedded within decision tree that includes creature spells?)

TestEngagement()

Test for engagement and store in IsEngaged

MeleeAttack()

Attack the CurrentTarget with this creature's melee attack.

If out of range, this method could still be called (but obviously no attack will take place).

RangedAttack()

Attack the CurrentTarget with this creature's ranged attack.

If out of range, this method could still be called (but obviously no attack will take place).

MoveToTarget()

Make a movement decision for the current creature, based on it targeting the specified target.

If engaged, MoveToTarget() will return without movement having happened.

Movement assumes doing a pathfind to desired position and moving through that route as many place as is permitted by creature's movement ability.

Does not consider terrain types (other than in the sense that they're passable by some creatures and not others) - i.e. a defensive move for a weak creature vs one that can't pass terrain x, would be to move into terrain x and attack ranged only.

Also does not consider avoiding engagement and tactical choices on which side to engage an enemy, blocking opponent paths etc.

OPTION 1
    If the creature has a melee attack, move to within Melee Range (which may mean staying put).
    If the creature only has a ranged attack, either:
        Stay put if in range
        Move to within range (but no further)

OPTION 2
    Make assessment of relative threat and either act:
    AGGRESSIVELY
        If creature has melee move to within melee
        If no melee, move toward target (expand - how far toward target?)
    DEFENSIVELY
        Regardless of melee ability, move to just within ranged range
    SCARED
        Move away from target (which may still be in ranged range)

PurgeTargets

Check each creature / wizard in RankedTargets list still exists (if not, remove it from list)

Threat (attacker, defender)

The relative threat imposed by creature a on creature b.

EXPAND CALCULATION

Must sum (or multiply as appropriate):
- Actual Attack (a, d)
- Actual Defense (a, d)
- Proximity for Melee (in terms of number of turns to reach range - 0 should be special case)
- Proximity for Ranged (in terms of number of turns to reach range - 0 should be special case)
- Chance of hit (is this applicable)
- Chance of resist
- Chance of engagement and/or being engaged

Actual Attack (attacker, defender)

The actual attack value of creature a when attacking creature b.

EXPAND

Includes:
- base attack value
- buffs
- terrain bonus for attacker (inc special terrain types - citadel etc - if applicable)

Actual Defense (attacker, defender)

The actual attack value of creature a when attacking creature b.

EXPAND

Includes:
- base defence value
- buffs
- terrain bonus for attacker (inc special terrain types - citadel etc - if applicable)

Concept descriptions

Note: most are methods that return a scalar.

Relative Value

Typically used for AI player's creatures. The value of a creature compared to other creatures.


Calculated as a sum of relevant creature attributes with an individual multiplier constant on each. Attribute sum may look like:

RELATIVE_VALUE=
  movePoints * IMPORTANCE_OF_AGILITY
+ attack * IMPORTANCE_OF_ATTACK
+ defence * IMPORTANCE_OF_DEFENCE
+ magicdefence * IMPORTANCE_OF_DEFENCE
+ initiative * IMPORTANCE_OF_AGILITY
+ canFly * IMPORTANCE_OF_AGILITY
+ isUndead * IMPORTANCE_OF_UNDEAD
+ isMount * IMPORTANCE_OF_AGILITY

Note: the IMPORTANCE_OF_UNDEAD is no more complicated than the AI Player favoring undead creatures in spell selection and tactics - however, see alternative note 2 below where it could be more significant.

ALTERNATIVE 1
: a finer grained weighting could apply constants to each part of the calculation (i.e. split out agility and the like).

ALTERNATIVE 2: a more complicated calculation could be based upon game state, e.g. other creatures on the map (e.g. an undead creature is worth more if there are no other undead creatures, for example).

Note: Could be calculated differently per AI Type, but shouldn't need to be directly - changes in constants should be sufficient.

Perceived Value

The apparent value of an opponent creature or wizard. Similar to Relative Value, but:

- Ignorant of illusions
- Doesn't know stats on wizard
- Wizards' value will be multiplied by a fixed (per AI Type) constant PERCEIVED_WIZARD_IMPORTANCE such that they are more directly targeted.

Note: A separate set of IMPORTANCE_OF_ constants could be used for perceived value (for each AI Type) but is unlikely to be needed.

Compatibility

The ability for the given creature to attack (in any form) the given target. 0 if incompatible (i.e. attacking undead with a non-magic-casting mortal), 1 otherwise.

If water creatures are invunerable to attack (other than magic, other water creatures and dive bombs) this would include return 0 in such a circumstance.

The logic for any such compatibility test (or incompatibility between creature types / situations) can be embedded here without modifications elsewhere.

Wizards are always 1 against any target.

Team Combatibility

The team's mean compatibility with the target (3 of 4, including wizard would be 0.75).

Attention from Opponent

Relatively, how attention is the AI Player getting from the give opponent.


Could be calculated (remembered) as:
Total Number of Opponent Attacks / Total Number of Opponent Attacks Against Me

Note: A human player will likely make a judgement decision on this, not an actual one - but remembering the attack distribution for the purposes of satisfying the above sum for AI Players shouldn't have a significant unfair impact.

AI Type

A set of fixed weightings and constants that characterise a particular AI. See "Weighting Constants" in the Constants section.

Simple Distance

Straight-line distance between creatures.

ALTERNATIVE: use Move Proximity (far more potential computation due to aggregate use of Simple Distance in IdentifyTargets).

Melee Range

Generally 1, but greater in some cases (creatures with Dive Bomb ability, for example).

Move Proximity

Number of moves (spaces) required to be adjacent to target. If the target's already adjacent, should return 0.


If it's not possible to reach the target (i.e. blocked or incompatible terrain), return PROXIMITY_INFINITE.


Number of moves based on path find to target, not straight line.


Proximity should include adverse terrain affects (i.e. a single hex width 50% movement speed will result in a distance of 2, not 1, for that hex). Note - irrelevant if moves are costed.


Melee Attack Proximity

=Move Proximity - Melee Range (floored to zero - negative results only indicate creature is already in range).

Note: not accurate/optimal under certain conditions (i.e. dive bombing could bomb over impassable terrain, meaning a move pathfind takes a longer route).

Ranged Attack Proximity

Based on getting to a point from which a ranged attack can be initiated.

For simple calculation, it could be:

= Move Proximity - Ranged Range

However, this doesn't provide an optimal path as blocking in the later section is different for ranged weapons and creature movement.

Melee Defense Proximity

=Move Proximity - Melee Range of targeted creature (floored to zero - negative results only indicate already in range of that creature).

Note: not accurate/optimal under certain conditions (i.e. dive bombing could bomb over impassable terrain, meaning a move pathfind takes a longer route).

See note 1. regarding AI Player's knowledge of other creatures' abilities.

Ranged Defense Proximity

Based on the targeted creature getting with ranged distance.

For simple calculation, it could be:

= Move Proximity - Ranged Range of targeted creature

However, this doesn't provide an optimal path as blocking in the later section is different for ranged weapons and creature movement.

See note 1. regarding AI Player's knowledge of other creatures' abilities.

Turn Age

The number of turn for which a creature has been present in the game.


Data descriptions

Boolean values stored as int(0|1) for the purposes of calculation.

RankedPOPs - see RankPOPs - top of list is greatest value (Relative Value - with Wizard at top regardless)

Targets - list of targets (see IdentifyTargets)

RankedTargets - ranked list of targets (see RankTargets)

CurrentTarget - (per creature) the target a creature is currently operating on

RankedLocalTargets - re-ranked version of RankedTargets based on applicability to current creature

IsEngaged (bool) - is current creature currently engaged

Constants

See AI Type for details on usage

Note: each constant may require a companion constant (multiplier) (not specific to AI Type) in order to balance disparate figures and obtain approximate balance amongst design-adjusted constants (those below) such that they can all be represented in similar orders of magnitude and/or are otherwise clear in usage. A range of viable/sensible parameters should come out in testing (and analysis of ranking functions outputs).

General constants

MAX_TARGETS - The max number of targets considered in AI players decision


PROXIMITY_INFINITE - Likely 999 or similar.


Weighting constants (all are relative - i.e. increasing every constant by the same factor will have no affect).


PERCEIVED_WIZARD_IMPORTANCE - Higher values will cause AI Players to target player wizards more directly

ENGAGEMENT_PARANOIA - Higher value will cause creatures that can't be engaged (no adjacent enemies) to act first.

FOCUS_ON_ENGAGING_TARGETS - Higher values will cause creatures to directly target any adjacent creatures when engaged, lower values won't necessarily mean the oppposite but will allow for a chance of attacking other creature with ranged attacks if other circumstances promote/permit it.

ATTENTION_TO_ENGAGED_COMPANIONS - Higher value will cause more attacks on creatures that are potentially engaging companions.

IMPORTANCE_OF_AGILITY - Used in relative value. Will cause AI Player to favor agile creatures in spell selection and tactical importance.

IMPORTANCE_OF_ATTACK - Used in relative value. Will cause AI Player to favor high attack value creatures in spell selection and tactical importance.

IMPORTANCE_OF_DEFENCE - Used in relative value. Will cause AI Player to favor high defence value creatures in spell selection and tactical importance.

IMPORTANCE_OF_UNDEAD - Used in relative value. Will cause AI Player to favor undead creatures in spell selection and tactical importance.

TARGET_NEARBY_CREATURES - Higher value mean creatures that are closer to more of the AI Player's creatures will be targeted more readily.

WIZARD_PROTECTION - Higher values will cause all creatures to target creatures that threaten the wizard most.

COMPANION_PROTECTION - Higher values will distort targets such that the most threatening creatures (to the entire party) are ranked at the top.

PARTY_DETERMINATION - The extent to which targeting choices should be carried between turns. High values will cause creatures that are ranked high to continue to rank high until they are killed and new creatures to be ignored.

ATTENTION_TO_NEW_CREATURES - Higher values will cause newly casted creatures to be ranked higher. Can be used to balance PARTY_DETERMINATION

FOCUS_ON_AGGRESORS - Higher values will cause higher ranking of creatures belonging to opponents who have attacked this AI Player more than other players, and subsequently should cause opponents who have not attacked this AI Player to be left alone (all else being equal).


CREATURE_SELFISHNESS - The attention paid to creatures who impose a local (personal) threat to the creature in question. Essentially the extent to which tactics are followed.

DESIRE_TO_KILL - Higher values will cause higher targeting of creatures that this AI Creature has a better chance of killing. THIS IS IMPORTANT as it effectively dicatates the sensible matchmaking of creatures in the AI Player's roster with the tactical list of targets). Obviously needs to be balanced against everything else though ;)

CREATURE_DETERMINATION - Higher values will cause the creature to prefer creatures that it's previously targeted.

ATTENTION_TO_DIFFICULT_TARGETS - Higher values will cause creatures that are compatible with creatures that are difficult (in the sense than not many companions can target then - i.e. undead) to target them more directly. I.e. undeads will always go for undeads all else being equal.