uint8_t Map::isTileClear(uint16_t x, uint16_t y, uint8_t z) const
{
const Tile* tile = getTile(x, y, z);
if (!tile || !tile->hasProperty(CONST_PROP_BLOCKPROJECTILE)) {
return 0;
}
return tile->getFieldItem() ? 2 : 1;
}
uint8_t Map::getSteepLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) const
{
float dx = x1 - x0;
float dy = y1 - y0;
float grad = (dx == 0) ? 1 : dy / dx;
float xy = y0 + grad;
for (int y = x0 + 1; y < x1; ++y) {
uint16_t newX = std::floor(xy);
uint8_t tileClear = isTileClear(newX, y, z);
if (tileClear != 0) {
return tileClear;
}
xy += grad;
}
return 0;
}
uint8_t Map::getSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) const
{
float dx = x1 - x0;
float dy = y1 - y0;
float grad = (dx == 0) ? 1 : dy / dx;
float xy = y0 + grad;
for (int x = x0 + 1; x < x1; ++x) {
uint16_t newY = std::floor(xy + 0.1);
uint8_t tileClear = isTileClear(x, newY, z);
if (tileClear != 0) {
return tileClear;
}
xy += grad;
}
return 0;
}
uint8_t Map::checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) const
{
if (x0 == x1 && y0 == y1) {
return 0;
}
if (std::abs(y1 - y0) > std::abs(x1 - x0)) {
if (y1 > y0) {
return getSteepLine(y0, x0, y1, x1, z);
}
return getSteepLine(y1, x1, y0, x0, z);
}
if (x0 > x1) {
return getSlightLine(x1, y1, x0, y0, z);
}
return getSlightLine(x0, y0, x1, y1, z);
}
bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck) const
{
uint8_t z0 = fromPos.z, z1 = toPos.z;
if (floorCheck && z0 != z1) {
return false;
}
uint16_t x0 = fromPos.x, y0 = fromPos.y, x1 = toPos.x, y1 = toPos.y;
uint8_t sightClear = checkSightLine(x0, y0, x1, y1, z0);
if (sightClear == 2 || sightClear == 1 && z0 == z1) {
return false;
}
if (z0 < z1) {
if (sightClear == 1 || isTileClear(x1, y1, z0) != 0) {
return false;
}
for (uint8_t z = z0 + 1; z <= z1; ++z) {
if (isTileClear(x1, y1, z) != 0 || checkSightLine(x0, y0, x1, y1, z) == 2) {
return false;
}
}
}
else if (isTileClear(x1, y1, z1) != 0 || checkSightLine(x0, y0, x1, y1, z1) != 0) {
return false;
}
return true;
}