Refactored BullyMove, using the new AIManeuver
For future AI helpers
This commit is contained in:
parent
8b256aa95c
commit
5cffb1680c
27
src/scripts/game/ai/AIManeuver.ts
Normal file
27
src/scripts/game/ai/AIManeuver.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
module SpaceTac.Game.AI {
|
||||
"use strict";
|
||||
|
||||
// Ship maneuver for an artifical intelligence
|
||||
// A maneuver is like a human player action, choosing an equipment and using it
|
||||
export class AIManeuver {
|
||||
// Concerned ship
|
||||
ship: Ship;
|
||||
|
||||
// Equipment to use
|
||||
equipment: Equipment;
|
||||
|
||||
// Target for the action;
|
||||
target: Target;
|
||||
|
||||
constructor(ship: Ship, equipment: Equipment, target: Target) {
|
||||
this.ship = ship;
|
||||
this.equipment = equipment;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
// Apply the maneuver in current battle
|
||||
apply(): void {
|
||||
this.equipment.action.apply(this.ship.getBattle(), this.ship, this.target);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,23 +2,23 @@
|
|||
module SpaceTac.Game.AI {
|
||||
"use strict";
|
||||
|
||||
export class BullyMove {
|
||||
// Position to move to, before firing
|
||||
move_to: Target;
|
||||
// Combination of a move action and a fire action
|
||||
export class BullyManeuver {
|
||||
// Move action to position the ship before firing
|
||||
move: AIManeuver;
|
||||
|
||||
// Engine used to move
|
||||
engine: Equipment;
|
||||
// Fire action
|
||||
fire: AIManeuver;
|
||||
|
||||
// Weapon to use
|
||||
weapon: Equipment;
|
||||
|
||||
// Ship to target
|
||||
target: Ship;
|
||||
constructor(move: AIManeuver = null, fire: AIManeuver = null) {
|
||||
this.move = move;
|
||||
this.fire = fire;
|
||||
}
|
||||
|
||||
// Get a sorting score, by distance to another point
|
||||
// Nearest means higher score
|
||||
getScoreByDistance(point: Target): number {
|
||||
return -point.getDistanceTo(Target.newFromShip(this.target));
|
||||
return -point.getDistanceTo(this.fire.target);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,13 +35,13 @@ module SpaceTac.Game.AI {
|
|||
|
||||
protected initWork(): void {
|
||||
this.addWorkItem(() => {
|
||||
var moves = this.listAllMoves();
|
||||
var maneuvers = this.listAllManeuvers();
|
||||
|
||||
if (moves.length > 0) {
|
||||
var move = this.pickMove(moves);
|
||||
this.applyMove(move);
|
||||
if (maneuvers.length > 0) {
|
||||
var maneuver = this.pickManeuver(maneuvers);
|
||||
this.applyManeuver(maneuver);
|
||||
|
||||
// Try to make another move
|
||||
// Try to make another maneuver
|
||||
this.initWork();
|
||||
}
|
||||
});
|
||||
|
@ -65,18 +65,18 @@ module SpaceTac.Game.AI {
|
|||
return this.ship.listEquipment(SlotType.Weapon);
|
||||
}
|
||||
|
||||
// List all available "moves" for the playing ship
|
||||
listAllMoves(): BullyMove[] {
|
||||
var result: BullyMove[] = [];
|
||||
// List all available maneuvers for the playing ship
|
||||
listAllManeuvers(): BullyManeuver[] {
|
||||
var result: BullyManeuver[] = [];
|
||||
|
||||
var enemies = this.listAllEnemies();
|
||||
var weapons = this.listAllWeapons();
|
||||
|
||||
enemies.forEach((ship: Ship) => {
|
||||
weapons.forEach((weapon: Equipment) => {
|
||||
var move = this.checkBullyMove(ship, weapon);
|
||||
if (move) {
|
||||
result.push(move);
|
||||
var maneuver = this.checkBullyManeuver(ship, weapon);
|
||||
if (maneuver) {
|
||||
result.push(maneuver);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -85,8 +85,8 @@ module SpaceTac.Game.AI {
|
|||
}
|
||||
|
||||
// Check if a weapon can be used against an enemy
|
||||
// Returns the BullyMove, or null if impossible to fire
|
||||
checkBullyMove(enemy: Ship, weapon: Equipment): BullyMove {
|
||||
// Returns the BullyManeuver, or null if impossible to fire
|
||||
checkBullyManeuver(enemy: Ship, weapon: Equipment): BullyManeuver {
|
||||
// Check if enemy in range
|
||||
var target = Target.newFromShip(enemy);
|
||||
var distance = target.getDistanceTo(Target.newFromShip(this.ship));
|
||||
|
@ -121,40 +121,40 @@ module SpaceTac.Game.AI {
|
|||
// Not enough AP to fire
|
||||
return null;
|
||||
} else {
|
||||
var result = new BullyMove();
|
||||
result.move_to = move;
|
||||
result.engine = engine;
|
||||
result.target = enemy;
|
||||
result.weapon = weapon;
|
||||
var result = new BullyManeuver();
|
||||
if (move) {
|
||||
result.move = new AIManeuver(this.ship, engine, move);
|
||||
}
|
||||
result.fire = new AIManeuver(this.ship, weapon, target);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Pick a move from a list of available ones
|
||||
// Pick a maneuver from a list of available ones
|
||||
// By default, it chooses the nearest enemy
|
||||
pickMove(available: BullyMove[]): BullyMove {
|
||||
pickManeuver(available: BullyManeuver[]): BullyManeuver {
|
||||
if (available.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Sort by descending score
|
||||
available.sort((m1: BullyMove, m2: BullyMove): number => {
|
||||
available.sort((m1: BullyManeuver, m2: BullyManeuver): number => {
|
||||
var point = Target.newFromShip(this.ship);
|
||||
return m1.getScoreByDistance(point) < m2.getScoreByDistance(point) ? 1 : -1;
|
||||
});
|
||||
return available[0];
|
||||
}
|
||||
|
||||
// Effectively apply the chosen move
|
||||
applyMove(move: BullyMove): void {
|
||||
if (move.move_to) {
|
||||
// Effectively apply the chosen maneuver
|
||||
applyManeuver(maneuver: BullyManeuver): void {
|
||||
if (maneuver.move) {
|
||||
this.addWorkItem(() => {
|
||||
move.engine.action.apply(this.battle, this.ship, move.move_to);
|
||||
maneuver.move.apply();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
this.addWorkItem(() => {
|
||||
move.weapon.action.apply(this.fleet.battle, this.ship, Target.newFromShip(move.target));
|
||||
maneuver.fire.apply();
|
||||
}, 1500);
|
||||
|
||||
this.addWorkItem(null, 1500);
|
||||
|
|
|
@ -63,10 +63,10 @@ module SpaceTac.Game.AI.Specs {
|
|||
ship.arena_y = 0;
|
||||
enemy.arena_x = 3;
|
||||
enemy.arena_y = 0;
|
||||
var result = ai.checkBullyMove(enemy, weapon);
|
||||
expect(result.move_to).toBeNull();
|
||||
expect(result.target).toBe(enemy);
|
||||
expect(result.weapon).toBe(weapon);
|
||||
var result = ai.checkBullyManeuver(enemy, weapon);
|
||||
expect(result.move).toBeNull();
|
||||
expect(result.fire.target).toEqual(Target.newFromShip(enemy));
|
||||
expect(result.fire.equipment).toBe(weapon);
|
||||
|
||||
// enemy out of range, but moving can bring it in range
|
||||
ship.ap_current.set(8);
|
||||
|
@ -74,10 +74,10 @@ module SpaceTac.Game.AI.Specs {
|
|||
ship.arena_y = 0;
|
||||
enemy.arena_x = 6;
|
||||
enemy.arena_y = 0;
|
||||
result = ai.checkBullyMove(enemy, weapon);
|
||||
expect(result.move_to).toEqual(Target.newFromLocation(3, 0));
|
||||
expect(result.target).toBe(enemy);
|
||||
expect(result.weapon).toBe(weapon);
|
||||
result = ai.checkBullyManeuver(enemy, weapon);
|
||||
expect(result.move.target).toEqual(Target.newFromLocation(3, 0));
|
||||
expect(result.fire.target).toEqual(Target.newFromShip(enemy));
|
||||
expect(result.fire.equipment).toBe(weapon);
|
||||
|
||||
// enemy out of range, but moving can bring it in range, except for the safety margin
|
||||
ai.move_margin = 0.1;
|
||||
|
@ -86,7 +86,7 @@ module SpaceTac.Game.AI.Specs {
|
|||
ship.arena_y = 0;
|
||||
enemy.arena_x = 6;
|
||||
enemy.arena_y = 0;
|
||||
result = ai.checkBullyMove(enemy, weapon);
|
||||
result = ai.checkBullyManeuver(enemy, weapon);
|
||||
expect(result).toBeNull();
|
||||
ai.move_margin = 0;
|
||||
|
||||
|
@ -96,7 +96,7 @@ module SpaceTac.Game.AI.Specs {
|
|||
ship.arena_y = 0;
|
||||
enemy.arena_x = 30;
|
||||
enemy.arena_y = 0;
|
||||
result = ai.checkBullyMove(enemy, weapon);
|
||||
result = ai.checkBullyManeuver(enemy, weapon);
|
||||
expect(result).toBeNull();
|
||||
|
||||
// enemy in range but not enough AP to fire
|
||||
|
@ -105,7 +105,7 @@ module SpaceTac.Game.AI.Specs {
|
|||
ship.arena_y = 0;
|
||||
enemy.arena_x = 3;
|
||||
enemy.arena_y = 0;
|
||||
result = ai.checkBullyMove(enemy, weapon);
|
||||
result = ai.checkBullyManeuver(enemy, weapon);
|
||||
expect(result).toBeNull();
|
||||
|
||||
// can move in range of enemy, but not enough AP to fire
|
||||
|
@ -114,7 +114,7 @@ module SpaceTac.Game.AI.Specs {
|
|||
ship.arena_y = 0;
|
||||
enemy.arena_x = 6;
|
||||
enemy.arena_y = 0;
|
||||
result = ai.checkBullyMove(enemy, weapon);
|
||||
result = ai.checkBullyManeuver(enemy, weapon);
|
||||
expect(result).toBeNull();
|
||||
|
||||
// no engine, can't move
|
||||
|
@ -124,7 +124,7 @@ module SpaceTac.Game.AI.Specs {
|
|||
ship.arena_y = 0;
|
||||
enemy.arena_x = 6;
|
||||
enemy.arena_y = 0;
|
||||
result = ai.checkBullyMove(enemy, weapon);
|
||||
result = ai.checkBullyManeuver(enemy, weapon);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
|
@ -144,7 +144,7 @@ module SpaceTac.Game.AI.Specs {
|
|||
var ai = new BullyAI(ship1.fleet);
|
||||
ai.ship = ship1;
|
||||
|
||||
var result = ai.listAllMoves();
|
||||
var result = ai.listAllManeuvers();
|
||||
expect(result.length).toBe(0);
|
||||
|
||||
var weapon1 = new Equipment(SlotType.Weapon);
|
||||
|
@ -159,7 +159,7 @@ module SpaceTac.Game.AI.Specs {
|
|||
ai.ship.ap_current.setMaximal(10);
|
||||
ai.ship.ap_current.set(8);
|
||||
|
||||
result = ai.listAllMoves();
|
||||
result = ai.listAllManeuvers();
|
||||
expect(result.length).toBe(3);
|
||||
});
|
||||
|
||||
|
@ -196,12 +196,12 @@ module SpaceTac.Game.AI.Specs {
|
|||
ship2.hull.set(15);
|
||||
ship2.shield.set(10);
|
||||
|
||||
var move = ai.checkBullyMove(ship2, weapon);
|
||||
var move = ai.checkBullyManeuver(ship2, weapon);
|
||||
expect(move).not.toBeNull();
|
||||
|
||||
battle.playing_ship = ai.ship;
|
||||
battle.log.clear();
|
||||
ai.applyMove(move);
|
||||
ai.applyManeuver(move);
|
||||
|
||||
expect(battle.log.events.length).toBe(7);
|
||||
|
||||
|
|
Loading…
Reference in a new issue