/*********************************************************** constructor from 3 angles ***********************************************************/ LbaQuaternion::LbaQuaternion(float anglex, float angley, float anglez) { LbaQuaternion qx(anglex, LbaVec3(1, 0, 0)); LbaQuaternion qy(angley, LbaVec3(0, 1, 0)); LbaQuaternion qz(anglez, LbaVec3(0, 0, 1)); LbaQuaternion res = (qy * qx * qz); X = res.X; Y = res.Y; Z = res.Z; W = res.W; }
/*********************************************************** server attach actor ***********************************************************/ void ExternalActor::ServerAttachActor(boost::shared_ptr<DynamicObject> actor, float posX, float posY, float posZ, float rotation) { _externalattachedactor = actor; boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); physo->MoveTo(posX, posY, posZ); LbaQuaternion Q(rotation, LbaVec3(0,1,0)); physo->RotateTo(Q); }
/*********************************************************** update with external info ***********************************************************/ void ExternalPlayer::UpdateMove(double updatetime, const LbaNet::PlayerMoveInfo &info, bool teleport) { // set free move _freemove = true; if(updatetime > _last_update) { std::stringstream strs; strs<<"Updating external player move with anim"<<info.AnimationIdx; LogHandler::getInstance()->LogToFile(strs.str(), _character->GetId()); // update imediatly modifiable states _last_update = updatetime; _shouldupdate = true; if(!_playingscript) { boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); _velocityX = info.CurrentSpeedX; _velocityY = info.CurrentSpeedY; _velocityZ = info.CurrentSpeedZ; _velocityR = info.CurrentSpeedRotation; bool finishedmove = false; if(teleport || (abs(_velocityX) < 0.000001f && abs(_velocityY) < 0.000001f && abs(_velocityZ) < 0.000001f)) { finishedmove = true; physo->SetPosition(info.CurrentPos.X, info.CurrentPos.Y, info.CurrentPos.Z); } if(teleport || (abs(_velocityR) < 0.00001f)) { LbaQuaternion Q(info.CurrentPos.Rotation, LbaVec3(0,1,0)); physo->RotateTo(Q); // do not need to update if no rotation and no rotation if(finishedmove) { _shouldupdate = false; } } } // update dead reckon for the rest _dr.Set(info.CurrentPos.X, info.CurrentPos.Y, info.CurrentPos.Z, info.CurrentPos.Rotation, info.CurrentSpeedX, info.CurrentSpeedY, info.CurrentSpeedZ, info.CurrentSpeedRotation); //update animation if(info.AnimationIdx != "") _character->GetDisplayObject()->Update(new LbaNet::AnimationStringUpdate(info.AnimationIdx), _playingscript); } }
/*********************************************************** get direction vector ***********************************************************/ LbaVec3 LbaQuaternion::GetDirection(const LbaVec3 &vec) { NxVec3 dir(vec.x, vec.y, vec.z); NxQuat current; current.setXYZW(X, Y, Z, W); current.rotate(dir); return LbaVec3(dir.x, dir.y, dir.z); }
/*********************************************************** used by lua to get an actor Position ***********************************************************/ LbaVec3 NPCHandler::GetActorPosition(bool fromattackscript) { if(fromattackscript && _freemove) { if(_character) { boost::shared_ptr<PhysicalObjectHandlerBase> physO = _character->GetPhysicalObject(); if(physO) { float X, Y, Z; physO->GetPosition(X, Y, Z); return LbaVec3(X, Y, Z); } } return LbaVec3(); } else return ActorHandler::GetActorPosition(fromattackscript); }
//! update sound with position void DynamicObject::UpdateSoundPosition() { if(_phH && _soundH) { float posX, posY, posZ; LbaQuaternion Quat; _phH->GetPosition(posX, posY, posZ); _phH->GetRotation(Quat); LbaVec3 ldX(Quat.GetDirection(LbaVec3(0, 0, 1))); _soundH->Update(posX, posY, posZ, ldX.x, ldX.y, ldX.z); } }
/*********************************************************** untarget ***********************************************************/ void ExternalActor::UnTarget() { if(_targetting) { _currentScripts = _targetsavedScripts; if(!_playingscript) { boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); LbaQuaternion Q(_targetsavedangle, LbaVec3(0, 1, 0)); physo->SetRotation(Q); } _targetsavedScripts = boost::shared_ptr<ScriptPartBase>(); _targetting = false; } }
/*********************************************************** when update npc position ***********************************************************/ void ExternalActor::NpcChangedUpdate(double updatetime, float CurrPosX, float CurrPosY, float CurrPosZ, float CurrRotation, const std::string &CurrAnimation, bool ResetPosition, bool ResetRotation, const LbaNet::PlayingSoundSequence &Sounds, LbaNet::NpcUpdateBasePtr Update, ScriptEnvironmentBase* scripthandler) { // reset free move _freemove = false; // reset projectiles if(_character) _character->ClearActionsOnAnimation(); // update only newest info if(updatetime < _last_update) return; _last_update = updatetime; if(_playingscript) return; boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); float posX, posY, posZ; physo->GetPosition(posX, posY, posZ); float rotation = physo->GetRotationYAxis(); // update position and rotation float diffpos = (CurrPosX-posX)*(CurrPosX-posX) + (CurrPosY-posY)*(CurrPosY-posY) + (CurrPosZ-posZ)*(CurrPosZ-posZ); float diffrot = abs(CurrRotation-rotation); // reset actor position if(ResetPosition || diffpos > 64 || _shouldreset) { physo->SetPosition(CurrPosX, CurrPosY, CurrPosZ); posX = CurrPosX; posY = CurrPosY; posZ = CurrPosZ; } // reset actor rotation if(ResetRotation || diffrot > 20 || _shouldreset) { LbaQuaternion Q(CurrRotation, LbaVec3(0,1,0)); physo->SetRotation(Q); rotation = CurrRotation; } _differencePosX = CurrPosX-posX; _differencePosY = CurrPosY-posY; _differencePosZ = CurrPosZ-posZ; _differenceRotation = CurrRotation-rotation; //update animation if(CurrAnimation != "") _character->GetDisplayObject()->Update(new LbaNet::AnimationStringUpdate(CurrAnimation), _playingscript); _shouldreset = false; // update sounds boost::shared_ptr<SoundObjectHandlerBase> soundo = _character->GetSoundObject(); if(soundo) { soundo->SetSoundVector(Sounds, false); _character->UpdateSoundPosition(); } // update the script part if(!Update) { _currentScripts = boost::shared_ptr<ScriptPartBase>(); return; } LbaNet::NpcUpdateBase & obj = *Update; const std::type_info& info = typeid(obj); // StraightWalkToNpcUpd if(info == typeid(LbaNet::StraightWalkToNpcUpd)) { LbaNet::StraightWalkToNpcUpd * castedptr = dynamic_cast<LbaNet::StraightWalkToNpcUpd *>(&obj); _currentScripts = boost::shared_ptr<ScriptPartBase>(new StraightWalkToScriptPart(0, false, castedptr->PosX, castedptr->PosY, castedptr->PosZ, _character)); return; } if(info == typeid(LbaNet::WalkToPointNpcUpd)) { LbaNet::WalkToPointNpcUpd * castedptr = dynamic_cast<LbaNet::WalkToPointNpcUpd *>(&obj); _currentScripts = boost::shared_ptr<ScriptPartBase>(new WalkToPointScriptPart(0, false, castedptr->PosX, castedptr->PosY, castedptr->PosZ, castedptr->RotationSpeedPerSec, castedptr->moveForward)); return; } // GoToNpcUpd if(info == typeid(LbaNet::GoToNpcUpd)) { LbaNet::GoToNpcUpd * castedptr = dynamic_cast<LbaNet::GoToNpcUpd *>(&obj); _currentScripts = boost::shared_ptr<ScriptPartBase>(new GoToScriptPart(0, false, castedptr->PosX, castedptr->PosY, castedptr->PosZ, castedptr->Speed, _character)); return; } // RotateNpcUpd if(info == typeid(LbaNet::RotateNpcUpd)) { LbaNet::RotateNpcUpd * castedptr = dynamic_cast<LbaNet::RotateNpcUpd *>(&obj); _currentScripts = boost::shared_ptr<ScriptPartBase>(new RotateScriptPart(0, false, castedptr->Angle, castedptr->RotationSpeedPerSec, castedptr->ManageAnimation)); return; } // AnimateNpcUpd if(info == typeid(LbaNet::AnimateNpcUpd)) { LbaNet::AnimateNpcUpd * castedptr = dynamic_cast<LbaNet::AnimateNpcUpd *>(&obj); _currentScripts = boost::shared_ptr<ScriptPartBase>(new PlayAnimationScriptPart(0, false, castedptr->AnimationMove, castedptr->NbAnimation)); return; } // RotateFromPointNpcUpd if(info == typeid(LbaNet::RotateFromPointNpcUpd)) { LbaNet::RotateFromPointNpcUpd * castedptr = dynamic_cast<LbaNet::RotateFromPointNpcUpd *>(&obj); _currentScripts = boost::shared_ptr<ScriptPartBase>(new RotateFromPointScriptPart(0, false, castedptr->Angle, castedptr->PosX, castedptr->PosY, castedptr->PosZ, castedptr->Speed, _character)); return; } // FollowWaypointNpcUpd if(info == typeid(LbaNet::FollowWaypointNpcUpd)) { LbaNet::FollowWaypointNpcUpd * castedptr = dynamic_cast<LbaNet::FollowWaypointNpcUpd *>(&obj); LbaVec3 Pm1X(castedptr->Pm1X, castedptr->Pm1Y, castedptr->Pm1Z); LbaVec3 P0(castedptr->P0X, castedptr->P0Y, castedptr->P0Z); LbaVec3 P1(castedptr->P1X, castedptr->P1Y, castedptr->P1Z); LbaVec3 P2(castedptr->P2X, castedptr->P2Y, castedptr->P2Z); LbaVec3 P3(castedptr->P3X, castedptr->P3Y, castedptr->P3Z); LbaVec3 P4(castedptr->P4X, castedptr->P4Y, castedptr->P4Z); _currentScripts = boost::shared_ptr<ScriptPartBase>(new FollowWaypointScriptPart(0, false, Pm1X, P0, P1, P2, P3, P4)); return; } }
/*********************************************************** process child ***********************************************************/ void NPCHandler::ProcessChild(double tnow, float tdiff) { bool animfinished = false; // process attack script if(_fightscriptrunning) { //process NPC animation int pout = _character->Process(tnow, tdiff); animfinished = (pout == 1); if(_weaponanimating) { // wait until prepare weapon anim finished before processing with attack script if(animfinished) _weaponanimating = false; } else { if(!_fightscriptpartrunning && m_scripthandler && m_attackfunctionname != "") m_scripthandler->RunAttackScript(GetId(), m_attackfunctionname); } } else { //process char in case we are not scripted if(m_paused || m_launchedscript < 0) { int pout = _character->Process(tnow, tdiff); animfinished = (pout == 1); } } //target players that are too close if(_aggresive && _targetedattackplayer < 0) { //todo - target player that are too close } //flag saying if we should move according to animations bool movewithanimation = false; //in case of hurt if(_agentstatenum == 2) { if(animfinished) { #ifdef _DEBUG_NPC_ filecheck<<SynchronizedTimeHandler::GetTimeString()<<" "<<"hurt finished"<<std::endl; #endif // revert back to previous state if(ChangeState(_savedstate)) UpdateActorAnimation(_savedanim, false, false); } else movewithanimation = true; } // in case of use weapon if(_agentstatenum == 6) { if(animfinished) { #ifdef _DEBUG_NPC_ filecheck<<SynchronizedTimeHandler::GetTimeString()<<" "<<"use weapon finished"<<std::endl; #endif //stop hurt player m_currenthitpower = -1; _immuneplayers.clear(); // inform script YieldRunningScript(); } else movewithanimation = true; } // in case we rotate to target if(_agentstatenum == 7) { float rotdiff = GetTargetRotationDiff(); if(fabs(rotdiff) <= m_rotationtargettolerance) { #ifdef _DEBUG_NPC_ filecheck<<SynchronizedTimeHandler::GetTimeString()<<" "<<"rotate finished"<<std::endl; #endif // inform script YieldRunningScript(); } else { //rotate to direction boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); if(physo) { if((rotdiff > 0 && rotdiff < 180) || (rotdiff < -180)) physo->RotateYAxis(std::min((m_rotationtargetspeed*tdiff), (float)(fabs(rotdiff)))); else physo->RotateYAxis(std::max((-m_rotationtargetspeed*tdiff), (float)(-fabs(rotdiff)))); } } } // move agent depending of animation if(movewithanimation) { boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); boost::shared_ptr<DisplayObjectHandlerBase> disso = _character->GetDisplayObject(); // get animation speed float speedX = disso->GetCurrentAssociatedSpeedX(); float speedY = disso->GetCurrentAssociatedSpeedY(); float speedZ = disso->GetCurrentAssociatedSpeedZ(); LbaQuaternion Q; physo->GetRotation(Q); LbaVec3 current_directionX(Q.GetDirection(LbaVec3(0, 0, 1))); LbaVec3 current_directionZ(Q.GetDirection(LbaVec3(1, 0, 0))); float ajustedspeedx = speedX*current_directionX.x + speedZ*current_directionZ.x; float ajustedspeedZ = speedX*current_directionX.z + speedZ*current_directionZ.z; if(speedX != 0 || speedY != 0 || speedZ != 0) physo->Move(ajustedspeedx*tdiff, speedY*tdiff, ajustedspeedZ*tdiff, false); } //if dead - respawn if(_agentState->IsDead() && _respwantime >= 0) { if((tnow - _dietime) > (_respwantime*1000)) { Respawn(); } } //if chasing if(_agentstatenum == 4) { // check if we arrive at destination if(IsTargetInRange(m_minimalchasingdistance)) { // inform script YieldRunningScript(); } else { //check if did not get stuck if((tnow-_lastchasingchecktime) > 500) { boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); if(physo) { float checkX, checkY, checkZ; physo->GetPosition(checkX, checkY, checkZ); float diff = fabs(checkX-_lastchasingcheckposX) + fabs(checkY-_lastchasingcheckposY) + fabs(checkZ-_lastchasingcheckposZ); if(diff < 0.3f) { //reset target if(_targetedattackplayer > 0 && m_NavMAgent && m_scripthandler) { LbaVec3 pos = m_scripthandler->GetPlayerPositionVec((long)_targetedattackplayer); m_NavMAgent->SetTargetPosition(false, pos.x, pos.y, pos.z); } } _lastchasingcheckposX = checkX; _lastchasingcheckposY = checkY; _lastchasingcheckposZ = checkZ; } _lastchasingchecktime = tnow; } } } //if coming back if(_agentstatenum == 5) { //check if we arrived boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); if(physo) { float curX, curY, curZ; physo->GetPosition(curX, curY, curZ); float diff = fabs(m_saved_X-curX) + fabs(m_saved_Y-curY) + fabs(m_saved_Z-curZ); if(diff <= 0.6f) { //rotate back to starting point ChangeState(8); } else if((tnow-_lastchasingchecktime) > 500)//check if did not get stuck { float difftt = fabs(curX-_lastchasingcheckposX) + fabs(curY-_lastchasingcheckposY) + fabs(curZ-_lastchasingcheckposZ); //reset target if(difftt < 0.3f && m_NavMAgent) { ++_counterresetchasing; if(_counterresetchasing >= 8) { //stop chasing if we get stuck too long ChangeState(8); } else m_NavMAgent->SetTargetPosition(false, m_saved_X, m_saved_Y, m_saved_Z); } _lastchasingcheckposX = curX; _lastchasingcheckposY = curY; _lastchasingcheckposZ = curZ; _lastchasingchecktime = tnow; } } } //if rotating back if(_agentstatenum == 8) { //check if we arrived boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); if(physo) { float currrot = physo->GetRotationYAxis(); float rdiff = fmod((m_saved_rot - currrot), 360); if(rdiff > 180) rdiff = rdiff - 360; if(rdiff < -180) rdiff = rdiff + 360; if(fabs(rdiff) <= 4) { EndChasing(); } else { //rotate to direction if((rdiff > 0 && rdiff < 180) || (rdiff < -180)) physo->RotateYAxis(std::min((0.1f*tdiff), (float)(fabs(rdiff)))); else physo->RotateYAxis(std::max((-0.1f*tdiff), (float)(-fabs(rdiff)))); } } } }
/*********************************************************** sphere sphere sweep test ***********************************************************/ bool CollisionTester::SphereSphereSweep(const float ra, //radius of sphere A const LbaVec3& A0, //previous position of sphere A const LbaVec3& A1, //current position of sphere A const float rb, //radius of sphere B const LbaVec3& B0, //previous position of sphere B const LbaVec3& B1, //current position of sphere B float& u0, //normalized time of first collision float& u1 //normalized time of second collision ) { //vector from A0 to A1 const LbaVec3 va = A1 - A0; //vector from B0 to B1 const LbaVec3 vb = B1 - B0; //vector from A0 to B0 const LbaVec3 AB = B0 - A0; //relative velocity (in normalized time) const LbaVec3 vab = vb - va; const float rab = ra + rb; const float ab2 = AB.dot(AB); const float rab2 = rab*rab; const float fpdot2 = AB.dot(LbaVec3(0,0,0)-vab); //check if they're currently overlapping if( ab2 <= rab2 ) { u0 = 0; u1 = 0; return true; } //TODO - doesnt work... // //u*u coefficient // const float a = vab.dot(vab); // //u coefficient // const float b = 2*fpdot2;//vab.dot(AB); // //constant term // const float c = ab2 - rab2; // //check if they hit each other // // during the frame // if( QuadraticFormula( a, b, c, u0, u1 ) ) // { // if( u0 > u1 ) // SWAP( u0, u1 ); //if(u1 > 1) // return false; //if(u0 < 0) // return false; // return true; // } return false; }
/*********************************************************** operator - ***********************************************************/ LbaVec3 LbaVec3::operator -(const LbaVec3 & q) const { return LbaVec3(x-q.x, y-q.y, z-q.z); }
/*********************************************************** do all check to be done when idle ***********************************************************/ void ExternalPlayer::Process(double tnow, float tdiff, ScriptEnvironmentBase* scripthandler) { if(_playingscript) { // process script if(!ProcessScript(tnow, tdiff, scripthandler)) { // if not moved - move with attached actor if(_attachedactor) { boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); boost::shared_ptr<PhysicalObjectHandlerBase> attchedphys = _attachedactor->GetPhysicalObject(); if(physo && attchedphys) { physo->RotateYAxis(attchedphys->GetLastRotation()); float addspeedX=0, addspeedY=0, addspeedZ=0; attchedphys->GetLastMove(addspeedX, addspeedY, addspeedZ); physo->Move(addspeedX, addspeedY, addspeedZ); } } } //still update dead recon _dr.Update(tnow, tdiff); return; } //update display and animation _character->Process(tnow, tdiff); if(_shouldupdate) { boost::shared_ptr<PhysicalObjectHandlerBase> physo = _character->GetPhysicalObject(); // calculate prediction float predicted_posX, predicted_posY, predicted_posZ; physo->GetPosition(predicted_posX, predicted_posY, predicted_posZ); predicted_posX += (_velocityX*tdiff); predicted_posY += (_velocityY*tdiff); predicted_posZ += (_velocityZ*tdiff); float predicted_rotation = physo->GetRotationYAxis() + (_velocityR*tdiff); // calculate dead reckon _dr.Update(tnow, tdiff); //// do interpolation X { float diffX = (_dr._predicted_posX - predicted_posX); if(fabs(diffX) > 8) predicted_posX = _dr._predicted_posX; else predicted_posX += diffX / 40; } //// do interpolation Y { float diffY = (_dr._predicted_posY - predicted_posY); if(fabs(diffY) > 8) predicted_posY = _dr._predicted_posY; else predicted_posY += diffY / 40; } //// do interpolation Z { float diffZ = (_dr._predicted_posZ - predicted_posZ); if(fabs(diffZ) > 8) predicted_posZ = _dr._predicted_posZ; else predicted_posZ += diffZ / 40; } //// do interpolation rotation { float diffR = (_dr._predicted_rotation - predicted_rotation); if(fabs(diffR) > 20) predicted_rotation = _dr._predicted_rotation; else predicted_rotation += diffR / 5; } physo->MoveTo(predicted_posX, predicted_posY, predicted_posZ); LbaQuaternion Q(predicted_rotation, LbaVec3(0,1,0)); physo->RotateTo(Q); } }