//******************************************************************************* Position HapticObject::getPosition() { hduVector3Dd origin; hduVector3Dd pos(origin * m_transformMatrix); return Position(pos[0], pos[1], pos[2]); }
void CCamera::CheckForMovement() { // Once we have the frame interval, we find the current speed float speed = (float)(kSpeed * g_FrameInterval); // Before we move our camera we want to store the old position. We then use // this data to test collision detection. CVector3 vOldPosition = Position(); /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Store the old view vector to restore it if we collided backwards CVector3 vOldView = View(); // Use a flag to see if we movement backwards or not bool bMovedBack = false; /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Check if we hit the Up arrow or the 'w' key if(GetKeyState(VK_UP) & 0x80 || GetKeyState('W') & 0x80) { // Move our camera forward by a positive SPEED MoveCamera(speed); } // Check if we hit the Down arrow or the 's' key if(GetKeyState(VK_DOWN) & 0x80 || GetKeyState('S') & 0x80) { // Move our camera backward by a negative SPEED MoveCamera(-speed); bMovedBack = true; } // Check if we hit the Left arrow or the 'a' key if(GetKeyState(VK_LEFT) & 0x80 || GetKeyState('A') & 0x80) { // Strafe the camera left StrafeCamera(-speed); } // Check if we hit the Right arrow or the 'd' key if(GetKeyState(VK_RIGHT) & 0x80 || GetKeyState('D') & 0x80) { // Strafe the camera right StrafeCamera(speed); } // Now that we moved, let's get the current position and test our movement // vector against the level data to see if there is a collision. CVector3 vCurrentPosition = Position(); // We will not use sphere collision from now on, but AABB collision (box) // CVector3 vNewPosition = g_Level.TraceSphere(vOldPosition, vCurrentPosition, 25.0f); /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // We are now using AABB collision now, so we no longer use sphere checks. // Below we pass into the TraceBox() function some generic Min and Max values // for our bounding box. We then get the new position if we collided CVector3 vNewPosition = g_Level.TraceBox(vOldPosition, vCurrentPosition, CVector3(-20, -50, -20), CVector3(20, 50, 20)); // We add some code below to make it so when we back into a wall, our view vector // doesn't keep going backwards, since we aren't moving backwards. If we don't // do this check, it will turn our camera around and look like a glitch. Not desired! // Check if we collided and we moved backwards if(g_Level.Collided() && bMovedBack) { // If or x or y didn't move, then we are backed into a wall so restore the view vector if(vNewPosition.x == vOldPosition.x || vNewPosition.z == vOldPosition.z) m_vView = vOldView; } /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Set the new position that was returned from our trace function m_vPosition = vNewPosition; }
bool Spawns::parseSpawnNode(xmlNodePtr p, bool checkDuplicate) { if(xmlStrcmp(p->name, (const xmlChar*)"spawn")) return false; int32_t intValue; std::string strValue; Position centerPos; if(!readXMLString(p, "centerpos", strValue)) { if(!readXMLInteger(p, "centerx", intValue)) return false; centerPos.x = intValue; if(!readXMLInteger(p, "centery", intValue)) return false; centerPos.y = intValue; if(!readXMLInteger(p, "centerz", intValue)) return false; centerPos.z = intValue; } else { IntegerVec posVec = vectorAtoi(explodeString(strValue, ",")); if(posVec.size() < 3) return false; centerPos = Position(posVec[0], posVec[1], posVec[2]); } if(!readXMLInteger(p, "radius", intValue)) return false; int32_t radius = intValue; Spawn* spawn = new Spawn(centerPos, radius); if(checkDuplicate) { for(SpawnList::iterator it = spawnList.begin(); it != spawnList.end(); ++it) { if((*it)->getPosition() == centerPos) delete *it; } } spawnList.push_back(spawn); for(xmlNodePtr tmpNode = p->children; tmpNode; tmpNode = tmpNode->next) { if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"monster")) { if(!readXMLString(tmpNode, "name", strValue)) continue; std::string name = strValue; int32_t interval = MINSPAWN_INTERVAL / 1000; if(readXMLInteger(tmpNode, "spawntime", intValue) || readXMLInteger(tmpNode, "interval", intValue)) { if(intValue <= interval) { std::clog << "[Warning - Spawns::loadFromXml] " << name << " " << centerPos << " spawntime cannot" << " be less than " << interval << " seconds." << std::endl; continue; } interval = intValue; } interval *= 1000; Position placePos = centerPos; if(readXMLInteger(tmpNode, "x", intValue)) placePos.x += intValue; if(readXMLInteger(tmpNode, "y", intValue)) placePos.y += intValue; if(readXMLInteger(tmpNode, "z", intValue)) placePos.z /*+*/= intValue; Direction direction = NORTH; if(readXMLInteger(tmpNode, "direction", intValue) && direction >= EAST && direction <= WEST) direction = (Direction)intValue; spawn->addMonster(name, placePos, direction, interval); } else if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"npc")) { if(!readXMLString(tmpNode, "name", strValue)) continue; std::string name = strValue; Position placePos = centerPos; if(readXMLInteger(tmpNode, "x", intValue)) placePos.x += intValue; if(readXMLInteger(tmpNode, "y", intValue)) placePos.y += intValue; if(readXMLInteger(tmpNode, "z", intValue)) placePos.z /*+*/= intValue; Direction direction = NORTH; if(readXMLInteger(tmpNode, "direction", intValue) && direction >= EAST && direction <= WEST) direction = (Direction)intValue; Npc* npc = Npc::createNpc(name); if(!npc) continue; npc->setMasterPosition(placePos, radius); npc->setDirection(direction); npcList.push_back(npc); } } return true; }
/* Test the method 'move2side'*/ TEST_F(PositionVectorTest, test_method_move2side) { PositionVector vec1; vec1.push_back(Position(0,1,0)); vec1.push_back(Position(0,0,0)); vec1.push_back(Position(1,0,0)); vec1.move2side(.5); EXPECT_EQ(Position(-.5,1), vec1[0]); EXPECT_EQ(Position(-.5,-.5), vec1[1]); EXPECT_EQ(Position(1,-.5), vec1[2]); vec1.move2side(-1); EXPECT_EQ(Position(.5,1), vec1[0]); EXPECT_EQ(Position(.5,.5), vec1[1]); EXPECT_EQ(Position(1,.5), vec1[2]); // parallel case PositionVector vec2; vec2.push_back(Position(0,0,0)); vec2.push_back(Position(1,0,0)); vec2.push_back(Position(3,0,0)); vec2.move2side(.5); EXPECT_EQ(Position(0,-.5), vec2[0]); EXPECT_EQ(Position(1,-.5), vec2[1]); EXPECT_EQ(Position(3,-.5), vec2[2]); vec2.move2side(-1); EXPECT_EQ(Position(0,.5), vec2[0]); EXPECT_EQ(Position(1,.5), vec2[1]); EXPECT_EQ(Position(3,.5), vec2[2]); // counterparallel case { PositionVector vec3; vec3.push_back(Position(0,0,0)); vec3.push_back(Position(3,0,0)); vec3.push_back(Position(1,0,0)); vec3.move2side(.5); EXPECT_EQ(Position(0,-.5), vec3[0]); EXPECT_EQ(Position(3.5,0), vec3[1]); EXPECT_EQ(Position(1,.5), vec3[2]); } /*{ PositionVector vec3; vec3.push_back(Position(0,0,0)); vec3.push_back(Position(3,0,0)); vec3.push_back(Position(1,0,0)); vec3.move2side(-.5); EXPECT_EQ(Position(0,-.5), vec3[0]); EXPECT_EQ(Position(3.5,0), vec3[1]); EXPECT_EQ(Position(1,.5), vec3[2]); }*/ }
/* Test the method 'distance'*/ TEST_F(PositionVectorTest, test_method_distance) { { PositionVector vec1; vec1.push_back(Position(1,0)); vec1.push_back(Position(10,0)); vec1.push_back(Position(10,5)); vec1.push_back(Position(20,5)); Position on(4,0); Position left(4,1); Position right(4,-1); Position left2(4,2); Position right2(4,-2); Position cornerRight(13,-4); Position cornerLeft(7,9); Position before(-3,-3); Position beyond(24,8); EXPECT_EQ(0, vec1.distance(on)); EXPECT_EQ(1, vec1.distance(left)); EXPECT_EQ(1, vec1.distance(right)); EXPECT_EQ(2, vec1.distance(left2)); EXPECT_EQ(2, vec1.distance(right2)); EXPECT_EQ(5, vec1.distance(cornerRight)); EXPECT_EQ(5, vec1.distance(cornerLeft)); EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance(before, true)); EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance(beyond, true)); EXPECT_EQ(5, vec1.distance(before)); EXPECT_EQ(5, vec1.distance(beyond)); } { PositionVector vec1; // the same tests as before, mirrored on x-axis vec1.push_back(Position(1,0)); vec1.push_back(Position(10,0)); vec1.push_back(Position(10,-5)); vec1.push_back(Position(20,-5)); Position on(4,0); Position left(4,-1); Position right(4,1); Position left2(4,-2); Position right2(4,2); Position cornerRight(13,4); Position cornerLeft(7,-9); Position before(-3,3); Position beyond(24,-8); EXPECT_EQ(0, vec1.distance(on)); EXPECT_EQ(1, vec1.distance(left)); EXPECT_EQ(1, vec1.distance(right)); EXPECT_EQ(2, vec1.distance(left2)); EXPECT_EQ(2, vec1.distance(right2)); EXPECT_EQ(5, vec1.distance(cornerRight)); EXPECT_EQ(5, vec1.distance(cornerLeft)); EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance(before, true)); EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance(beyond, true)); EXPECT_EQ(5, vec1.distance(before)); EXPECT_EQ(5, vec1.distance(beyond)); } }
NS_IMETHODIMP HTMLProgressElement::GetPosition(double* aPosition) { *aPosition = Position(); return NS_OK; }
bool Spawns::loadFromXml(const std::string& _filename) { if (loaded) { return true; } pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(_filename.c_str()); if (!result) { printXMLError("Error - Spawns::loadFromXml", _filename, result); return false; } filename = _filename; loaded = true; for (auto spawnNode : doc.child("spawns").children()) { Position centerPos( pugi::cast<uint16_t>(spawnNode.attribute("centerx").value()), pugi::cast<uint16_t>(spawnNode.attribute("centery").value()), pugi::cast<uint16_t>(spawnNode.attribute("centerz").value()) ); int32_t radius; pugi::xml_attribute radiusAttribute = spawnNode.attribute("radius"); if (radiusAttribute) { radius = pugi::cast<int32_t>(radiusAttribute.value()); } else { radius = -1; } spawnList.emplace_front(centerPos, radius); Spawn& spawn = spawnList.front(); for (auto childNode : spawnNode.children()) { if (strcasecmp(childNode.name(), "monster") == 0) { pugi::xml_attribute nameAttribute = childNode.attribute("name"); if (!nameAttribute) { continue; } Direction dir; pugi::xml_attribute directionAttribute = childNode.attribute("direction"); if (directionAttribute) { dir = static_cast<Direction>(pugi::cast<uint16_t>(directionAttribute.value())); } else { dir = DIRECTION_NORTH; } Position pos( centerPos.x + pugi::cast<uint16_t>(childNode.attribute("x").value()), centerPos.y + pugi::cast<uint16_t>(childNode.attribute("y").value()), centerPos.z ); uint32_t interval = pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * 1000; if (interval > MINSPAWN_INTERVAL) { spawn.addMonster(nameAttribute.as_string(), pos, dir, interval); } else { std::cout << "[Warning - Spawns::loadFromXml] " << nameAttribute.as_string() << ' ' << pos << " spawntime can not be less than " << MINSPAWN_INTERVAL / 1000 << " seconds." << std::endl; } } else if (strcasecmp(childNode.name(), "npc") == 0) { pugi::xml_attribute nameAttribute = childNode.attribute("name"); if (!nameAttribute) { continue; } Npc* npc = Npc::createNpc(nameAttribute.as_string()); if (!npc) { continue; } pugi::xml_attribute directionAttribute = childNode.attribute("direction"); if (directionAttribute) { npc->setDirection(static_cast<Direction>(pugi::cast<uint16_t>(directionAttribute.value()))); } npc->setMasterPos(Position( centerPos.x + pugi::cast<uint16_t>(childNode.attribute("x").value()), centerPos.y + pugi::cast<uint16_t>(childNode.attribute("y").value()), centerPos.z ), radius); npcList.push_front(npc); } } } return true; }
bool Monster::getDanceStep(const Position& creaturePos, Direction& dir, bool keepAttack /*= true*/, bool keepDistance /*= true*/) { assert(attackedCreature); bool canDoAttackNow = canUseAttack(creaturePos, attackedCreature); const Position& centerPos = attackedCreature->getPosition(); uint32_t tmpDist, centerToDist = std::max(std::abs(creaturePos.x - centerPos.x), std::abs(creaturePos.y - centerPos.y)); DirVector dirVector; if(!keepDistance || creaturePos.y - centerPos.y >= 0) { tmpDist = std::max(std::abs((creaturePos.x) - centerPos.x), std::abs((creaturePos.y - 1) - centerPos.y)); if(tmpDist == centerToDist && canWalkTo(creaturePos, NORTH)) { bool result = true; if(keepAttack) result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y - 1, creaturePos.z), attackedCreature)); if(result) dirVector.push_back(NORTH); } } if(!keepDistance || creaturePos.y - centerPos.y <= 0) { tmpDist = std::max(std::abs((creaturePos.x) - centerPos.x), std::abs((creaturePos.y + 1) - centerPos.y)); if(tmpDist == centerToDist && canWalkTo(creaturePos, SOUTH)) { bool result = true; if(keepAttack) result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y + 1, creaturePos.z), attackedCreature)); if(result) dirVector.push_back(SOUTH); } } if(!keepDistance || creaturePos.x - centerPos.x >= 0) { tmpDist = std::max(std::abs((creaturePos.x + 1) - centerPos.x), std::abs((creaturePos.y) - centerPos.y)); if(tmpDist == centerToDist && canWalkTo(creaturePos, EAST)) { bool result = true; if(keepAttack) result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x + 1, creaturePos.y, creaturePos.z), attackedCreature)); if(result) dirVector.push_back(EAST); } } if(!keepDistance || creaturePos.x - centerPos.x <= 0) { tmpDist = std::max(std::abs((creaturePos.x - 1) - centerPos.x), std::abs((creaturePos.y) - centerPos.y)); if(tmpDist == centerToDist && canWalkTo(creaturePos, WEST)) { bool result = true; if(keepAttack) result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x - 1, creaturePos.y, creaturePos.z), attackedCreature)); if(result) dirVector.push_back(WEST); } } if(dirVector.empty()) return false; std::random_shuffle(dirVector.begin(), dirVector.end()); dir = dirVector[random_range(0, dirVector.size() - 1)]; return true; }
void Render(double time) { gl.Clear().ColorBuffer().DepthBuffer(); // auto camera = CamMatrixf::Orbiting( Vec3f(0.0, 1.5, 0.0), 7.0 + SineWave(time / 11.0)*1.5, FullCircles(time / 19.0), Degrees(SineWave(time / 20.0) * 30 + 35) ); cube_prog.camera_matrix = camera; cube_prog.camera_position = camera.Position(); // shiny gray/blue checkered cube cube_prog.frag_subroutines.Apply(cube_prog.frag_shiny_checker); cube_prog.specular_factor = 32; cube_prog.color_1 = Vec3f(0.9, 0.8, 0.7); cube_prog.color_2 = Vec3f(0.3, 0.4, 0.5); cube_prog.tex_scale = Vec2f(4, 4); cube_prog.model_matrix = ModelMatrixf::RotationY(FullCircles(time / 7.0))* ModelMatrixf::Translation( 2.0, 0.0, 0.0)* ModelMatrixf::RotationX(Degrees(25 * time)); cube.Draw(); // shiny textured cube cube_prog.frag_subroutines.Apply(cube_prog.frag_shiny_texture); cube_prog.specular_factor = 16; cube_prog.tex_scale = Vec2f(1, 1); cube_prog.model_matrix = ModelMatrixf::RotationY(FullCircles(time / 7.0))* ModelMatrixf::Translation(-2.0, 0.0, 0.0)* ModelMatrixf::RotationX(Degrees(-17 * time)); cube.Draw(); // shiny yellow/black striped cube cube_prog.frag_subroutines.Apply(cube_prog.frag_shiny_strips); cube_prog.specular_factor = 32; cube_prog.color_1 = Vec3f(0.9, 0.9, 0.1); cube_prog.color_2 = Vec3f(0.1, 0.1, 0.1); cube_prog.tex_scale = Vec2f(16, 16); cube_prog.model_matrix = ModelMatrixf::RotationY(FullCircles(time / 7.0))* ModelMatrixf::Translation( 0.0, 2.0, 0.0)* ModelMatrixf::RotationY(Degrees(37 * time)); cube.Draw(); // shiny gray/green spiral cube cube_prog.frag_subroutines.Apply(cube_prog.frag_shiny_spiral); cube_prog.specular_factor = 24; cube_prog.color_1 = Vec3f(0.9, 0.9, 0.9); cube_prog.color_2 = Vec3f(0.4, 0.9, 0.4); cube_prog.tex_scale = Vec2f(1, 1); cube_prog.model_matrix = ModelMatrixf::RotationY(FullCircles(time / 7.0))* ModelMatrixf::Translation( 0.0,-2.0, 0.0)* ModelMatrixf::RotationY(Degrees(-13 * time)); cube.Draw(); // dull white/red striped cube cube_prog.frag_subroutines .Assign( cube_prog.pixel_light_func, cube_prog.dull ).Assign( cube_prog.pixel_color_func, cube_prog.strips ).Apply(); cube_prog.specular_factor = 32; cube_prog.color_2 = Vec3f(1.0, 1.0, 1.0); cube_prog.color_1 = Vec3f(0.9, 0.2, 0.2); cube_prog.tex_scale = Vec2f(8, 6); cube_prog.model_matrix = ModelMatrixf::RotationY(FullCircles(time / 7.0))* ModelMatrixf::Translation( 0.0, 0.0, 2.0)* ModelMatrixf::RotationZ(Degrees(27 * time)); cube.Draw(); // dull textured cube cube_prog.frag_subroutines .Assign( cube_prog.pixel_color_func, cube_prog.texture_bgr ).Apply(); cube_prog.tex_scale = Vec2f(1, 1); cube_prog.model_matrix = ModelMatrixf::RotationY(FullCircles(time / 7.0))* ModelMatrixf::Translation( 0.0, 0.0,-2.0)* ModelMatrixf::RotationZ(Degrees(-23 * time)); cube.Draw(); }
/** * Calculates the effects of the explosion. */ void ExplosionBState::explode() { bool terrainExplosion = false; SavedBattleGame *save = _parent->getSave(); // after the animation is done, the real explosion/hit takes place if (_item) { if (!_unit && _item->getPreviousOwner()) { _unit = _item->getPreviousOwner(); } BattleUnit *victim = 0; if (_areaOfEffect) { save->getTileEngine()->explode(_center, _power, _item->getRules()->getDamageType(), _item->getRules()->getExplosionRadius(), _unit); } else if (!_cosmetic) { ItemDamageType type = _item->getRules()->getDamageType(); victim = save->getTileEngine()->hit(_center, _power, type, _unit); } // check if this unit turns others into zombies if (!_item->getRules()->getZombieUnit().empty() && victim && victim->getArmor()->getSize() == 1 && (victim->getGeoscapeSoldier() || victim->getUnitRules()->getRace() == "STR_CIVILIAN") && victim->getSpawnUnit().empty()) { // converts the victim to a zombie on death victim->setRespawn(true); victim->setSpawnUnit(_item->getRules()->getZombieUnit()); } } if (_tile) { ItemDamageType DT; switch (_tile->getExplosiveType()) { case 0: DT = DT_HE; break; case 5: DT = DT_IN; break; case 6: DT = DT_STUN; break; default: DT = DT_SMOKE; break; } if (DT != DT_HE) { _tile->setExplosive(0,0,true); } save->getTileEngine()->explode(_center, _power, DT, _power/10); terrainExplosion = true; } if (!_tile && !_item) { int radius = 6; // explosion not caused by terrain or an item, must be by a unit (cyberdisc) if (_unit && (_unit->getSpecialAbility() == SPECAB_EXPLODEONDEATH || _unit->getSpecialAbility() == SPECAB_BURN_AND_EXPLODE)) { radius = _parent->getMod()->getItem(_unit->getArmor()->getCorpseGeoscape(), true)->getExplosionRadius(); } save->getTileEngine()->explode(_center, _power, DT_HE, radius); terrainExplosion = true; } if (!_cosmetic) { // now check for new casualties _parent->checkForCasualties(_item, _unit, false, terrainExplosion); } // if this explosion was caused by a unit shooting, now it's the time to put the gun down if (_unit && !_unit->isOut() && _lowerWeapon) { _unit->aim(false); _unit->setCache(0); } _parent->getMap()->cacheUnits(); _parent->popState(); // check for terrain explosions Tile *t = save->getTileEngine()->checkForTerrainExplosions(); if (t) { Position p = Position(t->getPosition().x * 16, t->getPosition().y * 16, t->getPosition().z * 24); p += Position(8,8,0); _parent->statePushFront(new ExplosionBState(_parent, p, 0, _unit, t)); } if (_item && (_item->getRules()->getBattleType() == BT_GRENADE || _item->getRules()->getBattleType() == BT_PROXIMITYGRENADE)) { _parent->getSave()->removeItem(_item); } }
/** * Initializes the explosion. * The animation and sound starts here. * If the animation is finished, the actual effect takes place. */ void ExplosionBState::init() { if (_item) { _power = _item->getRules()->getPower(); // this usually only applies to melee, but as a concession for modders i'll leave it here in case they wanna make bows or something. if (_item->getRules()->isStrengthApplied() && _unit) { _power += _unit->getBaseStats()->strength; } _areaOfEffect = _item->getRules()->getBattleType() != BT_MELEE && _item->getRules()->getExplosionRadius() != 0 && !_cosmetic; } else if (_tile) { _power = _tile->getExplosive(); _areaOfEffect = true; } else if (_unit && (_unit->getSpecialAbility() == SPECAB_EXPLODEONDEATH || _unit->getSpecialAbility() == SPECAB_BURN_AND_EXPLODE)) { _power = _parent->getMod()->getItem(_unit->getArmor()->getCorpseGeoscape(), true)->getPower(); _areaOfEffect = true; } else { _power = 120; _areaOfEffect = true; } Tile *t = _parent->getSave()->getTile(Position(_center.x/16, _center.y/16, _center.z/24)); if (_areaOfEffect) { if (_power) { int frame = Mod::EXPLOSION_OFFSET; if (_item) { frame = _item->getRules()->getHitAnimation(); } if (_parent->getDepth() > 0) { frame -= Explosion::EXPLODE_FRAMES; } int frameDelay = 0; int counter = std::max(1, (_power/5) / 5); _parent->getMap()->setBlastFlash(true); int lowerLimit = std::max(1, _power/5); for (int i = 0; i < lowerLimit; i++) { int X = RNG::generate(-_power/2,_power/2); int Y = RNG::generate(-_power/2,_power/2); Position p = _center; p.x += X; p.y += Y; Explosion *explosion = new Explosion(p, frame, frameDelay, true); // add the explosion on the map _parent->getMap()->getExplosions()->push_back(explosion); if (i > 0 && i % counter == 0) { frameDelay++; } } _parent->setStateInterval(BattlescapeState::DEFAULT_ANIM_SPEED/2); // explosion sound if (_power <= 80) _parent->getMod()->getSoundByDepth(_parent->getDepth(), Mod::SMALL_EXPLOSION)->play(); else _parent->getMod()->getSoundByDepth(_parent->getDepth(), Mod::LARGE_EXPLOSION)->play(); _parent->getMap()->getCamera()->centerOnPosition(t->getPosition(), false); } else { _parent->popState(); } } else // create a bullet hit { _parent->setStateInterval(std::max(1, ((BattlescapeState::DEFAULT_ANIM_SPEED/2) - (10 * _item->getRules()->getExplosionSpeed())))); int anim = _item->getRules()->getHitAnimation(); int sound = _item->getRules()->getHitSound(); if (_cosmetic) // Play melee animation on hitting and psiing { anim = _item->getRules()->getMeleeAnimation(); } if (anim != -1) { Explosion *explosion = new Explosion(_center, anim, 0, false, _cosmetic); _parent->getMap()->getExplosions()->push_back(explosion); } _parent->getMap()->getCamera()->setViewLevel(_center.z / 24); BattleUnit *target = t->getUnit(); if (_cosmetic && _parent->getSave()->getSide() == FACTION_HOSTILE && target && target->getFaction() == FACTION_PLAYER) { _parent->getMap()->getCamera()->centerOnPosition(t->getPosition(), false); } if (sound != -1 && !_cosmetic) { // bullet hit sound _parent->getMod()->getSoundByDepth(_parent->getDepth(), sound)->play(-1, _parent->getMap()->getSoundAngle(_center / Position(16,16,24))); } } }
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "InstanceScript.h" #include "naxxramas.h" BossBoundaryData const boundaries = { /* Arachnid Quarter */ { BOSS_ANUBREKHAN, new CircleBoundary(Position(3273.376709f, -3475.876709f), Position(3195.668213f, -3475.930176f)) }, { BOSS_FAERLINA, new RectangleBoundary(3315.0f, 3402.0f, -3727.0f, -3590.0f) }, { BOSS_FAERLINA, new CircleBoundary(Position(3372.68f, -3648.2f), Position(3316.0f, -3704.26f)) }, { BOSS_MAEXXNA, new CircleBoundary(Position(3502.2587f, -3892.1697f), Position(3418.7422f, -3840.271f)) }, /* Plague Quarter */ { BOSS_NOTH, new RectangleBoundary(2618.0f, 2754.0f, -3557.43f, -3450.0f) }, { BOSS_HEIGAN, new CircleBoundary(Position(2772.57f, -3685.28f), 56.0f) }, { BOSS_LOATHEB, new CircleBoundary(Position(2909.0f, -3997.41f), 57.0f) }, /* Military Quarter */ { BOSS_RAZUVIOUS, new ZRangeBoundary(260.0f, 287.0f) }, // will not chase onto the upper floor { BOSS_GOTHIK, new RectangleBoundary(2627.0f, 2764.0f, -3440.0f, -3275.0f) }, { BOSS_HORSEMEN, new ParallelogramBoundary(AreaBoundary::DoublePosition(2646.0, -2959.0), AreaBoundary::DoublePosition(2529.0, -3075.0), AreaBoundary::DoublePosition(2506.0, -2854.0)) }, /* Construct Quarter */
Physics::CollisionType Physics::checkCollision( const Body &a, const Body &b ) { const Position &pa = a.getPosition(); const Position &pb = b.getPosition(); const BoundingVolume &va = a.getBounds(); const BoundingVolume &vb = b.getBounds(); if (va.getType() == vb.getType()) { switch (va.getType()) { case BoundingVolume::AABB: { // box <-> box collision test Position minA = pa - Position(va.getDimensions()); Position maxA = pa + Position(va.getDimensions()); Position minB = pb - Position(vb.getDimensions()); Position maxB = pb + Position(vb.getDimensions()); if ( minA.x <= maxB.x + Epsilon && minA.y <= maxB.y + Epsilon && minA.z <= maxB.z + Epsilon && minB.x <= maxA.x + Epsilon && minB.y <= maxA.y + Epsilon && minB.z <= maxA.z + Epsilon ) { if ( minA.x < maxB.x - Epsilon && minA.y < maxB.y - Epsilon && minA.z < maxB.z - Epsilon && minB.x < maxA.x - Epsilon && minB.y < maxA.y - Epsilon && minB.z < maxA.z - Epsilon ) { return CollisionType::Intrusion; } else { return CollisionType::Contact; } } else { return CollisionType::None; } } case BoundingVolume::Sphere: { // sphere <-> sphere collision test Position c = pb - pa; LargeDelta r = vb.getRadius() + va.getRadius(); HugeDelta d = c.x * c.x + c.y * c.y + c.z * c.z - r * r; if (d >= Epsilon) { return CollisionType::None; } else if (d > -Epsilon) { return CollisionType::Contact; } else { return CollisionType::Intrusion; } } case BoundingVolume::Capsule: { // capsule <-> capsule collision test Position c = pb - pa; LargeDelta r = vb.getRadius() + va.getRadius(); //~ LargeDelta h = b.getHeight() + a.getHeight() - r; HugeDelta d = c.x * c.x + c.z * c.z - r * r; if (d >= Epsilon) { // out of horizontal range, no need to check vertical return CollisionType::None; } else if (d > -Epsilon) { //! @todo vertical contact test return CollisionType::Contact; } else { //! @todo vertical intrusion test return CollisionType::Intrusion; } } } } else { if (va.getType() == BoundingVolume::AABB && vb.getType() == BoundingVolume::Sphere) { //! @todo box <-> sphere collision test } else if (va.getType() == BoundingVolume::Sphere && vb.getType() == BoundingVolume::AABB) { //! @todo sphere <-> box collision test } else if (va.getType() == BoundingVolume::AABB && vb.getType() == BoundingVolume::Capsule) { //! @todo box <-> capsule collision test } else if (va.getType() == BoundingVolume::Capsule && vb.getType() == BoundingVolume::AABB) { //! @todo capsule <-> box collision test } else if (va.getType() == BoundingVolume::Sphere && vb.getType() == BoundingVolume::Capsule) { //! @todo sphere <-> capsule collision test } else if (va.getType() == BoundingVolume::Capsule && vb.getType() == BoundingVolume::Sphere) { //! @todo capsule <-> sphere collision test } } // no collision, or no test for given bounding volumes sf::err() << "no collision test for given bounding volumes (" << va.getType() << ", " << vb.getType() << ")\n"; return CollisionType::None; }
void Physics::update(Body &b, const sf::Time &t) const { float s = t.asSeconds(); b.mPosition += Position(b.mVelocity.x * s, b.mVelocity.y * s, b.mVelocity.z * s); }
void InsertTextCommand::doApply() { ASSERT(m_text.find('\n') == notFound); if (!endingSelection().isNonOrphanedCaretOrRange()) return; // Delete the current selection. // FIXME: This delete operation blows away the typing style. if (endingSelection().isRange()) { if (performTrivialReplace(m_text, m_selectInsertedText)) return; deleteSelection(false, true, true, false); // deleteSelection eventually makes a new endingSelection out of a Position. If that Position doesn't have // a renderer (e.g. it is on a <frameset> in the DOM), the VisibleSelection cannot be canonicalized to // anything other than NoSelection. The rest of this function requires a real endingSelection, so bail out. if (endingSelection().isNone()) return; } Position startPosition(endingSelection().start()); Position placeholder; // We want to remove preserved newlines and brs that will collapse (and thus become unnecessary) when content // is inserted just before them. // FIXME: We shouldn't really have to do this, but removing placeholders is a workaround for 9661. // If the caret is just before a placeholder, downstream will normalize the caret to it. Position downstream(startPosition.downstream()); if (lineBreakExistsAtPosition(downstream)) { // FIXME: This doesn't handle placeholders at the end of anonymous blocks. VisiblePosition caret(startPosition); if (isEndOfBlock(caret) && isStartOfParagraph(caret)) placeholder = downstream; // Don't remove the placeholder yet, otherwise the block we're inserting into would collapse before // we get a chance to insert into it. We check for a placeholder now, though, because doing so requires // the creation of a VisiblePosition, and if we did that post-insertion it would force a layout. } // Insert the character at the leftmost candidate. startPosition = startPosition.upstream(); // It is possible for the node that contains startPosition to contain only unrendered whitespace, // and so deleteInsignificantText could remove it. Save the position before the node in case that happens. Position positionBeforeStartNode(positionInParentBeforeNode(startPosition.containerNode())); deleteInsignificantText(startPosition.upstream(), startPosition.downstream()); if (!startPosition.anchorNode()->inDocument()) startPosition = positionBeforeStartNode; if (!startPosition.isCandidate()) startPosition = startPosition.downstream(); startPosition = positionAvoidingSpecialElementBoundary(startPosition); Position endPosition; if (m_text == "\t") { endPosition = insertTab(startPosition); startPosition = endPosition.previous(); if (placeholder.isNotNull()) removePlaceholderAt(placeholder); } else { // Make sure the document is set up to receive m_text startPosition = positionInsideTextNode(startPosition); ASSERT(startPosition.anchorType() == Position::PositionIsOffsetInAnchor); ASSERT(startPosition.containerNode()); ASSERT(startPosition.containerNode()->isTextNode()); if (placeholder.isNotNull()) removePlaceholderAt(placeholder); RefPtr<Text> textNode = startPosition.containerText(); const unsigned offset = startPosition.offsetInContainerNode(); insertTextIntoNode(textNode, offset, m_text); endPosition = Position(textNode, offset + m_text.length()); if (m_rebalanceType == RebalanceLeadingAndTrailingWhitespaces) { // The insertion may require adjusting adjacent whitespace, if it is present. rebalanceWhitespaceAt(endPosition); // Rebalancing on both sides isn't necessary if we've inserted only spaces. if (!shouldRebalanceLeadingWhitespaceFor(m_text)) rebalanceWhitespaceAt(startPosition); } else { ASSERT(m_rebalanceType == RebalanceAllWhitespaces); if (canRebalance(startPosition) && canRebalance(endPosition)) rebalanceWhitespaceOnTextSubstring(textNode, startPosition.offsetInContainerNode(), endPosition.offsetInContainerNode()); } } // We could have inserted a part of composed character sequence, // so we are basically treating ending selection as a range to avoid validation. // <http://bugs.webkit.org/show_bug.cgi?id=15781> VisibleSelection forcedEndingSelection; forcedEndingSelection.setWithoutValidation(startPosition, endPosition); forcedEndingSelection.setIsDirectional(endingSelection().isDirectional()); setEndingSelection(forcedEndingSelection); // Handle the case where there is a typing style. if (RefPtr<EditingStyle> typingStyle = document()->frame()->selection()->typingStyle()) { typingStyle->prepareToApplyAt(endPosition, EditingStyle::PreserveWritingDirection); if (!typingStyle->isEmpty()) applyStyle(typingStyle.get()); } if (!m_selectInsertedText) setEndingSelection(VisibleSelection(endingSelection().end(), endingSelection().affinity(), endingSelection().isDirectional())); }
C *PosSearch<C>::FindNearest(const Point &pos, const Rect16 &area, F IsValid, F2 Position) { int right_pos = NewFind(pos.x); int left_pos = right_pos - 1; int max_dist = INT_MAX; C *closest = nullptr; bool cont = true; while (cont) { cont = false; if (left_pos >= 0) { int left = left_positions[left_pos]; int widest_right = left + max_width; if (widest_right < area.left || pos.x - widest_right > max_dist) left_pos = -1; else { cont = true; C *value = &left_to_value[left_pos]; Point val_pos = Position(*value); if (val_pos.y < area.bottom && val_pos.y >= area.top && val_pos.x >= area.left) { if (IsValid(*value)) { int dist = Distance(pos, val_pos); if (dist < max_dist) { closest = value; max_dist = dist; } } } left_pos--; } } if (right_pos < (int)Size()) { int right = left_to_right[right_pos]; int widest_left = right - max_width; if (widest_left > area.right || widest_left - pos.x > max_dist) right_pos = Size(); else { cont = true; C *value = &left_to_value[right_pos]; Point val_pos = Position(*value); if (val_pos.y < area.bottom && val_pos.y >= area.top && val_pos.x < area.right) { if (IsValid(*value)) { int dist = Distance(pos, val_pos); if (dist < max_dist) { closest = value; max_dist = dist; } } } right_pos++; } } } return closest; }
drape_ptr<LayerRenderer> LayerCacher::RecacheDebugLabels(ref_ptr<dp::TextureManager> textures) { drape_ptr<LayerRenderer> renderer = make_unique_dp<LayerRenderer>(); float const vs = df::VisualParams::Instance().GetVisualScale(); DebugInfoLabels debugLabels = DebugInfoLabels(Position(m2::PointF(10.0f * vs, 50.0f * vs), dp::Center)); debugLabels.AddLabel(textures, "visible: km2, readed: km2, ratio:", [](ScreenBase const & screen, string & content) -> bool { double const sizeX = screen.PixelRectIn3d().SizeX(); double const sizeY = screen.PixelRectIn3d().SizeY(); m2::PointD const p0 = screen.PtoG(screen.P3dtoP(m2::PointD(0.0, 0.0))); m2::PointD const p1 = screen.PtoG(screen.P3dtoP(m2::PointD(0.0, sizeY))); m2::PointD const p2 = screen.PtoG(screen.P3dtoP(m2::PointD(sizeX, sizeY))); m2::PointD const p3 = screen.PtoG(screen.P3dtoP(m2::PointD(sizeX, 0.0))); double const areaG = MercatorBounds::AreaOnEarth(p0, p1, p2) + MercatorBounds::AreaOnEarth(p2, p3, p0); double const sizeX_2d = screen.PixelRect().SizeX(); double const sizeY_2d = screen.PixelRect().SizeY(); m2::PointD const p0_2d = screen.PtoG(m2::PointD(0.0, 0.0)); m2::PointD const p1_2d = screen.PtoG(m2::PointD(0.0, sizeY_2d)); m2::PointD const p2_2d = screen.PtoG(m2::PointD(sizeX_2d, sizeY_2d)); m2::PointD const p3_2d = screen.PtoG(m2::PointD(sizeX_2d, 0.0)); double const areaGTotal = MercatorBounds::AreaOnEarth(p0_2d, p1_2d, p2_2d) + MercatorBounds::AreaOnEarth(p2_2d, p3_2d, p0_2d); ostringstream out; out << fixed << setprecision(2) << "visible: " << areaG / 1000000.0 << " km2" << ", readed: " << areaGTotal / 1000000.0 << " km2" << ", ratio: " << areaGTotal / areaG; content.assign(out.str()); return true; }); debugLabels.AddLabel(textures, "scale2d: m/px, scale2d * vs: m/px", [](ScreenBase const & screen, string & content) -> bool { double const distanceG = MercatorBounds::DistanceOnEarth(screen.PtoG(screen.PixelRect().LeftBottom()), screen.PtoG(screen.PixelRect().RightBottom())); double const vs = df::VisualParams::Instance().GetVisualScale(); double const scale = distanceG / screen.PixelRect().SizeX(); ostringstream out; out << fixed << setprecision(2) << "scale2d: " << scale << " m/px" << ", scale2d * vs: " << scale * vs << " m/px"; content.assign(out.str()); return true; }); debugLabels.AddLabel(textures, "distance: m", [](ScreenBase const & screen, string & content) -> bool { double const sizeX = screen.PixelRectIn3d().SizeX(); double const sizeY = screen.PixelRectIn3d().SizeY(); double const distance = MercatorBounds::DistanceOnEarth(screen.PtoG(screen.P3dtoP(m2::PointD(sizeX / 2.0, 0.0))), screen.PtoG(screen.P3dtoP(m2::PointD(sizeX / 2.0, sizeY)))); ostringstream out; out << fixed << setprecision(2) << "distance: " << distance << " m"; content.assign(out.str()); return true; }); debugLabels.AddLabel(textures, "angle: ", [](ScreenBase const & screen, string & content) -> bool { ostringstream out; out << fixed << setprecision(2) << "angle: " << screen.GetRotationAngle() * 180.0 / math::pi; content.assign(out.str()); return true; }); renderer->AddShapeRenderer(WIDGET_DEBUG_INFO, debugLabels.Draw(textures)); // Flush gui geometry. GLFunctions::glFlush(); return renderer; }
/** * 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 (_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(); originVoxel.z += bu->getHeight(); 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) { foundCurve = true; } else { curvature += 1.0; } _trajectory.clear(); } if (curvature == 5.0) { return false; } // apply some accuracy modifiers if (accuracy > 100) accuracy = 100; static const double maxDeviation = 0.08; static const double minDeviation = 0; double baseDeviation = (maxDeviation - (maxDeviation * accuracy / 100.0)) + 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; }
void CCamera::CheckForMovement() { // Once we have the frame interval, we find the current speed float speed = (float)(kSpeed * g_FrameInterval); // Store the last position and view of the camera CVector3 vOldPosition = Position(); CVector3 vOldView = View(); // Use a flag to see if we movement backwards or not bool bMovedBack = false; /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Here is where we subtract the gravity acceleration from our velocity vector. // We then add that velocity vector to our camera to effect our camera (or player) // This is also how we handle the jump velocity when we hit space bar. // Notice that we multiply the gravity by the frame interval (dt). This makes // it so faster video cards don't do a 2 frame jump, while TNT2 cards do 20 frames :) // This is necessary to make every computer use the same movement and jump speed. g_vVelocity.y -= (float)(kGravity * g_FrameInterval); m_vPosition = m_vPosition + g_vVelocity; /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Check if we hit the Up arrow or the 'w' key if(GetKeyState(VK_UP) & 0x80 || GetKeyState('W') & 0x80) { // Move our camera forward by a positive SPEED MoveCamera(speed); } // Check if we hit the Down arrow or the 's' key if(GetKeyState(VK_DOWN) & 0x80 || GetKeyState('S') & 0x80) { // Move our camera backward by a negative SPEED MoveCamera(-speed); bMovedBack = true; } // Check if we hit the Left arrow or the 'a' key if(GetKeyState(VK_LEFT) & 0x80 || GetKeyState('A') & 0x80) { // Strafe the camera left StrafeCamera(-speed); } // Check if we hit the Right arrow or the 'd' key if(GetKeyState(VK_RIGHT) & 0x80 || GetKeyState('D') & 0x80) { // Strafe the camera right StrafeCamera(speed); } // Now that we moved, let's get the current position and test our movement // vector against the level data to see if there is a collision. CVector3 vCurrentPosition = Position(); // Check for collision with AABB's and grab the new position CVector3 vNewPosition = g_Level.TraceBox(vOldPosition, vCurrentPosition, CVector3(-20, -50, -20), CVector3(20, 50, 20)); // Check if we collided and we moved backwards if(g_Level.Collided() && bMovedBack) { // If or x or y didn't move, then we are backed into a wall so restore the view vector if(vNewPosition.x == vOldPosition.x || vNewPosition.z == vOldPosition.z) m_vView = vOldView; } // Set the new position that was returned from our trace function m_vPosition = vNewPosition; /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // After we check for collision, we only want to add the velocity vector to // our view vector when we are falling. If we aren't on the ground then // we don't want to push the the camera view down to the ground. It's okay // if the position goes down because the collision detection fixes that so // we don't go through the ground, however, it's not natural to push the view // down too. Well, assuming is strong enough to push our face down to the ground :) if(!g_Level.IsOnGround()) m_vView = m_vView + g_vVelocity; else { // If we ARE on the ground, we want to get rid of the jump acceleration // that we add when the user hits the space bar. Below we check to see // if our velocity is below 0 then we are done with our jump and can just // float back to the ground by the gravity. We do also add our gravity // acceleration to the velocity every frame, so this resets this to zero // for that as well. if(g_vVelocity.y < 0) g_vVelocity.y = 0; } /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * }
/** * 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); }
/* Test the method 'splitAt'*/ TEST_F(PositionVectorTest, test_method_splitAt) { PositionVector vec; vec.push_back(Position(0,0)); vec.push_back(Position(2,0)); vec.push_back(Position(5,0)); SUMOReal smallDiff = POSITION_EPS / 2; std::pair<PositionVector, PositionVector> result; // split in first segment result = vec.splitAt(1); EXPECT_DOUBLE_EQ(2, result.first.size()); EXPECT_DOUBLE_EQ(0, result.first[0].x()); EXPECT_DOUBLE_EQ(1, result.first[1].x()); EXPECT_DOUBLE_EQ(3, result.second.size()); EXPECT_DOUBLE_EQ(1, result.second[0].x()); EXPECT_DOUBLE_EQ(2, result.second[1].x()); EXPECT_DOUBLE_EQ(5, result.second[2].x()); // split in second segment result = vec.splitAt(4); EXPECT_DOUBLE_EQ(3, result.first.size()); EXPECT_DOUBLE_EQ(0, result.first[0].x()); EXPECT_DOUBLE_EQ(2, result.first[1].x()); EXPECT_DOUBLE_EQ(4, result.first[2].x()); EXPECT_DOUBLE_EQ(2, result.second.size()); EXPECT_DOUBLE_EQ(4, result.second[0].x()); EXPECT_DOUBLE_EQ(5, result.second[1].x()); // split close before inner point result = vec.splitAt(2 - smallDiff); EXPECT_DOUBLE_EQ(2, result.first.size()); EXPECT_DOUBLE_EQ(0, result.first[0].x()); EXPECT_DOUBLE_EQ(2, result.first[1].x()); EXPECT_DOUBLE_EQ(2, result.second.size()); EXPECT_DOUBLE_EQ(2, result.second[0].x()); EXPECT_DOUBLE_EQ(5 ,result.second[1].x()); // split close after inner point result = vec.splitAt(2 + smallDiff); EXPECT_DOUBLE_EQ(2, result.first.size()); EXPECT_DOUBLE_EQ(0, result.first[0].x()); EXPECT_DOUBLE_EQ(2, result.first[1].x()); EXPECT_DOUBLE_EQ(2, result.second.size()); EXPECT_DOUBLE_EQ(2, result.second[0].x()); EXPECT_DOUBLE_EQ(5 ,result.second[1].x()); // catch a bug vec.push_back(Position(6,0)); vec.push_back(Position(8,0)); // split at inner point result = vec.splitAt(5); EXPECT_DOUBLE_EQ(3, result.first.size()); EXPECT_DOUBLE_EQ(0, result.first[0].x()); EXPECT_DOUBLE_EQ(2, result.first[1].x()); EXPECT_DOUBLE_EQ(5, result.first[2].x()); EXPECT_DOUBLE_EQ(3, result.second.size()); EXPECT_DOUBLE_EQ(5, result.second[0].x()); EXPECT_DOUBLE_EQ(6 ,result.second[1].x()); EXPECT_DOUBLE_EQ(8 ,result.second[2].x()); // split short vector PositionVector vec2; vec2.push_back(Position(0,0)); vec2.push_back(Position(2,0)); result = vec2.splitAt(1); EXPECT_DOUBLE_EQ(2, result.first.size()); EXPECT_DOUBLE_EQ(0, result.first[0].x()); EXPECT_DOUBLE_EQ(1, result.first[1].x()); EXPECT_DOUBLE_EQ(2, result.second.size()); EXPECT_DOUBLE_EQ(1, result.second[0].x()); EXPECT_DOUBLE_EQ(2 ,result.second[1].x()); // split very short vector PositionVector vec3; vec3.push_back(Position(0,0)); vec3.push_back(Position(POSITION_EPS,0)); // supress expected warning MsgHandler::getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr")); result = vec3.splitAt(smallDiff); MsgHandler::getWarningInstance()->addRetriever(&OutputDevice::getDevice("stderr")); EXPECT_DOUBLE_EQ(2, result.first.size()); EXPECT_DOUBLE_EQ(0, result.first[0].x()); EXPECT_DOUBLE_EQ(smallDiff, result.first[1].x()); EXPECT_DOUBLE_EQ(2, result.second.size()); EXPECT_DOUBLE_EQ(smallDiff, result.second[0].x()); EXPECT_DOUBLE_EQ(POSITION_EPS ,result.second[1].x()); }
/** * Converts unit to a corpse (item). */ void UnitDieBState::convertUnitToCorpse() { _parent->getSave()->getBattleState()->showPsiButton(false); // in case the unit was unconscious _parent->getSave()->removeUnconsciousBodyItem(_unit); Position lastPosition = _unit->getPosition(); int size = _unit->getArmor()->getSize() - 1; BattleItem *itemToKeep = 0; bool dropItems = !Options::getBool("weaponSelfDestruction") || (_unit->getOriginalFaction() != FACTION_HOSTILE || _unit->getStatus() == STATUS_UNCONSCIOUS); // move inventory from unit to the ground for non-large units if (size == 0 && dropItems) { for (std::vector<BattleItem*>::iterator i = _unit->getInventory()->begin(); i != _unit->getInventory()->end(); ++i) { _parent->dropItem(_unit->getPosition(), (*i)); if (!(*i)->getRules()->isFixed()) { (*i)->setOwner(0); } else { itemToKeep = *i; } } } _unit->getInventory()->clear(); if (itemToKeep != 0) { _unit->getInventory()->push_back(itemToKeep); } // remove unit-tile link _unit->setTile(0); if (size == 0) { BattleItem *corpse = new BattleItem(_parent->getRuleset()->getItem(_unit->getArmor()->getCorpseItem()),_parent->getSave()->getCurrentItemId()); corpse->setUnit(_unit); _parent->dropItem(_unit->getPosition(), corpse, true); if (_parent->getSave()->getTile(lastPosition)->getUnit() == _unit) // check in case unit was displaced by another unit { _parent->getSave()->getTile(lastPosition)->setUnit(0); } } else { int i = 1; for (int y = 0; y <= size; y++) { for (int x = 0; x <= size; x++) { std::ostringstream ss; ss << _unit->getArmor()->getCorpseItem() << i; BattleItem *corpse = new BattleItem(_parent->getRuleset()->getItem(ss.str()),_parent->getSave()->getCurrentItemId()); corpse->setUnit(_unit); if (_parent->getSave()->getTile(lastPosition + Position(x,y,0))->getUnit() == _unit) // check in case unit was displaced by another unit { _parent->getSave()->getTile(lastPosition + Position(x,y,0))->setUnit(0); } _parent->dropItem(lastPosition + Position(x,y,0), corpse, true); i++; } } } }
/* Test the method 'transformToVectorCoordinates'*/ TEST_F(PositionVectorTest, test_method_transformToVectorCoordinates) { { PositionVector vec1; vec1.push_back(Position(1,0)); vec1.push_back(Position(10,0)); vec1.push_back(Position(10,5)); vec1.push_back(Position(20,5)); Position on(4,0); Position left(4,1); Position right(4,-1); Position left2(4,2); Position right2(4,-2); Position cornerRight(13,-4); Position cornerLeft(7,9); Position before(0,-1); Position beyond(24,9); EXPECT_EQ(Position(3, 0), vec1.transformToVectorCoordinates(on)); EXPECT_EQ(Position(3, -1), vec1.transformToVectorCoordinates(left)); EXPECT_EQ(Position(3, 1), vec1.transformToVectorCoordinates(right)); EXPECT_EQ(Position(3, -2), vec1.transformToVectorCoordinates(left2)); EXPECT_EQ(Position(3, 2), vec1.transformToVectorCoordinates(right2)); EXPECT_EQ(Position(9, 5), vec1.transformToVectorCoordinates(cornerRight)); EXPECT_EQ(Position(14, -5), vec1.transformToVectorCoordinates(cornerLeft)); EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(before)); EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(beyond)); EXPECT_EQ(Position(-1, 1), vec1.transformToVectorCoordinates(before, true)); EXPECT_EQ(Position(28, -4), vec1.transformToVectorCoordinates(beyond, true)); } { PositionVector vec1; // the same tests as before, mirrored on x-axis vec1.push_back(Position(1,0)); vec1.push_back(Position(10,0)); vec1.push_back(Position(10,-5)); vec1.push_back(Position(20,-5)); Position on(4,0); Position left(4,-1); Position right(4,1); Position left2(4,-2); Position right2(4,2); Position cornerRight(13,4); Position cornerLeft(7,-9); Position before(0,1); Position beyond(24,-9); EXPECT_EQ(Position(3, 0), vec1.transformToVectorCoordinates(on)); EXPECT_EQ(Position(3, 1), vec1.transformToVectorCoordinates(left)); EXPECT_EQ(Position(3, -1), vec1.transformToVectorCoordinates(right)); EXPECT_EQ(Position(3, 2), vec1.transformToVectorCoordinates(left2)); EXPECT_EQ(Position(3, -2), vec1.transformToVectorCoordinates(right2)); EXPECT_EQ(Position(9, -5), vec1.transformToVectorCoordinates(cornerRight)); EXPECT_EQ(Position(14, 5), vec1.transformToVectorCoordinates(cornerLeft)); EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(before)); EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(beyond)); EXPECT_EQ(Position(-1, -1), vec1.transformToVectorCoordinates(before, true)); EXPECT_EQ(Position(28, 4), vec1.transformToVectorCoordinates(beyond, true)); } }
void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries() { if (m_base.isNull() || m_start.isNull() || m_end.isNull()) return; Node* baseRoot = highestEditableRoot(m_base); Node* startRoot = highestEditableRoot(m_start); Node* endRoot = highestEditableRoot(m_end); Node* baseEditableAncestor = lowestEditableAncestor(m_base.containerNode()); // The base, start and end are all in the same region. No adjustment necessary. if (baseRoot == startRoot && baseRoot == endRoot) return; // The selection is based in editable content. if (baseRoot) { // If the start is outside the base's editable root, cap it at the start of that root. // If the start is in non-editable content that is inside the base's editable root, put it // at the first editable position after start inside the base's editable root. if (startRoot != baseRoot) { VisiblePosition first = firstEditablePositionAfterPositionInRoot(m_start, baseRoot); m_start = first.deepEquivalent(); if (m_start.isNull()) { ASSERT_NOT_REACHED(); m_start = m_end; } } // If the end is outside the base's editable root, cap it at the end of that root. // If the end is in non-editable content that is inside the base's root, put it // at the last editable position before the end inside the base's root. if (endRoot != baseRoot) { VisiblePosition last = lastEditablePositionBeforePositionInRoot(m_end, baseRoot); m_end = last.deepEquivalent(); if (m_end.isNull()) m_end = m_start; } // The selection is based in non-editable content. } else { // FIXME: Non-editable pieces inside editable content should be atomic, in the same way that editable // pieces in non-editable content are atomic. // The selection ends in editable content or non-editable content inside a different editable ancestor, // move backward until non-editable content inside the same lowest editable ancestor is reached. Node* endEditableAncestor = lowestEditableAncestor(m_end.containerNode()); if (endRoot || endEditableAncestor != baseEditableAncestor) { Position p = previousVisuallyDistinctCandidate(m_end); Node* shadowAncestor = endRoot ? endRoot->shadowAncestorNode() : 0; if (p.isNull() && endRoot && (shadowAncestor != endRoot)) p = positionAfterNode(shadowAncestor); while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) { Node* root = editableRootForPosition(p); shadowAncestor = root ? root->shadowAncestorNode() : 0; p = isAtomicNode(p.containerNode()) ? positionInParentBeforeNode(p.containerNode()) : previousVisuallyDistinctCandidate(p); if (p.isNull() && (shadowAncestor != root)) p = positionAfterNode(shadowAncestor); } VisiblePosition previous(p); if (previous.isNull()) { // The selection crosses an Editing boundary. This is a // programmer error in the editing code. Happy debugging! ASSERT_NOT_REACHED(); m_base = Position(); m_extent = Position(); validate(); return; } m_end = previous.deepEquivalent(); } // The selection starts in editable content or non-editable content inside a different editable ancestor, // move forward until non-editable content inside the same lowest editable ancestor is reached. Node* startEditableAncestor = lowestEditableAncestor(m_start.containerNode()); if (startRoot || startEditableAncestor != baseEditableAncestor) { Position p = nextVisuallyDistinctCandidate(m_start); Node* shadowAncestor = startRoot ? startRoot->shadowAncestorNode() : 0; if (p.isNull() && startRoot && (shadowAncestor != startRoot)) p = positionBeforeNode(shadowAncestor); while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) { Node* root = editableRootForPosition(p); shadowAncestor = root ? root->shadowAncestorNode() : 0; p = isAtomicNode(p.containerNode()) ? positionInParentAfterNode(p.containerNode()) : nextVisuallyDistinctCandidate(p); if (p.isNull() && (shadowAncestor != root)) p = positionBeforeNode(shadowAncestor); } VisiblePosition next(p); if (next.isNull()) { // The selection crosses an Editing boundary. This is a // programmer error in the editing code. Happy debugging! ASSERT_NOT_REACHED(); m_base = Position(); m_extent = Position(); validate(); return; } m_start = next.deepEquivalent(); } } // Correct the extent if necessary. if (baseEditableAncestor != lowestEditableAncestor(m_extent.containerNode())) m_extent = m_baseIsFirst ? m_end : m_start; }
/* Test the method 'around'*/ TEST_F(PositionVectorTest, test_method_around) { EXPECT_TRUE(vectorPolygon->around(Position(1,1))); EXPECT_TRUE(vectorPolygon->around(Position(1,2))); EXPECT_FALSE(vectorPolygon->around(Position(4,4))); EXPECT_FALSE(vectorPolygon->around(Position(0,0))); EXPECT_FALSE(vectorLine->around(Position(1,1))); EXPECT_FALSE(vectorLine->around(Position(0,2))); // with positive offset EXPECT_TRUE(vectorPolygon->around(Position(4,2), 1)); EXPECT_FALSE(vectorPolygon->around(Position(5,2), 1)); // what was true remains true EXPECT_TRUE(vectorPolygon->around(Position(1,1), POSITION_EPS)); EXPECT_TRUE(vectorPolygon->around(Position(1,2), POSITION_EPS)); // with negative offset EXPECT_FALSE(vectorPolygon->around(Position(4,2), -POSITION_EPS)); EXPECT_TRUE(vectorPolygon->around(Position(1,1), -1)); EXPECT_FALSE(vectorPolygon->around(Position(0.5,0.5), -1)); }
int32 CreatureAI::VisualizeBoundary(uint32 duration, Unit* owner, bool fill) const { typedef std::pair<int32, int32> coordinate; if (!owner) return -1; if (!_boundary || _boundary->empty()) return LANG_CREATURE_MOVEMENT_NOT_BOUNDED; std::queue<coordinate> Q; std::unordered_set<coordinate> alreadyChecked; std::unordered_set<coordinate> outOfBounds; Position startPosition = owner->GetPosition(); if (!CheckBoundary(&startPosition)) { // fall back to creature position startPosition = me->GetPosition(); if (!CheckBoundary(&startPosition)) { // fall back to creature home position startPosition = me->GetHomePosition(); if (!CheckBoundary(&startPosition)) return LANG_CREATURE_NO_INTERIOR_POINT_FOUND; } } float spawnZ = startPosition.GetPositionZ() + BOUNDARY_VISUALIZE_SPAWN_HEIGHT; bool boundsWarning = false; Q.push({ 0,0 }); while (!Q.empty()) { coordinate front = Q.front(); bool hasOutOfBoundsNeighbor = false; for (coordinate off : std::initializer_list<coordinate>{{1,0}, {0,1}, {-1,0}, {0,-1}}) { coordinate next(front.first + off.first, front.second + off.second); if (next.first > BOUNDARY_VISUALIZE_FAILSAFE_LIMIT || next.first < -BOUNDARY_VISUALIZE_FAILSAFE_LIMIT || next.second > BOUNDARY_VISUALIZE_FAILSAFE_LIMIT || next.second < -BOUNDARY_VISUALIZE_FAILSAFE_LIMIT) { boundsWarning = true; continue; } if (alreadyChecked.find(next) == alreadyChecked.end()) // never check a coordinate twice { Position nextPos(startPosition.GetPositionX() + next.first*BOUNDARY_VISUALIZE_STEP_SIZE, startPosition.GetPositionY() + next.second*BOUNDARY_VISUALIZE_STEP_SIZE, startPosition.GetPositionZ()); if (CheckBoundary(&nextPos)) Q.push(next); else { outOfBounds.insert(next); hasOutOfBoundsNeighbor = true; } alreadyChecked.insert(next); } else if (outOfBounds.find(next) != outOfBounds.end()) hasOutOfBoundsNeighbor = true; } if (fill || hasOutOfBoundsNeighbor) if (TempSummon* point = owner->SummonCreature(BOUNDARY_VISUALIZE_CREATURE, Position(startPosition.GetPositionX() + front.first*BOUNDARY_VISUALIZE_STEP_SIZE, startPosition.GetPositionY() + front.second*BOUNDARY_VISUALIZE_STEP_SIZE, spawnZ), TEMPSUMMON_TIMED_DESPAWN, duration * IN_MILLISECONDS)) { point->SetObjectScale(BOUNDARY_VISUALIZE_CREATURE_SCALE); point->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); point->SetImmuneToAll(true); if (!hasOutOfBoundsNeighbor) point->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } Q.pop(); } return boundsWarning ? LANG_CREATURE_MOVEMENT_MAYBE_UNBOUNDED : 0; }
String CodeDocument::getAllContent() const { return getTextBetween (Position (*this, 0), Position (*this, lines.size(), 0)); }
Window* Window::Create(int x, int y, int w, int h, string title, Color bckg) { return Window::Create(Position(x,y), Size(w,h), title, bckg); }
void CBaseMonster::update_pos_by_grouping_behaviour () { if ( !m_grouping_behaviour ) { return; } Fvector acc = get_steer_manager()->calc_acceleration(); acc.y = 0; // remove vertical component if ( !m_last_grouping_behaviour_update_tick ) { m_last_grouping_behaviour_update_tick = Device.dwTimeGlobal; } const float dt = 0.001f * (Device.dwTimeGlobal - m_last_grouping_behaviour_update_tick); m_last_grouping_behaviour_update_tick = Device.dwTimeGlobal; const Fvector old_pos = Position(); Fvector offs = acc*dt; const float offs_mag = magnitude(offs); if ( offs_mag < 0.000001f ) { // too little force applied, ignore it and save cpu return; } // this control maximum offset // higher values allow stronger forces, but can lead to jingling const float max_offs = 0.005f; if ( offs_mag > max_offs ) { offs.set_length(0.005f); } Fvector new_pos = old_pos + offs; const u32 old_vertex = ai_location().level_vertex_id(); u32 new_vertex = ai().level_graph().check_position_in_direction(old_vertex, old_pos, new_pos); if ( !ai().level_graph().valid_vertex_id(new_vertex) ) { // aiming out of ai-map, ignore return; } // use physics simulation to slide along obstacles character_physics_support()->movement()->VirtualMoveTo(new_pos, new_pos); if ( !ai().level_graph().valid_vertex_position(new_pos) ) { // aiming out of ai-map, ignore return; } new_vertex = ai().level_graph().check_position_in_direction(old_vertex, old_pos, new_pos); if ( !ai().level_graph().valid_vertex_id(new_vertex) ) { return; } // finally, new position is valid on the ai-map, we can use it character_physics_support()->movement()->SetPosition(new_pos); Position() = new_pos; ai_location().level_vertex(new_vertex); }
Path Map::findPath(const int startX, const int startY, const int destX, const int destY) { // Path to be built up (empty by default) Path path; // Declare open list, a list with open tiles sorted on F cost std::priority_queue<Location> openList; // Reset starting tile's G cost to 0 MetaTile *startTile = getMetaTile(startX, startY); startTile->Gcost = 0; // Add the start point to the open list openList.push(Location(startX, startY, startTile)); bool foundPath = false; // Keep trying new open tiles until no more tiles to try or target found while (!openList.empty() && !foundPath) { // Take the location with the lowest F cost from the open list. Location curr = openList.top(); openList.pop(); // If the tile is already on the closed list, this means it has already // been processed with a shorter path to the start point (lower G cost) if (curr.tile->whichList == mOnClosedList) continue; // Put the current tile on the closed list curr.tile->whichList = mOnClosedList; // Check the adjacent tiles for (int dy = -1; dy <= 1; dy++) { for (int dx = -1; dx <= 1; dx++) { // Calculate location of tile to check const int x = curr.x + dx; const int y = curr.y + dy; // Skip if if we're checking the same tile we're leaving from, // or if the new location falls outside of the map boundaries if ((dx == 0 && dy == 0) || !contains(x, y)) { continue; } MetaTile *newTile = getMetaTile(x, y); // Skip if the tile is on the closed list or collides unless // its the destination tile if (newTile->whichList == mOnClosedList || (tileCollides(x, y) && !(x == destX && y == destY))) { continue; } // When taking a diagonal step, verify that we can skip the // corner. We allow skipping past beings but not past non- // walkable tiles. if (dx != 0 && dy != 0) { MetaTile *t1 = getMetaTile(curr.x, curr.y + dy); MetaTile *t2 = getMetaTile(curr.x + dx, curr.y); if (!(t1->walkable && t2->walkable)) continue; } // Calculate G cost for this route, 10 for moving straight and // 14 for moving diagonal (sqrt(200) = 14.1421...) int Gcost = curr.tile->Gcost + ((dx == 0 || dy == 0) ? 10 : 14); // Skip if Gcost becomes too much // Warning: probably not entirely accurate if (Gcost > 200) { continue; } if (newTile->whichList != mOnOpenList) { // Found a new tile (not on open nor on closed list) // Update Hcost of the new tile using Manhatten distance newTile->Hcost = 10 * (abs(x - destX) + abs(y - destY)); // Set the current tile as the parent of the new tile newTile->parentX = curr.x; newTile->parentY = curr.y; // Update Gcost and Fcost of new tile newTile->Gcost = Gcost; newTile->Fcost = Gcost + newTile->Hcost; if (x != destX || y != destY) { // Add this tile to the open list newTile->whichList = mOnOpenList; openList.push(Location(x, y, newTile)); } else { // Target location was found foundPath = true; } } else if (Gcost < newTile->Gcost) { // Found a shorter route. // Update Gcost and Fcost of the new tile newTile->Gcost = Gcost; newTile->Fcost = Gcost + newTile->Hcost; // Set the current tile as the parent of the new tile newTile->parentX = curr.x; newTile->parentY = curr.y; // Add this tile to the open list (it's already // there, but this instance has a lower F score) openList.push(Location(x, y, newTile)); } } } } // Two new values to indicate whether a tile is on the open or closed list, // this way we don't have to clear all the values between each pathfinding. mOnClosedList += 2; mOnOpenList += 2; // If a path has been found, iterate backwards using the parent locations // to extract it. if (foundPath) { int pathX = destX; int pathY = destY; while (pathX != startX || pathY != startY) { // Add the new path node to the start of the path list path.push_front(Position(pathX, pathY)); // Find out the next parent MetaTile *tile = getMetaTile(pathX, pathY); pathX = tile->parentX; pathY = tile->parentY; } } return path; }