mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-30 21:42:59 +00:00 
			
		
		
		
	symmetric pathdist
This commit is contained in:
		| @@ -54,20 +54,14 @@ EX vector<cell*> worms, ivies, ghosts, golems, hexsnakes; | |||||||
| /** temporary changes during bfs */ | /** temporary changes during bfs */ | ||||||
| vector<pair<cell*, eMonster>> tempmonsters; | 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..]. */ | /** The position of the first cell in dcal in distance 7. New wandering monsters can be generated in dcal[first7..]. */ | ||||||
| EX int first7;            | EX int first7;            | ||||||
|  |  | ||||||
| /** the list of all nearby cells, according to cpdist */ | /** the list of all nearby cells, according to cpdist */ | ||||||
| EX vector<cell*> dcal; | EX vector<cell*> dcal; | ||||||
|  |  | ||||||
| /** the list of all nearby cells, according to current pathdist */ | /** 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 */ | /** the number of big statues -- they increase monster generation */ | ||||||
| EX int statuecount; | EX int statuecount; | ||||||
| @@ -88,25 +82,61 @@ EX int gamerange() { return getDistLimit() + gamerange_bonus; } | |||||||
| EX cell *pd_from; | EX cell *pd_from; | ||||||
| EX int pd_range; | EX int pd_range; | ||||||
|  |  | ||||||
| EX void onpath(cell *c, int d) { | #if HDR | ||||||
|   if(!pathlock) { println(hlog, "onpath without pathlock"); } | /** The pathdata is used to keep a list of visited cells. It is used as follows: | ||||||
|   c->pathdist = d; |  *  1) create pathdata object: pathdata pd(identifier) | ||||||
|   pathq.push_back(c); |  *  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) { | /** using pathdata, record a cell as visited, with random direction */ | ||||||
|   onpath(c, d); | EX void onpath_random_dir(cell *c, int d) { | ||||||
|   path_reachedfrom.push_back(sp); |   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() { | EX void clear_pathdata() { | ||||||
|   for(auto c: pathq) c->pathdist = PINFD; |   for(auto c: pathq) c.at->pathdist = PINFD; | ||||||
|   pathq.clear();  |   pathq.clear();  | ||||||
|   pathqm.clear(); |   pathqm.clear(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | /** This ensures that we do not use two pathdata objects at once */ | ||||||
| EX int pathlock = 0; | 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() { | EX void compute_graphical_distance() { | ||||||
|   if(pathlock) { printf("path error: compute_graphical_distance\n"); } |   if(pathlock) { printf("path error: compute_graphical_distance\n"); } | ||||||
|   cell *c1 = centerover ? centerover : pd_from ? pd_from : cwt.at; |   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; |   if(pd_from == c1 && pd_range == sr) return; | ||||||
|   clear_pathdata(); |   clear_pathdata(); | ||||||
|    |    | ||||||
|  |   pathlock++; | ||||||
|   pd_from = c1; |   pd_from = c1; | ||||||
|   pd_range = sr; |   pd_range = sr; | ||||||
|   c1->pathdist = 0; |   onpath(c1, 0); | ||||||
|   pathq.push_back(pd_from); |  | ||||||
|   pathlock++; |  | ||||||
|  |  | ||||||
|   for(int qb=0; qb<isize(pathq); qb++) { |   for(int qb=0; qb<isize(pathq); qb++) { | ||||||
|     cell *c = pathq[qb]; |     cell *c = pathq[qb].at; | ||||||
|     if(c->pathdist == pd_range) break; |     if(c->pathdist == pd_range) break; | ||||||
|     if(qb == 0) forCellCM(c1, c) ; |     if(qb == 0) forCellCM(c1, c) ; | ||||||
|     forCellEx(c1, c) |     forCellEx(c1, c) | ||||||
| @@ -153,7 +182,7 @@ struct princess_ai { | |||||||
| void princess_ai::run() { | void princess_ai::run() { | ||||||
|   int radius = toggle_radius(waOpenPlate); |   int radius = toggle_radius(waOpenPlate); | ||||||
|   if(pathq.empty()) return; |   if(pathq.empty()) return; | ||||||
|   int d = pathq.back()->pathdist; |   int d = pathq.back().at->pathdist; | ||||||
|   if(d == PINFD - 1) return; |   if(d == PINFD - 1) return; | ||||||
|   d++; |   d++; | ||||||
|   if(d < 5) d = 5; /* the Princess AI avoids plates when too close to the player */ |   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); |         info[0].visit(c1); | ||||||
|       } |       } | ||||||
|     if(k == radius && c->wall == waOpenPlate && c->pathdist == PINFD) |     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)) { | EX void computePathdist(eMonster param, bool include_allies IS(true)) { | ||||||
|    |    | ||||||
|   path_reachedfrom.clear(); |  | ||||||
|  |  | ||||||
|   for(cell *c: targets) |   for(cell *c: targets) | ||||||
|     if(include_allies || isPlayerOn(c)) |     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); |   int qtarg = isize(targets); | ||||||
|    |    | ||||||
| @@ -191,8 +218,10 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) { | |||||||
|   princess_retry: |   princess_retry: | ||||||
|    |    | ||||||
|   for(; qb < isize(pathq); qb++) { |   for(; qb < isize(pathq); qb++) { | ||||||
|     cell *c = pathq[qb]; |     cellwalker cw = pathq[qb]; | ||||||
|     int fd = path_reachedfrom[qb] + c->type/2; |     /* 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)) { |     if(c->monst && !isBug(c) && !(isFriendly(c) && !c->stuntime)) { | ||||||
|       pathqm.push_back(c);  |       pathqm.push_back(c);  | ||||||
|       continue; // no paths going through monsters |       continue; // no paths going through monsters | ||||||
| @@ -206,9 +235,9 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) { | |||||||
|     int d = c->pathdist; |     int d = c->pathdist; | ||||||
|     if(d == PINFD - 1) continue; |     if(d == PINFD - 1) continue; | ||||||
|     for(int j=0; j<c->type; j++) { |     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); |       // 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; |       flagtype f = P_MONSTER | P_REVDIR; | ||||||
|       if(param == moTameBomberbird) f |= P_FLYING; |       if(param == moTameBomberbird) f |= P_FLYING; | ||||||
| @@ -224,7 +253,7 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) { | |||||||
|             continue; |             continue; | ||||||
|           } |           } | ||||||
|  |  | ||||||
|         onpath_rf(c2, d+1, c->c.spin(i)); |         onpath_with_dir(cw1 + wstep, d+1); | ||||||
|         } |         } | ||||||
|        |        | ||||||
|       else if(c2 && c2->wall == waClosedGate && princess) |       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() { | pathdata::~pathdata() { | ||||||
|   pathlock--; |   pathlock--; | ||||||
|   clear_pathdata(); |   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; |     if((mf & MF_ONLYEAGLE) && bird_disruption(c) && markOrb(itOrbGravity)) return; | ||||||
|     // in the gravity lands, eagles cannot ascend in their second move |     // in the gravity lands, eagles cannot ascend in their second move | ||||||
|     if((mf & MF_ONLYEAGLE) && gravityLevelDiff(c, from) < 0) { |     if((mf & MF_ONLYEAGLE) && gravityLevelDiff(c, from) < 0) { | ||||||
|       onpath(c, 0); |       onpath_mark(c); | ||||||
|       return; |       return; | ||||||
|       } |       } | ||||||
|     if((mf & MF_NOFRIEND) && isFriendly(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)) { |       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); |         attackMonster(c->move(j), AF_NORMAL | AF_GETPLAYER | AF_MSG, c->monst); | ||||||
|         animateAttack(movei(c, j), LAYER_SMALL); |         animateAttack(movei(c, j), LAYER_SMALL); | ||||||
|         onpath(c, 0); |         onpath_mark(c); | ||||||
|         // XLATC eagle |         // XLATC eagle | ||||||
|         return; |         return; | ||||||
|         } |         } | ||||||
|      |      | ||||||
|     if(from->cpdist == 0 || from->monst) { onpath(c, 0); return; } |     if(from->cpdist == 0 || from->monst) { onpath_mark(c); return; } | ||||||
|      |      | ||||||
|     if(movtype == moDragonHead) { |     if(movtype == moDragonHead) { | ||||||
|       dragon::move(mi); |       dragon::move(mi); | ||||||
| @@ -1164,16 +1164,16 @@ EX void groupmove2(const movei& mi, eMonster movtype, flagtype mf) { | |||||||
|      |      | ||||||
|     moveMonster(mi); |     moveMonster(mi); | ||||||
|      |      | ||||||
|     onpath(from, 0); |     onpath_mark(from); | ||||||
|  |  | ||||||
|     if(isDie(mi.t->monst)) { |     if(isDie(mi.t->monst)) { | ||||||
|       /* other dice will not pathfind through the original cell */ |       /* other dice will not pathfind through the original cell */ | ||||||
|       /* this makes it easier for the player to roll dice correctly */ |       /* this makes it easier for the player to roll dice correctly */ | ||||||
|       onpath(c, 0); |       onpath_mark(c); | ||||||
|       return; |       return; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   onpath(c, 0); |   onpath_mark(c); | ||||||
|   // MAXGCELL |   // MAXGCELL | ||||||
|   if(isize(gendfs) < 1000 || c->cpdist <= 6) gendfs.push_back(c); |   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((mf & MF_ONLYEAGLE) && c->monst != moEagle && c->monst != moBat) return; | ||||||
|     if(movegroup(c->monst) == movtype && c->pathdist != 0) { |     if(movegroup(c->monst) == movtype && c->pathdist != 0) { | ||||||
|       cell *c2 = moveNormal(c, mf); |       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); |     moveHexSnake(movei(from, d).rev(), mounted); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   onpath(c, 0); |   onpath_mark(c); | ||||||
|  |  | ||||||
|   // MAXGCELL |   // MAXGCELL | ||||||
|   if(isize(hexdfs) < 2000 || c->cpdist <= 6)  |   if(isize(hexdfs) < 2000 || c->cpdist <= 6)  | ||||||
| @@ -1337,12 +1337,12 @@ EX void movehex(bool mounted, int colorpair) { | |||||||
|   if(mounted) {  |   if(mounted) {  | ||||||
|     if(dragon::target && dragon::target->monst != moHexSnake) { |     if(dragon::target && dragon::target->monst != moHexSnake) { | ||||||
|       hexdfs.push_back(dragon::target);  |       hexdfs.push_back(dragon::target);  | ||||||
|       onpath(dragon::target, 0); |       onpath_mark(dragon::target); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   else for(cell *c: targets) { |   else for(cell *c: targets) { | ||||||
|     hexdfs.push_back(c); |     hexdfs.push_back(c); | ||||||
|     onpath(c, 0); |     onpath_mark(c); | ||||||
|     } |     } | ||||||
|   //hexdfs.push_back(cwt.at); |   //hexdfs.push_back(cwt.at); | ||||||
|    |    | ||||||
|   | |||||||
| @@ -2667,7 +2667,7 @@ EX void turn(int delta) { | |||||||
|  |  | ||||||
|     int qb = 0; |     int qb = 0; | ||||||
|     for(qb=0; qb < isize(pathq); qb++) { |     for(qb=0; qb < isize(pathq); qb++) { | ||||||
|       cell *c = pathq[qb]; |       cell *c = pathq[qb].at; | ||||||
|       int d = c->pathdist; |       int d = c->pathdist; | ||||||
|       if(d == PINFD-1) continue; |       if(d == PINFD-1) continue; | ||||||
|       for(int i=0; i<c->type; i++) { |       for(int i=0; i<c->type; i++) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Zeno Rogue
					Zeno Rogue