/*================================================================= 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 //0200E798 |. E8 E9BDF7FF CALL //02002858 |. E8 E57DF7FF CALL //6FCA4498 |. E8 3B62F8FF CALL //6FCDFB28 |. E8 77ADF4FF CALL //6FC92BE8 |. E8 DD7AF9FF CALL //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 =================================*/