/** * Select next soldier. * @param action Pointer to an action. */ void BattlescapeState::btnNextSoldierClick(Action *action) { if (_popup) return; BattleUnit *unit = _battleGame->selectNextPlayerUnit(); updateSoldierInfo(unit); if (unit) _map->centerOnPosition(unit->getPosition()); }
/** * Updates all soldier stats when the soldier changes. */ void InventoryState::init() { State::init(); BattleUnit *unit = _battleGame->getSelectedUnit(); // no selected unit, close inventory if (unit == 0) { btnOkClick(0); return; } // skip to the first unit with inventory if (!unit->hasInventory()) { if (_parent) { _parent->selectNextPlayerUnit(false, false, true); } else { _battleGame->selectNextPlayerUnit(false, false, true); } // no available unit, close inventory if (_battleGame->getSelectedUnit() == 0 || !_battleGame->getSelectedUnit()->hasInventory()) { // starting a mission with just vehicles btnOkClick(0); return; } else { unit = _battleGame->getSelectedUnit(); } } if (_parent) _parent->getMap()->getCamera()->centerOnPosition(unit->getPosition(), false); unit->setCache(0); _soldier->clear(); _btnRank->clear(); _txtName->setBig(); _txtName->setText(unit->getName(_game->getLanguage())); _inv->setSelectedUnit(unit); Soldier *s = _game->getSavedGame()->getSoldier(unit->getId()); if (s) { SurfaceSet *texture = _game->getResourcePack()->getSurfaceSet("BASEBITS.PCK"); texture->getFrame(s->getRankSprite())->setX(0); texture->getFrame(s->getRankSprite())->setY(0); texture->getFrame(s->getRankSprite())->blit(_btnRank); std::string look = s->getArmor()->getSpriteInventory(); if (s->getGender() == GENDER_MALE) look += "M"; else look += "F"; if (s->getLook() == LOOK_BLONDE) look += "0"; if (s->getLook() == LOOK_BROWNHAIR) look += "1"; if (s->getLook() == LOOK_ORIENTAL) look += "2"; if (s->getLook() == LOOK_AFRICAN) look += "3"; look += ".SPK"; if (!CrossPlatform::fileExists(CrossPlatform::getDataFile("UFOGRAPH/" + look)) && !_game->getResourcePack()->getSurface(look)) { look = s->getArmor()->getSpriteInventory() + ".SPK"; } _game->getResourcePack()->getSurface(look)->blit(_soldier); } else { Surface *armorSurface = _game->getResourcePack()->getSurface(unit->getArmor()->getSpriteInventory()); if (armorSurface) { armorSurface->blit(_soldier); } } updateStats(); }
/** * Updates all soldier stats when the soldier changes. */ void InventoryState::init() { BattleUnit *unit = _battleGame->getSelectedUnit(); // no selected unit, close inventory if (unit == 0) { btnOkClick(0); return; } // skip to the first unit with inventory if (!unit->hasInventory()) { if (_parent) { _parent->selectNextPlayerUnit(false, false, true); } else { _battleGame->selectNextPlayerUnit(false, false, true); } // no available unit, close inventory if (_battleGame->getSelectedUnit() == 0) { // starting a mission with just vehicles btnOkClick(0); return; } else { unit = _battleGame->getSelectedUnit(); } } if (_parent) _parent->getMap()->getCamera()->centerOnPosition(unit->getPosition()); unit->setCache(0); _soldier->clear(); _btnRank->clear(); _txtName->setBig(); _txtName->setText(unit->getName(_game->getLanguage())); _inv->setSelectedUnit(unit); Soldier *s = _game->getSavedGame()->getSoldier(unit->getId()); if (s) { SurfaceSet *texture = _game->getResourcePack()->getSurfaceSet("BASEBITS.PCK"); texture->getFrame(s->getRankSprite())->setX(0); texture->getFrame(s->getRankSprite())->setY(0); texture->getFrame(s->getRankSprite())->blit(_btnRank); std::string look = s->getArmor()->getSpriteInventory(); if (s->getGender() == GENDER_MALE) look += "M"; else look += "F"; if (s->getLook() == LOOK_BLONDE) look += "0"; if (s->getLook() == LOOK_BROWNHAIR) look += "1"; if (s->getLook() == LOOK_ORIENTAL) look += "2"; if (s->getLook() == LOOK_AFRICAN) look += "3"; look += ".SPK"; if (!CrossPlatform::fileExists(CrossPlatform::getDataFile("UFOGRAPH/" + look)) && !_game->getResourcePack()->getSurface(look)) { look = s->getArmor()->getSpriteInventory() + ".SPK"; } _game->getResourcePack()->getSurface(look)->blit(_soldier); } else { Surface *armorSurface = _game->getResourcePack()->getSurface(unit->getArmor()->getSpriteInventory()); if (armorSurface) { armorSurface->blit(_soldier); } } if (_showMoreStatsInInventoryView && !_tu) { std::wstringstream ss2; ss2 << tr("STR_FACCURACY") << L'\x01' << (int)(unit->getStats()->firing * unit->getAccuracyModifier()); _txtFAcc->setText(ss2.str()); std::wstringstream ss3; ss3 << tr("STR_REACT") << L'\x01' << unit->getStats()->reactions; _txtReact->setText(ss3.str()); if (unit->getStats()->psiSkill > 0) { std::wstringstream ss4; ss4 << tr("STR_PSKILL") << L'\x01' << unit->getStats()->psiSkill; _txtPSkill->setText(ss4.str()); std::wstringstream ss5; ss5 << tr("STR_PSTRENGTH") << L'\x01' << unit->getStats()->psiStrength; _txtPStr->setText(ss5.str()); } else { _txtPSkill->setText(L""); _txtPStr->setText(L""); } } updateStats(); }
/** * Runs state functionality every cycle. * Progresses the fall, updates the battlescape, ... */ void UnitFallBState::think() { for (std::list<BattleUnit*>::iterator unit = _parent->getSave()->getFallingUnits()->begin(); unit != _parent->getSave()->getFallingUnits()->end();) { if ((*unit)->getStatus() == STATUS_TURNING) { (*unit)->abortTurn(); } bool largeCheck = true; bool falling = true; int size = (*unit)->getArmor()->getSize() - 1; if ((*unit)->getHealth() == 0 || (*unit)->getStunlevel() >= (*unit)->getHealth()) { unit = _parent->getSave()->getFallingUnits()->erase(unit); continue; } bool onScreen = ((*unit)->getVisible() && _parent->getMap()->getCamera()->isOnScreen((*unit)->getPosition(), true, size, false)); Tile *tileBelow = _parent->getSave()->getTile((*unit)->getPosition() + Position(0,0,-1)); for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { Tile *otherTileBelow = _parent->getSave()->getTile((*unit)->getPosition() + Position(x,y,-1)); if (!_parent->getSave()->getTile((*unit)->getPosition() + Position(x,y,0))->hasNoFloor(otherTileBelow) || (*unit)->getMovementType() == MT_FLY) { largeCheck = false; } } } if ((*unit)->getStatus() == STATUS_WALKING || (*unit)->getStatus() == STATUS_FLYING) { (*unit)->keepWalking(tileBelow, true); // advances the phase _parent->getMap()->cacheUnit(*unit); // make sure the unit sprites are up to date if ((*unit)->getPosition() != (*unit)->getLastPosition()) { // Reset tiles moved from. for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { // A falling unit might have already taken up this position so check that this unit is still here. if (_parent->getSave()->getTile((*unit)->getLastPosition() + Position(x,y,0))->getUnit() == (*unit)) { _parent->getSave()->getTile((*unit)->getLastPosition() + Position(x,y,0))->setUnit(0); } } } // Update tiles moved to. for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { _parent->getSave()->getTile((*unit)->getPosition() + Position(x,y,0))->setUnit((*unit), _parent->getSave()->getTile((*unit)->getPosition() + Position(x,y,-1))); } } } ++unit; continue; } falling = largeCheck && (*unit)->getPosition().z != 0 && (*unit)->getTile()->hasNoFloor(tileBelow) && (*unit)->getMovementType() != MT_FLY && (*unit)->getWalkingPhase() == 0; if (falling) { // Tile(s) unit is falling into. for (int x = (*unit)->getArmor()->getSize() - 1; x >= 0; --x) { for (int y = (*unit)->getArmor()->getSize() - 1; y >= 0; --y) { Tile *tileTarget = _parent->getSave()->getTile((*unit)->getPosition() + Position(x,y,-1)); tilesToFallInto.push_back(tileTarget); } } // Check each tile for units that need moving out of the way. for (std::vector<Tile*>::iterator i = tilesToFallInto.begin(); i < tilesToFallInto.end(); ++i) { BattleUnit *unitBelow = (*i)->getUnit(); if (unitBelow && (*unit) != unitBelow // falling units do not fall on themselves && !(std::find(unitsToMove.begin(), unitsToMove.end(), unitBelow) != unitsToMove.end())) // already added { unitsToMove.push_back(unitBelow); } } } falling = largeCheck && (*unit)->getPosition().z != 0 && (*unit)->getTile()->hasNoFloor(tileBelow) && (*unit)->getMovementType() != MT_FLY && (*unit)->getWalkingPhase() == 0; // Find somewhere to move the unit(s) endanger of being squashed. if (!unitsToMove.empty()) { std::vector<Tile*> escapeTiles; for (std::vector<BattleUnit*>::iterator ub = unitsToMove.begin(); ub < unitsToMove.end(); ) { BattleUnit *unitBelow = (*ub); bool escapeFound = false; // We need to move all sections of the unit out of the way. std::vector<Position> bodySections; for (int x = unitBelow->getArmor()->getSize() - 1; x >= 0; --x) { for (int y = unitBelow->getArmor()->getSize() - 1; y >= 0; --y) { Position bs = unitBelow->getPosition() + Position(x, y, 0); bodySections.push_back(bs); } } // Check in each compass direction. for (int dir = 0; dir < Pathfinding::DIR_UP && !escapeFound; dir++) { Position offset; Pathfinding::directionToVector(dir, &offset); for (std::vector<Position>::iterator bs = bodySections.begin(); bs < bodySections.end(); ) { Position originalPosition = (*bs); Position endPosition = originalPosition + offset; Tile *t = _parent->getSave()->getTile(endPosition); Tile *bt = _parent->getSave()->getTile(endPosition + Position(0,0,-1)); bool aboutToBeOccupiedFromAbove = t && std::find(tilesToFallInto.begin(), tilesToFallInto.end(), t) != tilesToFallInto.end(); bool alreadyTaken = t && std::find(escapeTiles.begin(), escapeTiles.end(), t) != escapeTiles.end(); bool alreadyOccupied = t && t->getUnit() && (t->getUnit() != unitBelow); bool movementBlocked = _parent->getSave()->getPathfinding()->getTUCost(originalPosition, dir, &endPosition, *ub, 0, false) == 255; bool hasFloor = t && !t->hasNoFloor(bt); bool unitCanFly = unitBelow->getMovementType() == MT_FLY; bool canMoveToTile = t && !alreadyOccupied && !alreadyTaken && !aboutToBeOccupiedFromAbove && !movementBlocked && (hasFloor || unitCanFly); if (canMoveToTile) { // Check next section of the unit. ++bs; } else { // Try next direction. break; } // If all sections of the fallen onto unit can be moved, then we move it. if (bs == bodySections.end()) { if (_parent->getSave()->addFallingUnit(unitBelow)) { escapeFound = true; // Now ensure no other unit escapes to here too. for (int x = unitBelow->getArmor()->getSize() - 1; x >= 0; --x) { for (int y = unitBelow->getArmor()->getSize() - 1; y >= 0; --y) { Tile *et = _parent->getSave()->getTile(t->getPosition() + Position(x,y,0)); escapeTiles.push_back(et); } } Tile *bu = _parent->getSave()->getTile(originalPosition + Position(0,0,-1)); unitBelow->startWalking(dir, unitBelow->getPosition() + offset, bu, onScreen); ub = unitsToMove.erase(ub); } } } } if (!escapeFound) { unitBelow->knockOut(_parent); ub = unitsToMove.erase(ub); } } _parent->checkForCasualties(0,*unit); } // we are just standing around, we are done falling. if ((*unit)->getStatus() == STATUS_STANDING) { if (falling) { Position destination = (*unit)->getPosition() + Position(0,0,-1); Tile *tileDest = _parent->getSave()->getTile(destination); (*unit)->startWalking(Pathfinding::DIR_DOWN, destination, tileDest, onScreen); (*unit)->setCache(0); _parent->getMap()->cacheUnit(*unit); ++unit; } else { // if the unit burns floortiles, burn floortiles if ((*unit)->getSpecialAbility() == SPECAB_BURNFLOOR || (*unit)->getSpecialAbility() == SPECAB_BURN_AND_EXPLODE) { (*unit)->getTile()->ignite(1); Position groundVoxel = ((*unit)->getPosition() * Position(16,16,24)) + Position(8,8,-((*unit)->getTile()->getTerrainLevel())); _parent->getTileEngine()->hit(groundVoxel, (*unit)->getBaseStats()->strength, DT_IN, (*unit)); if ((*unit)->getStatus() != STATUS_STANDING) // ie: we burned a hole in the floor and fell through it { _parent->getPathfinding()->abortPath(); } } // move our personal lighting with us _terrain->calculateUnitLighting(); _parent->getMap()->cacheUnit(*unit); (*unit)->setCache(0); _terrain->calculateFOV(*unit); _parent->checkForProximityGrenades(*unit); if ((*unit)->getStatus() == STATUS_STANDING) { if (_parent->getTileEngine()->checkReactionFire(*unit)) _parent->getPathfinding()->abortPath(); unit = _parent->getSave()->getFallingUnits()->erase(unit); } } } else { ++unit; } } if (_parent->getSave()->getFallingUnits()->empty()) { tilesToFallInto.clear(); unitsToMove.clear(); _parent->popState(); return; } }