symmetric pathdist

This commit is contained in:
Zeno Rogue 2022-09-17 11:21:33 +02:00
parent f0f6ae7514
commit db353755d3
3 changed files with 70 additions and 50 deletions

View File

@ -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();

View File

@ -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);

View File

@ -2667,7 +2667,7 @@ EX void turn(int delta) {
int qb = 0;
for(qb=0; qb < isize(pathq); qb++) {
cell *c = pathq[qb];
cell *c = pathq[qb].at;
int d = c->pathdist;
if(d == PINFD-1) continue;
for(int i=0; i<c->type; i++) {