/** * 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 true when a trajectory is possible. */ bool 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->isKneeled()?bu->getUnit()->getKneelHeight():bu->getUnit()->getStandHeight(); originVoxel.z -= 3; if (originVoxel.z >= (_origin.z + 1)*24) { _origin.z++; } direction = bu->getDirection(); originVoxel.x += dirXshift[direction]; originVoxel.y += 15-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(_target); if (tile->getUnit() != 0) { if (_origin == _target) { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 8, _target.z*24); } else { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 8, _target.z*24 + tile->getUnit()->getUnit()->getStandHeight()/2); } } else if (tile->getMapData(O_OBJECT) != 0) { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 8, _target.z*24 + 10); } else if (tile->getMapData(O_NORTHWALL) != 0) { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 16, _target.z*24 + 10); } else if (tile->getMapData(O_WESTWALL) != 0) { targetVoxel = Position(_target.x*16, _target.y*16 + 8, _target.z*24 + 10); } else if (tile->getMapData(O_FLOOR) != 0) { targetVoxel = Position(_target.x*16 + 8, _target.y*16 + 8, _target.z*24); } else { return false; // 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. _save->getTerrainModifier()->calculateLine(originVoxel, targetVoxel, true, &_trajectory, bu); 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; 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); }