-
Notifications
You must be signed in to change notification settings - Fork 1
/
UnitAI.js
173 lines (160 loc) · 5.81 KB
/
UnitAI.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*global MainGame*/
var UnitAI = {
takeTurn: function(unit) {
//console.log(MainGame.global.turn, unit.name, unit.currentIndex);
if (unit.target === null) {
unit.target = UnitAI.findTarget(unit);
}
var newMoveIndex = UnitAI.chooseMove(unit);
//console.log(newMoveIndex);
unit.move(newMoveIndex);
if (unit.isAttacking)
UnitAI.attackTarget(unit);
//console.log("");
},
findTarget: function(unit) {
if (unit.type === Unit.Riot) {
if(unit.currentIndex === unit.origin && MainGame.board.at(unit.currentIndex).getBuilding().name !== 'rubble'){
return unit.origin;
} else {
return MainGame.board.findBuilding('palace',null,null,null)[0];
}
} else if (unit.type === Unit.Army) { // Should never call findTarget with a homeless group, but just to be sure
var riotIndecies = MainGame.board.findUnits(Unit.Riot);
if (riotIndecies.length > 0) {
var palaceIndex = MainGame.board.findBuilding('palace',null,null,null)[0];
var armyDistance = MainGame.board.distanceOf(palaceIndex, unit.currentIndex);
var minDistance = null;
var minIndex = null;
for (var i = 0; i < riotIndecies.length; ++i) {
var totalDistance = MainGame.board.distanceOf(palaceIndex,riotIndecies[i]) + armyDistance;
if (!minDistance) {
minDistance = totalDistance;
minIndex = riotIndecies[i];
} else if (totalDistance < minDistance) {
minDistance = totalDistance;
minIndex = riotIndecies[i];
}
}
return MainGame.board.at(minIndex).getUnit();
} else {
return null;
}
}
},
// Determines what index to move the unit to. Returns either a tile index adjacent to the current index, or null if no move is desired
chooseMove: function(unit) {
var targetIndex = null;
if (unit.type === Unit.Army) {
if (unit.target !== null) {
targetIndex = unit.target;
} else {
// If an Army unit does not have a target, then it will patrol roads
// If it is not on a road, it will move toward the army base until it finds a road
if (MainGame.board.at(unit.currentIndex).getBuilding().name === "road" || unit.currentIndex === unit.origin) {
var adjacent = MainGame.board.allAdjacent(unit.currentIndex,1);
var roads = [];
for(var i=0; i<adjacent.length; ++i){
if(MainGame.board.at(adjacent[i]).getBuilding().name)
roads.push(adjacent[i]);
}
if(roads.length>0){
return roads[Math.floor(Math.random()*roads.length)];
}
else{
targetIndex = unit.origin;
}
}else{
targetIndex = unit.origin;
}
}
} else if (unit.type === Unit.Riot) {
if (unit.currentIndex === unit.target) {
unit.isAttacking = true;
return null;
}
targetIndex = unit.target;
}
var currentWeight = MainGame.board.distanceOf(unit.currentIndex, targetIndex);
var adjacentTiles = MainGame.board.allAdjacent(unit.currentIndex, 1);
var choices = [];
for(var i = 0; i < adjacentTiles.length; ++i) {
if(adjacentTiles[i])
// Checking to see if the adjacent hex is the unit's target
// if so, then the unit will immediately attack it
if (adjacentTiles[i] === targetIndex) {
if (unit.type === Unit.Army && unit.target != null) {
unit.isAttacking = true;
return null;
} else {
if(unit.type === Unit.Riot){
unit.isAttacking = true;
}
return adjacentTiles[i];
}
}
choices.push({tileIndex:adjacentTiles[i],weight:0,building:""});
var tile = MainGame.board.at(adjacentTiles[i]);
if(tile.hasBuilding())
choices[i].building = tile.getBuilding().name;
if(tile.hasUnit()){
choices[i].weight = 999;
var adjacentUnit = tile.getUnit();
if(unit.type === Unit.Riot && adjacentUnit.type === Unit.Riot && unit.health <= adjacentUnit.health && choices[i].weight < currentWeight){
UnitAI.mergeUnits(adjacentUnit,unit);
return null;
}
}else if(tile.getTerrainType() !== "water" && tile.getTerrainType() !== "mountain"){
choices[i].weight = MainGame.board.distanceOf(adjacentTiles[i],targetIndex)*100;
if(choices[i].building === "road" || choices[i].building === "rubble")
choices[i].weight -= Math.floor(Math.random()*50);
else if(unit.type === Unit.Riot && choices[i].building !== "" && choices[i].weight <= currentWeight)
choices[i].weight = Math.floor(Math.random()*choices[i].weight);
else
choices[i].weight += Math.floor(Math.random()*50);
}
}
// sort choices by their weighted values
choices.sort(function(a,b){return a.weight-b.weight;});
// targeting nearby building
if (unit.type === Unit.Riot) {
if(choices[0].building !== "road" && choices[0].building !== "rubble" && choices[0].building !== ""){
unit.isAttacking = true;
unit.target = choices[0].tileIndex;
}
}
return choices[0].tileIndex;
},
attackTarget: function(unit) {
if (unit.type === Unit.Riot) {
var targetTile = MainGame.board.at(unit.target);
// If the building is about to die...
if(unit.health >= targetTile.getBuilding().integrity){
unit.target = null;
unit.isAttacking = false;
// Before we actually demolish the building, send a telemetry payload!
Telemetry.send({
type: 'building_destroyed',
buildingName: targetTile.getBuilding().name,
buildingIndex: targetTile.index,
turn: MainGame.global.turn,
});
}
targetTile.damageBuilding(unit.health);
} else if (unit.type === Unit.Army) {
var targetUnit = unit.target;
// If the targeted unit is about to die...
if(unit.health >= targetUnit.health){
unit.target = null;
unit.isAttacking = false;
}
targetUnit.takeDamage(unit.health);
}
unit.attackSfx.play();
},
mergeUnits: function(unit1, unit2) {
var transfer = Math.min(unit2.health, Unit.maxSize - unit1.health);
unit1.addPeople(transfer);
unit2.subtractPeople(transfer);
}
};