All 5 phases of the open-source Decal rebuild: Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil) Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters - Decal.Core, DecalControls, DecalRender, D3DService Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL Phase 4: DenAgent WinForms tray application Phase 5: WiX installer and build script 25 C# projects building with 0 errors. Native C++ projects require VS 2022 + Windows SDK (x86). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1849 lines
No EOL
56 KiB
C++
1849 lines
No EOL
56 KiB
C++
// 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 <time.h>
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// cCharacterStats
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <set>
|
|
|
|
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<cEnchantment *>::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 <DWORD> (TPS);
|
|
}
|
|
|
|
//Get Spellbook
|
|
CComPtr<IMessageIterator> pBegin;
|
|
CComPtr<IMessageIterator> pSpell;
|
|
CComPtr<IMessageIterator> 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<cAllegianceInfo *> 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<cAllegianceInfo *>::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;i<vNumSpells.lVal;i++)
|
|
{
|
|
pMember->get_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;i<vNumSpells.lVal;i++)
|
|
{
|
|
pMember->get_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<DWORD, float> FamilyMap;
|
|
|
|
switch (tpench->dwAffectMask & 0x13)
|
|
{
|
|
case 0x01: //Primary Stat
|
|
{
|
|
tpench->dwAffected--;
|
|
|
|
for (std::list<cEnchantment *>::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<DWORD, float>::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++)
|
|
tpsf += (*tpf).second;
|
|
|
|
CurStat[tpench->dwAffected] = static_cast <DWORD> (tpsf + 0.5f);
|
|
|
|
RecalcSecStats();
|
|
RecalcSkills();
|
|
}
|
|
break;
|
|
case 0x02: //Secondary Stat
|
|
{
|
|
tpench->dwAffected--;
|
|
tpench->dwAffected /= 2;
|
|
|
|
for (std::list<cEnchantment *>::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<DWORD, float>::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++)
|
|
tpsf += (*tpf).second;
|
|
|
|
CurSecStat[tpench->dwAffected] = static_cast <DWORD> (tpsf);
|
|
}
|
|
break;
|
|
case 0x10: //Skill
|
|
{
|
|
for (std::list<cEnchantment *>::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<DWORD, float> 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<DWORD, float>::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++)
|
|
tpsf += (*tpf).second;
|
|
|
|
CurStat[Stat] = static_cast <DWORD> (tpsf);
|
|
}
|
|
|
|
void cCharacterStats::RecalcSecStats()
|
|
{
|
|
for (int i=0;i<3;i++)
|
|
RecalcSecStat(i);
|
|
}
|
|
|
|
void cCharacterStats::RecalcSecStat(int SecStat)
|
|
{
|
|
std::map<DWORD, float> 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<DWORD, float>::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++)
|
|
tpsf += (*tpf).second;
|
|
|
|
CurSecStat[SecStat] = static_cast <DWORD> (tpsf);
|
|
}
|
|
void cCharacterStats::RecalcSkills()
|
|
{
|
|
for (int i=0;i<40;i++)
|
|
RecalcSkill(i);
|
|
}
|
|
void cCharacterStats::RecalcSkill(int Skill)
|
|
{
|
|
std::map<DWORD, float> FamilyMap;
|
|
|
|
for (std::list<cEnchantment *>::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<DWORD, float>::iterator tpf = FamilyMap.begin(); tpf != FamilyMap.end(); tpf++)
|
|
TPS += (*tpf).second;
|
|
|
|
CurSkill[Skill] = static_cast <DWORD> (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<cEnchantment *>::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;
|
|
} |