-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.pathing.js
147 lines (144 loc) · 5.47 KB
/
util.pathing.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
/* TODOs:
- Treat planned roads as cheaper during multiple passes.
*/
function roomCallback(roomName) {
const room = Game.rooms[roomName];
var out = new PathFinder.CostMatrix();
if(!room) {
return out;
}
var obstacles = room.find(FIND_STRUCTURES).concat(room.find(FIND_CONSTRUCTION_SITES));
_.forEach(obstacles, s => {
if(OBSTACLE_OBJECT_TYPES.includes(s.structureType)) {
out.set(s.pos.x, s.pos.y, 255);
} else if(s.structureType == STRUCTURE_ROAD) {
out.set(s.pos.x, s.pos.y, 1);
}
});
return out;
}
module.exports = {
roomCallback: roomCallback,
swampCheck: function(src, dest, roomMatrix=null) {
// XXX will break if this ever tries to span a room.
// TODO(baptr): Presumably there could be cases where leaving the room
// could give a better path.
if(!roomMatrix) {
roomMatrix = roomCallback(src.roomName);
}
var vis = (Game.rooms[src.roomName] || {}).visual;
if(!vis) {
console.log('Warning: unable to see for path planning '+src.roomName);
vis = new RoomVisual(src.roomName);
}
// TODO(baptr): Safe to always assume range: 1? I think so.
// Should be even further for controllers, since they have 3 upgrade range.
// TODO(baptr): Doesn't handle return trips from controllers...
var range = 1;
if(dest instanceof StructureController) {
range = 3;
}
var res = PathFinder.search(src, {pos: dest, range: range}, {roomCallback: () => roomMatrix, swampCost: 2, maxRooms: 1});
var ret = [];
var cloneMatrix = roomMatrix.clone();
// TODO(baptr): can't short-cut the first pass on swamp traversal.
//if(res.path.length < res.cost) { // Ended up traversing a swamp!
_.forEach(res.path, (p, i) => {
// Pretend there's a creep in the way for the next pass.
cloneMatrix.set(p.x, p.y, 5);
var prev = res.path[i-1] || src;
var t = p.lookFor(LOOK_TERRAIN)[0];
if(t == 'swamp') {
// TODO(baptr): Ignore it if there's already a road there??
ret.push(p);
vis.line(prev, p, {color: '#55ff11'})
} else {
vis.line(prev, p);
}
})
//}
// Do another pass with the first path soft-blocked (by creeps)
var cloneRes = PathFinder.search(src, {pos: dest, range: 1}, {roomCallback: () => cloneMatrix, swampCost: 2, maxRooms: 1});
// TODO(baptr): The second pass can be short-circuited, but then you lose visualization.
//if(cloneRes.path.length < cloneRes.cost) { // Hit another swamp, or had to wait for a creep to move
_.forEach(cloneRes.path, (p, i) => {
var prev = cloneRes.path[i-1] || src;
var t = p.lookFor(LOOK_TERRAIN)[0];
if(t == 'swamp') {
ret.push(p);
vis.line(prev, p, {color: '#11aa00'});
} else {
vis.line(prev, p, {color: '#555555'});
}
});
//}
return ret;
},
// return the number of walkable spaces adjacent to the provided room position.
spacesNear: function(pos, range = 1, ignoreCreeps = true) {
var room = Game.rooms[pos.roomName];
var area = room.lookAtArea(pos.y-range, pos.x-range, pos.y+range, pos.x+range, false);
var free = [];
for(var y = pos.y-range; y <= pos.y+range; y++) {
for(var x = pos.x-range; x <= pos.x+range; x++) {
if(!area[y][x]) {
console.log(`spacesNear(${pos}): missing ${x}, ${y}`);
continue;
}
var blocked = false;
for(var i = 0; i < area[y][x].length; i++) {
var o = area[y][x][i];
var t = o.type;
switch(t) {
case LOOK_STRUCTURES:
case LOOK_CONSTRUCTION_SITES:
t = o[t].structureType;
break;
case LOOK_TERRAIN:
t = o[t];
break;
case LOOK_CREEPS:
if(ignoreCreeps) continue;
}
if(t == 'wall') {
// soft blocked, unless there's also a road...
blocked = true;
room.visual.rect(x-0.5, y-0.5, 1, 1, {fill: "#ff5555", opacity: 0.25});
}
if(blocked && t == STRUCTURE_ROAD && o.type == LOOK_STRUCTURES) {
blocked = false;
room.visual.rect(x-0.5, y-0.5, 1, 1, {fill: "#55ff55", opacity: 0.25});
}
if(OBSTACLE_OBJECT_TYPES.includes(t)) {
blocked = true;
room.visual.rect(x-0.5, y-0.5, 1, 1, {fill: "#ff0000", opacity: 0.25});
break;
}
}
if(!blocked) {
room.visual.rect(x-0.5, y-0.5, 1, 1, {fill: "#00ff00", opacity: 0.25});
var p = room.getPositionAt(x, y);
if(p) { // Ignore out of bounds.
free.push(p);
}
}
}
}
// TOOD(baptr): Sort by linear distance from the target?
return free;
},
visPath: function(path) {
var roomVis;
var lastRoom;
for(let i = 1; i < path.length; i++) {
let prev = path[i-1];
let cur = path[i];
if(prev.roomName != cur.roomName) continue;
if(cur.roomName != lastRoom) {
lastRoom = cur.roomName;
roomVis = new RoomVisual(cur.roomName);
}
roomVis.line(prev, cur);
}
}
};