/** * Get a tile in the direction of a destination, randomized a bit. * * @param packed_from The origin. * @param packed_to The destination. * @return A packed tile. */ uint16 Tile_GetTileInDirectionOf(uint16 packed_from, uint16 packed_to) { int16 distance; uint8 direction; uint8 i; if (packed_from == 0 || packed_to == 0) return 0; distance = Tile_GetDistancePacked(packed_from, packed_to); direction = Tile_GetDirectionPacked(packed_to, packed_from); if (distance <= 10) return 0; for (i = 0; i < 4; i++) { int16 dir; tile32 position; uint16 packed; dir = 29 + (Tools_Random_256() & 0x3F); if ((Tools_Random_256() & 1) != 0) dir = -dir; position = Tile_UnpackTile(packed_to); position = Tile_MoveByDirection(position, direction + dir, min(distance, 20) << 8); packed = Tile_PackTile(position); if (Map_IsValidPosition(packed)) return packed; } return 0; }
/** * Try to find a path between two points. * * @param packedSrc The start point. * @param packedDst The end point. * @param buffer The buffer to store the route in. * @param bufferSize The size of the buffer. * @return A struct with information about the found route. */ static Pathfinder_Data Script_Unit_Pathfinder(uint16 packedSrc, uint16 packedDst, void *buffer, int16 bufferSize) { uint16 packedCur; Pathfinder_Data res; res.packed = packedSrc; res.score = 0; res.routeSize = 0; res.buffer = buffer; res.buffer[0] = 0xFF; bufferSize--; packedCur = packedSrc; while (res.routeSize < bufferSize) { uint8 direction; uint16 packedNext; int16 score; if (packedCur == packedDst) break; /* Try going directly to the destination tile */ direction = Tile_GetDirectionPacked(packedCur, packedDst) / 32; packedNext = packedCur + s_mapDirection[direction]; /* Check for valid movement towards the tile */ score = Script_Unit_Pathfind_GetScore(packedNext, direction); if (score <= 255) { res.buffer[res.routeSize++] = direction; res.score += score; } else { uint8 dir; bool foundCounterclockwise = false; bool foundClockwise = false; int16 routeSize; Pathfinder_Data routes[2]; uint8 routesBuffer[2][102]; Pathfinder_Data *bestRoute; while (true) { if (packedNext == packedDst) break; /* Find the first valid tile on the (direct) route. */ dir = Tile_GetDirectionPacked(packedNext, packedDst) / 32; packedNext += s_mapDirection[dir]; if (Script_Unit_Pathfind_GetScore(packedNext, dir) > 255) continue; /* Try to find a connection between our last valid tile and the new valid tile */ routes[1].packed = packedCur; routes[1].score = 0; routes[1].routeSize = 0; routes[1].buffer = routesBuffer[0]; foundCounterclockwise = Script_Unit_Pathfinder_Connect(packedNext, &routes[1], -1, direction); routes[0].packed = packedCur; routes[0].score = 0; routes[0].routeSize = 0; routes[0].buffer = routesBuffer[1]; foundClockwise = Script_Unit_Pathfinder_Connect(packedNext, &routes[0], 1, direction); if (foundCounterclockwise || foundClockwise) break; do { if (packedNext == packedDst) break; dir = Tile_GetDirectionPacked(packedNext, packedDst) / 32; packedNext += s_mapDirection[dir]; } while (Script_Unit_Pathfind_GetScore(packedNext, dir) <= 255); } if (foundCounterclockwise || foundClockwise) { /* Find the best (partial) route */ if (!foundClockwise) { bestRoute = &routes[1]; } else if (!foundCounterclockwise) { bestRoute = &routes[0]; } else { bestRoute = &routes[routes[1].score < routes[0].score ? 1 : 0]; } /* Calculate how much more we can copy into our own buffer */ routeSize = min(bufferSize - res.routeSize, bestRoute->routeSize); if (routeSize <= 0) break; /* Copy the rest into our own buffer */ memcpy(&res.buffer[res.routeSize], bestRoute->buffer, routeSize); res.routeSize += routeSize; res.score += bestRoute->score; } else { /* Means we didn't find a route. packedNext is now equal to packedDst */ break; } } packedCur = packedNext; } if (res.routeSize < bufferSize) res.buffer[res.routeSize++] = 0xFF; Script_Unit_Pathfinder_Smoothen(&res); return res; }