char BattleHex::getDistance(BattleHex hex1, BattleHex hex2) { int y1 = hex1.getY(), y2 = hex2.getY(); int x1 = hex1.getX() + y1 / 2.0, x2 = hex2.getX() + y2 / 2.0; int xDst = x2 - x1, yDst = y2 - y1; if ((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0)) return std::max(std::abs(xDst), std::abs(yDst)); else return std::abs(xDst) + std::abs(yDst); }
std::vector<BattleHex> CObstacleInfo::getBlocked(BattleHex hex) const { std::vector<BattleHex> ret; if(isAbsoluteObstacle) { assert(!hex.isValid()); range::copy(blockedTiles, std::back_inserter(ret)); return ret; } BOOST_FOREACH(int offset, blockedTiles) { BattleHex toBlock = hex + offset; if((hex.getY() & 1) && !(toBlock.getY() & 1)) toBlock += BattleHex::LEFT; if(!toBlock.isValid()) tlog1 << "Misplaced obstacle!\n"; else ret.push_back(toBlock); }
bool Teleport::prepareEffects(std::string & errorMessage, BattleStackMoved & pack, const Mechanics * m, const EffectTarget & target) const { if(target.size() != 2) { errorMessage = "Teleport requires 2 destinations."; return false; } auto targetUnit = target[0].unitValue; if(nullptr == targetUnit) { errorMessage = "No unit to teleport"; return false; } const BattleHex destination = target[1].hexValue; if(!destination.isValid()) { errorMessage = "Invalid teleport destination"; return false; } //TODO: move here all teleport checks if(!m->cb->battleCanTeleportTo(targetUnit, destination, m->getEffectLevel())) { errorMessage = "Forbidden teleport."; return false; } pack.distance = 0; pack.stack = targetUnit->unitId(); std::vector<BattleHex> tiles; tiles.push_back(destination); pack.tilesToMove = tiles; pack.teleporting = true; return true; }
std::vector<BattleHex> CObstacleInfo::getBlocked(BattleHex hex) const { std::vector<BattleHex> ret; if(isAbsoluteObstacle) { assert(!hex.isValid()); range::copy(blockedTiles, std::back_inserter(ret)); return ret; } for(int offset : blockedTiles) { BattleHex toBlock = hex + offset; if((hex.getY() & 1) && !(toBlock.getY() & 1)) toBlock += BattleHex::LEFT; if(!toBlock.isValid()) logGlobal->errorStream() << "Misplaced obstacle!"; else ret.push_back(toBlock); } return ret; }
BattleHex BattleHex::getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities) { std::vector<BattleHex> sortedTiles (possibilities.begin(), possibilities.end()); //set can't be sorted properly :( BattleHex initialHex = BattleHex(initialPos); auto compareDistance = [initialHex](const BattleHex left, const BattleHex right) -> bool { return initialHex.getDistance (initialHex, left) < initialHex.getDistance (initialHex, right); }; boost::sort (sortedTiles, compareDistance); //closest tiles at front int closestDistance = initialHex.getDistance(initialPos, sortedTiles.front()); //sometimes closest tiles can be many hexes away auto notClosest = [closestDistance, initialPos](const BattleHex here) -> bool { return closestDistance < here.getDistance (initialPos, here); }; vstd::erase_if(sortedTiles, notClosest); //only closest tiles are interesting auto compareHorizontal = [attackerOwned, initialPos](const BattleHex left, const BattleHex right) -> bool { if(left.getX() != right.getX()) { if (attackerOwned) return left.getX() > right.getX(); //find furthest right else return left.getX() < right.getX(); //find furthest left } else { //Prefer tiles in the same row. return std::abs(left.getY() - initialPos.getY()) < std::abs(right.getY() - initialPos.getY()); } }; boost::sort (sortedTiles, compareHorizontal); return sortedTiles.front(); }
void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret) { if(tile.isAvailable()) ret.push_back(tile); }
std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const { std::vector<BattleHex> ret; if(id == Spells::FIRE_WALL || id == Spells::FORCE_FIELD) { //Special case - shape of obstacle depends on caster's side //TODO make it possible through spell_info config BattleHex::EDir firstStep, secondStep; if(side) { firstStep = BattleHex::TOP_LEFT; secondStep = BattleHex::TOP_RIGHT; } else { firstStep = BattleHex::TOP_RIGHT; secondStep = BattleHex::TOP_LEFT; } //Adds hex to the ret if it's valid. Otherwise sets output arg flag if given. auto addIfValid = [&](BattleHex hex) { if(hex.isValid()) ret.push_back(hex); else if(outDroppedHexes) *outDroppedHexes = true; }; ret.push_back(centralHex); addIfValid(centralHex.moveInDir(firstStep, false)); if(schoolLvl >= 2) //advanced versions of fire wall / force field cotnains of 3 hexes addIfValid(centralHex.moveInDir(firstStep, false).moveInDir(secondStep, false)); return ret; } std::string rng = range[schoolLvl] + ','; //copy + artificial comma for easier handling if(rng.size() >= 1 && rng[0] != 'X') //there is at lest one hex in range { std::string number1, number2; int beg, end; bool readingFirst = true; for(int it=0; it<rng.size(); ++it) { if( std::isdigit(rng[it]) ) //reading numer { if(readingFirst) number1 += rng[it]; else number2 += rng[it]; } else if(rng[it] == ',') //comma { //calculating variables if(readingFirst) { beg = atoi(number1.c_str()); number1 = ""; } else { end = atoi(number2.c_str()); number2 = ""; } //obtaining new hexes std::set<ui16> curLayer; if(readingFirst) { curLayer = getInRange(centralHex, beg, beg); } else { curLayer = getInRange(centralHex, beg, end); readingFirst = true; } //adding abtained hexes for(std::set<ui16>::iterator it = curLayer.begin(); it != curLayer.end(); ++it) { ret.push_back(*it); } } else if(rng[it] == '-') //dash { beg = atoi(number1.c_str()); number1 = ""; readingFirst = false; } } } //remove duplicates (TODO check if actually needed) range::unique(ret); return ret; }