mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-24 17:10:36 +00:00
symmetric pathdist
This commit is contained in:
parent
f0f6ae7514
commit
db353755d3
@ -54,20 +54,14 @@ EX vector<cell*> worms, ivies, ghosts, golems, hexsnakes;
|
||||
/** temporary changes during bfs */
|
||||
vector<pair<cell*, eMonster>> tempmonsters;
|
||||
|
||||
/** additional direction information for BFS algorithms.
|
||||
* It remembers from where we have got to this location
|
||||
* the opposite cell will be added to the queue first,
|
||||
* which helps the AI. Used by computePathdist and its callees.
|
||||
**/
|
||||
EX vector<int> path_reachedfrom;
|
||||
|
||||
/** The position of the first cell in dcal in distance 7. New wandering monsters can be generated in dcal[first7..]. */
|
||||
EX int first7;
|
||||
|
||||
/** the list of all nearby cells, according to cpdist */
|
||||
EX vector<cell*> dcal;
|
||||
|
||||
/** the list of all nearby cells, according to current pathdist */
|
||||
EX vector<cell*> pathq;
|
||||
EX vector<cellwalker> pathq;
|
||||
|
||||
/** the number of big statues -- they increase monster generation */
|
||||
EX int statuecount;
|
||||
@ -88,25 +82,61 @@ EX int gamerange() { return getDistLimit() + gamerange_bonus; }
|
||||
EX cell *pd_from;
|
||||
EX int pd_range;
|
||||
|
||||
EX void onpath(cell *c, int d) {
|
||||
if(!pathlock) { println(hlog, "onpath without pathlock"); }
|
||||
c->pathdist = d;
|
||||
pathq.push_back(c);
|
||||
#if HDR
|
||||
/** The pathdata is used to keep a list of visited cells. It is used as follows:
|
||||
* 1) create pathdata object: pathdata pd(identifier)
|
||||
* 2) use one of the following methods to mark cells as visited:
|
||||
* 2a) onpath_with_dir or onpath_random_dir, to mark a cell together with its distance and the direction we came from (used by computePathdist to make pathfinding not sensitive to direction indexing)
|
||||
* 2b) onpath, to mark a cell at its distance (used when ordering is irrelevant: compute_graphical_distance and in shmup)
|
||||
* 2c) onpatk_mark, to just mark a cell (used in groupmove2)
|
||||
* 3) All the visited cells are listed in pathq, and they have 'pathdist' set to their recorded distance (0 in case of onpath_mark).
|
||||
* 4) When the pathdata object is deleted, all the pathdist values are cleared back to PINFD.
|
||||
* The variable 'pathlock' ensures that we do not use two pathdata objects at once.
|
||||
**/
|
||||
|
||||
struct pathdata {
|
||||
void checklock();
|
||||
~pathdata();
|
||||
pathdata(eMonster m, bool include_allies IS(true));
|
||||
pathdata(int i);
|
||||
};
|
||||
#endif
|
||||
|
||||
/** using pathdata, record a cell (together with direction) as visited */
|
||||
EX void onpath_with_dir(cellwalker cw, int d) {
|
||||
if(!pathlock) {
|
||||
println(hlog, "onpath(", cw, ", ", d, ") without pathlock");
|
||||
}
|
||||
cw.at->pathdist = d;
|
||||
pathq.push_back(cw);
|
||||
}
|
||||
|
||||
void onpath_rf(cell *c, int d, int sp) {
|
||||
onpath(c, d);
|
||||
path_reachedfrom.push_back(sp);
|
||||
/** using pathdata, record a cell as visited, with random direction */
|
||||
EX void onpath_random_dir(cell *c, int d) {
|
||||
onpath_with_dir(cellwalker(c, hrand(c->type), hrand(2)), d);
|
||||
}
|
||||
|
||||
EX void onpath(cell *c, int d) {
|
||||
onpath_with_dir(cellwalker(c, 0, 0), d);
|
||||
}
|
||||
|
||||
EX void onpath_mark(cell *c) {
|
||||
onpath_with_dir(cellwalker(c, 0, 0), 0);
|
||||
}
|
||||
|
||||
EX void clear_pathdata() {
|
||||
for(auto c: pathq) c->pathdist = PINFD;
|
||||
for(auto c: pathq) c.at->pathdist = PINFD;
|
||||
pathq.clear();
|
||||
pathqm.clear();
|
||||
}
|
||||
|
||||
/** This ensures that we do not use two pathdata objects at once */
|
||||
EX int pathlock = 0;
|
||||
|
||||
/** compute_graphical_distance determines the distance of every cell
|
||||
* from the current FOV center. It uses the pathq structures but
|
||||
* does not lock them */
|
||||
|
||||
EX void compute_graphical_distance() {
|
||||
if(pathlock) { printf("path error: compute_graphical_distance\n"); }
|
||||
cell *c1 = centerover ? centerover : pd_from ? pd_from : cwt.at;
|
||||
@ -114,14 +144,13 @@ EX void compute_graphical_distance() {
|
||||
if(pd_from == c1 && pd_range == sr) return;
|
||||
clear_pathdata();
|
||||
|
||||
pathlock++;
|
||||
pd_from = c1;
|
||||
pd_range = sr;
|
||||
c1->pathdist = 0;
|
||||
pathq.push_back(pd_from);
|
||||
pathlock++;
|
||||
onpath(c1, 0);
|
||||
|
||||
for(int qb=0; qb<isize(pathq); qb++) {
|
||||
cell *c = pathq[qb];
|
||||
cell *c = pathq[qb].at;
|
||||
if(c->pathdist == pd_range) break;
|
||||
if(qb == 0) forCellCM(c1, c) ;
|
||||
forCellEx(c1, c)
|
||||
@ -153,7 +182,7 @@ struct princess_ai {
|
||||
void princess_ai::run() {
|
||||
int radius = toggle_radius(waOpenPlate);
|
||||
if(pathq.empty()) return;
|
||||
int d = pathq.back()->pathdist;
|
||||
int d = pathq.back().at->pathdist;
|
||||
if(d == PINFD - 1) return;
|
||||
d++;
|
||||
if(d < 5) d = 5; /* the Princess AI avoids plates when too close to the player */
|
||||
@ -168,17 +197,15 @@ void princess_ai::run() {
|
||||
info[0].visit(c1);
|
||||
}
|
||||
if(k == radius && c->wall == waOpenPlate && c->pathdist == PINFD)
|
||||
onpath_rf(c, d, hrand(c->type));
|
||||
onpath_random_dir(c, d);
|
||||
}
|
||||
}
|
||||
|
||||
EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
||||
|
||||
path_reachedfrom.clear();
|
||||
|
||||
for(cell *c: targets)
|
||||
if(include_allies || isPlayerOn(c))
|
||||
onpath_rf(c, isPlayerOn(c) ? 0 : 1, hrand(c->type));
|
||||
onpath_random_dir(c, isPlayerOn(c) ? 0 : 1);
|
||||
|
||||
int qtarg = isize(targets);
|
||||
|
||||
@ -191,8 +218,10 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
||||
princess_retry:
|
||||
|
||||
for(; qb < isize(pathq); qb++) {
|
||||
cell *c = pathq[qb];
|
||||
int fd = path_reachedfrom[qb] + c->type/2;
|
||||
cellwalker cw = pathq[qb];
|
||||
/* The opposite cell will be added to the queue first, which helps the AI. */
|
||||
cw += cw.at->type/2;
|
||||
cell*& c = cw.at;
|
||||
if(c->monst && !isBug(c) && !(isFriendly(c) && !c->stuntime)) {
|
||||
pathqm.push_back(c);
|
||||
continue; // no paths going through monsters
|
||||
@ -206,9 +235,9 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
||||
int d = c->pathdist;
|
||||
if(d == PINFD - 1) continue;
|
||||
for(int j=0; j<c->type; j++) {
|
||||
int i = (fd+j) % c->type;
|
||||
cellwalker cw1 = cw + j;
|
||||
// printf("i=%d cd=%d\n", i, c->move(i)->cpdist);
|
||||
cell *c2 = c->move(i);
|
||||
cell *c2 = cw1.peek();
|
||||
|
||||
flagtype f = P_MONSTER | P_REVDIR;
|
||||
if(param == moTameBomberbird) f |= P_FLYING;
|
||||
@ -224,7 +253,7 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
onpath_rf(c2, d+1, c->c.spin(i));
|
||||
onpath_with_dir(cw1 + wstep, d+1);
|
||||
}
|
||||
|
||||
else if(c2 && c2->wall == waClosedGate && princess)
|
||||
@ -238,15 +267,6 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
||||
}
|
||||
}
|
||||
|
||||
#if HDR
|
||||
struct pathdata {
|
||||
void checklock();
|
||||
~pathdata();
|
||||
pathdata(eMonster m, bool include_allies IS(true));
|
||||
pathdata(int i);
|
||||
};
|
||||
#endif
|
||||
|
||||
pathdata::~pathdata() {
|
||||
pathlock--;
|
||||
clear_pathdata();
|
||||
|
@ -1135,7 +1135,7 @@ EX void groupmove2(const movei& mi, eMonster movtype, flagtype mf) {
|
||||
if((mf & MF_ONLYEAGLE) && bird_disruption(c) && markOrb(itOrbGravity)) return;
|
||||
// in the gravity lands, eagles cannot ascend in their second move
|
||||
if((mf & MF_ONLYEAGLE) && gravityLevelDiff(c, from) < 0) {
|
||||
onpath(c, 0);
|
||||
onpath_mark(c);
|
||||
return;
|
||||
}
|
||||
if((mf & MF_NOFRIEND) && isFriendly(c)) return;
|
||||
@ -1150,12 +1150,12 @@ EX void groupmove2(const movei& mi, eMonster movtype, flagtype mf) {
|
||||
if(c->move(j) && canAttack(c, c->monst, c->move(j), c->move(j)->monst, af)) {
|
||||
attackMonster(c->move(j), AF_NORMAL | AF_GETPLAYER | AF_MSG, c->monst);
|
||||
animateAttack(movei(c, j), LAYER_SMALL);
|
||||
onpath(c, 0);
|
||||
onpath_mark(c);
|
||||
// XLATC eagle
|
||||
return;
|
||||
}
|
||||
|
||||
if(from->cpdist == 0 || from->monst) { onpath(c, 0); return; }
|
||||
if(from->cpdist == 0 || from->monst) { onpath_mark(c); return; }
|
||||
|
||||
if(movtype == moDragonHead) {
|
||||
dragon::move(mi);
|
||||
@ -1164,16 +1164,16 @@ EX void groupmove2(const movei& mi, eMonster movtype, flagtype mf) {
|
||||
|
||||
moveMonster(mi);
|
||||
|
||||
onpath(from, 0);
|
||||
onpath_mark(from);
|
||||
|
||||
if(isDie(mi.t->monst)) {
|
||||
/* other dice will not pathfind through the original cell */
|
||||
/* this makes it easier for the player to roll dice correctly */
|
||||
onpath(c, 0);
|
||||
onpath_mark(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
onpath(c, 0);
|
||||
onpath_mark(c);
|
||||
// MAXGCELL
|
||||
if(isize(gendfs) < 1000 || c->cpdist <= 6) gendfs.push_back(c);
|
||||
}
|
||||
@ -1232,7 +1232,7 @@ EX void groupmove(eMonster movtype, flagtype mf) {
|
||||
if((mf & MF_ONLYEAGLE) && c->monst != moEagle && c->monst != moBat) return;
|
||||
if(movegroup(c->monst) == movtype && c->pathdist != 0) {
|
||||
cell *c2 = moveNormal(c, mf);
|
||||
if(c2) onpath(c2, 0);
|
||||
if(c2) onpath_mark(c2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1323,7 +1323,7 @@ EX void hexvisit(cell *c, cell *from, int d, bool mounted, int colorpair) {
|
||||
moveHexSnake(movei(from, d).rev(), mounted);
|
||||
}
|
||||
|
||||
onpath(c, 0);
|
||||
onpath_mark(c);
|
||||
|
||||
// MAXGCELL
|
||||
if(isize(hexdfs) < 2000 || c->cpdist <= 6)
|
||||
@ -1337,12 +1337,12 @@ EX void movehex(bool mounted, int colorpair) {
|
||||
if(mounted) {
|
||||
if(dragon::target && dragon::target->monst != moHexSnake) {
|
||||
hexdfs.push_back(dragon::target);
|
||||
onpath(dragon::target, 0);
|
||||
onpath_mark(dragon::target);
|
||||
}
|
||||
}
|
||||
else for(cell *c: targets) {
|
||||
hexdfs.push_back(c);
|
||||
onpath(c, 0);
|
||||
onpath_mark(c);
|
||||
}
|
||||
//hexdfs.push_back(cwt.at);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user