/** * Calculates the trajectory for a curved path. * @param accuracy The unit's accuracy. * @param doTestTrajectory * @return True when a trajectory is possible. */ int Projectile::calculateThrow(double accuracy, bool doTestTrajectory) { Tile *targetTile = _save->getTile(_action.target); Position originVoxel = _save->getTileEngine()->getOriginVoxel(_action, 0); Position targetVoxel = _action.target * Position(16,16,24) + Position(8,8, (2 + -targetTile->getTerrainLevel())); if (_action.type != BA_THROW) { BattleUnit *tu = targetTile->getUnit(); if (!tu && _action.target.z > 0 && targetTile->hasNoFloor(0)) tu = _save->getTile(_action.target - Position(0, 0, 1))->getUnit(); if (tu) { targetVoxel.z += ((tu->getHeight()/2) + tu->getFloatHeight()) - 2; } } double curvature = 0.0; int retVal = V_OUTOFBOUNDS; if (_save->getTileEngine()->validateThrow(_action, originVoxel, targetVoxel, &curvature, &retVal)) { if (doTestTrajectory) { return V_FLOOR; // retVal; } int test = V_OUTOFBOUNDS; // finally do a line calculation and store this trajectory, make sure it's valid. while (test == V_OUTOFBOUNDS) { Position deltas = targetVoxel; // apply some accuracy modifiers applyAccuracy(originVoxel, &deltas, accuracy, true, _save->getTile(_action.target), false); //calling for best flavor deltas -= targetVoxel; _trajectory.clear(); test = _save->getTileEngine()->calculateParabola(originVoxel, targetVoxel, true, &_trajectory, _action.actor, curvature, deltas); Position endPoint = _trajectory.back(); endPoint.x /= 16; endPoint.y /= 16; endPoint.z /= 24; Tile *endTile = _save->getTile(endPoint); // check if the item would land on a tile with a blocking object if (_action.type == BA_THROW && endTile && endTile->getMapData(MapData::O_OBJECT) && endTile->getMapData(MapData::O_OBJECT)->getTUCost(MT_WALK) == 255) { test = V_OUTOFBOUNDS; } } return retVal; } return V_OUTOFBOUNDS; }
/** * Runs state functionality every cycle. */ void UnitWalkBState::think() { bool unitSpotted = false; int size = _unit->getArmor()->getSize() - 1; bool onScreen = (_unit->getVisible() && _parent->getMap()->getCamera()->isOnScreen(_unit->getPosition(), true, size, false)); if (_unit->isKneeled()) { if (_parent->kneel(_unit)) { _unit->setCache(0); _terrain->calculateFOV(_unit); _parent->getMap()->cacheUnit(_unit); return; } else { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; _pf->abortPath(); _parent->popState(); return; } } Tile *tileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(0,0,-1)); if (_unit->isOut()) { _pf->abortPath(); _parent->popState(); return; } if (_unit->getStatus() == STATUS_WALKING || _unit->getStatus() == STATUS_FLYING) { if ((_parent->getSave()->getTile(_unit->getDestination())->getUnit() == 0) || // next tile must be not occupied (_parent->getSave()->getTile(_unit->getDestination())->getUnit() == _unit)) { bool onScreenBoundary = (_unit->getVisible() && _parent->getMap()->getCamera()->isOnScreen(_unit->getPosition(), true, size, true)); _unit->keepWalking(tileBelow, onScreenBoundary); // advances the phase playMovementSound(); } else if (!_falling) { _unit->lookAt(_unit->getDestination(), (_unit->getTurretType() != -1)); // turn to undiscovered unit _pf->abortPath(); } // unit moved from one tile to the other, update the tiles if (_unit->getPosition() != _unit->getLastPosition()) { bool largeCheck = true; 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; _parent->getSave()->getTile(_unit->getLastPosition() + Position(x,y,0))->setUnit(0); } } 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))); } } _falling = largeCheck && _unit->getPosition().z != 0 && _unit->getTile()->hasNoFloor(tileBelow) && _unit->getMovementType() != MT_FLY && _unit->getWalkingPhase() == 0; if (_falling) { 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 (otherTileBelow && otherTileBelow->getUnit()) { _falling = false; _pf->dequeuePath(); _parent->getSave()->addFallingUnit(_unit); _parent->statePushFront(new UnitFallBState(_parent)); return; } } } } if (!_parent->getMap()->getCamera()->isOnScreen(_unit->getPosition(), true, size, false) && _unit->getFaction() != FACTION_PLAYER && _unit->getVisible()) _parent->getMap()->getCamera()->centerOnPosition(_unit->getPosition()); // if the unit changed level, camera changes level with _parent->getMap()->getCamera()->setViewLevel(_unit->getPosition().z); } // is the step finished? if (_unit->getStatus() == STATUS_STANDING) { // update the TU display _parent->getSave()->getBattleState()->updateSoldierInfo(); // if the unit burns floortiles, burn floortiles as long as we're not falling if (!_falling && (_unit->getSpecialAbility() == SPECAB_BURNFLOOR || _unit->getSpecialAbility() == SPECAB_BURN_AND_EXPLODE)) { _unit->getTile()->ignite(1); Position posHere = _unit->getPosition(); Position voxelHere = (posHere * Position(16,16,24)) + Position(8,8,-(_unit->getTile()->getTerrainLevel())); _parent->getTileEngine()->hit(voxelHere, _unit->getBaseStats()->strength, DT_IN, _unit); if (_unit->getStatus() != STATUS_STANDING) // ie: we burned a hole in the floor and fell through it { _pf->abortPath(); return; } } // move our personal lighting with us _terrain->calculateUnitLighting(); if (_unit->getFaction() != FACTION_PLAYER) { _unit->setVisible(false); } _terrain->calculateFOV(_unit->getPosition()); unitSpotted = (!_falling && !_action.desperate && _parent->getPanicHandled() && _numUnitsSpotted != _unit->getUnitsSpottedThisTurn().size()); if (_parent->checkForProximityGrenades(_unit)) { _parent->popState(); return; } if (unitSpotted) { _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _pf->abortPath(); _parent->popState(); return; } // check for reaction fire if (!_falling) { if (_terrain->checkReactionFire(_unit)) { // unit got fired upon - stop walking _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _pf->abortPath(); _parent->popState(); return; } } } else if (onScreen) { // make sure the unit sprites are up to date if (_pf->getStrafeMove()) { // This is where we fake out the strafe movement direction so the unit "moonwalks" int dirTemp = _unit->getDirection(); _unit->setDirection(_unit->getFaceDirection()); _parent->getMap()->cacheUnit(_unit); _unit->setDirection(dirTemp); } else { _parent->getMap()->cacheUnit(_unit); } } } // we are just standing around, shouldn't we be walking? if (_unit->getStatus() == STATUS_STANDING || _unit->getStatus() == STATUS_PANICKING) { // check if we did spot new units if (unitSpotted && !_action.desperate && _unit->getCharging() == 0 && !_falling) { if (Options::traceAI) { Log(LOG_INFO) << "Uh-oh! Company!"; } _unit->setHiding(false); // clearly we're not hidden now _parent->getMap()->cacheUnit(_unit); postPathProcedures(); return; } if (onScreen || _parent->getSave()->getDebugMode()) { setNormalWalkSpeed(); } else { _parent->setStateInterval(0); } int dir = _pf->getStartDirection(); if (_falling) { dir = Pathfinding::DIR_DOWN; } if (dir != -1) { if (_pf->getStrafeMove()) { _unit->setFaceDirection(_unit->getDirection()); } Position destination; int tu = _pf->getTUCost(_unit->getPosition(), dir, &destination, _unit, 0, false); // gets tu cost, but also gets the destination position. if (_unit->getFaction() != FACTION_PLAYER && _unit->getSpecialAbility() < SPECAB_BURNFLOOR && _parent->getSave()->getTile(destination) && _parent->getSave()->getTile(destination)->getFire() > 0) { tu -= 32; // we artificially inflate the TU cost by 32 points in getTUCost under these conditions, so we have to deflate it here. } if (_falling) { tu = 0; } int energy = tu; if (dir >= Pathfinding::DIR_UP) { energy = 0; } else if (_action.run) { tu *= 0.75; energy *= 1.5; } if (tu > _unit->getTimeUnits()) { if (_parent->getPanicHandled() && tu < 255) { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; } _pf->abortPath(); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _parent->popState(); return; } if (energy / 2 > _unit->getEnergy()) { if (_parent->getPanicHandled()) { _action.result = "STR_NOT_ENOUGH_ENERGY"; } _pf->abortPath(); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _parent->popState(); return; } if (_parent->getPanicHandled() && _parent->checkReservedTU(_unit, tu) == false) { _pf->abortPath(); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); return; } // we are looking in the wrong way, turn first (unless strafing) // we are not using the turn state, because turning during walking costs no tu if (dir != _unit->getDirection() && dir < Pathfinding::DIR_UP && !_pf->getStrafeMove()) { _unit->lookAt(dir); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); return; } // now open doors (if any) if (dir < Pathfinding::DIR_UP) { int door = _terrain->unitOpensDoor(_unit, false, dir); if (door == 3) { return; // don't start walking yet, wait for the ufo door to open } if (door == 0) { _parent->getMod()->getSoundByDepth(_parent->getDepth(), Mod::DOOR_OPEN)->play(-1, _parent->getMap()->getSoundAngle(_unit->getPosition())); // normal door } if (door == 1) { _parent->getMod()->getSoundByDepth(_parent->getDepth(), Mod::SLIDING_DOOR_OPEN)->play(-1, _parent->getMap()->getSoundAngle(_unit->getPosition())); // ufo door return; // don't start walking yet, wait for the ufo door to open } } for (int x = size; x >= 0; --x) { for (int y = size; y >= 0; --y) { BattleUnit* unitInMyWay = _parent->getSave()->getTile(destination + Position(x,y,0))->getUnit(); BattleUnit* unitBelowMyWay = 0; Tile* belowDest = _parent->getSave()->getTile(destination + Position(x,y,-1)); if (belowDest) { unitBelowMyWay = belowDest->getUnit(); } // can't walk into units in this tile, or on top of other units sticking their head into this tile if (!_falling && ((unitInMyWay && unitInMyWay != _unit) || (belowDest && unitBelowMyWay && unitBelowMyWay != _unit && (-belowDest->getTerrainLevel() + unitBelowMyWay->getFloatHeight() + unitBelowMyWay->getHeight()) >= 28))) // 4+ voxels poking into the tile above, we don't kick people in the head here at XCom. { _action.TU = 0; _pf->abortPath(); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _parent->popState(); return; } } } // now start moving dir = _pf->dequeuePath(); if (_falling) { dir = Pathfinding::DIR_DOWN; } if (_unit->spendTimeUnits(tu)) { if (_unit->spendEnergy(energy)) { Tile *tileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(0,0,-1)); _unit->startWalking(dir, destination, tileBelow, onScreen); _beforeFirstStep = false; } } // make sure the unit sprites are up to date if (onScreen) { if (_pf->getStrafeMove()) { // This is where we fake out the strafe movement direction so the unit "moonwalks" int dirTemp = _unit->getDirection(); _unit->setDirection(_unit->getFaceDirection()); _parent->getMap()->cacheUnit(_unit); _unit->setDirection(dirTemp); } else { _parent->getMap()->cacheUnit(_unit); } } } else { postPathProcedures(); return; } } // turning during walking costs no tu if (_unit->getStatus() == STATUS_TURNING) { // except before the first step. if (_beforeFirstStep) { _preMovementCost++; } _unit->turn(); // calculateFOV is unreliable for setting the unitSpotted bool, as it can be called from various other places // in the code, ie: doors opening, and this messes up the result. _terrain->calculateFOV(_unit); unitSpotted = (!_falling && !_action.desperate && _parent->getPanicHandled() && _numUnitsSpotted != _unit->getUnitsSpottedThisTurn().size()); // make sure the unit sprites are up to date _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); if (unitSpotted && !_action.desperate && !_unit->getCharging() && !_falling) { if (_beforeFirstStep) { _unit->spendTimeUnits(_preMovementCost); } if (Options::traceAI) { Log(LOG_INFO) << "Egads! A turn reveals new units! I must pause!"; } _unit->setHiding(false); // not hidden, are we... _pf->abortPath(); _unit->abortTurn(); //revert to a standing state. _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _parent->popState(); } } }
/** * calculateTrajectory. * @return true when a trajectory is possible. */ bool Projectile::calculateThrow(double accuracy) { Position originVoxel, targetVoxel; bool foundCurve = false; // object blocking - can't throw here if (_action.type == BA_THROW &&_save->getTile(_action.target) && _save->getTile(_action.target)->getMapData(MapData::O_OBJECT) && _save->getTile(_action.target)->getMapData(MapData::O_OBJECT)->getTUCost(MT_WALK) == 255) { return false; } originVoxel = Position(_origin.x*16 + 8, _origin.y*16 + 8, _origin.z*24); originVoxel.z += -_save->getTile(_origin)->getTerrainLevel(); BattleUnit *bu = _save->getTile(_origin)->getUnit(); if(!bu) bu = _save->getTile(Position(_origin.x, _origin.y, _origin.z-1))->getUnit(); originVoxel.z += bu->getHeight() + bu->getFloatHeight(); originVoxel.z -= 3; if (originVoxel.z >= (_origin.z + 1)*24) { _origin.z++; } // determine the target voxel. // aim at the center of the floor targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24 + 2); // we try 4 different curvatures to try and reach our goal. double curvature = 1.0; while (!foundCurve && curvature < 5.0) { _save->getTileEngine()->calculateParabola(originVoxel, targetVoxel, false, &_trajectory, bu, curvature, 1.0); if ((int)_trajectory.at(0).x/16 == (int)targetVoxel.x/16 && (int)_trajectory.at(0).y/16 == (int)targetVoxel.y/16 && (int)_trajectory.at(0).z/24 == (int)targetVoxel.z/24) { foundCurve = true; } else { curvature += 1.0; } _trajectory.clear(); } if ( AreSame(curvature, 5.0) ) { return false; } // apply some accuracy modifiers if (accuracy > 1) accuracy = 1; static const double maxDeviation = 0.08; static const double minDeviation = 0; double baseDeviation = (maxDeviation - (maxDeviation * accuracy)) + minDeviation; double deviation = RNG::boxMuller(0, baseDeviation); _trajectory.clear(); // finally do a line calculation and store this trajectory. _save->getTileEngine()->calculateParabola(originVoxel, targetVoxel, true, &_trajectory, bu, curvature, 1.0 + deviation); Position endPoint = _trajectory.at(_trajectory.size() - 1); endPoint.x /= 16; endPoint.y /= 16; endPoint.z /= 24; // check if the item would land on a tile with a blocking object, if so then we let it fly without deviation, it must land on a valid tile in that case if (_save->getTile(endPoint) && _save->getTile(endPoint)->getMapData(MapData::O_OBJECT) && _save->getTile(endPoint)->getMapData(MapData::O_OBJECT)->getTUCost(MT_WALK) == 255) { _trajectory.clear(); // finally do a line calculation and store this trajectory. _save->getTileEngine()->calculateParabola(originVoxel, targetVoxel, true, &_trajectory, bu, curvature, 1.0); } return true; }
/** * calculateTrajectory. * @return the objectnumber(0-3) or unit(4) or out of map (5) or -1(no line of fire) */ int Projectile::calculateTrajectory(double accuracy) { Position originVoxel, targetVoxel; Tile *targetTile = 0; int direction; int dirYshift[24] = {1, 3, 9, 15, 15, 13, 7, 1, 1, 1, 7, 13, 15, 15, 9, 3, 1, 2, 8, 14, 15, 14, 8, 2}; int dirXshift[24] = {9, 15, 15, 13, 8, 1, 1, 3, 7, 13, 15, 15, 9, 3, 1, 1, 8, 14, 15, 14, 8, 2, 1, 2}; int offset = 0; originVoxel = Position(_origin.x*16, _origin.y*16, _origin.z*24); BattleUnit *bu = _action.actor; if (bu->getArmor()->getSize() > 1) { offset = 16; } else if(_action.weapon == _action.weapon->getOwner()->getItem("STR_LEFT_HAND") && !_action.weapon->getRules()->isTwoHanded()) { offset = 8; } // take into account soldier height and terrain level if the projectile is launched from a soldier if (_action.actor->getPosition() == _origin) { // calculate offset of the starting point of the projectile originVoxel.z += -_save->getTile(_origin)->getTerrainLevel(); originVoxel.z += bu->getHeight() + bu->getFloatHeight(); originVoxel.z -= 4; if (originVoxel.z >= (_origin.z + 1)*24) { _origin.z++; } direction = bu->getDirection(); if (bu->getTurretType() != -1) direction = bu->getTurretDirection(); originVoxel.x += dirXshift[direction+offset]*bu->getArmor()->getSize(); originVoxel.y += dirYshift[direction+offset]*bu->getArmor()->getSize(); } else { // don't take into account soldier height and terrain level if the projectile is not launched from a soldier(from a waypoint) originVoxel.x += 8; originVoxel.y += 8; originVoxel.z += 12; } if (_action.type == BA_LAUNCH || (SDL_GetModState() & KMOD_CTRL) != 0) { // target nothing, targets the middle of the tile targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24 + 12); } else { // determine the target voxel. // aim at the center of the unit, the object, the walls or the floor (in that priority) // if there is no LOF to the center, try elsewhere (more outward). // Store this target voxel. targetTile = _save->getTile(_action.target); Position hitPos; int test = -1; if (targetTile->getUnit() != 0) { if (_origin == _action.target || targetTile->getUnit() == _action.actor) { // don't shoot at yourself but shoot at the floor targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24); } else { _save->getTileEngine()->canTargetUnit(&originVoxel, targetTile, &targetVoxel, bu); } } else if (targetTile->getMapData(MapData::O_OBJECT) != 0) { if (!_save->getTileEngine()->canTargetTile(&originVoxel, targetTile, MapData::O_OBJECT, &targetVoxel, bu)) { targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24 + 10); } } else if (targetTile->getMapData(MapData::O_NORTHWALL) != 0) { if (!_save->getTileEngine()->canTargetTile(&originVoxel, targetTile, MapData::O_NORTHWALL, &targetVoxel, bu)) { targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16, _action.target.z*24 + 9); } } else if (targetTile->getMapData(MapData::O_WESTWALL) != 0) { if (!_save->getTileEngine()->canTargetTile(&originVoxel, targetTile, MapData::O_WESTWALL, &targetVoxel, bu)) { targetVoxel = Position(_action.target.x*16, _action.target.y*16 + 8, _action.target.z*24 + 9); } } else if (targetTile->getMapData(MapData::O_FLOOR) != 0) { if (!_save->getTileEngine()->canTargetTile(&originVoxel, targetTile, MapData::O_FLOOR, &targetVoxel, bu)) { targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24); } } else { // target nothing, targets the middle of the tile targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24 + 10); } test = _save->getTileEngine()->calculateLine(originVoxel, targetVoxel, false, &_trajectory, bu); if (test == 4 && !_trajectory.empty()) { hitPos = Position(_trajectory.at(0).x/16, _trajectory.at(0).y/16, _trajectory.at(0).z/24); if (_save->getTile(hitPos) && _save->getTile(hitPos)->getUnit() == 0) //no unit? must be lower { hitPos = Position(hitPos.x, hitPos.y, hitPos.z-1); } } if (test != -1 && !_trajectory.empty() && _action.actor->getFaction() == FACTION_PLAYER && _action.autoShotCounter == 1) { //skip already estimated hitPos if (test != 4) { hitPos = Position(_trajectory.at(0).x/16, _trajectory.at(0).y/16, _trajectory.at(0).z/24); } if (hitPos != _action.target && _action.result == "") { if (test == 2) { if (hitPos.y - 1 == _action.target.y) { _trajectory.clear(); return _save->getTileEngine()->calculateLine(originVoxel, targetVoxel, true, &_trajectory, bu); } } if (test == 1) { if (hitPos.x - 1 == _action.target.x) { _trajectory.clear(); return _save->getTileEngine()->calculateLine(originVoxel, targetVoxel, true, &_trajectory, bu); } } _trajectory.clear(); return -1; } } _trajectory.clear(); } // apply some accuracy modifiers (todo: calculate this) // This will results in a new target voxel if (_action.type != BA_LAUNCH) applyAccuracy(originVoxel, &targetVoxel, accuracy, false, targetTile); // finally do a line calculation and store this trajectory. return _save->getTileEngine()->calculateLine(originVoxel, targetVoxel, true, &_trajectory, bu); }
/** * calculateTrajectory. * @return the objectnumber(0-3) or unit(4) or out of map (5) or -1(no line of fire) */ int Projectile::calculateTrajectory(double accuracy) { Position originVoxel, targetVoxel; int direction; int dirYshift[8] = {1, 1, 8, 15, 15, 15, 8, 1 }; int dirXshift[8] = {8, 14, 15, 15, 8, 1, 1, 1 }; // large units : x2 originVoxel = Position(_origin.x*16, _origin.y*16, _origin.z*24); originVoxel.z += -_save->getTile(_origin)->getTerrainLevel(); BattleUnit *bu = _save->getTile(_origin)->getUnit(); originVoxel.z += bu->getHeight(); originVoxel.z -= 3; if (originVoxel.z >= (_origin.z + 1)*24) { _origin.z++; } direction = bu->getDirection(); originVoxel.x += dirXshift[direction]; originVoxel.y += dirYshift[direction]; // determine the target voxel. // aim at the center of the unit, the object, the walls or the floor (in that priority) // if there is no LOF to the center, try elsewhere (more outward). // Store this target voxel. Tile *tile = _save->getTile(_action.target); if (tile->getUnit() != 0) { if (_origin == _action.target) { // don't shoot at yourself but shoot at the floor targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24); } else { // first try is at half the unit height targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24 + tile->getUnit()->getUnit()->getStandHeight()/2); int test = _save->getTileEngine()->calculateLine(originVoxel, targetVoxel, false, &_trajectory, bu); _trajectory.clear(); if (test != 4) { // did not hit a unit, try at different heights (for ex: unit behind a window can only be hit in the head) targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24 + (tile->getUnit()->getUnit()->getStandHeight()*3)/4); test = _save->getTileEngine()->calculateLine(originVoxel, targetVoxel, false, &_trajectory, bu); _trajectory.clear(); } } } else if (tile->getMapData(MapData::O_OBJECT) != 0) { targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24 + 10); } else if (tile->getMapData(MapData::O_NORTHWALL) != 0) { targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16, _action.target.z*24 + 10); } else if (tile->getMapData(MapData::O_WESTWALL) != 0) { targetVoxel = Position(_action.target.x*16, _action.target.y*16 + 8, _action.target.z*24 + 10); } else if (tile->getMapData(MapData::O_FLOOR) != 0) { targetVoxel = Position(_action.target.x*16 + 8, _action.target.y*16 + 8, _action.target.z*24); } else { return -1; // no line of fire } // apply some accuracy modifiers (todo: calculate this) // This will results in a new target voxel applyAccuracy(originVoxel, &targetVoxel, accuracy); // finally do a line calculation and store this trajectory. return _save->getTileEngine()->calculateLine(originVoxel, targetVoxel, true, &_trajectory, bu); }