double Character::GetSPPerMin(SkillRef skill) const { double primaryVal = attributes.GetReal( (EVEAttributeMgr::Attr)skill->primaryAttribute() ); double secondaryVal = attributes.GetReal( (EVEAttributeMgr::Attr)skill->secondaryAttribute() ); uint8 skillLearningLevel = 0; //3374 - Skill Learning SkillRef skillLearning = GetSkill( 3374 ); if( skillLearning ) skillLearningLevel = skillLearning->skillLevel(); return (primaryVal + secondaryVal / 2.0) * (1.0 + 0.02 * skillLearningLevel) * 2.0; /* this is hacky and should be applied only if total SP < 1.6M */ }
void Character::UpdateSkillQueue() { Client *c = m_factory.entity_list.FindCharacter( itemID() ); SkillRef currentTraining = GetSkillInTraining(); if( currentTraining ) { if( m_skillQueue.empty() || currentTraining->typeID() != m_skillQueue.front().typeID ) { // either queue is empty or skill with different typeID is in training ... // stop training: _log( ITEM__ERROR, "%s (%u): Stopping training of skill %s (%u).", itemName().c_str(), itemID(), currentTraining->itemName().c_str(), currentTraining->itemID() ); uint64 timeEndTrain = currentTraining->expiryTime(); if(timeEndTrain != 0) { double nextLevelSP = currentTraining->GetSPForLevel( currentTraining->skillLevel() + 1 ); double SPPerMinute = GetSPPerMin( currentTraining ); double minRemaining = (double)(timeEndTrain - Win32TimeNow()) / (double)Win32Time_Minute; currentTraining->Set_skillPoints( nextLevelSP - (minRemaining * SPPerMinute) ); } currentTraining->Clear_expiryTime(); currentTraining->MoveInto( *this, flagSkill, true ); if( c != NULL ) { OnSkillTrainingStopped osst; osst.itemID = currentTraining->itemID(); osst.endOfTraining = 0; PyTuple* tmp = osst.Encode(); c->QueueDestinyEvent( &tmp ); PySafeDecRef( tmp ); c->UpdateSkillTraining(); } // nothing currently in training currentTraining = SkillRef(); } } uint64 nextStartTime = Win32TimeNow(); while( !m_skillQueue.empty() ) { if( !currentTraining ) { // something should be trained, get desired skill uint32 skillTypeID = m_skillQueue.front().typeID; currentTraining = GetSkill( skillTypeID ); if( !currentTraining ) { _log( ITEM__ERROR, "%s (%u): Skill %u to train was not found.", itemName().c_str(), itemID(), skillTypeID ); break; } _log( ITEM__TRACE, "%s (%u): Starting training of skill %s (%u).", m_itemName.c_str(), m_itemID, currentTraining->itemName().c_str(), currentTraining->itemID() ); double SPPerMinute = GetSPPerMin( currentTraining ); double SPToNextLevel = currentTraining->GetSPForLevel( currentTraining->skillLevel() + 1 ) - currentTraining->skillPoints(); uint64 timeTraining = nextStartTime + Win32Time_Minute * SPToNextLevel / SPPerMinute; currentTraining->MoveInto( *this, flagSkillInTraining ); currentTraining->Set_expiryTime( timeTraining ); if( c != NULL ) { OnSkillStartTraining osst; osst.itemID = currentTraining->itemID(); osst.endOfTraining = timeTraining; PyTuple* tmp = osst.Encode(); c->QueueDestinyEvent( &tmp ); PySafeDecRef( tmp ); c->UpdateSkillTraining(); } } if( currentTraining->expiryTime() <= Win32TimeNow() ) { // training has been finished: _log( ITEM__ERROR, "%s (%u): Finishing training of skill %s (%u).", itemName().c_str(), itemID(), currentTraining->itemName().c_str(), currentTraining->itemID() ); currentTraining->Set_skillLevel( currentTraining->skillLevel() + 1 ); currentTraining->Set_skillPoints( currentTraining->GetSPForLevel( currentTraining->skillLevel() ) ); nextStartTime = currentTraining->expiryTime(); currentTraining->Clear_expiryTime(); currentTraining->MoveInto( *this, flagSkill, true ); if( c != NULL ) { OnSkillTrained ost; ost.itemID = currentTraining->itemID(); PyTuple* tmp = ost.Encode(); c->QueueDestinyEvent( &tmp ); PySafeDecRef( tmp ); c->UpdateSkillTraining(); } // erase first element in skill queue m_skillQueue.erase( m_skillQueue.begin() ); // nothing currently in training currentTraining = SkillRef(); } // else the skill is in training ... else break; } SaveSkillQueue(); }