Skip to content

Commit 8b557a3

Browse files
RobalianRobalian
and
Robalian
authored
ExcuseMe - A set of functions that makes creeps tell other creeps to get out of the way using creep memory (#26) manual due to gitconsensus broken (would have merged)
Co-authored-by: Robalian <[email protected]>
1 parent 99f2f06 commit 8b557a3

File tree

3 files changed

+429
-0
lines changed

3 files changed

+429
-0
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,5 @@ For pull requests, we use [GitConsensus](https://www.gitconsensus.com/) to allow
145145
|| [DefineProperty Tutorial.js](/src/prototypes/JavaScript/DefineProperty%20Tutorial.js) |helam|see name|
146146
|| [functionMiddleware.js](/src/prototypes/JavaScript/functionMiddleware.js) |warinternal|Loops over only functions on the prototype and passes them to a callback function|
147147
|| [Monkey Patching Tutorial.js](/src/prototypes/JavaScript/Monkey%20Patching%20Tutorial.js) |helam|see name|
148+
|JS/Creep| [excuseMe.js](/src/prototypes/JavaScript/Creep/excuseMe.js) |Robalian|A set of functions that makes creeps tell other creeps to get out of the way using creep memory|
149+
|TS| [excuseMe.ts](/src/prototypes/Typescript/excuseMe.ts) |Robalian|A set of functions that makes creeps tell other creeps to get out of the way using creep memory|
+208
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*
2+
* A set of functions that makes creeps tell other creeps to get out of the way using creep memory
3+
*
4+
* call so creep reacts to being nudged
5+
* Creep.giveWay() - swaps places with creep that nudged it
6+
* Creep.giveWay(true) - moves into random available spot
7+
* Creep.giveWay({pos: controller.pos, range: 3 }) - moves into random available spot in range of target, if none are avaiable fallbacks to random spot
8+
*/
9+
10+
/*
11+
* if alwaysNudge false you have to call Creep.move with additional argument -
12+
* creep.move(direction, true); - for creep to nudge other creeps,
13+
* so it's not compatible with creep.moveTo
14+
*
15+
* if alwaysNudge is true then creeps... always nudge creeps in front of them
16+
*/
17+
const alwaysNudge = true;
18+
19+
/*
20+
* some utils that I'm using
21+
*/
22+
const offsetX = [0, 0, 1, 1, 1, 0, -1, -1, -1];
23+
const offsetY = [0, -1, -1, 0, 1, 1, 1, 0, -1];
24+
function getRandomDir() {
25+
return (Math.floor(Math.random() * 8) + 1);
26+
}
27+
function getOppositeDir(dir) {
28+
return ((dir + 3) % 8 + 1);
29+
}
30+
31+
/**
32+
* returns a weighted random direction from given position
33+
* prefers empty tiles over ones with creeps
34+
* never picks a direction that would result in hitting a wall or an obstacle structure
35+
*
36+
* @param {RoomPosition} pos
37+
*/
38+
function getNudgeDirection_Random(pos) {
39+
const room = Game.rooms[pos.roomName];
40+
const terrain = Game.map.getRoomTerrain(pos.roomName);
41+
let totalWeight = 0;
42+
let dirCandidates = new Uint8Array(9);
43+
for (let dir = TOP; dir <= TOP_LEFT; ++dir) {
44+
let posX = pos.x + offsetX[dir];
45+
let posY = pos.y + offsetY[dir];
46+
if (posX < 1 || posX > 48 || posY < 1 || posY > 48)
47+
continue;
48+
if ((terrain.get(posX, posY) & TERRAIN_MASK_WALL) > 0)
49+
continue;
50+
if (room.lookForAt(LOOK_STRUCTURES, posX, posY).find(s => OBSTACLE_OBJECT_TYPES.includes(s.structureType)))
51+
continue;
52+
53+
const hasCreeps = room.lookForAt(LOOK_CREEPS, posX, posY).length > 0;
54+
const addWeight = hasCreeps ? 1 : 2;
55+
dirCandidates[dir] += addWeight;
56+
totalWeight += dirCandidates[dir];
57+
}
58+
59+
let sum = 0;
60+
let rnd = _.random(1, totalWeight, false);
61+
for (let dir = TOP; dir <= TOP_LEFT; ++dir) {
62+
if (dirCandidates[dir] > 0) {
63+
sum += dirCandidates[dir];
64+
if (rnd <= sum) {
65+
return dir;
66+
}
67+
}
68+
}
69+
70+
// this should never happen, unless creep is spawned into a corner
71+
// or structure is built next to it and seals the only path out
72+
return getRandomDir();
73+
}
74+
75+
/**
76+
* returns a weighted random direction from given position
77+
* tries to stay in targets range, if it's impossible then fallbacks to random direction
78+
* prefers empty tiles over ones with creeps
79+
* never picks a direction that would result in hitting a wall or an obstacle structure
80+
*
81+
* @param {RoomPosition} pos
82+
* @param {Object} target
83+
* @param {RoomPosition} target.pos
84+
* @param {number} target.range
85+
*/
86+
function getNudgeDirection_KeepRange(pos, target) {
87+
const room = Game.rooms[pos.roomName];
88+
const terrain = Game.map.getRoomTerrain(pos.roomName);
89+
let keepRangeTotalWeight = 0;
90+
let keepRangeDirCandidates = new Uint8Array(9);
91+
let randomTotalWeight = 0;
92+
let randomDirCandidates = new Uint8Array(9);
93+
for (let dir = TOP; dir <= TOP_LEFT; ++dir) {
94+
let posX = pos.x + offsetX[dir];
95+
let posY = pos.y + offsetY[dir];
96+
if (posX < 1 || posX > 48 || posY < 1 || posY > 48)
97+
continue;
98+
if ((terrain.get(posX, posY) & TERRAIN_MASK_WALL) > 0)
99+
continue;
100+
if (room.lookForAt(LOOK_STRUCTURES, posX, posY).find(s => OBSTACLE_OBJECT_TYPES.includes(s.structureType)))
101+
continue;
102+
103+
const hasCreeps = room.lookForAt(LOOK_CREEPS, posX, posY).length > 0;
104+
const addWeight = hasCreeps ? 1 : 2;
105+
randomDirCandidates[dir] += addWeight;
106+
if (target.pos.inRangeTo(posX, posY, target.range))
107+
keepRangeDirCandidates[dir] += addWeight;
108+
keepRangeTotalWeight += keepRangeDirCandidates[dir];
109+
randomTotalWeight += randomDirCandidates[dir];
110+
}
111+
112+
const dirCandidates = keepRangeTotalWeight > 0 ? keepRangeDirCandidates : randomDirCandidates;
113+
const totalWeight = keepRangeTotalWeight > 0 ? keepRangeTotalWeight : randomTotalWeight;
114+
let sum = 0;
115+
if (totalWeight > 0) {
116+
let rnd = _.random(1, totalWeight, false);
117+
for (let dir = TOP; dir <= TOP_LEFT; ++dir) {
118+
if (dirCandidates[dir] > 0) {
119+
sum += dirCandidates[dir];
120+
if (rnd <= sum) {
121+
return dir;
122+
}
123+
}
124+
}
125+
}
126+
127+
// this should never happen, unless creep is spawned into a corner
128+
// or structure is built next to it and seals the only path out
129+
return getRandomDir();
130+
}
131+
132+
/**
133+
* a nudge
134+
*
135+
* @param {RoomPosition} pos - a nudge origin point
136+
* @param {DirectionConstant} direction
137+
*/
138+
function excuseMe(pos, direction) {
139+
const nextX = pos.x + offsetX[direction];
140+
const nextY = pos.y + offsetY[direction];
141+
if (nextX > 49 || nextX < 0 || nextY > 49 || nextY < 0)
142+
return;
143+
144+
const room = Game.rooms[pos.roomName];
145+
const creeps = room.lookForAt(LOOK_CREEPS, nextX, nextY);
146+
if (creeps.length > 0 && creeps[0].my)
147+
creeps[0].memory.excuseMe = getOppositeDir(direction);
148+
const powerCreeps = room.lookForAt(LOOK_POWER_CREEPS, nextX, nextY);
149+
if (powerCreeps.length > 0 && powerCreeps[0].my)
150+
powerCreeps[0].memory.excuseMe = getOppositeDir(direction);
151+
}
152+
153+
/*
154+
*
155+
*/
156+
let creepsThatTriedToMove = {};
157+
const move = Creep.prototype.move;
158+
Creep.prototype.move = function (direction, nudge) {
159+
if ((alwaysNudge || nudge) && _.isNumber(direction))
160+
excuseMe(this.pos, direction);
161+
creepsThatTriedToMove[this.name] = this.pos;
162+
return move.call(this, direction);
163+
};
164+
165+
/*
166+
* call this on creeps that should react to being nudged
167+
*/
168+
function giveWay(creep, arg) {
169+
if (creep.memory.excuseMe) {
170+
if (!arg)
171+
creep.move(creep.memory.excuseMe, true);
172+
else if (typeof arg === 'object')
173+
creep.move(getNudgeDirection_KeepRange(creep.pos, arg), true);
174+
else
175+
creep.move(getNudgeDirection_Random(creep.pos), true);
176+
}
177+
}
178+
Creep.prototype.giveWay = function(arg) {
179+
giveWay(this, arg);
180+
};
181+
PowerCreep.prototype.giveWay = function(arg) {
182+
giveWay(this, arg);
183+
};
184+
185+
/*
186+
* clears nudges from memory of creeps that moved
187+
* call on tick start
188+
*/
189+
function clearNudges() {
190+
for (let creepName in creepsThatTriedToMove) {
191+
const creep = Game.creeps[creepName];
192+
const powerCreep = Game.powerCreeps[creepName];
193+
const prevPos = creepsThatTriedToMove[creepName];
194+
if ((!creep || !creep.pos.isEqualTo(prevPos)) && (!powerCreep || !powerCreep.pos.isEqualTo(prevPos))) {
195+
const creepMemory = Memory.creeps[creepName];
196+
if (creepMemory)
197+
creepMemory.excuseMe = undefined;
198+
const powerCreepMemory = Memory.powerCreeps[creepName];
199+
if (powerCreepMemory)
200+
powerCreepMemory.excuseMe = undefined;
201+
delete creepsThatTriedToMove[creepName];
202+
}
203+
}
204+
}
205+
206+
module.exports = {
207+
clearNudges: clearNudges
208+
};

0 commit comments

Comments
 (0)