void MobMovementManager::UpdatePathGround(Mob * who, float x, float y, float z, MobMovementMode mode) { PathfinderOptions opts; opts.smooth_path = true; opts.step_size = RuleR(Pathing, NavmeshStepSize); opts.offset = who->GetZOffset(); opts.flags = PathingNotDisabled ^ PathingZoneLine; //This is probably pointless since the nav mesh tool currently sets zonelines to disabled anyway auto partial = false; auto stuck = false; auto route = zone->pathing->FindPath( glm::vec3(who->GetX(), who->GetY(), who->GetZ()), glm::vec3(x, y, z), partial, stuck, opts); auto eiter = _impl->Entries.find(who); auto &ent = (*eiter); if (route.size() == 0) { HandleStuckBehavior(who, x, y, z, mode); return; } AdjustRoute(route, who); //avoid doing any processing if the mob is stuck to allow normal stuck code to work. if (!stuck) { //there are times when the routes returned are no differen than where the mob is currently standing. What basically happens //is a mob will get 'stuck' in such a way that it should be moving but the 'moving' place is the exact same spot it is at. //this is a problem and creates an area of ground that if a mob gets to, will stay there forever. If socal this creates a //"Ball of Death" (tm). This code tries to prevent this by simply warping the mob to the requested x/y. Better to have a warp than //have stuck mobs. auto routeNode = route.begin(); bool noValidPath = true; while (routeNode != route.end() && noValidPath == true) { auto ¤tNode = (*routeNode); if (routeNode == route.end()) { continue; } if (!(currentNode.pos.x == who->GetX() && currentNode.pos.y == who->GetY())) { //if one of the nodes to move to, is not our current node, pass it. noValidPath = false; break; } //move to the next node routeNode++; } if (noValidPath) { //we are 'stuck' in a path, lets just get out of this by 'teleporting' to the next position. PushTeleportTo(ent.second, x, y, z, CalculateHeadingAngleBetweenPositions(who->GetX(), who->GetY(), x, y)); return; } } auto iter = route.begin(); glm::vec3 previous_pos(who->GetX(), who->GetY(), who->GetZ()); bool first_node = true; while (iter != route.end()) { auto ¤t_node = (*iter); iter++; if (iter == route.end()) { continue; } previous_pos = current_node.pos; auto &next_node = (*iter); if (first_node) { if (mode == MovementWalking) { auto h = who->CalculateHeadingToTarget(next_node.pos.x, next_node.pos.y); PushRotateTo(ent.second, who, h, mode); } first_node = false; } //move to / teleport to node + 1 if (next_node.teleport && next_node.pos.x != 0.0f && next_node.pos.y != 0.0f) { PushTeleportTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, CalculateHeadingAngleBetweenPositions(current_node.pos.x, current_node.pos.y, next_node.pos.x, next_node.pos.y)); } else { if (zone->watermap->InLiquid(previous_pos)) { PushSwimTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, mode); } else { PushMoveTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, mode); } } } if (stuck) { HandleStuckBehavior(who, x, y, z, mode); } else { PushStopMoving(ent.second); } }
void MobMovementManager::UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode mode) { auto eiter = _impl->Entries.find(who); auto &ent = (*eiter); if (zone->watermap->InLiquid(who->GetPosition()) && zone->watermap->InLiquid(glm::vec3(x, y, z)) && zone->zonemap->CheckLoS(who->GetPosition(), glm::vec3(x, y, z))) { PushSwimTo(ent.second, x, y, z, mode); PushStopMoving(ent.second); return; } PathfinderOptions opts; opts.smooth_path = true; opts.step_size = RuleR(Pathing, NavmeshStepSize); opts.offset = who->GetZOffset(); opts.flags = PathingNotDisabled ^ PathingZoneLine; auto partial = false; auto stuck = false; auto route = zone->pathing->FindPath( glm::vec3(who->GetX(), who->GetY(), who->GetZ()), glm::vec3(x, y, z), partial, stuck, opts); if (route.size() == 0) { HandleStuckBehavior(who, x, y, z, mode); return; } AdjustRoute(route, who); auto iter = route.begin(); glm::vec3 previous_pos(who->GetX(), who->GetY(), who->GetZ()); bool first_node = true; while (iter != route.end()) { auto ¤t_node = (*iter); if (!zone->watermap->InLiquid(current_node.pos)) { stuck = true; while (iter != route.end()) { iter = route.erase(iter); } break; } else { iter++; } } if (route.size() == 0) { HandleStuckBehavior(who, x, y, z, mode); return; } iter = route.begin(); while (iter != route.end()) { auto ¤t_node = (*iter); iter++; if (iter == route.end()) { continue; } previous_pos = current_node.pos; auto &next_node = (*iter); if (first_node) { if (mode == MovementWalking) { auto h = who->CalculateHeadingToTarget(next_node.pos.x, next_node.pos.y); PushRotateTo(ent.second, who, h, mode); } first_node = false; } //move to / teleport to node + 1 if (next_node.teleport && next_node.pos.x != 0.0f && next_node.pos.y != 0.0f) { PushTeleportTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, CalculateHeadingAngleBetweenPositions(current_node.pos.x, current_node.pos.y, next_node.pos.x, next_node.pos.y)); } else { PushSwimTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, mode); } } if (stuck) { HandleStuckBehavior(who, x, y, z, mode); } else { PushStopMoving(ent.second); } }
mvtype get_computer_move(struct postype brd) { int i,j,oldval; time_t seconds; int top, bottom, prevscore; struct movelist moves; char goagain; mvtype legalmove, openmove; struct pathtype curr,path; struct postype newpos; int thismove, movesleft; char todepth; mainmover=brd.mvr; #ifdef windowsearch prevscore=0; #endif if (options.game!=REGULARCHESS || !options.library || no_more_openings || !get_opening(&openmove)) { //if (options.analysis) show_blue_tiles(); if (!options.analysis) analoffmessg(); computer_move_displays(); show_mouse(); moves=get_children(&brd); for (i=0; i<40; i++) dontmove[i].f=0; game.movenum=game.movenum+1; draws=0; for (i=1; i<=moves.amount && draws<39; i++) { legalmove=moves.move[i]; alter(&brd,legalmove,&newpos); if (previous_pos(newpos, game, 1)) dontmove[draws++]=legalmove; } // check for moves that may draw a position on next move game.movenum=game.movenum-1; nodes=0; nomore=FALSE; for (i=0; i<=11; i++) curr.move[i].f=0; path.value=0; nomore=FALSE; make_current=TRUE; switch (options.playstyle) { case FIXEDLEVEL:todepth=options.maxdepth; break; case FIXEDTIME:todepth=16; maxtime=options.maxtime; break; case CHAMPIONSHIP:todepth=16; maxtime=(options.champtime*60/options.champmoves); break; } g_depth=1; for (i=0; i<32; i++) best_at[i].f=0; for (iteration=1; iteration<=todepth && !nomore; iteration++) { oldval=path.value; if (iteration<=2) quiescence_depth=0; else quiescence_depth=iteration+2; path.move[0].f=0; #ifdef windowsearch top=prevscore+50; bottom=prevscore-50; do { goagain=0; #else top=32700; bottom=-32700; #endif switch(options.game) { case KINGLET:kinglet_minimax(&brd,0,top,bottom,curr,&path,0); break; case GIVEAWAY:giveaway_minimax(&brd,0,top,bottom,curr,&path,0); break; case SHATRANJ:shatranj_minimax(&brd,0,top,bottom,curr,&path,FALSE,0); break; case REGULARCHESS:minimax(&brd,0,top,bottom,curr,&path,FALSE,0); } for (i=0; path.move[i].f!=0 && i<8; i++) best_at[i]=path.move[i]; best_at[i].f=0; if (path.value>9900) { nomore=TRUE; make_current=TRUE; } #ifdef windowsearch /* if (!(path.value>bottom && path.value<top)) { top=32700; bottom=-32700; goagain=1; } */ if (path.value<bottom) { bottom=-32700; top=path.value; goagain=1; } if (path.value>top) { top=32700; bottom=path.value; goagain=1; } } while (goagain); prevscore=path.value; #endif } } else { path.move[0]=openmove; alter(¤t, openmove, &newpos); if (mainmover=='b') path.move[0].check=check(&newpos, newpos.wking[0]); else path.move[0].check=check(&newpos, newpos.bking[0]); path.move[0].lastwin=current.brd[openmove.t]; make_current=TRUE; } if (path.move[0].f==0) make_current=FALSE; // if user requests to make current move then ensure that there is one! if (path.value<-10000) { path.value=oldval; } if (nomore && !make_current) { path.move[0].t=0; } else { seconds=time(NULL)-starttime; seconds+=seconds==0; g_path=path; g_seconds=seconds; } hide_mouse(); if (options.analysis) display_score_slab(nodes,path.value); return(path.move[0]); }