plugy/PlugY/WorldEvent.cpp
2021-01-04 08:07:29 +01:00

321 lines
10 KiB
C++

/*=================================================================
File created by Yohann NICOLAS.
Add support 1.13d by L'Autour.
Add support 1.14d by haxifix.
World Event Management.
=================================================================*/
#include "worldEvent.h"
#include "common.h"
#pragma pack(1)
struct s_WEdata
{
BYTE type;
BYTE fct;
BYTE id;
DWORD param;
WORD z;
BYTE uk[31];
};
#pragma pack()
bool active_WorldEvent=0;
DWORD WEactive = 0;
DWORD DCloneSpawned = 0;
DWORD nbSOJSold = 0;
DWORD nbNeedSOJSold = 0;
DWORD nbManagedSOJSold = 0;
DWORD nbTicksForNextSOJSold = 0;
DWORD prevTicks = 0;
DWORD showSOJSoldCounterInAllDiff=0;
char* itemsToSell="The Stone of Jordan";
DWORD worldEventmonsterID = 333;
DWORD valueOfOwnSOJSold=100;
DWORD valueInitSOJSoldMin=200;
DWORD valueInitSOJSoldDelta=2000;
DWORD triggerAtSolJSoldMin=75;
DWORD triggerAtSolJSoldDelta=51;
bool active_AutomaticSell=1;
DWORD timeBeforeAutoSellMin=00000;
DWORD timeBeforeAutoSellDelta=120000;
CubeInput itemNeeded;
DWORD getTicksForNextSOJSold()
{
return ((DWORD)(rand()/(RAND_MAX+1.0)*timeBeforeAutoSellDelta)+timeBeforeAutoSellMin);//average of +100 in 25hours max 41h40
}
void FASTCALL sendDataToClient(void* ptclient, DWORD* param)
{
D2SendPacket(ptclient, (void*)param[0], (DWORD)param[1]);
}
void STDCALL worldEventBroadcast(Game* ptGame, DWORD activeWE, DWORD nbSOJSold)
{
void* param[2];
s_WEdata data;
data.type = 0x5A;
data.fct = activeWE ? 0x12 : 0x11;
data.id = 4;
data.param = nbSOJSold;
data.z = 0;
param[0]=&data;
param[1]=(void*)sizeof(data);
D2BroadcastFunction(ptGame,&sendDataToClient,param);
}
Game* STDCALL WEManagement(DWORD clientID)
{
Game* ptGame = D2GetGameByClientID(clientID);
if (!ptGame) return ptGame;
if (active_AutomaticSell)
{
while (GetTickCount() - prevTicks >= nbTicksForNextSOJSold)
{
nbSOJSold++;
prevTicks = prevTicks + nbTicksForNextSOJSold;
nbTicksForNextSOJSold = getTicksForNextSOJSold();
}
}
if (nbSOJSold == nbManagedSOJSold)
return ptGame;
DWORD newWE;
if (!WEactive && (ptGame->difficultyLevel == D2DM_HELL) && (nbSOJSold >= nbNeedSOJSold))
{
newWE = 1;
WEactive = 1;
}
else
newWE = 0;
if ( showSOJSoldCounterInAllDiff || (ptGame->difficultyLevel == D2DM_HELL))
worldEventBroadcast(ptGame, newWE, nbSOJSold);
nbManagedSOJSold = nbSOJSold;
return ptGame;
}
DWORD FASTCALL spawnDClone(Game* ptGame, Room* ptRoom, DWORD p3, DWORD p4, DWORD p5, DWORD p6, DWORD monsterID, DWORD p8)
{
if (WEactive && (ptGame->difficultyLevel == D2DM_HELL) && !DCloneSpawned)
{
DCloneSpawned=1;
D2SpawnSuperUnique(ptGame,ptRoom,p3,p4,p5,p6,worldEventmonsterID,p8);
return 0;//no minions
}
else
return D2SpawnSuperUnique(ptGame,ptRoom,p3,p4,p5,p6,monsterID,p8);
}
DWORD STDCALL verifIfWEItem (Unit* ptItem, DWORD flags, DWORD line, const char* filename)
{
ItemsBIN* ptItemStats = D2GetItemsBIN(ptItem->nTxtFileNo);
ItemsBIN* ptWantedItemStats = D2GetItemsBIN(itemNeeded.ID);
if((itemNeeded.byItemTypeID && D2CheckItemType(ptItem,itemNeeded.ID))
|| (itemNeeded.byItemID && (itemNeeded.ID == 0xFFFF))
|| (itemNeeded.byItemID && !itemNeeded.includeUpgradedVersions && ((DWORD)itemNeeded.ID == ptItem->nTxtFileNo))
|| (itemNeeded.byItemID && itemNeeded.includeUpgradedVersions) && (
(ptItemStats->ItemCode == ptItemStats->NormCode) && (ptItemStats->ItemCode == ptWantedItemStats->NormCode)
|| (ptItemStats->ItemCode == ptItemStats->UberCode) && (ptItemStats->ItemCode == ptWantedItemStats->NormCode)
|| (ptItemStats->ItemCode == ptItemStats->UberCode) && (ptItemStats->ItemCode == ptWantedItemStats->UberCode)
|| (ptItemStats->ItemCode == ptItemStats->HellCode) && (ptItemStats->ItemCode == ptWantedItemStats->NormCode)
|| (ptItemStats->ItemCode == ptItemStats->HellCode) && (ptItemStats->ItemCode == ptWantedItemStats->UberCode)
|| (ptItemStats->ItemCode == ptItemStats->HellCode) && (ptItemStats->ItemCode == ptWantedItemStats->HellCode)
))
if(!(itemNeeded.isSpecificItem && (D2GetUniqueID(ptItem) != itemNeeded.specificID-1))
&& !(itemNeeded.haveNoSocket && (D2GetPlayerStat(ptItem, STATS_ITEM_NUMSOCKETS, 0) > 0))
&& !(itemNeeded.haveSockets && (D2GetPlayerStat(ptItem, STATS_ITEM_NUMSOCKETS, 0) == 0))
&& !(itemNeeded.isNotEthereal && ptItem->ptItemData->isEtheral)
&& !(itemNeeded.isEthereal && !ptItem->ptItemData->isEtheral)
&& !(itemNeeded.isBasic && (ptItemStats->ItemCode != ptWantedItemStats->NormCode))
&& !(itemNeeded.isExceptional && (ptItemStats->ItemCode != ptWantedItemStats->UberCode))
&& !(itemNeeded.isElite && (ptItemStats->ItemCode != ptWantedItemStats->HellCode))
&& !(itemNeeded.isNotRuneword && ptItem->ptItemData->isRuneword) )
{
nbSOJSold += valueOfOwnSOJSold;
return 1;// Can't re-buy the item.
}
return D2TestFlags(ptItem, flags, line, filename);
}
void initWorldEventVariables()
{
char buf[50];
memset(&itemNeeded,0,sizeof(itemNeeded));
strncpy(buf,itemsToSell,50);
D2CompileCubeInput(&itemNeeded,buf,0,0);
nbManagedSOJSold = 0;
DCloneSpawned = 0;
WEactive = 0;
while (nbSOJSold >= nbNeedSOJSold)
nbNeedSOJSold += (DWORD)(rand()/(RAND_MAX+1.0)*triggerAtSolJSoldDelta + triggerAtSolJSoldMin);
log_msg("initWorldEventVariables - nbSOJSold = %d, nbNeedSOJSold = %d\n", nbSOJSold, nbNeedSOJSold);
}
FCT_ASM ( caller_WEManagement_114 )
PUSH ECX
CALL WEManagement
RETN
}}
FCT_ASM ( caller_WEManagement_1XX )
POP EAX
PUSH ECX
PUSH EAX
JMP WEManagement
}}
FCT_ASM ( caller_spawnDClone_111 )
PUSH DWORD PTR SS:[ESP+0x14]
PUSH EAX
PUSH DWORD PTR SS:[ESP+0x18]
PUSH DWORD PTR SS:[ESP+0x18]
PUSH DWORD PTR SS:[ESP+0x18]
PUSH ECX
MOV ECX,DWORD PTR SS:[ESP+0x1C]
CALL spawnDClone
RETN 0x14
}}
FCT_ASM ( caller_spawnDClone_111b )
PUSH EDX
PUSH ECX
PUSH DWORD PTR SS:[ESP+0x1C]
PUSH DWORD PTR SS:[ESP+0x1C]
PUSH DWORD PTR SS:[ESP+0x1C]
PUSH EAX
MOV EDX,DWORD PTR SS:[ESP+0x20]
MOV ECX,DWORD PTR SS:[ESP+0x1C]
CALL spawnDClone
RETN 0x14
}}
FCT_ASM( caller_spawnDClone_114 )
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ESI
PUSH 0
PUSH EBX
PUSH 0xFFFFFFFF
PUSH DWORD PTR SS : [ESP + 0x30]
PUSH DWORD PTR SS : [ESP + 0x30]
PUSH DWORD PTR SS : [ESP + 0x30]
MOV ECX, EDI
MOV EDX, EAX
CALL spawnDClone
POP ESI
POP EDI
POP EDX
POP ECX
POP EBX
RETN 0x18
}}
FCT_ASM( caller_addClientForWE_111 )
PUSH EAX
CALL initWorldEventVariables
POP EAX
JMP D2AddClient
}}
FCT_ASM( caller_addClientForWE )
PUSH ECX
CALL initWorldEventVariables
POP ECX
JMP D2AddClient
}}
void Install_WorldEvent()
{
static int isInstalled = false;
if (isInstalled) return;
if ( version_D2Game < V110 )
return;
nbSOJSold = (DWORD)(rand()/(RAND_MAX+1.0)*valueInitSOJSoldDelta + valueInitSOJSoldMin);
if (active_AutomaticSell)
{
prevTicks = GetTickCount();
nbTicksForNextSOJSold = (DWORD)(rand()/(RAND_MAX+1.0)*(timeBeforeAutoSellDelta+timeBeforeAutoSellMin));
}
log_msg("Patch D2Game for active World Event. (WorldEvent)\n");
// spawn DClone
mem_seek R8(D2Game, 0000, 0000, 3F720, 4BCB1, ECF10, 41570, 25280, CFBD0, 1A4A4F);
MEMC_REF4( V2SpawnSuperUnique , version_D2Game >= V114a ? (DWORD)caller_spawnDClone_114 : version_D2Game >= V111b ? (DWORD)caller_spawnDClone_111b : version_D2Game == V111 ? (DWORD)caller_spawnDClone_111 : (DWORD)spawnDClone);
//6FC6F71F |. E8 FCFAFFFF CALL D2Game.6FC6F220
//01FCBCB0 |. E8 2BEFFFFF CALL D2Game.01FCABE0 ; \D2Game.01FCABE0
//0205CF0F |. E8 CCF8FFFF CALL D2Game.0205C7E0 ; \D2Game.0205C7E0
//6FC6156F |. E8 1CF6FFFF CALL D2Game.6FC60B90 ; \D2Game.6FC60B90
//6FC4527F |. E8 CCF6FFFF CALL D2Game.6FC44950 ; \D2Game.6FC44950
//6FCEFBCF |. E8 4CE2FFFF CALL D2Game.6FCEDE20 ; \D2Game.6FCEDE20
//005A4A4E |. E8 8DBFFFFF CALL Game.005A09E0 ; \Game.005A09E0
// verify if the item sold is a trigger of WE
mem_seek R8(D2Game, 0000, 0000, 977D0, 8E799, 92859, 84499, BFB29, 72BE9, 179667);
MEMJ_REF4( D2TestFlags , verifIfWEItem);
//6FCC77CF |. E8 32400500 CALL <JMP.&D2Common.#10707>
//0200E798 |. E8 E9BDF7FF CALL <JMP.&D2Common.#10911>
//02002858 |. E8 E57DF7FF CALL <JMP.&D2Common.#10303>
//6FCA4498 |. E8 3B62F8FF CALL <JMP.&D2Common.#10989>
//6FCDFB28 |. E8 77ADF4FF CALL <JMP.&D2Common.#10202>
//6FC92BE8 |. E8 DD7AF9FF CALL <JMP.&D2Common.#10458>
//00579666 |. E8 35EA0A00 CALL Game.006280A0 ; \Game.006280A0
// management of the WorldEvent
mem_seek R8(D2Game, 0000, 0000, 3CE0, 51F01, C5681, EBF41, 4A791, E5F51, 12FEED);
MEMC_REF4( V2GetGameByClientID , version_D2Game >= V114a ? (DWORD)caller_WEManagement_114 : version_D2Game >= V111 ? (DWORD)WEManagement : (DWORD)caller_WEManagement_1XX);
//6FC33CDF . E8 FC570000 CALL D2Game.6FC394E0
//01FD1F00 |. E8 1BE60800 CALL D2Game.02060520
//02035680 |. E8 1BF30100 CALL D2Game.020549A0
//6FD0BF40 |. E8 1BA4FBFF CALL D2Game.6FCC6360
//6FC6A790 |. E8 4B03FEFF CALL D2Game.6FC4AAE0
//6FD05F50 |. E8 AB67FDFF CALL D2Game.6FCDC700
//0052FEEC |. E8 6FE9FFFF CALL Game.0052E860
//to check : 005389B0 |. E8 2B75FFFF CALL Game.0052FEE0
// add client for the WorldEvent
mem_seek R8(D2Game, 0000, 0000, 1AEF, 3786A, 7055A, 6265F, CB0BF, D556F, 13F2D2);
MEMC_REF4( D2AddClient , version_D2Game >= V111 && version_D2Game <= V113d ? caller_addClientForWE_111 : caller_addClientForWE);
//6FC31AEE |. E8 6D510000 CALL D2Game.6FC36C60
//01FB7869 |. E8 32C50A00 CALL D2Game.02063DA0
//01FE0559 |. E8 B27C0700 CALL D2Game.02058210
//6FC8265E |. E8 FD890800 CALL D2Game.6FD0B060
//6FCEB0BE |. E8 6DE8F7FF CALL D2Game.6FC69930
//6FCF556E |. E8 FDFA0000 CALL D2Game.6FD05070
//0053F2D1 |. E8 7AD2FEFF CALL Game.0052C550
log_msg("\n");
isInstalled = true;
}
/*================================= END OF FILE =================================*/