diff -ruN ../src_orig/Battlescape/Projectile.cpp ../src_new/Battlescape/Projectile.cpp --- ../src_orig/Battlescape/Projectile.cpp Sun Oct 30 04:09:41 2016 +++ ../src_new/Battlescape/Projectile.cpp Tue Nov 1 03:02:05 2016 @@ -218,52 +219,107 @@ 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())); + Position targetVoxel; + std::vector targets; + double curvature; + targetVoxel = _action.target * Position(16,16,24) + Position(8,8, (1 + -targetTile->getTerrainLevel())); + targets.clear(); + bool forced = false; - if (_action.type != BA_THROW) + if (_action.type == BA_THROW) + { + targets.push_back(targetVoxel); + } + else //arcing shot { 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) + if (Options::forceFire && (SDL_GetModState() & KMOD_CTRL) != 0 && _save->getSide() == FACTION_PLAYER) + { + targets.push_back(_action.target * Position(16,16,24) + Position(0, 0, 12)); + forced = true; + } + else if (tu && ((_action.actor->getFaction() != FACTION_PLAYER) || + tu->getVisible())) + { //unit + targetVoxel.z += tu->getFloatHeight(); //ground level is the base + targets.push_back(targetVoxel + Position(0, 0, tu->getHeight()/2 + 1)); + targets.push_back(targetVoxel + Position(0, 0, 2)); + targets.push_back(targetVoxel + Position(0, 0, tu->getHeight() - 1)); + } + else if (targetTile->getMapData(O_OBJECT) != 0) + { + targetVoxel = _action.target * Position(16,16,24) + Position(8,8,0); + targets.push_back(targetVoxel + Position(0, 0, 13)); + targets.push_back(targetVoxel + Position(0, 0, 8)); + targets.push_back(targetVoxel + Position(0, 0, 23)); + targets.push_back(targetVoxel + Position(0, 0, 2)); + } + else if (targetTile->getMapData(O_NORTHWALL) != 0) + { + targetVoxel = _action.target * Position(16,16,24) + Position(8,0,0); + targets.push_back(targetVoxel + Position(0, 0, 13)); + targets.push_back(targetVoxel + Position(0, 0, 8)); + targets.push_back(targetVoxel + Position(0, 0, 20)); + targets.push_back(targetVoxel + Position(0, 0, 3)); + } + else if (targetTile->getMapData(O_WESTWALL) != 0) { - targetVoxel.z += ((tu->getHeight()/2) + tu->getFloatHeight()) - 2; + targetVoxel = _action.target * Position(16,16,24) + Position(0,8,0); + targets.push_back(targetVoxel + Position(0, 0, 13)); + targets.push_back(targetVoxel + Position(0, 0, 8)); + targets.push_back(targetVoxel + Position(0, 0, 20)); + targets.push_back(targetVoxel + Position(0, 0, 2)); + } + else if (targetTile->getMapData(O_FLOOR) != 0) + { + targets.push_back(targetVoxel); } } - double curvature = 0.0; - int retVal = V_OUTOFBOUNDS; - if (_save->getTileEngine()->validateThrow(_action, originVoxel, targetVoxel, &curvature, &retVal)) + int test = V_OUTOFBOUNDS; + for (std::vector::iterator i = targets.begin(); i != targets.end(); ++i) { - int test = V_OUTOFBOUNDS; - // finally do a line calculation and store this trajectory, make sure it's valid. - while (test == V_OUTOFBOUNDS) + targetVoxel = *i; + if (_save->getTileEngine()->validateThrow(_action, originVoxel, targetVoxel, &curvature, &test, forced)) + { + break; + } + } + if (!forced && test == V_OUTOFBOUNDS) return test; //no line of fire + + 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 + _trajectory.clear(); + if (_action.type == BA_THROW) { - Position deltas = targetVoxel; - // apply some accuracy modifiers applyAccuracy(originVoxel, &deltas, accuracy, true, false); //calling for best flavor deltas -= targetVoxel; - _trajectory.clear(); - test = _save->getTileEngine()->calculateParabola(originVoxel, targetVoxel, true, &_trajectory, _action.actor, curvature, deltas); + } + else + { + applyAccuracy(originVoxel, &targetVoxel, accuracy, true, false); //arcing shot deviation + deltas = Position(0,0,0); + } + 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(O_OBJECT) - && endTile->getMapData(O_OBJECT)->getTUCost(MT_WALK) == 255 - && !(endTile->isBigWall() && (endTile->getMapData(O_OBJECT)->getBigWall()<1 || endTile->getMapData(O_OBJECT)->getBigWall()>3))) - { - test = V_OUTOFBOUNDS; - } + if (forced) return O_OBJECT; //fake hit + Position endPoint = _trajectory.back() / Position (16, 16, 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(O_OBJECT) + && endTile->getMapData(O_OBJECT)->getTUCost(MT_WALK) == 255 + && !(endTile->isBigWall() && (endTile->getMapData(O_OBJECT)->getBigWall()<1 || endTile->getMapData(O_OBJECT)->getBigWall()>3))) + { + test = V_OUTOFBOUNDS; } - return retVal; } - return V_OUTOFBOUNDS; + return test; } /** diff -ruN ../src_orig/Battlescape/TileEngine.cpp ../src_new/Battlescape/TileEngine.cpp --- ../src_orig/Battlescape/TileEngine.cpp Sun Oct 30 16:18:20 2016 +++ ../src_new/Battlescape/TileEngine.cpp Tue Nov 1 02:55:12 2016 @@ -2180,7 +2162,7 @@ if (doVoxelCheck) voxelCheckFlush(); //step through longest delta (which we have swapped to x) - for (x = x0; x != (x1+step_x); x += step_x) + for (x = x0;; x += step_x) { //copy position cx = x; cy = y; cz = z; @@ -2193,6 +2175,7 @@ { trajectory->push_back(Position(cx, cy, cz)); } + //passes through this point? if (doVoxelCheck) { @@ -2228,6 +2211,9 @@ lastPoint = Position(cx, cy, cz); } + + if (x == x1) break; + //update progress in other planes drift_xy = drift_xy - delta_y; drift_xz = drift_xz - delta_z; @@ -2314,39 +2300,37 @@ int y = origin.y; int z = origin.z; int i = 8; + int result = V_EMPTY; + std::vector _trajectory; Position lastPosition = Position(x,y,z); + Position nextPosition = lastPosition; while (z > 0) { x = (int)((double)origin.x + (double)i * cos(te) * sin(fi)); y = (int)((double)origin.y + (double)i * sin(te) * sin(fi)); z = (int)((double)origin.z + (double)i * cos(fi) - zK * ((double)i - ro / 2.0) * ((double)i - ro / 2.0) + zA); - if (storeTrajectory && trajectory) - { - trajectory->push_back(Position(x, y, z)); - } //passes through this point? - Position nextPosition = Position(x,y,z); - int result = calculateLine(lastPosition, nextPosition, false, 0, excludeUnit); + nextPosition = Position(x,y,z); + _trajectory.clear(); + result = calculateLine(lastPosition, nextPosition, false, 0, excludeUnit); if (result != V_EMPTY) { - if (lastPosition.z < nextPosition.z) - { - result = V_OUTOFBOUNDS; - } - if (!storeTrajectory && trajectory != 0) - { // store the position of impact - trajectory->push_back(nextPosition); - } - return result; - } - lastPosition = Position(x,y,z); + result = calculateLine(lastPosition, nextPosition, true, &_trajectory, excludeUnit); + nextPosition = _trajectory.back(); //pick the INSIDE position of impact + break; + } + if (storeTrajectory && trajectory) + { + trajectory->push_back(nextPosition); + } + lastPosition = nextPosition; ++i; } - if (!storeTrajectory && trajectory != 0) + if (trajectory) { // store the position of impact - trajectory->push_back(Position(x, y, z)); + trajectory->push_back(nextPosition); } - return V_EMPTY; + return result; } /** @@ -2787,7 +2771,7 @@ * @param voxelType The type of voxel at which this parabola terminates. * @return Validity of action. */ -bool TileEngine::validateThrow(BattleAction &action, Position originVoxel, Position targetVoxel, double *curve, int *voxelType) +bool TileEngine::validateThrow(BattleAction &action, Position originVoxel, Position targetVoxel, double *curve, int *voxelType, bool forced) { bool foundCurve = false; double curvature = 0.5; @@ -2803,6 +2787,7 @@ } Tile *targetTile = _save->getTile(action.target); + Position targetPos = (targetVoxel / Position(16, 16, 24)); // object blocking - can't throw here if (action.type == BA_THROW && targetTile @@ -2826,7 +2811,8 @@ { std::vector trajectory; test = calculateParabola(originVoxel, targetVoxel, false, &trajectory, action.actor, curvature, Position(0,0,0)); - if (test != V_OUTOFBOUNDS && (trajectory.at(0) / Position(16, 16, 24)) == (targetVoxel / Position(16, 16, 24))) + Position tilePos = ((trajectory.at(0) + Position(0,0,1)) / Position(16, 16, 24)); + if (forced || (test != V_OUTOFBOUNDS && tilePos == targetPos)) { if (voxelType) { diff -ruN ../src_orig/Battlescape/TileEngine.h ../src_new/Battlescape/TileEngine.h --- ../src_orig/Battlescape/TileEngine.h Sun Oct 30 16:17:36 2016 +++ ../src_new/Battlescape/TileEngine.h Tue Nov 1 02:55:12 2016 @@ -122,7 +122,7 @@ /// Blows this tile up. bool detonate(Tile* tile); /// Validates a throwing action. - bool validateThrow(BattleAction &action, Position originVoxel, Position targetVoxel, double *curve = 0, int *voxelType = 0); + bool validateThrow(BattleAction &action, Position originVoxel, Position targetVoxel, double *curve = 0, int *voxelType = 0, bool forced = false); /// Opens any doors this door is connected to. void checkAdjacentDoors(Position pos, int part); /// Creates a vector of units that can spot this unit.