Figure* Board::swap(const Coords &pos, const Figure * const fig) { Figure * const result = board[coordsToIndex(pos)]; // TODO: Figure parametrisieren board[coordsToIndex(pos)] = (fig == NULL) ? NULL : fig->clone(); return result; }
bool Board::move(const Coords &from, const Coords &to) { if (board[coordsToIndex(from)] == NULL || board[coordsToIndex(to)] == NULL) { return false; } // TODO: Figure parametrisieren board[coordsToIndex(to)] = board[coordsToIndex(from)]; board[coordsToIndex(from)] = NULL; return true; }
toweringinferno::World::ActionSuccess toweringinferno::World::updateHoseRelease( const TCOD_key_t& command ) { if (isActionKey(command) == false) { return eAction_InvalidInput; } const Point playerPos = m_player.getPos(); for(int col = playerPos.col - 1; col < playerPos.col + 2; ++col) { for(int row = playerPos.row - 1; row < playerPos.row + 2; ++row) { if (getType(col, row) != eHose) { continue; } Cell& hose = m_floorData.map[coordsToIndex(col, row)]; if (hose.hp == 0.0f) { continue; } hose.water = 3.5f; hose.hp = 0.0f; return eAction_Succeeded; } } return eAction_Failed; }
toweringinferno::World::ActionSuccess toweringinferno::World::updateAxe( const TCOD_key_t& command ) { if (isAxeKey(command) == false) { return eAction_InvalidInput; } if (m_player.getAxesRemaining() == 0) { return eAction_Failed; } Cell* wallToAxe = NULL; const Point playerPos = m_player.getPos(); for(int col = playerPos.col - 1; col < playerPos.col + 2; ++col) { for(int row = playerPos.row - 1; row < playerPos.row + 2; ++row) { if ((col == playerPos.col && row == playerPos.row) || isValidCoords(col, row) == false) { continue; } Cell& axisNeighbourCell = m_floorData.map[coordsToIndex(col, row)]; if (axisNeighbourCell.type == eWall && (wallToAxe == NULL || isDeltaWithDirection(col - playerPos.col, row - playerPos.row, m_floorData.lastMovementDir))) { wallToAxe = &axisNeighbourCell; } } } if (wallToAxe != NULL) { wallToAxe->hp -= 0.34f; if (wallToAxe->hp <= 0.0f) { wallToAxe->type = eFloor; m_player.useAxe(); } return eAction_Succeeded; } else { return eAction_Failed; } }
toweringinferno::World::ActionSuccess toweringinferno::World::updateSprinklerControl( const TCOD_key_t& command ) { if (isActionKey(command) == false) { return eAction_InvalidInput; } if (m_floorData.isSprinklerAvailable == false) { return eAction_Failed; } const Point playerPos = m_player.getPos(); for(int col = playerPos.col - 1; col < playerPos.col + 2; ++col) { for(int row = playerPos.row - 1; row < playerPos.row + 2; ++row) { if (getType(col, row) != eSprinklerControl) { continue; } // GO GO SPRINKLERS const int sprinklerSpacing = 9; for (int sprinklerCol = sprinklerSpacing; sprinklerCol < m_width; sprinklerCol += sprinklerSpacing) { for(int sprinklerRow = sprinklerSpacing; sprinklerRow < m_height; sprinklerRow += sprinklerSpacing) { Cell& cell = m_floorData.map[coordsToIndex(sprinklerCol, sprinklerRow)]; if (cell.type == eFloor) { cell.water = 1.5f; cell.fire = 0.0f; cell.heat = 0.0f; } } } m_floorData.isSprinklerAvailable = false; return eAction_Succeeded; } } return eAction_Failed; }
toweringinferno::World::ActionSuccess toweringinferno::World::updateDoors( const TCOD_key_t& command ) { if (isDoorToggleKey(command) == false) { return eAction_InvalidInput; } bool didAnyDoorFlip = false; const Point playerPos = m_player.getPos(); for(int col = playerPos.col - 1; col < playerPos.col + 2; ++col) { for(int row = playerPos.row - 1; row < playerPos.row + 2; ++row) { if (isValidCoords(col, row) == false) { continue; } Cell& axisNeighbourCell = m_floorData.map[coordsToIndex(col, row)]; if (axisNeighbourCell.type == eOpenDoor) { axisNeighbourCell.type = eClosedDoor; didAnyDoorFlip = true; } else if (axisNeighbourCell.type == eClosedDoor) { axisNeighbourCell.type = eOpenDoor; didAnyDoorFlip = true; } } } return didAnyDoorFlip ? eAction_Succeeded : eAction_Failed; }
void toweringinferno::World::updateDynamics() { for(int col = 0; col < getWidth(); ++col) { for(int row = 0; row < getHeight(); ++row) { Cell& cell = m_floorData.map[coordsToIndex(col, row)]; cell.typeFlip = cell.type; } } for(int col = 0; col < getWidth(); ++col) { for(int row = 0; row < getHeight(); ++row) { Cell& cell = m_floorData.map[coordsToIndex(col, row)]; if (cell.type == eSky) { continue; } // calculate heat float heat = 0.0f; const float minEvaporation = utils::mapValue(cell.water, 0.1f, 0.15f, 0.0f, 0.1f); const float evaporation = utils::mapValue(cell.heat, 0.0f, 1.0f, minEvaporation, 0.6f); float waterTotal = cell.water - evaporation; int waterContributors = 1; float condensationScore = cell.water; int condensationContributors = 1; for(int neighbourCol = utils::max(col - 1, 0); neighbourCol < utils::min(getWidth(), col + 2); ++neighbourCol) { for (int neighbourRow = utils::max(row - 1, 0); neighbourRow < utils::min(getHeight(), row + 2); ++neighbourRow) { if (neighbourCol == col && neighbourRow == row) { continue; } Cell& neighbour = m_floorData.map[coordsToIndex(neighbourCol,neighbourRow)]; const bool isDiagonalNeighbour = row != neighbourRow && col != neighbourCol; const bool wallCanContributeHeat = (row == neighbourRow && getType(col + 1, row) != eClosedDoor && getType(col - 1, row) != eClosedDoor && ((getType(col, row - 1) == eFloor && getType(col + (neighbourCol < col ? -1 : 1), row - 1) != eClosedDoor) || (getType(col, row + 1) == eFloor && getType(col + (neighbourCol < col ? -1 : 1), row + 1) != eClosedDoor))) || (col == neighbourCol && getType(col, row - 1) != eClosedDoor && getType(col, row + 1) != eClosedDoor && ((getType(col - 1, row) == eFloor && getType(col - 1, row + (neighbourRow < row ? -1 : 1)) != eClosedDoor) || (getType(col + 1, row) == eFloor && getType(col + 1, row + (neighbourRow < row ? -1 : 1)) != eClosedDoor))); const float heatContribution = isDiagonalNeighbour ? 0.0f : neighbour.type == eWall && cell.type == eWall && wallCanContributeHeat == false ? 0.0f : neighbour.type == eWall ? (3.5f/6.0f) : (1.5f/6.0f); heat += neighbour.heat * heatContribution; if (isDiagonalNeighbour == false) { condensationScore += neighbour.water; condensationContributors += neighbour.water > 0.0f ? 1 : 0; } const bool isNeighbourContributingWater = isWaterBlocker(neighbour) == false && cell.water < neighbour.water; waterTotal += (isNeighbourContributingWater ? neighbour.water : 0.0f); waterContributors += isNeighbourContributingWater ? 1 : 0; } } cell.waterFlip = isWaterBlocker(cell) ? 0.0f : utils::max(waterTotal / static_cast<float>(waterContributors), 0.0f); const float heatBuildRate = cell.type == eWall ? 0.65f : isHeatProof(cell.type) ? 0.0f : 0.25f; const float condensation = utils::mapValue(condensationScore / static_cast<float>(condensationContributors), 0.0f, 1.0f, 0.01f, 0.6f); cell.heatFlip = utils::clamp( cell.heat + heat * heatBuildRate - condensation, 0.0f, 1.0f); if (cell.type == eWall) { cell.hp = utils::max(0.0f, cell.hp - utils::mapValue(cell.fire, 0.9f, 1.0f, 0.0f, 0.02f)); if (cell.hp == 0.0f) { cell.typeFlip = eFloor; cell.fire = 0.75f; } } } } for(int col = 0; col < getWidth(); ++col) { for(int row = 0; row < getHeight(); ++row) { Cell& cell = m_floorData.map[coordsToIndex(col, row)]; cell.type = cell.typeFlip; cell.water = cell.waterFlip; cell.heat = cell.heatFlip; const float fireThreshold = 0.5f; if (cell.heat > fireThreshold) { cell.fire = utils::clamp(cell.fire + utils::mapValue(cell.heat, fireThreshold, 1.0f, 0.0f, 0.05f), 0.0f, 1.0f); } else { cell.fire = 0.0f; } } } }
bool Board::apply(BoardTransaction &tr) { MutableBoardTransaction mtr(tr); if (mtr.isAccepted()) { return false; // transaction has already been accepted/applied } mtr.setTransactionNumber(nextTransaction); // assign preliminary transaction number if (mtr.getBoardOps().size() == 0) { // empty transaction, apply rules if (!inRange(mtr.getFrom()) || !inRange(mtr.getTo())) { throw std::out_of_range("Source or target coordinates are outside of board range"); } if (mtr.getFrom() == mtr.getTo()) { mtr.setStateCode(bsc_SourceAndDestinationAreEqual); return false; } Figure *fig = board[coordsToIndex(mtr.getFrom())]; if (fig == NULL) { return false; // no figure which could do something is there } if (!fig->apply(mtr)) { mtr.setAccepted(false); mtr.getBoardOps().clear(); return false; // failed to prepare transaction } } std::vector<BoardOp::Operation*> &ops = mtr.getBoardOps(); bool result = true; size_t i = 0; for (; result && i < ops.size(); i++) { result &= ops[i]->apply(*this); } if (result) { mtr.setAccepted(true); nextTransaction++; // Increment for next transaction return true; // transaction has been applied successfully } // else: transaction failed, rollback result = true; do { i--; result &= ops[i]->undo(*this); } while (result && i != 0); if (!result) { // rollback has failed, too ... something is broken utterly // we don't bother about invalidating the transaction, this is a major // problem which can not be resolved throw std::logic_error("Undo operation failed to recover from failure"); } mtr.setAccepted(false); return false; }
const Figure* Board::get(const Coords &pos) const { return board[coordsToIndex(pos)]; }