// CharacterStats.cpp : Implementation of cCharacterStats #include "stdafx.h" #include "DecalFilters.h" #include "CharacterStats.h" #include "AllegianceInfo.h" #include "AttributeInfo.h" #include "SkillInfo.h" #include "Enchantment.h" #include ///////////////////////////////////////////////////////////////////////////// // cCharacterStats #include #include #include struct stSkillInfo { LPTSTR Name; long AttribA, AttribB; long Divider; int TrainStyle; }; const DWORD PrimStatArray[] = { 0, 110,277,501,784,1125,1527,1988,2511,3097,3746,4459,5238,6084,6998,7982,9038,10167,11372,12654,14015,15459,16988,18604,20311,22113,24012,26014,28122,30341,32676,35132,37716,40434,43293,46301,49465,52795,56300,59991,63878,67975,72295,76851,81659,86737,92102,97775,103775,110128,116858,123991,131559,139591,148124,157194,166843,177113,188053,199715,212153,225429,239609,254762,270967,288306,306870,326756,348070,370928,395453,421779,450054,480434,513091,548210,585992,626654,670432,717582,768378,823122,882136,945773,1014414,1088469,1168386,1254649,1347781,1448351,1556972,1674311,1801089,1938088,2086155,2246205,2419233,2606314,2808613,3027394,3264023,3519983,3796877,4096444,4420567,4771285,5150808,5561528,6006039,6487148,7007896,7571580,8181768,8842327,9557443,10331656,11169877,12077431,13060084,14124082,15276190,16523738,17874666,19337572,20921773,22637359,24495261,26507320,28686361,31046278,33602120,36370190,39368147,42615120,46131828,49940719,54066105,58534323,63373901,68615745,74293328,80442912,87103777,94318471,102133083,110597540,119765922,129696811,140453665,152105222,164725942,178396483,193204214,209243776,226617688,245437001,265822007,287903011,311821164,337729361,365793227,396192167,429120520,464788799,503425038,545276249,590610001,639716134,692908610,750527522,812941268,880548904,953782704,1033110914,1119040753,1212121655,1312948783,1422166831,1540474151,1668627219,1807445467,1957816530,2120701915,2297143157,2488268472,2695299977,2919561502,3162487055,3425629996,3710672964,4019438644 }; const DWORD SecondaryStatArray[] = { 0, 73,183,331,517,743,1008,1312,1658,2044,2472,2943,3457,4015,4619,5268,5965,6711,7505,8352,9250,10203,11212,12279,13406,14595,15848,17169,18561,20025,21566,23187,24893,26687,28574,30559,32647,34845,37158,39594,42160,44864,47715,50722,53895,57247,60788,64531,68492,72685,77126,81834,86829,92130,97762,103748,110116,116895,124115,131812,140021,148784,158142,168143,178838,190282,202534,215659,229726,244812,260999,278375,297036,317087,338640,361819,386755,413592,442486,473604,507130,543260,582210,624211,669513,718390,771135,828069,889536,955912,1027602,1105046,1188719,1279139,1376862,1482495,1596694,1720167,1853685,1998080,2154256,2323189,2505939,2703654,2917575,3149049,3399533,3670609,3963986,4281518,4625212,4997243,5399967,5835936,6307913,6818893,7372119,7971105,8619656,9321894,10082286,10905668,11797280,12762798,13808370,14940657,16166873,17494831,18932998,20490543,22177399,24004326,25982977,28125979,30447007,32960875,35683629,38632653,41826775,45286392,49033597,53092322,57488493,62250191,67407835,72994377,79045509,85599896,92699419,100389447,108719122,117741679,127514781,138100892,149567674,161988421,175442525,190015988,205801968,222901379,241423530,261486830,283219543,306760608,332260525,359882324,389802601,422212649,457319683,495348165,536541237,581162277,629496585,681853203,738566897,800000293,866546197,938630108,1016712940,1101293965,1192914009,1292158910,1399663264,1516114484,1642257192,1778897985,1926910591,2087241457,2260915797,2449044157,2652829505,2873574933,3112691986,3371709687,3652284316,3956210003,4285430197 }; static stSkillInfo SkillInfo[] = { { _T( "Unknown" ), eAttrNULL, eAttrNULL, 1, eTrainUnusable }, { _T( "Axe" ), eAttrStrength, eAttrCoordination, 3, eTrainUnusable }, { _T( "Bow" ), eAttrCoordination, eAttrNULL, 2, eTrainUnusable }, { _T( "Crossbow" ), eAttrCoordination, eAttrNULL, 2, eTrainUnusable }, { _T( "Dagger" ), eAttrQuickness, eAttrCoordination, 3, eTrainUnusable }, { _T( "Mace" ), eAttrStrength, eAttrCoordination, 3, eTrainUnusable }, { _T( "Melee Defense" ), eAttrQuickness, eAttrCoordination, 3, eTrainUnusable }, { _T( "Missile Defense" ), eAttrQuickness, eAttrCoordination, 5, eTrainUnusable }, { _T( "Unknown" ), eAttrNULL, eAttrNULL, 1, eTrainUnusable }, { _T( "Spear" ), eAttrStrength, eAttrCoordination, 3, eTrainUnusable }, { _T( "Staff" ), eAttrStrength, eAttrCoordination, 3, eTrainUnusable }, { _T( "Sword" ), eAttrStrength, eAttrCoordination, 3, eTrainUnusable }, { _T( "Thrown Weapons" ), eAttrCoordination, eAttrNULL, 2, eTrainUnusable }, { _T( "Unarmed Combat" ), eAttrStrength, eAttrCoordination, 3, eTrainUnusable }, { _T( "Arcane Lore" ), eAttrFocus, eAttrNULL, 3, eTrainUnusable }, { _T( "Magic Defense" ), eAttrFocus, eAttrSelf, 7, eTrainUnusable }, { _T( "Mana Conversion" ), eAttrFocus, eAttrSelf, 6, eTrainUnusable }, { _T( "Unknown" ), eAttrNULL, eAttrNULL, 1, eTrainUnusable }, { _T( "Item Tinkering" ), eAttrFocus, eAttrCoordination, 2, eTrainUnusable }, { _T( "Assess Person" ), eAttrFocus, eAttrSelf, 2, eTrainUnusable }, { _T( "Deception" ), eAttrFocus, eAttrSelf, 4, eTrainUnusable }, { _T( "Healing" ), eAttrFocus, eAttrCoordination, 3, eTrainUnusable }, { _T( "Jump" ), eAttrStrength, eAttrCoordination, 2, eTrainUnusable }, { _T( "Lockpick" ), eAttrFocus, eAttrCoordination, 3, eTrainUnusable }, { _T( "Run" ), eAttrQuickness, eAttrNULL, 1, eTrainUnusable }, { _T( "Unknown" ), eAttrNULL, eAttrNULL, 1, eTrainUnusable }, { _T( "Unknown" ), eAttrNULL, eAttrNULL, 1, eTrainUnusable }, { _T( "Assess Creature" ), eAttrFocus, eAttrSelf, 2, eTrainUnusable }, { _T( "Weapon Tinkering" ), eAttrFocus, eAttrStrength, 2, eTrainUnusable }, { _T( "Armor Tinkering" ), eAttrFocus, eAttrEndurance, 2, eTrainUnusable }, { _T( "Magic Item Tinkering" ), eAttrFocus, eAttrNULL, 1, eTrainUnusable }, { _T( "Creature Enchantment" ), eAttrFocus, eAttrSelf, 4, eTrainUnusable }, { _T( "Item Enchantment" ), eAttrFocus, eAttrSelf, 4, eTrainUnusable }, { _T( "Life Magic" ), eAttrFocus, eAttrSelf, 4, eTrainUnusable }, { _T( "War Magic" ), eAttrFocus, eAttrSelf, 4, eTrainUnusable }, { _T( "Leadership" ), eAttrSelf, eAttrNULL, 4, eTrainUnusable }, { _T( "Loyalty" ), eAttrSelf, eAttrNULL, 4, eTrainUnusable }, { _T( "Fletching" ), eAttrFocus, eAttrCoordination, 3, eTrainUnusable }, { _T( "Alchemy" ), eAttrFocus, eAttrCoordination, 3, eTrainUnusable }, { _T( "Cooking" ), eAttrFocus, eAttrCoordination, 3, eTrainUnusable } }; STDMETHODIMP cCharacterStats::Initialize(INetService *pService) { m_pService = pService; m_pService->get_Decal( &m_pDecal ); SpellsLearned.clear(); Enchantments.clear(); GotLogin = false; GotAlleg = false; memset( Name, 0, sizeof( Name ) ); memset( Gender, 0, sizeof( Gender ) ); memset( Race, 0, sizeof( Race ) ); memset( Class, 0, sizeof( Class ) ); memset( Server, 0, sizeof( Server ) ); memset( PrimStat, 0, sizeof( PrimStat ) ); memset( PrimStatInitial, 0, sizeof( PrimStatInitial ) ); memset( SecStatInc, 0, sizeof( SecStatInc ) ); memset( SkillInc, 0, sizeof( SkillInc ) ); memset( SkillTrain, 0, sizeof( SkillTrain ) ); memset( SkillXP, 0, sizeof( SkillXP ) ); memset( SkillBonus, 0, sizeof( SkillBonus ) ); memset( &MyAlleg, 0, sizeof( MyAlleg ) ); memset( &Monarch, 0, sizeof( Monarch ) ); memset( &Patron, 0, sizeof( Patron ) ); memset( Vassals, 0, sizeof( Vassals ) ); TotalBurden = 0; TotalPyreal = 0; TotalXP = 0; UnassignedXP = 0; SkillPoints = 0; Level = 0; Rank = 0; Deaths = 0; Birth = 0; Age = 0; Vitae = 1.0f; DrainRange = 0.0f; HarmRange = 0.0f; GUID = 0; VassalCount = 0; Followers = 0; MonarchFollowers = 0; return S_OK; } STDMETHODIMP cCharacterStats::Terminate() { m_pService.Release(); m_pDecal.Release(); return S_OK; } STDMETHODIMP cCharacterStats::DispatchClient(IMessage2 *pMsg) { return S_OK; } STDMETHODIMP cCharacterStats::DispatchServer(IMessage2 *pMessage) { USES_CONVERSION; long dwType; pMessage->get_Type( &dwType ); switch( dwType ) { case 0xF746: // Character Entering World { _variant_t vObjectID; pMessage->get_Member (_variant_t ("character"), &vObjectID); GUID = vObjectID.lVal; break; } case 0xF659: // Login Failure - Char in World { GotLogin = false; GotAlleg = false; memset( Name, 0, sizeof( Name ) ); memset( Gender, 0, sizeof( Gender ) ); memset( Race, 0, sizeof( Race ) ); memset( Class, 0, sizeof( Class ) ); memset( PrimStat, 0, sizeof( PrimStat ) ); memset( PrimStatInitial, 0, sizeof( PrimStatInitial ) ); memset( SecStatInc, 0, sizeof( SecStatInc ) ); memset( SkillInc, 0, sizeof( SkillInc ) ); memset( SkillTrain, 0, sizeof( SkillTrain ) ); memset( SkillXP, 0, sizeof( SkillXP ) ); memset( SkillBonus, 0, sizeof( SkillBonus ) ); memset( &MyAlleg, 0, sizeof( MyAlleg ) ); memset( &Monarch, 0, sizeof( Monarch ) ); memset( &Patron, 0, sizeof( Patron ) ); memset( Vassals, 0, sizeof( Vassals ) ); TotalBurden = 0; TotalPyreal = 0; TotalXP = 0; UnassignedXP = 0; SkillPoints = 0; Level = 0; Rank = 0; Deaths = 0; Birth = 0; Age = 0; Vitae = 1.0f; DrainRange = 0.0f; HarmRange = 0.0f; GUID = 0; VassalCount = 0; Followers = 0; MonarchFollowers = 0; SpellsLearned.clear(); Enchantments.clear(); break; } case 0xF653: // End 3d Mode { GotLogin = false; GotAlleg = false; memset( Name, 0, sizeof( Name ) ); memset( Gender, 0, sizeof( Gender ) ); memset( Race, 0, sizeof( Race ) ); memset( Class, 0, sizeof( Class ) ); memset( PrimStat, 0, sizeof( PrimStat ) ); memset( PrimStatInitial, 0, sizeof( PrimStatInitial ) ); memset( SecStatInc, 0, sizeof( SecStatInc ) ); memset( SkillInc, 0, sizeof( SkillInc ) ); memset( SkillTrain, 0, sizeof( SkillTrain ) ); memset( SkillXP, 0, sizeof( SkillXP ) ); memset( SkillBonus, 0, sizeof( SkillBonus ) ); memset( &MyAlleg, 0, sizeof( MyAlleg ) ); memset( &Monarch, 0, sizeof( Monarch ) ); memset( &Patron, 0, sizeof( Patron ) ); memset( Vassals, 0, sizeof( Vassals ) ); TotalBurden = 0; TotalPyreal = 0; TotalXP = 0; UnassignedXP = 0; SkillPoints = 0; Level = 0; Rank = 0; Deaths = 0; Birth = 0; Age = 0; Vitae = 1.0f; DrainRange = 0.0f; HarmRange = 0.0f; GUID = 0; VassalCount = 0; Followers = 0; MonarchFollowers = 0; SpellsLearned.clear(); Enchantments.clear(); break; } case 0xF65A: // MOTD ? { _variant_t vMess; pMessage->get_Member( _variant_t ("message"), &vMess); memcpy(Server, OLE2T( vMess.bstrVal ) + 24, sizeof( Server ) ); //char *szPeriod = strstr( Server, "." ); // para - fix for the ever changing dt motd char * szLf = strstr( Server, "\n" ); //if( szPeriod ) // *szPeriod = 0; if ( szLf ) { *(--szLf) = 0; // seems ac uses /r/n, but strstr for /r didn't work in testing if (*(--szLf) == '.') *szLf = 0; //check for spaces (eff u dt!!!) szLf = strstr(Server, " "); if (szLf) *szLf = 0; } else //something went wrong, put "Unknown" strncpy(Server, "Unknown\0", 8); break; } case 0x0244: // Update Vital Statistic { _variant_t vStat; _variant_t vValue; pMessage->get_Member (_variant_t ("vital"), &vStat); _ASSERTE(vStat.vt == VT_I4); pMessage->get_Member (_variant_t ("value"), &vValue); _ASSERTE(vValue.vt == VT_I4); switch (vStat.lVal) { case 2: //Health Health = vValue.lVal; break; case 4: //Stam Stamina = vValue.lVal; break; case 6: //Mana Mana = vValue.lVal; break; } break; } case 0xF748: // Set Position and Motion { _variant_t vGUID; pMessage->get_Member(_variant_t ("object"), &vGUID); if (vGUID.lVal == GUID) { _variant_t vLandblock, vX, vY, vZ, vW; _variant_t vLoc; pMessage->get_Member (_variant_t ("position"), &vLoc); IMessageMember *pLoc = (IMessageMember *) vLoc.pdispVal; pLoc->get_Member(_variant_t ("landblock"), &vLandblock); pLoc->get_Member(_variant_t ("xOffset"), &vX); pLoc->get_Member(_variant_t ("yOffset"), &vY); pLoc->get_Member(_variant_t ("zOffset"), &vZ); pLoc->get_Member(_variant_t ("xHeading"), &vW); Location.landblock = vLandblock.lVal; Location.x = vX.fltVal; Location.y = vY.fltVal; Location.z = vZ.fltVal; Location.w = vW.fltVal; } break; } case 0x0237: { //Update Statistic _variant_t vType, vVal, vSeq; pMessage->get_Member(_variant_t("statistic"), &vType); pMessage->get_Member(_variant_t("value"), &vVal); if (vType.lVal == 0x05) TotalBurden = vVal.lVal; else if (vType.lVal == 0x14) TotalPyreal = vVal.lVal; else if (vType.lVal == 0x15) TotalXP = vVal.lVal; else if (vType.lVal == 0x16) UnassignedXP = vVal.lVal; else if (vType.lVal == 0x18) SkillPoints = vVal.lVal; else if (vType.lVal == 0x19) Level = vVal.lVal; else if (vType.lVal == 0x1E) Rank = vVal.lVal; else if (vType.lVal == 0x2B) { Deaths = vVal.lVal; // Remove all but item based enchantments for (std::list::iterator tpi = Enchantments.begin(); tpi != Enchantments.end(); tpi++) { time_t CurrentTime = time(NULL); long SecondsLeft = (*tpi)->ExpireTime - CurrentTime; if ( SecondsLeft >= 0 ) { delete *tpi; Enchantments.erase(tpi--); } } RecalcSecStats(); RecalcSkills(); } else if (vType.lVal == 0x62) Birth = vVal.lVal; else if (vType.lVal == 0x7D) Age = vVal.lVal; break; } case 0x023E: { //Update Skill _variant_t vSkill, vInc, vTrain, vXP; pMessage->get_Member(_variant_t("skill"), &vSkill); pMessage->get_Member(_variant_t("skillOffset"), &vInc); pMessage->get_Member(_variant_t("skillTrained"), &vTrain); pMessage->get_Member(_variant_t("appliedXP"), &vXP); SkillInc[vSkill.iVal] = vInc.iVal; SkillTrain[vSkill.iVal] = vTrain.lVal; SkillXP[vSkill.iVal] = vXP.lVal; RecalcSkill(vSkill.iVal); break; } case 0x0241: { //Update Attribute _variant_t vAttrib, vNew, vStartingValue; pMessage->get_Member(_variant_t("Attribute"), &vAttrib); pMessage->get_Member(_variant_t("NewIncrement"), &vNew); pMessage->get_Member(_variant_t("StartingValue"), &vStartingValue); PrimStat[vAttrib.iVal - 1] = vNew.lVal + vStartingValue.lVal; RecalcStat(vAttrib.iVal - 1); RecalcSkills(); RecalcSecStats(); break; } case 0x0243: { //Update Secondary Attribute _variant_t vAttrib, vNew; pMessage->get_Member(_variant_t("Attribute"), &vAttrib); pMessage->get_Member(_variant_t("PointsAdded"), &vNew); SecStatInc[(vAttrib.iVal - 1) / 2] = vNew.lVal; RecalcSecStats(); break; } case 0xF7B0: // Game Event { _variant_t vEvent; pMessage->get_Member (_variant_t ("event"), &vEvent); _ASSERTE(vEvent.vt == VT_I4); switch (vEvent.intVal) { case (0x0013): // Character Login { GotLogin = true; _variant_t vObjectID; _variant_t vStrings, vSpells; _variant_t vStringCount, vSpellCount; _variant_t vName; pMessage->get_Member (_variant_t ("character"), &vObjectID); GUID = vObjectID.lVal; pMessage->get_Member (_variant_t ("countStrings"), &vStringCount); pMessage->get_Member (_variant_t ("strings"), &vStrings); for(int i = 0; i < (vStringCount.iVal); i++) { IMessageMember* pMember = (IMessageMember*) vStrings.pdispVal; _variant_t vString1; pMember->get_Member (_variant_t (long(i)), &vString1); IMessageMember* pString = (IMessageMember*) vString1.pdispVal; _variant_t vKey; pString->get_Member (_variant_t ("key"), &vKey); _variant_t vVal; pString->get_Member(_variant_t ("string"), &vVal); if (vKey.lVal == 0x01) strncpy( Name, OLE2T( vVal.bstrVal ),sizeof( Name ) ); else if (vKey.lVal == 0x03) strncpy( Gender, OLE2T( vVal.bstrVal ),sizeof( Gender ) ); else if (vKey.lVal == 0x04) strncpy( Race, OLE2T( vVal.bstrVal ),sizeof( Race ) ); else if (vKey.lVal == 0x05) strncpy( Class, OLE2T( vVal.bstrVal ),sizeof( Class ) ); } pMessage->get_Member (_variant_t ("countStats"), &vStringCount); pMessage->get_Member (_variant_t ("stats"), &vStrings); for(i = 0; i < (vStringCount.iVal); i++) { IMessageMember* pMember = (IMessageMember*) vStrings.pdispVal; _variant_t vString1; pMember->get_Member (_variant_t (long(i)), &vString1); IMessageMember* pString = (IMessageMember*) vString1.pdispVal; _variant_t vType, vVal; pString->get_Member (_variant_t ("key"), &vType); pString->get_Member (_variant_t ("value"), &vVal); if (vType.lVal == 0x05) TotalBurden = vVal.lVal; else if (vType.lVal == 0x14) TotalPyreal = vVal.lVal; else if (vType.lVal == 0x15) TotalXP = vVal.lVal; else if (vType.lVal == 0x16) UnassignedXP = vVal.lVal; else if (vType.lVal == 0x18) SkillPoints = vVal.lVal; else if (vType.lVal == 0x19) Level = vVal.lVal; else if (vType.lVal == 0x1E) Rank = vVal.lVal; else if (vType.lVal == 0x2B) Deaths = vVal.lVal; else if (vType.lVal == 0x62) Birth = vVal.lVal; else if (vType.lVal == 0x7D) Age = vVal.lVal; } //New CharInfo Stuff _variant_t G; pMessage->get_Member(_variant_t ("initialStrength"), &G); PrimStatInitial[0] = G.lVal; pMessage->get_Member(_variant_t ("initialEndurance"), &G); PrimStatInitial[1] = G.lVal; pMessage->get_Member(_variant_t ("initialQuickness"), &G); PrimStatInitial[2] = G.lVal; pMessage->get_Member(_variant_t ("initialCoordination"), &G); PrimStatInitial[3] = G.lVal; pMessage->get_Member(_variant_t ("initialFocus"), &G); PrimStatInitial[4] = G.lVal; pMessage->get_Member(_variant_t ("initialSelf"), &G); PrimStatInitial[5] = G.lVal; pMessage->get_Member(_variant_t ("incStrength"), &G); PrimStat[0] = G.lVal + PrimStatInitial[0]; CurStat[0] = PrimStat[0]; pMessage->get_Member(_variant_t ("incEndurance"), &G); PrimStat[1] = G.lVal + PrimStatInitial[1]; CurStat[1] = PrimStat[1]; pMessage->get_Member(_variant_t ("incQuickness"), &G); PrimStat[2] = G.lVal + PrimStatInitial[2]; CurStat[2] = PrimStat[2]; pMessage->get_Member(_variant_t ("incCoordination"), &G); PrimStat[3] = G.lVal + PrimStatInitial[3]; CurStat[3] = PrimStat[3]; pMessage->get_Member(_variant_t ("incFocus"), &G); PrimStat[4] = G.lVal + PrimStatInitial[4]; CurStat[4] = PrimStat[4]; pMessage->get_Member(_variant_t ("incSelf"), &G); PrimStat[5] = G.lVal + PrimStatInitial[5]; CurStat[5] = PrimStat[5]; pMessage->get_Member(_variant_t ("incHealth"), &G); SecStatInc[0] = G.lVal; pMessage->get_Member(_variant_t ("incStamina"), &G); SecStatInc[1] = G.lVal; pMessage->get_Member(_variant_t ("incMana"), &G); SecStatInc[2] = G.lVal; pMessage->get_Member(_variant_t ("currentHealth"), &G); Health = G.lVal; pMessage->get_Member(_variant_t ("currentStamina"), &G); Stamina = G.lVal; pMessage->get_Member(_variant_t ("currentMana"), &G); Mana = G.lVal; _variant_t vRecordCount, vSkills; pMessage->get_Member (_variant_t ("skillCount"), &vRecordCount); pMessage->get_Member (_variant_t ("skills"), &vSkills); ZeroMemory(SkillTrain, sizeof(SkillTrain)); for(i = 0; i < (vRecordCount.iVal); i++) { IMessageMember* pMember = (IMessageMember*) vSkills.pdispVal; _variant_t vMember1; pMember->get_Member (_variant_t (long(i)), &vMember1); IMessageMember* pRecord = (IMessageMember*) vMember1.pdispVal; _variant_t vSkillN, vSkillI, vSkillT, vSkillX, vSkillF; pRecord->get_Member(_variant_t ("skill"), &vSkillN); pRecord->get_Member(_variant_t ("increment"), &vSkillI); pRecord->get_Member(_variant_t ("trained"), &vSkillT); pRecord->get_Member(_variant_t ("exp"), &vSkillX); pRecord->get_Member(_variant_t ("bonusPoints"), &vSkillF); SkillBonus[vSkillN.iVal] = vSkillF.lVal; SkillXP[vSkillN.iVal] = vSkillX.lVal; SkillTrain[vSkillN.iVal] = vSkillT.lVal; SkillInc[vSkillN.iVal] = vSkillI.iVal; float TPS = 0; if (SkillInfo[vSkillN.iVal].AttribA != eAttrNULL) TPS += PrimStat[SkillInfo[vSkillN.iVal].AttribA]; if (SkillInfo[vSkillN.iVal].AttribB != eAttrNULL) TPS += PrimStat[SkillInfo[vSkillN.iVal].AttribB]; TPS /= SkillInfo[vSkillN.iVal].Divider; TPS += vSkillI.lVal + 0.5f; CurSkill[vSkillN.iVal] = static_cast (TPS); } //Get Spellbook CComPtr pBegin; CComPtr pSpell; CComPtr pSpellbook; pMessage->get_Begin( &pBegin ); pMessage->get_Member( _variant_t( "spellbookCount" ), &vSpellCount ); short sSpellbookCount = vSpellCount.iVal; HRESULT HRes = pBegin->get_NextObject( _bstr_t( "spellbook" ), &pSpellbook ); if( HRes == S_OK ) { for( int i = 0; i < sSpellbookCount; i++ ) { pSpellbook->get_NextObjectIndex( &pSpell ); long lSpellID; pSpell->get_NextInt( _bstr_t( "spell" ), &lSpellID ); SpellsLearned.insert( lSpellID ); pSpell.Release(); } } //Get Enchantments _variant_t vSpell1; _variant_t vEnchantment, vSpellID, vIndex, vSourceID, vDifficulty, vEffectMask, vAffected, vLevelMask, vFamily, vDuration, vTimeElapsed, vStartTime, vAdjustment; // Get Life Enchantments pMessage->get_Member (_variant_t ("lifeSpellCount"), &vSpellCount); _ASSERTE(vSpellCount.vt == VT_I4); if(vSpellCount.vt == VT_I4) { pMessage->get_Member (_variant_t ("lifeSpells"), &vSpells); _ASSERTE (vSpells.vt == VT_DISPATCH); if(vSpells.vt == VT_DISPATCH) { for(i = 0; i < (vSpellCount.lVal); i++) { IMessageMember* pMember = (IMessageMember*) vSpells.pdispVal; pMember->get_Member (_variant_t (long(i)), &vSpell1); _ASSERTE(vSpell1.vt == VT_DISPATCH); if (vSpell1.vt == VT_DISPATCH) { IMessageMember* pRecord = (IMessageMember*) vSpell1.pdispVal; pRecord->get_Member (_variant_t ("enchantment"), &vEnchantment); _ASSERTE (vEnchantment.vt == VT_DISPATCH); if(vEnchantment.vt != VT_DISPATCH) break; IMessageMember* pEnchantment = (IMessageMember*) vEnchantment.pdispVal; pEnchantment->get_Member (_variant_t ("spell"), &vSpellID); _ASSERTE(vSpellID.vt == VT_I2); pEnchantment->get_Member (_variant_t ("source"), &vSourceID); _ASSERTE(vSourceID.vt == VT_I4); pEnchantment->get_Member (_variant_t ("layers"), &vIndex); _ASSERTE(vIndex.vt == VT_I2); pEnchantment->get_Member (_variant_t ("difficulty"), &vDifficulty); _ASSERTE(vDifficulty.vt == VT_I4); pEnchantment->get_Member (_variant_t ("family"), &vFamily); _ASSERTE(vFamily.vt == VT_I4); pEnchantment->get_Member (_variant_t ("duration"), &vDuration); _ASSERTE(vDuration.vt == VT_R8); pEnchantment->get_Member (_variant_t ("timeElapsed"), &vTimeElapsed); _ASSERTE(vTimeElapsed.vt == VT_R8); pEnchantment->get_Member (_variant_t ("startTime"), &vStartTime); _ASSERTE(vStartTime.vt == VT_R8); pEnchantment->get_Member (_variant_t ("flags"), &vEffectMask); _ASSERTE(vEffectMask.vt == VT_I4); pEnchantment->get_Member (_variant_t ("affected"), &vAffected); _ASSERTE(vAffected.vt == VT_I4); pEnchantment->get_Member (_variant_t ("adjustment"), &vAdjustment); _ASSERTE(vAdjustment.vt == VT_R4); AddEnchant(vSpellID.iVal, vIndex.iVal, vDuration.dblVal, vFamily.lVal, vTimeElapsed.dblVal, vEffectMask.lVal, vAffected.lVal, vAdjustment.fltVal); } } } } // vSpellCount.vt == VT_I4 // Get Creature Enchantments pMessage->get_Member (_variant_t ("creatureSpellCount"), &vSpellCount); _ASSERTE(vSpellCount.vt == VT_I4); if(vSpellCount.vt == VT_I4) { pMessage->get_Member (_variant_t ("creatureSpells"), &vSpells); _ASSERTE (vSpells.vt == VT_DISPATCH); if(vSpells.vt == VT_DISPATCH) { for(i = 0; i < (vSpellCount.lVal); i++) { IMessageMember* pMember = (IMessageMember*) vSpells.pdispVal; pMember->get_Member (_variant_t (long(i)), &vSpell1); _ASSERTE(vSpell1.vt == VT_DISPATCH); if (vSpell1.vt == VT_DISPATCH) { IMessageMember* pRecord = (IMessageMember*) vSpell1.pdispVal; pRecord->get_Member (_variant_t ("enchantment"), &vEnchantment); _ASSERTE (vEnchantment.vt == VT_DISPATCH); if(vEnchantment.vt != VT_DISPATCH) break; IMessageMember* pEnchantment = (IMessageMember*) vEnchantment.pdispVal; pEnchantment->get_Member (_variant_t ("spell"), &vSpellID); _ASSERTE(vSpellID.vt == VT_I2); pEnchantment->get_Member (_variant_t ("source"), &vSourceID); _ASSERTE(vSourceID.vt == VT_I4); pEnchantment->get_Member (_variant_t ("layers"), &vIndex); _ASSERTE(vIndex.vt == VT_I2); pEnchantment->get_Member (_variant_t ("difficulty"), &vDifficulty); _ASSERTE(vDifficulty.vt == VT_I4); pEnchantment->get_Member (_variant_t ("family"), &vFamily); _ASSERTE(vFamily.vt == VT_I4); pEnchantment->get_Member (_variant_t ("duration"), &vDuration); _ASSERTE(vDuration.vt == VT_R8); pEnchantment->get_Member (_variant_t ("timeElapsed"), &vTimeElapsed); _ASSERTE(vTimeElapsed.vt == VT_R8); pEnchantment->get_Member (_variant_t ("startTime"), &vStartTime); _ASSERTE(vStartTime.vt == VT_R8); pEnchantment->get_Member (_variant_t ("flags"), &vEffectMask); _ASSERTE(vEffectMask.vt == VT_I4); pEnchantment->get_Member (_variant_t ("affected"), &vAffected); _ASSERTE(vAffected.vt == VT_I4); pEnchantment->get_Member (_variant_t ("adjustment"), &vAdjustment); _ASSERTE(vAdjustment.vt == VT_R4); AddEnchant(vSpellID.iVal, vIndex.iVal, vDuration.dblVal, vFamily.lVal, vTimeElapsed.dblVal, vEffectMask.lVal, vAffected.lVal, vAdjustment.fltVal); } } } } // vSpellCount.vt == VT_I4 _variant_t vVitae; if( SUCCEEDED(pMessage->get_Member(_variant_t ("vitae"), &vVitae))) { if( vVitae.vt != VT_EMPTY ) { IMessageMember* pVitae = (IMessageMember*) vVitae.pdispVal; pVitae->get_Member( _variant_t ("adjustment"), &vVitae); Vitae = vVitae.fltVal + 0.0000001f; // for float inaccuracies like 0.9499999881 } else Vitae = 1.0f; } else Vitae = 1.0f; // Added to allow for varying enchantmentMask section since the above section doesn't RecalcSecStats(); RecalcSkills(); Fire_Login( GUID ); } break; // Login case 0x0020: // Allegiance Info { GotAlleg = true; Patron.GUID = 0; Monarch.GUID = 0; MyAlleg.GUID = 0; VassalCount = 0; _variant_t vRecordCount, vRecords, vFol, vMonFol; pMessage->get_Member (_variant_t ("followers"), &vFol); pMessage->get_Member (_variant_t ("allegianceSize"), &vMonFol); Followers = vFol.lVal; MonarchFollowers = vMonFol.lVal; pMessage->get_Member (_variant_t ("recordCount"), &vRecordCount); _ASSERTE(vRecordCount.vt == VT_I2); pMessage->get_Member (_variant_t ("records"), &vRecords); _ASSERTE (vRecords.vt == VT_DISPATCH); //std::map< DWORD, cAllegianceInfo * > AllegMap; std::vector AllegInfo; for(int i = 0; i < (vRecordCount.bVal); i++) { IMessageMember* pMember = (IMessageMember*) vRecords.pdispVal; _variant_t vMember1; pMember->get_Member (_variant_t (long(i)), &vMember1); IMessageMember* pRecord = (IMessageMember*) vMember1.pdispVal; _variant_t vInfoRec; pRecord->get_Member (_variant_t ("info"), &vInfoRec); IMessageMember* pInfo = (IMessageMember*) vInfoRec.pdispVal; _variant_t vTreeParent, vGUID, vType, vXP, vGender, vRace, vRank, vLoyalty, vLeader, vName, vUnknown; pRecord->get_Member (_variant_t ("treeParent"), &vTreeParent); pInfo->get_Member (_variant_t ("character"), &vGUID); pInfo->get_Member (_variant_t ("type"), &vType); pInfo->get_Member (_variant_t ("exp"), &vXP); pInfo->get_Member (_variant_t ("gender"), &vGender); pInfo->get_Member (_variant_t ("race"), &vRace); pInfo->get_Member (_variant_t ("rank"), &vRank); pInfo->get_Member (_variant_t ("loyalty"), &vLoyalty); pInfo->get_Member (_variant_t ("leadership"), &vLeader); pInfo->get_Member (_variant_t ("unknown"), &vUnknown); pInfo->get_Member (_variant_t ("name"), &vName); cAllegianceInfo * tpai = new cAllegianceInfo; tpai->TreeParent = vTreeParent.lVal; tpai->GUID = vGUID.lVal; tpai->Type = vType.lVal; tpai->XP = vXP.lVal; tpai->Gender = vGender.bVal; tpai->Race = vRace.bVal; tpai->Rank = vRank.bVal; tpai->Loyalty = vLoyalty.iVal; tpai->Leadership = vLeader.iVal; tpai->Unknown = vUnknown.dblVal; strncpy( tpai->Name, OLE2A( vName.bstrVal ), sizeof( tpai->Name ) ); //AllegMap.insert( std::make_pair( vGUID.lVal, tpai ) ); AllegInfo.push_back(tpai); } //std::map< DWORD, cAllegianceInfo * >::iterator i = AllegMap.find( GUID ); // Solo player, get outta here //if( i == AllegMap.end() ) if ( AllegInfo.size() == 0 ) break; //we now 'know' that the monarch is the first entry, always //std::map< DWORD, cAllegianceInfo * >::iterator i2 = AllegMap.begin(); std::vector::iterator j = AllegInfo.begin(); if ( (*j)->GUID != GUID ) //i'm not the monarch, so find out who is { if ( (*(j + 1))->GUID != GUID ) //i'm not a direct either { memcpy(&Monarch, *j, sizeof(cAllegianceInfo)); //OutputDebugString(Monarch.Name); delete *j; j = AllegInfo.erase( j ); // this is my patron now } memcpy( &Patron, *j, sizeof( cAllegianceInfo ) ); //OutputDebugString(Patron.Name); delete *j; j = AllegInfo.erase( j ); } // we've taken care of any possible patron & monarch, // so i'm all that's left memcpy(&MyAlleg, *j, sizeof(cAllegianceInfo)); //OutputDebugString(MyAlleg.Name); delete *j; j = AllegInfo.erase( j ); //check for patron /* i = AllegMap.find( MyAlleg.TreeParent ); if ( i != AllegMap.end() ) { memcpy( &Patron, i->second, sizeof( cAllegianceInfo ) ); delete i->second; AllegMap.erase( i ); } //check for a monarch if ( Patron.GUID != 0 ) { i = AllegMap.find( Patron.TreeParent ); if ( i != AllegMap.end() ) { memcpy( &Monarch, i->second, sizeof( cAllegianceInfo ) ); delete i->second; AllegMap.erase( i ); } } */ //The remainder *should* all be vassals while( AllegInfo.size() > 0 ) { //for( i = AllegInfo.begin(); i != AllegInfo.end(); ++i ) //{ // Patron /* if( i->second->GUID == MyAlleg.TreeParent ) { memcpy( &Patron, i->second, sizeof( cAllegianceInfo ) ); OutputDebugString("Got Patron\n"); delete i->second; i = AllegMap.erase( i ); continue; } */ //Vassal //just leaving the sanity check in place here //if ((*i)->TreeParent == GUID) //{ memcpy( &Vassals[VassalCount], *j, sizeof( cAllegianceInfo ) ); //OutputDebugString(Vassals[VassalCount].Name); VassalCount++; delete *j; j = AllegInfo.erase( j ); //continue; //} //} } // only remnant should be monarch //p = AllegMap.begin()->second; //memcpy( &Monarch, p, sizeof( cAllegianceInfo ) ); //delete p; break; } case 0x004E: // Add Enchantment { _variant_t vEnchantment, vSpellID, vIndex, vSourceID, vDifficulty, vEffectMask, vAffected, vLevelMask, vFamily, vDuration, vTimeElapsed, vStartTime, vAdjustment; pMessage->get_Member (_variant_t ("enchantment"), &vEnchantment); IMessageMember* pEnchantment = (IMessageMember*) vEnchantment.pdispVal; pEnchantment->get_Member (_variant_t ("spell"), &vSpellID); _ASSERTE(vSpellID.vt == VT_I2); pEnchantment->get_Member (_variant_t ("source"), &vSourceID); _ASSERTE(vSourceID.vt == VT_I4); pEnchantment->get_Member (_variant_t ("layers"), &vIndex); _ASSERTE(vIndex.vt == VT_I2); pEnchantment->get_Member (_variant_t ("difficulty"), &vDifficulty); _ASSERTE(vDifficulty.vt == VT_I4); pEnchantment->get_Member (_variant_t ("family"), &vFamily); _ASSERTE(vFamily.vt == VT_I4); pEnchantment->get_Member (_variant_t ("duration"), &vDuration); _ASSERTE(vDuration.vt == VT_R8); pEnchantment->get_Member (_variant_t ("timeElapsed"), &vTimeElapsed); _ASSERTE(vTimeElapsed.vt == VT_R8); pEnchantment->get_Member (_variant_t ("startTime"), &vStartTime); _ASSERTE(vStartTime.vt == VT_R8); pEnchantment->get_Member (_variant_t ("flags"), &vEffectMask); _ASSERTE(vEffectMask.vt == VT_I4); pEnchantment->get_Member (_variant_t ("affected"), &vAffected); _ASSERTE(vAffected.vt == VT_I4); pEnchantment->get_Member (_variant_t ("adjustment"), &vAdjustment); _ASSERTE(vAdjustment.vt == VT_R4); if( 666 == vSpellID.iVal ) // Vitae isn't a normal enchantment { Vitae = vAdjustment.fltVal + 0.0000001f; // for float inaccuracies like 0.9499999881 RecalcSecStats(); RecalcSkills(); } else AddEnchant(vSpellID.iVal, vIndex.iVal, vDuration.dblVal, vFamily.lVal, vTimeElapsed.dblVal, vEffectMask.lVal, vAffected.lVal, vAdjustment.fltVal); break; } case 0x01AE: // Remove Multiple Enchantments { _variant_t vNumSpells, vSpells, vSpell1; pMessage->get_Member(_variant_t ("count"), &vNumSpells); pMessage->get_Member(_variant_t ("enchantments"), &vSpells); IMessageMember* pMember = (IMessageMember*) vSpells.pdispVal; for (int i=0;iget_Member (_variant_t (long(i)), &vSpell1); IMessageMember* pRecord = (IMessageMember*) vSpell1.pdispVal; _variant_t vSpellID, vLayer; pRecord->get_Member (_variant_t ("spell"), &vSpellID); pRecord->get_Member (_variant_t ("layer"), &vLayer); if( 666 == vSpellID.iVal ) // Vitae isn't a normal enchantment Vitae = 1.0f; else RemoveEnchant(vSpellID.iVal, vLayer.iVal); } break; } case 0x004F: // Remove Enchantment { _variant_t vSpellID, vLayer; pMessage->get_Member (_variant_t ("spell"), &vSpellID); pMessage->get_Member (_variant_t ("layer"), &vLayer); RemoveEnchant(vSpellID.iVal, vLayer.iVal); break; } case 0x01A4: // Remove Enchantment (Silent) { _variant_t vSpellID, vLayer; pMessage->get_Member (_variant_t ("spell"), &vSpellID); pMessage->get_Member (_variant_t ("layers"), &vLayer); RemoveEnchant(vSpellID.iVal, vLayer.iVal); break; } case 0x01A6: // Remove Multiple Enchantments { _variant_t vNumSpells, vSpells, vSpell1; pMessage->get_Member(_variant_t ("count"), &vNumSpells); pMessage->get_Member(_variant_t ("enchantments"), &vSpells); IMessageMember* pMember = (IMessageMember*) vSpells.pdispVal; for (int i=0;iget_Member (_variant_t (long(i)), &vSpell1); IMessageMember* pRecord = (IMessageMember*) vSpell1.pdispVal; _variant_t vSpellID, vLayer; pRecord->get_Member (_variant_t ("spell"), &vSpellID); pRecord->get_Member (_variant_t ("layer"), &vLayer); RemoveEnchant(vSpellID.iVal, vLayer.iVal); } break; } case 0x004C: // Spellbook Add { _variant_t vSpellID; pMessage->get_Member( _variant_t( "spell" ), &vSpellID ); DWORD nSpellID = vSpellID.lVal; std::pair< std::set< DWORD >::iterator, bool > pSuccess; pSuccess = SpellsLearned.insert( nSpellID ); if( pSuccess.second ) Fire_Spellbook_Add( nSpellID ); break; } case 0x004D: // Spellbook Delete { _variant_t vSpellID; pMessage->get_Member( _variant_t( "spell" ), &vSpellID ); DWORD nSpellID = vSpellID.lVal; if( SpellsLearned.erase( nSpellID ) ) Fire_Spellbook_Delete( nSpellID ); break; } } // End - F7B0 } } return S_OK; } void cCharacterStats::AddEnchant(int SpellID, int Layer, double Duration, DWORD Family, double Elapsed, DWORD AffectMask, DWORD Affected, float Adjustment) { time_t TimeExpires = time(NULL); // duration of the spell plus the (negative) number the server sends us indicating how many seconds have elapsed TimeExpires += (long(Duration + 0.5f) + long(Elapsed + 0.5f)); cEnchantment *tpench = new cEnchantment; tpench->iSpellID = SpellID; tpench->iLayer = Layer; tpench->dwFamily = Family; tpench->ExpireTime = TimeExpires; tpench->dwAffected = Affected; tpench->dwAffectMask = AffectMask; tpench->fAdjustment = Adjustment; Enchantments.push_back(tpench); std::map FamilyMap; switch (tpench->dwAffectMask & 0x13) { case 0x01: //Primary Stat { tpench->dwAffected--; for (std::list::iterator tpi = Enchantments.begin(); tpi != Enchantments.end(); tpi++) { if ((((*tpi)->dwAffectMask & 0x13) == 0x01) && ((*tpi)->dwAffected == tpench->dwAffected)) { if (abs(FamilyMap[(*tpi)->dwFamily]) <= abs((*tpi)->fAdjustment)) FamilyMap[(*tpi)->dwFamily] = (*tpi)->fAdjustment; } } float tpsf = PrimStat[tpench->dwAffected]; for (std::map::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++) tpsf += (*tpf).second; CurStat[tpench->dwAffected] = static_cast (tpsf + 0.5f); RecalcSecStats(); RecalcSkills(); } break; case 0x02: //Secondary Stat { tpench->dwAffected--; tpench->dwAffected /= 2; for (std::list::iterator tpi = Enchantments.begin(); tpi != Enchantments.end(); tpi++) { if ((((*tpi)->dwAffectMask & 0x13) == 0x02) && ((*tpi)->dwAffected == tpench->dwAffected)) { if (abs(FamilyMap[(*tpi)->dwFamily]) <= abs((*tpi)->fAdjustment)) FamilyMap[(*tpi)->dwFamily] = (*tpi)->fAdjustment; } } float tpsf = SecStatInc[tpench->dwAffected]; if (tpench->dwAffected == 0) tpsf += CurStat[1] / 2.0f + 0.5f; else if (tpench->dwAffected == 1) tpsf += CurStat[1]; else if (tpench->dwAffected == 2) tpsf += CurStat[5]; for (std::map::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++) tpsf += (*tpf).second; CurSecStat[tpench->dwAffected] = static_cast (tpsf); } break; case 0x10: //Skill { for (std::list::iterator tpi = Enchantments.begin(); tpi != Enchantments.end(); tpi++) { if ((((*tpi)->dwAffectMask & 0x13) == 0x10) && ((*tpi)->dwAffected == tpench->dwAffected)) { if (abs(FamilyMap[(*tpi)->dwFamily]) <= abs((*tpi)->fAdjustment)) FamilyMap[(*tpi)->dwFamily] = (*tpi)->fAdjustment; } } RecalcSkill(tpench->dwAffected); } break; } } void cCharacterStats::RemoveEnchant(int SpellID, int Layer) { for (std::list< cEnchantment * >::iterator tpi = Enchantments.begin(); tpi != Enchantments.end(); tpi++) { if( ( (*tpi)->iSpellID == SpellID) && ( (*tpi)->iLayer == Layer) ) { cEnchantment tpench; memcpy(&tpench, *tpi, sizeof(tpench)); delete *tpi; Enchantments.erase(tpi); if ((tpench.dwAffectMask & 0x013) == 0x01) { RecalcStat(tpench.dwAffected); RecalcSecStats(); RecalcSkills(); } else if ((tpench.dwAffectMask & 0x013) == 0x02) { RecalcSecStats(); } else if ((tpench.dwAffectMask & 0x013) == 0x10) { RecalcSkill(tpench.dwAffected); } tpi = Enchantments.begin(); } } } void cCharacterStats::RecalcStat(int Stat) { std::map FamilyMap; for (std::list< cEnchantment * >::iterator tpi = Enchantments.begin(); tpi != Enchantments.end(); tpi++) { if ((((*tpi)->dwAffectMask & 0x13) == 0x01) && ((*tpi)->dwAffected == Stat)) { if (abs(FamilyMap[(*tpi)->dwFamily]) <= abs((*tpi)->fAdjustment)) FamilyMap[(*tpi)->dwFamily] = (*tpi)->fAdjustment; } } float tpsf = (float) PrimStat[Stat]; for (std::map::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++) tpsf += (*tpf).second; CurStat[Stat] = static_cast (tpsf); } void cCharacterStats::RecalcSecStats() { for (int i=0;i<3;i++) RecalcSecStat(i); } void cCharacterStats::RecalcSecStat(int SecStat) { std::map FamilyMap; for (std::list< cEnchantment * >::iterator tpi = Enchantments.begin(); tpi != Enchantments.end(); tpi++) { if( (((*tpi)->dwAffectMask & 0x13) == 0x02) && ((*tpi)->dwAffected == SecStat) ) { if (abs(FamilyMap[(*tpi)->dwFamily]) <= abs((*tpi)->fAdjustment)) FamilyMap[(*tpi)->dwFamily] = (*tpi)->fAdjustment; } } float tpsf = SecStatInc[SecStat]; if (SecStat == 0) tpsf += CurStat[1] / 2.0f + 0.5f; else if (SecStat == 1) tpsf += CurStat[1]; else if (SecStat == 2) tpsf += CurStat[5]; for (std::map::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++) tpsf += (*tpf).second; CurSecStat[SecStat] = static_cast (tpsf); } void cCharacterStats::RecalcSkills() { for (int i=0;i<40;i++) RecalcSkill(i); } void cCharacterStats::RecalcSkill(int Skill) { std::map FamilyMap; for (std::list::iterator tpi = Enchantments.begin(); tpi != Enchantments.end(); tpi++) { if ((((*tpi)->dwAffectMask & 0x13) == 0x10) && ((*tpi)->dwAffected == Skill)) { if (abs(FamilyMap[(*tpi)->dwFamily]) <= abs((*tpi)->fAdjustment)) FamilyMap[(*tpi)->dwFamily] = (*tpi)->fAdjustment; } } float TPS = 0; if (SkillInfo[Skill].AttribA != eAttrNULL) TPS += CurStat[SkillInfo[Skill].AttribA - 1]; if (SkillInfo[Skill].AttribB != eAttrNULL) TPS += CurStat[SkillInfo[Skill].AttribB - 1]; TPS /= SkillInfo[Skill].Divider; TPS += SkillInc[Skill] + SkillBonus[Skill] + 0.5f; for (std::map::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++) TPS += (*tpf).second; CurSkill[Skill] = static_cast (TPS); } HRESULT cCharacterStats::get_TotalSpells(long *pVal) { if (!GotLogin) return E_FAIL; *pVal = SpellsLearned.size(); return S_OK; } HRESULT cCharacterStats::get_SpellLearned(long SpellID, long *pVal) { if (!GotLogin) return E_FAIL; if( SpellID < 0 ) { *pVal = -1; return E_FAIL; } std::set< DWORD >::iterator a = SpellsLearned.find( SpellID ); if( a == SpellsLearned.end() ) { *pVal = 0; return S_OK; } *pVal = 1; return S_OK; } HRESULT cCharacterStats::get_ClassTemplate(BSTR *pVal) { if (!GotLogin) return E_FAIL; *pVal = T2BSTR(Class); return S_OK; } HRESULT cCharacterStats::get_Gender(BSTR *pVal) { if (!GotLogin) return E_FAIL; *pVal = T2BSTR(Gender); return S_OK; } HRESULT cCharacterStats::get_Race(BSTR *pVal) { if (!GotLogin) return E_FAIL; *pVal = T2BSTR(Race); return S_OK; } HRESULT cCharacterStats::get_Name(BSTR *pVal) { if (!GotLogin) return E_FAIL; *pVal = T2BSTR(Name); return S_OK; } HRESULT cCharacterStats::get_Server(BSTR *pVal) { if( !(*Server) ) return E_FAIL; /* //DIE!! if( strncmp( Server, "DARKTIDE", 8 ) == 0 ) *pVal = T2BSTR( Server ); else if( stricmp( Server, "FROSTFELL" ) == 0 ) *pVal = T2BSTR( Server ); else if( stricmp( Server, "HARVESTGAIN" ) == 0 ) *pVal = T2BSTR( Server ); else if( stricmp( Server, "LEAFCULL" ) == 0 ) *pVal = T2BSTR( Server ); else if( stricmp( Server, "MORNINGTHAW" ) == 0 ) *pVal = T2BSTR( Server ); else if( stricmp( Server, "SOLCLAIM" ) == 0 ) *pVal = T2BSTR( Server ); else if( stricmp( Server, "THISTLEDOWN" ) == 0 ) *pVal = T2BSTR( Server ); else if( stricmp( Server, "WINTERSEBB" ) == 0 ) *pVal = T2BSTR( Server ); else if( stricmp( Server, "VERDANTINE" ) == 0 ) *pVal = T2BSTR( Server ); else *pVal = T2BSTR("Unknown"); */ *pVal = T2BSTR(Server); return S_OK; } HRESULT cCharacterStats::get_SkillPoints(/*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; *pVal = SkillPoints; return S_OK; } HRESULT cCharacterStats::get_UnassignedExp(/*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; *pVal = UnassignedXP; return S_OK; } HRESULT cCharacterStats::get_TotalExp(/*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; *pVal = TotalXP; return S_OK; } HRESULT cCharacterStats::get_Rank(/*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; *pVal = Rank; return S_OK; } HRESULT cCharacterStats::get_Level(/*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; *pVal = Level; return S_OK; } HRESULT cCharacterStats::get_Character(/*[out, retval]*/ long *pVal) { *pVal = GUID; return S_OK; } HRESULT cCharacterStats::get_VitalCount(/*[out, retval]*/ long *pVal) { *pVal = 3; return S_OK; } HRESULT cCharacterStats::get_SkillCount(/*[out, retval]*/ long *pVal) { *pVal = 40; return S_OK; } HRESULT cCharacterStats::get_AttributeCount(/*[out, retval]*/ long *pVal) { *pVal = 6; return S_OK; } HRESULT cCharacterStats::get_Vital(enum eVitalID Index, /*[out, retval]*/ ISkillInfo ** pVal) { if (!GotLogin) return E_FAIL; if ((Index < 1) || (Index > 3)) return E_FAIL; CComObject< ::cSkillInfo > *pSkill; CComObject< ::cSkillInfo >::CreateInstance( &pSkill ); pSkill->m_pStats = this; if (Index == 1) { pSkill->m_pSkill->m_szName = "Health"; pSkill->m_pSkill->m_nAttribute1 = eAttrEndurance; pSkill->m_pSkill->m_nAttribute2 = eAttrNULL; pSkill->m_pSkill->m_nDenominator = 2; } else if (Index == 2) { pSkill->m_pSkill->m_szName = "Stamina"; pSkill->m_pSkill->m_nAttribute1 = eAttrEndurance; pSkill->m_pSkill->m_nAttribute2 = eAttrNULL; pSkill->m_pSkill->m_nDenominator = 1; } else if (Index == 3) { pSkill->m_pSkill->m_szName = "Mana"; pSkill->m_pSkill->m_nAttribute1 = eAttrSelf; pSkill->m_pSkill->m_nAttribute2 = eAttrNULL; pSkill->m_pSkill->m_nDenominator = 1; } pSkill->m_pSkill->m_nExp = SecondaryStatArray[SecStatInc[Index - 1]]; pSkill->m_pSkill->m_nBonus = 0; pSkill->m_pSkill->m_nOffset = SecStatInc[Index - 1]; pSkill->m_pSkill->m_trained = eTrainTrained; return pSkill->QueryInterface( IID_ISkillInfo, reinterpret_cast< void ** >( pVal ) ); } HRESULT cCharacterStats::get_Skill(enum eSkillID Index, ISkillInfo ** pVal) { if (!GotLogin) return E_FAIL; if ((Index < 1) || (Index > 39)) return E_FAIL; CComObject< ::cSkillInfo > *pSkill; CComObject< ::cSkillInfo >::CreateInstance( &pSkill ); pSkill->m_pStats = this; pSkill->m_pSkill->m_nExp = SkillXP[Index]; pSkill->m_pSkill->m_nBonus = SkillBonus[Index]; pSkill->m_pSkill->m_nOffset = SkillInc[Index]; pSkill->m_pSkill->m_nAttribute1 = SkillInfo[Index].AttribA; pSkill->m_pSkill->m_nAttribute2 = SkillInfo[Index].AttribB; pSkill->m_pSkill->m_nDenominator = SkillInfo[Index].Divider; pSkill->m_pSkill->m_szName = SkillInfo[Index].Name; pSkill->m_pSkill->m_trained = (enum eTrainingType) SkillTrain[Index]; return pSkill->QueryInterface( IID_ISkillInfo, reinterpret_cast< void ** >( pVal ) ); } HRESULT cCharacterStats::get_Attribute(enum eAttributeID Index, /*[out, retval]*/ IAttributeInfo ** pVal) { if (!GotLogin) return E_FAIL; if ((Index < 1) || (Index > 6)) return E_FAIL; CComObject< ::cAttributeInfo > *pAttrib; CComObject< ::cAttributeInfo >::CreateInstance( &pAttrib ); pAttrib->m_pInfo->m_nBase = PrimStatInitial[Index - 1]; pAttrib->m_pInfo->m_nCurrent = PrimStat[Index - 1]; pAttrib->m_pInfo->m_nExp = PrimStatArray[PrimStat[Index - 1] - PrimStatInitial[Index - 1]]; if (Index == 1) pAttrib->m_pInfo->m_szName = "Strength"; else if (Index == 2) pAttrib->m_pInfo->m_szName = "Endurance"; else if (Index == 3) pAttrib->m_pInfo->m_szName = "Quickness"; else if (Index == 4) pAttrib->m_pInfo->m_szName = "Coordination"; else if (Index == 5) pAttrib->m_pInfo->m_szName = "Focus"; else if (Index == 6) pAttrib->m_pInfo->m_szName = "Self"; return pAttrib->QueryInterface( IID_IAttributeInfo, reinterpret_cast< void ** >( pVal ) ); } HRESULT cCharacterStats::get_Birth(/*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; *pVal = Birth; return S_OK; } HRESULT cCharacterStats::get_Age(/*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; *pVal = Age; return S_OK; } HRESULT cCharacterStats::get_Deaths(/*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; *pVal = Deaths; return S_OK; } HRESULT cCharacterStats::get_Monarch(IAllegianceInfo ** pVal) { if (!GotAlleg) return E_FAIL; if (!Monarch.GUID) return E_FAIL; CComObject< ::cAllegianceInfo > *pAlleg; CComObject< ::cAllegianceInfo >::CreateInstance( &pAlleg ); strncpy( pAlleg->m_pAllegiance->Name, Monarch.Name, sizeof( pAlleg->m_pAllegiance->Name ) ); pAlleg->m_pAllegiance->GUID = Monarch.GUID; pAlleg->m_pAllegiance->TreeParent = Monarch.TreeParent; pAlleg->m_pAllegiance->Leadership = Monarch.Leadership; pAlleg->m_pAllegiance->Loyalty = Monarch.Loyalty; pAlleg->m_pAllegiance->XP = Monarch.XP; pAlleg->m_pAllegiance->Race = Monarch.Race; pAlleg->m_pAllegiance->Rank = Monarch.Rank; pAlleg->m_pAllegiance->Gender = Monarch.Gender; pAlleg->m_pAllegiance->Type = Monarch.Type; pAlleg->m_pAllegiance->Unknown = Monarch.Unknown; return pAlleg->QueryInterface( IID_IAllegianceInfo, reinterpret_cast< void ** >( pVal ) ); } HRESULT cCharacterStats::get_Patron(IAllegianceInfo ** pVal) { if (!GotAlleg) return E_FAIL; if (!Patron.GUID) return E_FAIL; CComObject< ::cAllegianceInfo > *pAlleg; CComObject< ::cAllegianceInfo >::CreateInstance( &pAlleg ); strncpy( pAlleg->m_pAllegiance->Name, Patron.Name, sizeof( pAlleg->m_pAllegiance->Name ) ); pAlleg->m_pAllegiance->GUID = Patron.GUID; pAlleg->m_pAllegiance->TreeParent = Patron.TreeParent; pAlleg->m_pAllegiance->Leadership = Patron.Leadership; pAlleg->m_pAllegiance->Loyalty = Patron.Loyalty; pAlleg->m_pAllegiance->XP = Patron.XP; pAlleg->m_pAllegiance->Race = Patron.Race; pAlleg->m_pAllegiance->Rank = Patron.Rank; pAlleg->m_pAllegiance->Gender = Patron.Gender; pAlleg->m_pAllegiance->Type = Patron.Type; pAlleg->m_pAllegiance->Unknown = Patron.Unknown; return pAlleg->QueryInterface( IID_IAllegianceInfo, reinterpret_cast< void ** >( pVal ) ); } HRESULT cCharacterStats::get_MyAllegiance(IAllegianceInfo ** pVal) { if (!GotAlleg) return E_FAIL; if (!MyAlleg.GUID) return E_FAIL; CComObject< ::cAllegianceInfo > *pAlleg; CComObject< ::cAllegianceInfo >::CreateInstance( &pAlleg ); strncpy( pAlleg->m_pAllegiance->Name, MyAlleg.Name, sizeof( pAlleg->m_pAllegiance->Name ) ); pAlleg->m_pAllegiance->GUID = MyAlleg.GUID; pAlleg->m_pAllegiance->TreeParent = MyAlleg.TreeParent; pAlleg->m_pAllegiance->Leadership = MyAlleg.Leadership; pAlleg->m_pAllegiance->Loyalty = MyAlleg.Loyalty; pAlleg->m_pAllegiance->XP = MyAlleg.XP; pAlleg->m_pAllegiance->Race = MyAlleg.Race; pAlleg->m_pAllegiance->Rank = MyAlleg.Rank; pAlleg->m_pAllegiance->Gender = MyAlleg.Gender; pAlleg->m_pAllegiance->Type = MyAlleg.Type; pAlleg->m_pAllegiance->Unknown = MyAlleg.Unknown; return pAlleg->QueryInterface( IID_IAllegianceInfo, reinterpret_cast< void ** >( pVal ) ); } HRESULT cCharacterStats::get_Vassal(long VassalNum, IAllegianceInfo ** pVal) { if (!GotAlleg) return E_FAIL; if ((VassalNum < 0) || (VassalNum >= VassalCount)) return E_FAIL; if (!Vassals[ VassalNum ].GUID) return E_FAIL; CComObject< ::cAllegianceInfo > *pAlleg; CComObject< ::cAllegianceInfo >::CreateInstance( &pAlleg ); strncpy( pAlleg->m_pAllegiance->Name, Vassals[ VassalNum ].Name, sizeof( pAlleg->m_pAllegiance->Name ) ); pAlleg->m_pAllegiance->GUID = Vassals[ VassalNum ].GUID; pAlleg->m_pAllegiance->TreeParent = Vassals[ VassalNum ].TreeParent; pAlleg->m_pAllegiance->Leadership = Vassals[ VassalNum ].Leadership; pAlleg->m_pAllegiance->Loyalty = Vassals[ VassalNum ].Loyalty; pAlleg->m_pAllegiance->XP = Vassals[ VassalNum ].XP; pAlleg->m_pAllegiance->Race = Vassals[ VassalNum ].Race; pAlleg->m_pAllegiance->Rank = Vassals[ VassalNum ].Rank; pAlleg->m_pAllegiance->Gender = Vassals[ VassalNum ].Gender; pAlleg->m_pAllegiance->Type = Vassals[ VassalNum ].Type; pAlleg->m_pAllegiance->Unknown = Vassals[ VassalNum ].Unknown; return pAlleg->QueryInterface( IID_IAllegianceInfo, reinterpret_cast< void ** >( pVal ) ); } HRESULT cCharacterStats::get_VassalCount(long *pVal) { if (!GotAlleg) return E_FAIL; *pVal = VassalCount; return S_OK; } HRESULT cCharacterStats::get_Followers(long *pVal) { if (!GotAlleg) return E_FAIL; *pVal = Followers; return S_OK; } HRESULT cCharacterStats::get_MonarchFollowers(long *pVal) { if (!GotAlleg) return E_FAIL; *pVal = MonarchFollowers; return S_OK; } HRESULT cCharacterStats::get_EffectiveVital(enum eVitalID Index, /*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; if ((Index < 1) || (Index > 3)) return E_FAIL; float fSkill = SecStatInc[Index - 1]; if (Index == 1) fSkill += CurStat[1] / 2.0f + 0.5f; else if (Index == 2) fSkill += CurStat[1]; else if (Index == 3) fSkill += CurStat[5]; long nBuffs = CurSecStat[Index - 1] - static_cast< long >(fSkill); //calculates net buffs *pVal = long(long(fSkill) * Vitae + 0.5f + nBuffs); return S_OK; } HRESULT cCharacterStats::get_EffectiveSkill(enum eSkillID Index, /*[out, retval]*/ long *pVal) { if (!GotLogin) return E_FAIL; if ((Index < 1) || (Index > 39)) return E_FAIL; // get current skill float fSkill = 0.0; if( SkillInfo[Index].AttribA != eAttrNULL ) fSkill += CurStat[ SkillInfo[Index].AttribA - 1]; if( SkillInfo[Index].AttribB != eAttrNULL ) fSkill += CurStat[ SkillInfo[Index].AttribB - 1]; fSkill /= static_cast< float >( SkillInfo[Index].Divider ); fSkill += SkillInc[Index] + 0.5f; fSkill += SkillBonus[Index]; // get our net buffs long nBuffs = CurSkill[Index] - long(fSkill); // AC calculates the vitae penalty to a skill before buffs, so we do too *pVal = long(long(fSkill) * Vitae + 0.5f + nBuffs); return S_OK; } HRESULT cCharacterStats::get_EffectiveAttribute(enum eAttributeID Index, /*[out, retval]*/ long * pVal) { if (!GotLogin) return E_FAIL; if ((Index < 1) || (Index > 6)) return E_FAIL; *pVal = CurStat[Index - 1]; return S_OK; } HRESULT cCharacterStats::get_Health(long *pVal) { if (!GotLogin) return E_FAIL; *pVal = Health; return S_OK; } HRESULT cCharacterStats::get_Stamina(long *pVal) { if (!GotLogin) return E_FAIL; *pVal = Stamina; return S_OK; } HRESULT cCharacterStats::get_Mana(long *pVal) { if (!GotLogin) return E_FAIL; *pVal = Mana; return S_OK; } HRESULT cCharacterStats::get_EnchantmentCount(long *pVal) { if (!GotLogin) return E_FAIL; *pVal = Enchantments.size(); return S_OK; } HRESULT cCharacterStats::get_Enchantment(long EnchantNum, IEnchantment **pVal) { if (!GotLogin) return E_FAIL; if (EnchantNum < 0) return E_FAIL; std::list::iterator tpi = Enchantments.begin(); for( int i = 1; i < EnchantNum; i++ ) tpi++; time_t CurrentTime = time(NULL); long SecondsLeft = (*tpi)->ExpireTime - CurrentTime; // Item based spells have no expiration. // Sometimes nearly expired spells may also return -1 due to internet latency. if( SecondsLeft < 0 ) SecondsLeft = -1; CComObject< ::Enchantment > *pEnchant; CComObject< ::Enchantment >::CreateInstance( &pEnchant ); pEnchant->put_SpellID( (*tpi)->iSpellID ); pEnchant->put_Layer( (*tpi)->iLayer ); pEnchant->put_TimeRemaining( SecondsLeft ); pEnchant->put_Affected( (*tpi)->dwAffected ); pEnchant->put_AffectedMask( (*tpi)->dwAffectMask ); pEnchant->put_Family( (*tpi)->dwFamily ); pEnchant->put_Adjustment( (*tpi)->fAdjustment ); pEnchant->QueryInterface(pVal); return S_OK; } HRESULT cCharacterStats::get_Vitae(long *pVal) { if(!GotLogin) return E_FAIL; *pVal = long((1.00 - Vitae) * 100 + 0.5f); return S_OK; } HRESULT cCharacterStats::get_BurdenUnits(long *pVal) { if(!GotLogin) return E_FAIL; *pVal = long(TotalBurden); return S_OK; } HRESULT cCharacterStats::get_Burden(long *pVal) { if(!GotLogin) return E_FAIL; long nLegalBurden; get_EffectiveAttribute(eAttrStrength, &nLegalBurden); nLegalBurden *= 150; *pVal = long( ( float(TotalBurden) / nLegalBurden ) * 100 ); return S_OK; }