truelight@110: #include "stdafx.h" truelight@110: #include "ttd.h" tron@679: #include "map.h" truelight@110: #include "command.h" truelight@110: #include "ai.h" truelight@110: truelight@110: #define TEST_STATION_NO_DIR 0xFF truelight@110: truelight@110: // Tests if a station can be build on the given spot truelight@110: // TODO: make it train compatible truelight@110: bool TestCanBuildStationHere(uint tile, byte dir) { truelight@110: Player *p = DEREF_PLAYER(_current_player); truelight@110: if (dir == TEST_STATION_NO_DIR) { truelight@110: // TODO: currently we only allow spots that can be access from al 4 directions... truelight@110: // should be fixed!!! truelight@110: for (dir=0;dir<4;dir++) { truelight@110: int res = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST); truelight@110: if (res != CMD_ERROR) truelight@110: return true; truelight@110: } truelight@110: return false; truelight@110: } else { truelight@110: int res = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST); truelight@110: if (res == CMD_ERROR) truelight@110: return false; truelight@110: } truelight@110: return true; truelight@110: } truelight@110: truelight@110: // Checks if a tile 'a' is between the tiles 'b' and 'c' tron@926: #define TILES_BETWEEN(a, b, c) (TileX(a) >= TileX(b) && TileX(a) <= TileX(c) && TileY(a) >= TileY(b) && TileY(a) <= TileY(c)) truelight@110: truelight@110: // Check if the current tile is in our end-area truelight@110: int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current) { truelight@110: Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target; truelight@110: // It is not allowed to have a station on the end of a bridge or tunnel ;) truelight@110: if (current->path.node.user_data[0] != 0) return AYSTAR_DONE; truelight@110: if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) truelight@110: if (IS_TILETYPE(current->path.node.tile, MP_CLEAR) || IS_TILETYPE(current->path.node.tile, MP_TREES)) truelight@110: if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile,AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile))) truelight@110: return AYSTAR_FOUND_END_NODE; truelight@193: truelight@110: return AYSTAR_DONE; truelight@110: } truelight@110: truelight@110: // Calculates the hash truelight@110: // Currently it is a 10 bit hash, so the hash array has a max depth of 6 bits (so 64) truelight@110: uint AiPathFinder_Hash(uint key1, uint key2) { tron@926: return (TileX(key1) & 0x1F) + ((TileY(key1) & 0x1F) << 5); truelight@110: } truelight@110: truelight@110: // Clear the memory of all the things truelight@110: void AyStar_AiPathFinder_Free(AyStar *aystar) { truelight@110: AyStarMain_Free(aystar); truelight@110: free(aystar); truelight@110: } truelight@110: truelight@110: static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent); truelight@110: static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent); truelight@110: static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current); truelight@110: static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current); truelight@110: truelight@110: // This creates the AiPathFinder truelight@110: AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo) { truelight@110: PathNode start_node; truelight@110: uint x,y; truelight@110: // Create AyStar truelight@110: AyStar *result = malloc(sizeof(AyStar)); truelight@110: init_AyStar(result, AiPathFinder_Hash, 1 << 10); truelight@110: // Set the function pointers truelight@110: result->CalculateG = AyStar_AiPathFinder_CalculateG; truelight@110: result->CalculateH = AyStar_AiPathFinder_CalculateH; truelight@110: result->EndNodeCheck = AyStar_AiPathFinder_EndNodeCheck; truelight@110: result->FoundEndNode = AyStar_AiPathFinder_FoundEndNode; truelight@110: result->GetNeighbours = AyStar_AiPathFinder_GetNeighbours; truelight@110: truelight@110: result->free = AyStar_AiPathFinder_Free; truelight@110: truelight@110: // Set some information truelight@110: result->loops_per_tick = AI_PATHFINDER_LOOPS_PER_TICK; truelight@110: result->max_path_cost = 0; truelight@110: result->max_search_nodes = AI_PATHFINDER_MAX_SEARCH_NODES; truelight@110: truelight@110: // Set the user_data to the PathFinderInfo truelight@110: result->user_target = PathFinderInfo; truelight@110: truelight@110: // Set the start node truelight@110: start_node.parent = NULL; truelight@110: start_node.node.direction = 0; truelight@110: start_node.node.user_data[0] = 0; truelight@110: truelight@110: // Now we add all the starting tiles tron@926: for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) { tron@926: for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) { truelight@110: start_node.node.tile = TILE_XY(x,y); truelight@110: result->addstart(result, &start_node.node); truelight@110: } truelight@110: } truelight@110: truelight@110: return result; truelight@110: } truelight@110: truelight@110: // To reuse AyStar we sometimes have to clean all the memory truelight@110: void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo) { truelight@110: PathNode start_node; truelight@110: uint x,y; truelight@193: truelight@110: aystar->clear(aystar); truelight@110: truelight@110: // Set the user_data to the PathFinderInfo truelight@110: aystar->user_target = PathFinderInfo; truelight@110: truelight@110: // Set the start node truelight@110: start_node.parent = NULL; truelight@110: start_node.node.direction = 0; truelight@110: start_node.node.user_data[0] = 0; truelight@110: start_node.node.tile = PathFinderInfo->start_tile_tl; truelight@110: truelight@110: // Now we add all the starting tiles tron@926: for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) { tron@926: for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) { truelight@110: if (!(IS_TILETYPE(TILE_XY(x,y), MP_CLEAR) || IS_TILETYPE(TILE_XY(x,y), MP_TREES))) continue; truelight@110: if (!TestCanBuildStationHere(TILE_XY(x,y),TEST_STATION_NO_DIR)) continue; truelight@110: start_node.node.tile = TILE_XY(x,y); truelight@110: aystar->addstart(aystar, &start_node.node); truelight@110: } truelight@110: } truelight@110: } truelight@110: truelight@110: // The h-value, simple calculation truelight@110: static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent) { truelight@110: Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target; truelight@110: int r, r2; truelight@110: if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION) { truelight@110: // The station is pointing to a direction, add a tile towards that direction, so the H-value is more accurate tron@906: r = GetTileDist(current->tile, PathFinderInfo->end_tile_tl + TileOffsByDir(PathFinderInfo->end_direction)); tron@906: r2 = GetTileDist(current->tile, PathFinderInfo->end_tile_br + TileOffsByDir(PathFinderInfo->end_direction)); truelight@110: } else { truelight@110: // No direction, so just get the fastest route to the station truelight@110: r = GetTileDist(current->tile, PathFinderInfo->end_tile_tl); truelight@110: r2 = GetTileDist(current->tile, PathFinderInfo->end_tile_br); truelight@110: } miham@826: // See if the bottomright is faster than the topleft.. truelight@110: if (r2 < r) r = r2; truelight@110: return r * AI_PATHFINDER_H_MULTIPLER; truelight@110: } truelight@110: truelight@110: // We found the end.. let's get the route back and put it in an array truelight@110: static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current) { truelight@110: Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target; truelight@110: int i = 0; truelight@110: PathNode *parent = ¤t->path; truelight@193: truelight@110: do { truelight@110: PathFinderInfo->route_extra[i] = parent->node.user_data[0]; truelight@110: PathFinderInfo->route[i++] = parent->node.tile; truelight@110: if (i > lengthof(PathFinderInfo->route)) { truelight@110: // We ran out of space for the PathFinder truelight@110: DEBUG(ai,0)("[AiPathFinder] Ran out of spacein the route[] array!!!"); truelight@110: PathFinderInfo->route_length = -1; // -1 indicates out of space truelight@110: return; truelight@110: } truelight@110: parent = parent->parent; truelight@110: } while (parent != NULL); truelight@110: PathFinderInfo->route_length = i; truelight@110: DEBUG(ai,1)("[Ai-PathFinding] Found route of %d nodes long in %d nodes of searching",i,Hash_Size(&aystar->ClosedListHash)); truelight@110: } truelight@110: truelight@110: // What tiles are around us. truelight@110: static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current) { truelight@110: int i, r, dir; truelight@110: Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target; truelight@193: truelight@110: aystar->num_neighbours = 0; truelight@193: truelight@110: // Go through all surrounding tiles and check if they are within the limits truelight@110: for (i=0;i<4;i++) { tron@926: if (TileX(TileOffsByDir(i) + current->path.node.tile) > 1 && tron@926: TileX(TileOffsByDir(i) + current->path.node.tile) < MapMaxX() - 1 && tron@926: TileY(TileOffsByDir(i) + current->path.node.tile) > 1 && tron@926: TileY(TileOffsByDir(i) + current->path.node.tile) < MapMaxY() - 1) { truelight@110: // We also directly test if the current tile can connect to this tile.. truelight@110: // We do this simply by just building the tile! truelight@193: truelight@110: // If the next step is a bridge, we have to enter it the right way tron@906: if (!PathFinderInfo->rail_or_road && AI_PATHFINDER_IS_ROAD(current->path.node.tile + TileOffsByDir(i))) { tron@906: if (IS_TILETYPE(current->path.node.tile + TileOffsByDir(i), MP_TUNNELBRIDGE)) { truelight@110: // An existing bridge... let's test the direction ;) tron@906: if ((_map5[current->path.node.tile + TileOffsByDir(i)] & 1) != (i & 1)) continue; truelight@110: // This problem only is valid for tunnels: truelight@110: // When the last tile was not yet a tunnel, check if we enter from the right side.. tron@906: if (!IS_TILETYPE(current->path.node.tile, MP_TUNNELBRIDGE) && (_map5[current->path.node.tile + TileOffsByDir(i)] & 0x80) == 0) { tron@906: if (i != (_map5[current->path.node.tile + TileOffsByDir(i)] & 3)) continue; truelight@110: } truelight@110: } truelight@110: } truelight@110: // But also if we are on a bridge, we can only move a certain direction truelight@110: if (!PathFinderInfo->rail_or_road && AI_PATHFINDER_IS_ROAD(current->path.node.tile)) { truelight@110: if (IS_TILETYPE(current->path.node.tile, MP_TUNNELBRIDGE)) { truelight@110: // An existing bridge/tunnel... let's test the direction ;) truelight@110: if ((_map5[current->path.node.tile] & 1) != (i & 1)) continue; truelight@110: } truelight@110: } truelight@193: truelight@110: if ((AI_PATHFINDER_FLAG_BRIDGE & current->path.node.user_data[0]) != 0 || truelight@110: (AI_PATHFINDER_FLAG_TUNNEL & current->path.node.user_data[0]) != 0) { truelight@110: // We are a bridge/tunnel, how cool!! truelight@110: // This means we can only point forward.. get the direction from the user_data truelight@110: if (i != (current->path.node.user_data[0] >> 8)) continue; truelight@110: } truelight@110: dir = 0; truelight@193: truelight@110: // First, check if we have a parent truelight@110: if (current->path.parent == NULL && current->path.node.user_data[0] == 0) { truelight@110: // If not, this means we are at the starting station truelight@110: if (PathFinderInfo->start_direction != AI_PATHFINDER_NO_DIRECTION) { truelight@110: // We do need a direction? tron@906: if (AiNew_GetDirection(current->path.node.tile, current->path.node.tile + TileOffsByDir(i)) != PathFinderInfo->start_direction) truelight@110: // We are not pointing the right way, invalid tile truelight@110: continue; truelight@110: } truelight@110: } else if (current->path.node.user_data[0] == 0) { truelight@110: if (PathFinderInfo->rail_or_road) { truelight@110: // Rail check tron@906: dir = AiNew_GetRailDirection(current->path.parent->node.tile, current->path.node.tile, current->path.node.tile + TileOffsByDir(i)); truelight@110: r = DoCommandByTile(current->path.node.tile, 0, dir, DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL); truelight@110: if (r == CMD_ERROR) continue; truelight@110: #ifdef AI_PATHFINDER_NO_90DEGREES_TURN truelight@110: if (current->path.parent->parent != NULL) { truelight@110: // Check if we don't make a 90degree curve truelight@110: int dir1 = AiNew_GetRailDirection(current->path.parent->parent->node.tile, current->path.parent->node.tile, current->path.node.tile); truelight@110: if (_illegal_curves[dir1] == dir || _illegal_curves[dir] == dir1) { truelight@110: continue; truelight@110: } truelight@110: } truelight@110: #endif truelight@110: } else { truelight@110: // Road check tron@906: dir = AiNew_GetRoadDirection(current->path.parent->node.tile, current->path.node.tile, current->path.node.tile + TileOffsByDir(i)); truelight@110: if (AI_PATHFINDER_IS_ROAD(current->path.node.tile)) { truelight@110: if (IS_TILETYPE(current->path.node.tile, MP_TUNNELBRIDGE)) { truelight@110: // We have a bridge, how nicely! We should mark it... truelight@110: dir = 0; truelight@110: } else { truelight@110: // It already has road.. check if we miss any bits! truelight@110: if ((_map5[current->path.node.tile] & dir) != dir) { truelight@110: // We do miss some pieces :( truelight@110: dir &= ~_map5[current->path.node.tile]; truelight@110: } else { truelight@110: dir = 0; truelight@110: } truelight@110: } truelight@110: } truelight@110: // Only destruct things if it is MP_CLEAR of MP_TREES truelight@110: if (dir != 0) { truelight@110: r = DoCommandByTile(current->path.node.tile, dir, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD); truelight@110: if (r == CMD_ERROR) continue; truelight@110: } truelight@110: } truelight@193: truelight@110: } truelight@193: truelight@110: // The tile can be connected tron@906: aystar->neighbours[aystar->num_neighbours].tile = TileOffsByDir(i) + current->path.node.tile; truelight@110: aystar->neighbours[aystar->num_neighbours].user_data[0] = 0; truelight@110: aystar->neighbours[aystar->num_neighbours++].direction = 0; truelight@110: } truelight@110: } truelight@193: truelight@110: // Next step, check for bridges and tunnels truelight@110: if (current->path.parent != NULL && current->path.node.user_data[0] == 0) { truelight@110: truelight@110: TileInfo ti; truelight@110: // First we get the dir from this tile and his parent truelight@110: int dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile); truelight@110: // It means we can only walk with the track, so the bridge has to be in the same direction truelight@110: TileIndex tile = current->path.node.tile; truelight@110: TileIndex new_tile = tile; truelight@193: truelight@110: FindLandscapeHeightByTile(&ti, tile); truelight@193: truelight@110: // Bridges can only be build on land that is not flat truelight@110: // And if there is a road or rail blocking truelight@110: if (ti.tileh != 0 || tron@906: (PathFinderInfo->rail_or_road && IS_TILETYPE(tile + TileOffsByDir(dir), MP_STREET)) || tron@906: (!PathFinderInfo->rail_or_road && IS_TILETYPE(tile + TileOffsByDir(dir), MP_RAILWAY))) { truelight@110: truelight@110: for (;;) { tron@906: new_tile += TileOffsByDir(dir); truelight@193: truelight@110: // Precheck, is the length allowed? truelight@110: if (!CheckBridge_Stuff(0,GetBridgeLength(tile, new_tile))) break; truelight@193: truelight@110: // Check if we hit the station-tile.. we don't like that! truelight@110: if (TILES_BETWEEN(new_tile,PathFinderInfo->end_tile_tl,PathFinderInfo->end_tile_br)) break; truelight@110: truelight@110: // Try building the bridge.. truelight@110: r = DoCommandByTile(tile, new_tile, (0<<8) + (MAX_BRIDGES / 2), DC_AUTO, CMD_BUILD_BRIDGE); truelight@110: if (r == CMD_ERROR) continue; truelight@110: // We can build a bridge here.. add him to the neighbours truelight@110: aystar->neighbours[aystar->num_neighbours].tile = new_tile; truelight@110: aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_BRIDGE + (dir << 8); truelight@110: aystar->neighbours[aystar->num_neighbours++].direction = 0; truelight@110: // We can only have 12 neighbours, and we need 1 left for tunnels truelight@110: if (aystar->num_neighbours == 11) break; truelight@110: } truelight@110: } truelight@193: truelight@110: // Next, check for tunnels! truelight@110: // Tunnels can only be build with tileh of 3, 6, 9 or 12, depending on the direction truelight@110: // For now, we check both sides for this tile.. terraforming gives fuzzy result truelight@110: if ((dir == 0 && ti.tileh == 12) || truelight@110: (dir == 1 && ti.tileh == 6) || truelight@110: (dir == 2 && ti.tileh == 3) || truelight@110: (dir == 3 && ti.tileh == 9)) { truelight@110: // Now simply check if a tunnel can be build truelight@110: r = DoCommandByTile(tile, (PathFinderInfo->rail_or_road?0:0x200), 0, DC_AUTO, CMD_BUILD_TUNNEL); truelight@110: FindLandscapeHeightByTile(&ti, _build_tunnel_endtile); truelight@110: if (r != CMD_ERROR && (ti.tileh == 3 || ti.tileh == 6 || ti.tileh == 9 || ti.tileh == 12)) { truelight@110: aystar->neighbours[aystar->num_neighbours].tile = _build_tunnel_endtile; truelight@110: aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_TUNNEL + (dir << 8); truelight@110: aystar->neighbours[aystar->num_neighbours++].direction = 0; truelight@110: } truelight@110: } truelight@110: } truelight@110: } truelight@110: truelight@110: extern uint GetRailFoundation(uint tileh, uint bits); truelight@110: extern uint GetRoadFoundation(uint tileh, uint bits); truelight@110: extern uint GetBridgeFoundation(uint tileh, byte direction); truelight@110: enum { truelight@110: BRIDGE_NO_FOUNDATION = 1 << 0 | 1 << 3 | 1 << 6 | 1 << 9 | 1 << 12, truelight@110: }; truelight@110: truelight@110: // The most important function: it calculates the g-value truelight@110: static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent) { truelight@110: Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target; truelight@110: int r, res = 0; truelight@110: TileInfo ti, parent_ti; truelight@193: truelight@110: // Gather some information about the tile.. truelight@110: FindLandscapeHeightByTile(&ti, current->tile); truelight@110: FindLandscapeHeightByTile(&parent_ti, parent->path.node.tile); truelight@193: truelight@110: // Check if we hit the end-tile truelight@110: if (TILES_BETWEEN(current->tile,PathFinderInfo->end_tile_tl,PathFinderInfo->end_tile_br)) { truelight@110: // We are at the end-tile, check if we had a direction or something... truelight@110: if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION && AiNew_GetDirection(current->tile, parent->path.node.tile) != PathFinderInfo->end_direction) truelight@110: // We are not pointing the right way, invalid tile truelight@110: return AYSTAR_INVALID_NODE; truelight@110: // If it was valid, drop out.. we don't build on the endtile truelight@110: return 0; truelight@110: } truelight@193: truelight@110: // Give everything a small penalty truelight@110: res += AI_PATHFINDER_PENALTY; truelight@110: truelight@110: if (!PathFinderInfo->rail_or_road) { truelight@110: // Road has the lovely advantage it can use other road... check if truelight@110: // the current tile is road, and if so, give a good bonus truelight@110: if (AI_PATHFINDER_IS_ROAD(current->tile)) { truelight@110: res -= AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS; truelight@110: } truelight@110: } truelight@193: truelight@110: // We should give a penalty when the tile is going up or down.. this is one way to do so! truelight@110: // Too bad we have to count it from the parent.. but that is not so bad truelight@110: if (parent_ti.tileh != 0 && parent->path.parent != NULL) { truelight@110: // Skip if the tile was from a bridge or tunnel truelight@110: if (parent->path.node.user_data[0] == 0 && current->user_data[0] == 0) { truelight@110: if (PathFinderInfo->rail_or_road) { truelight@110: r = GetRailFoundation(parent_ti.tileh, 1 << AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile)); truelight@110: // Maybe is BRIDGE_NO_FOUNDATION a bit strange here, but it contains just the right information.. truelight@110: if (r >= 15 || (r == 0 && (BRIDGE_NO_FOUNDATION & (1 << ti.tileh)))) { truelight@110: res += AI_PATHFINDER_TILE_GOES_UP_PENALTY; truelight@110: } truelight@110: } else { truelight@110: if (!(AI_PATHFINDER_IS_ROAD(parent->path.node.tile) && IS_TILETYPE(parent->path.node.tile, MP_TUNNELBRIDGE))) { truelight@110: r = GetRoadFoundation(parent_ti.tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile)); truelight@110: if (r >= 15 || r == 0) truelight@110: res += AI_PATHFINDER_TILE_GOES_UP_PENALTY; truelight@110: } truelight@110: } truelight@110: } truelight@110: } truelight@193: truelight@110: // Are we part of a tunnel? truelight@110: if ((AI_PATHFINDER_FLAG_TUNNEL & current->user_data[0]) != 0) { truelight@110: // Tunnels are very expensive when build on long routes.. truelight@110: // Ironicly, we are using BridgeCode here ;) truelight@110: r = AI_PATHFINDER_TUNNEL_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile); truelight@110: res += r + (r >> 8); truelight@110: } truelight@110: truelight@110: // Are we part of a bridge? truelight@110: if ((AI_PATHFINDER_FLAG_BRIDGE & current->user_data[0]) != 0) { truelight@110: // That means for every length a penalty truelight@110: res += AI_PATHFINDER_BRIDGE_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile); truelight@110: // Check if we are going up or down, first for the starting point truelight@110: // In user_data[0] is at the 8th bit the direction truelight@110: if (!(BRIDGE_NO_FOUNDATION & (1 << parent_ti.tileh))) { truelight@110: if (GetBridgeFoundation(parent_ti.tileh, (current->user_data[0] >> 8) & 1) < 15) truelight@110: res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY; truelight@110: } truelight@110: // Second for the end point truelight@110: if (!(BRIDGE_NO_FOUNDATION & (1 << ti.tileh))) { truelight@110: if (GetBridgeFoundation(ti.tileh, (current->user_data[0] >> 8) & 1) < 15) truelight@110: res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY; truelight@110: } truelight@110: if (parent_ti.tileh == 0) truelight@110: res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY; truelight@110: if (ti.tileh == 0) truelight@110: res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY; truelight@110: } truelight@193: truelight@110: // To prevent the AI from taking the fastest way in tiles, but not the fastest way truelight@110: // in speed, we have to give a good penalty to direction changing truelight@110: // This way, we get almost the fastest way in tiles, and a very good speed on the track truelight@110: if (!PathFinderInfo->rail_or_road) { truelight@110: if (parent->path.parent != NULL && truelight@110: AiNew_GetDirection(current->tile, parent->path.node.tile) != AiNew_GetDirection(parent->path.node.tile, parent->path.parent->node.tile)) { truelight@110: // When road exists, we don't like turning, but its free, so don't be to piggy about it truelight@110: if (AI_PATHFINDER_IS_ROAD(parent->path.node.tile)) truelight@110: res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY; truelight@110: else truelight@110: res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY; truelight@110: } truelight@110: } else { truelight@110: // For rail we have 1 exeption: diagonal rail.. truelight@110: // So we fetch 2 raildirection. That of the current one, and of the one before that truelight@110: if (parent->path.parent != NULL && parent->path.parent->parent != NULL) { truelight@110: int dir1 = AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile); truelight@110: int dir2 = AiNew_GetRailDirection(parent->path.parent->parent->node.tile, parent->path.parent->node.tile, parent->path.node.tile); miham@826: // First, see if we are on diagonal path, that is better than straight path truelight@110: if (dir1 > 1) { res -= AI_PATHFINDER_DIAGONAL_BONUS; } truelight@110: truelight@110: // First see if they are different truelight@110: if (dir1 != dir2) { truelight@110: // dir 2 and 3 are 1 diagonal track, and 4 and 5. truelight@110: if (!(((dir1 == 2 || dir1 == 3) && (dir2 == 2 || dir2 == 3)) || ((dir1 == 4 || dir1 == 5) && (dir2 == 4 || dir2 == 5)))) { truelight@110: // It is not, so we changed of direction truelight@110: res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY; truelight@110: } truelight@110: if (parent->path.parent->parent->parent != NULL) { truelight@110: int dir3 = AiNew_GetRailDirection(parent->path.parent->parent->parent->node.tile, parent->path.parent->parent->node.tile, parent->path.parent->node.tile); truelight@110: // Check if we changed 3 tiles of direction in 3 tiles.. bad!!! truelight@110: if ((dir1 == 0 || dir1 == 1) && dir2 > 1 && (dir3 == 0 || dir3 == 1)) { truelight@110: res += AI_PATHFINDER_CURVE_PENALTY; truelight@110: } truelight@110: } truelight@110: } truelight@110: } truelight@110: } truelight@193: truelight@110: // Res should never be below zero.. if so, make it zero! truelight@110: if (res < 0) { res = 0; } truelight@110: truelight@110: // Return our value truelight@110: return res; truelight@110: }