devilutionX/Source/multi.cpp
Anders Jenbo 4aac75e836 Change msg attributes to signed where relevant
The variables are either being compared to -1, transfered between values
that are signed or closely related to such. Having them as unsigned has
the potential to break the game, having them signed shoudn't have any
negative effects.
2018-12-15 18:13:31 +01:00

1031 lines
27 KiB
C++

//HEADER_GOES_HERE
#include "../types.h"
char gbSomebodyWonGameKludge; // weak
char pkdata_6761C0[4100];
char szPlayerDescript[128];
short sgwPackPlrOffsetTbl[MAX_PLRS];
PkPlayerStruct netplr[MAX_PLRS];
char sgbPlayerTurnBitTbl[MAX_PLRS];
char sgbPlayerLeftGameTbl[MAX_PLRS];
int multi_cpp_init_value; // weak
int sgbSentThisCycle; // idb
int dword_678628; // weak
BYTE gbActivePlayers; // weak
char gbGameDestroyed; // weak
char sgbSendDeltaTbl[MAX_PLRS];
_gamedata sgGameInitInfo;
char byte_678640; // weak
int sglTimeoutStart; // weak
int sgdwPlayerLeftReasonTbl[MAX_PLRS];
char pkdata_678658[4100];
unsigned int sgdwGameLoops; // idb
BYTE gbMaxPlayers;
char sgbTimeout; // weak
char szPlayerName[128];
BYTE gbDeltaSender;
int sgbNetInited; // weak
int player_state[MAX_PLRS];
const int multi_inf = 0x7F800000; // weak
const int event_types[3] = {
EVENT_TYPE_PLAYER_LEAVE_GAME,
EVENT_TYPE_PLAYER_CREATE_GAME,
EVENT_TYPE_PLAYER_MESSAGE
};
struct multi_cpp_init {
multi_cpp_init()
{
multi_cpp_init_value = multi_inf;
}
} _multi_cpp_init;
// 47F154: using guessed type int multi_inf;
// 678620: using guessed type int multi_cpp_init_value;
void __fastcall multi_msg_add(BYTE *a1, unsigned char a2)
{
if (a1) {
if (a2)
tmsg_add(a1, a2);
}
}
void __fastcall NetSendLoPri(BYTE *pbMsg, BYTE bLen)
{
if (pbMsg) {
if (bLen) {
multi_copy_packet(pkdata_678658, pbMsg, bLen);
multi_send_packet(pbMsg, bLen);
}
}
}
void __fastcall multi_copy_packet(void *a1, void *packet, BYTE size)
{
int v3; // eax
int v4; // ebx
char *v5; // esi
v3 = *(_DWORD *)a1;
v4 = *(_DWORD *)a1 + (unsigned char)size;
if ((unsigned int)(v4 + 2) <= 0x1000) {
*(_DWORD *)a1 = v4 + 1;
*((_BYTE *)a1 + v3 + 4) = size;
v5 = (char *)a1 + v3 + 5;
memcpy(v5, packet, (unsigned char)size);
v5[(unsigned char)size] = 0;
}
}
void __fastcall multi_send_packet(void *packet, BYTE dwSize)
{
void *v2; // esi
unsigned char v3; // bl
TPkt pkt; // [esp+8h] [ebp-200h]
v2 = packet;
v3 = dwSize;
NetRecvPlrData(&pkt);
pkt.hdr.wLen = v3 + 19;
memcpy(pkt.body, v2, v3);
if (!SNetSendMessage(myplr, &pkt.hdr, (unsigned short)pkt.hdr.wLen))
nthread_terminate_game("SNetSendMessage0");
}
void __fastcall NetRecvPlrData(TPkt *pkt)
{
pkt->hdr.wCheck = 'ip';
pkt->hdr.px = plr[myplr].WorldX;
pkt->hdr.py = plr[myplr].WorldY;
pkt->hdr.targx = plr[myplr]._ptargx;
pkt->hdr.targy = plr[myplr]._ptargy;
pkt->hdr.php = plr[myplr]._pHitPoints;
pkt->hdr.pmhp = plr[myplr]._pMaxHP;
pkt->hdr.bstr = plr[myplr]._pBaseStr;
pkt->hdr.bmag = plr[myplr]._pBaseMag;
pkt->hdr.bdex = plr[myplr]._pBaseDex;
}
void __fastcall NetSendHiPri(BYTE *pbMsg, BYTE bLen)
{
unsigned char *v5; // eax
TSyncHeader *v6; // eax
int v7; // eax
int v8; // eax
TPkt pkt; // [esp+Ch] [ebp-204h]
int size; // [esp+20Ch] [ebp-4h]
if (pbMsg && bLen) {
multi_copy_packet(pkdata_6761C0, pbMsg, bLen);
multi_send_packet(pbMsg, bLen);
}
if (!dword_678628) {
dword_678628 = 1;
NetRecvPlrData(&pkt);
size = gdwNormalMsgSize - 19;
v5 = multi_recv_packet(pkdata_6761C0, pkt.body, &size);
v6 = (TSyncHeader *)multi_recv_packet(pkdata_678658, v5, &size);
v7 = sync_all_monsters(v6, size);
v8 = gdwNormalMsgSize - v7;
pkt.hdr.wLen = v8;
if (!SNetSendMessage(-2, &pkt.hdr, v8))
nthread_terminate_game("SNetSendMessage");
}
}
// 678628: using guessed type int dword_678628;
// 679760: using guessed type int gdwNormalMsgSize;
unsigned char *__fastcall multi_recv_packet(void *packet, unsigned char *a2, int *a3)
{
char *v3; // esi
unsigned char *result; // eax
char *v5; // ebx
size_t v6; // edi
char *v7; // ebx
unsigned char *v8; // [esp+4h] [ebp-4h]
v3 = (char *)packet;
result = a2;
v8 = a2;
if (*(_DWORD *)packet) {
v5 = (char *)packet + 4;
while (*v5) {
v6 = (unsigned char)*v5;
if (v6 > *a3)
break;
v7 = v5 + 1;
memcpy(v8, v7, v6);
v8 += v6;
v5 = &v7[v6];
*a3 -= v6;
}
memcpy(v3 + 4, v5, (size_t)&v3[*(_DWORD *)v3 - (_DWORD)v5 + 5]);
*(_DWORD *)v3 += v3 - v5 + 4;
result = v8;
}
return result;
}
void __fastcall multi_send_msg_packet(int a1, BYTE *a2, BYTE len)
{
//const void *v3; // edx
signed int v4; // ebx
unsigned int v5; // edi
TPkt pkt; // [esp+Ch] [ebp-204h]
int v8; // [esp+20Ch] [ebp-4h]
v8 = a1;
NetRecvPlrData(&pkt);
pkt.hdr.wLen = len + 19;
memcpy(pkt.body, a2, len);
v4 = 1;
v5 = 0;
while (1) {
if (v4 & v8) {
if (!SNetSendMessage(v5, &pkt.hdr, len + 19) && SErrGetLastError() != STORM_ERROR_INVALID_PLAYER)
break;
}
++v5;
v4 *= 2;
if (v5 >= 4)
return;
}
nthread_terminate_game("SNetSendMessage");
}
void __cdecl multi_msg_countdown()
{
int v0; // esi
v0 = 0;
do {
if (player_state[v0] & 0x20000) {
if (gdwMsgLenTbl[v0] == 4)
multi_parse_turn(v0, *(_DWORD *)glpMsgTbl[v0]);
}
++v0;
} while (v0 < MAX_PLRS);
}
void __fastcall multi_parse_turn(int pnum, int turn)
{
int v2; // esi
unsigned int v3; // esi
v2 = turn;
if (turn < 0)
multi_handle_turn_upper_bit(pnum);
v3 = v2 & 0x7FFFFFFF;
if (sgbSentThisCycle < gdwTurnsInTransit + v3) {
if (v3 >= 0x7FFFFFFF)
v3 = (unsigned short)v3;
sgbSentThisCycle = v3 + gdwTurnsInTransit;
sgdwGameLoops = 4 * v3 * (unsigned char)byte_679704;
}
}
// 679704: using guessed type char byte_679704;
// 679738: using guessed type int gdwTurnsInTransit;
void __fastcall multi_handle_turn_upper_bit(int pnum)
{
signed int v1; // eax
v1 = 0;
do {
if (player_state[v1] & 0x10000 && v1 != pnum)
break;
++v1;
} while (v1 < MAX_PLRS);
if (myplr == v1) {
sgbSendDeltaTbl[pnum] = 1;
} else if (myplr == pnum) {
gbDeltaSender = v1;
}
}
// 6796E4: using guessed type char gbDeltaSender;
void __fastcall multi_player_left(int pnum, int reason)
{
sgbPlayerLeftGameTbl[pnum] = 1;
sgdwPlayerLeftReasonTbl[pnum] = reason;
multi_clear_left_tbl();
}
void __cdecl multi_clear_left_tbl()
{
int v0; // esi
v0 = 0;
do {
if (sgbPlayerLeftGameTbl[v0]) {
if (gbBufferMsgs == 1)
msg_send_drop_pkt(v0, sgdwPlayerLeftReasonTbl[v0]);
else
multi_player_left_msg(v0, 1);
sgbPlayerLeftGameTbl[v0] = 0;
sgdwPlayerLeftReasonTbl[v0] = 0;
}
++v0;
} while (v0 < MAX_PLRS);
}
// 676194: using guessed type char gbBufferMsgs;
void __fastcall multi_player_left_msg(int pnum, int left)
{
int v2; // edi
int v3; // ebx
int v4; // esi
char *v5; // eax
int v6; // edi
v2 = pnum;
v3 = left;
v4 = pnum;
if (plr[pnum].plractive) {
RemovePlrFromMap(pnum);
RemovePortalMissile(v2);
DeactivatePortal(v2);
RemovePlrPortal(v2);
RemovePlrMissiles(v2);
if (v3) {
v5 = "Player '%s' just left the game";
v6 = sgdwPlayerLeftReasonTbl[v2] - 0x40000004;
if (v6) {
if (v6 == 2)
v5 = "Player '%s' dropped due to timeout";
} else {
v5 = "Player '%s' killed Diablo and left the game!";
gbSomebodyWonGameKludge = 1;
}
EventPlrMsg(v5, plr[v4]._pName);
}
plr[v4].plractive = 0;
plr[v4]._pName[0] = 0;
--gbActivePlayers;
}
}
// 6761B8: using guessed type char gbSomebodyWonGameKludge;
void __cdecl multi_net_ping()
{
sgbTimeout = 1;
sglTimeoutStart = GetTickCount();
}
// 678644: using guessed type int sglTimeoutStart;
// 679661: using guessed type char sgbTimeout;
int __cdecl multi_handle_delta()
{
int v0; // esi
int recieved; // [esp+4h] [ebp-4h]
if (gbGameDestroyed) {
gbRunGame = FALSE;
return 0;
}
v0 = 0;
do {
if (sgbSendDeltaTbl[v0]) {
sgbSendDeltaTbl[v0] = 0;
DeltaExportData(v0);
}
++v0;
} while (v0 < MAX_PLRS);
sgbSentThisCycle = nthread_send_and_recv_turn(sgbSentThisCycle, 1);
if (!nthread_recv_turns(&recieved)) {
multi_begin_timeout();
return 0;
}
sgbTimeout = 0;
if (recieved) {
if (dword_678628) {
dword_678628 = 0;
if (!multi_check_pkt_valid(pkdata_6761C0))
NetSendHiPri(0, 0);
} else {
NetSendHiPri(0, 0);
dword_678628 = 0;
}
}
multi_mon_seeds();
return 1;
}
// 678628: using guessed type int dword_678628;
// 67862D: using guessed type char gbGameDestroyed;
// 679661: using guessed type char sgbTimeout;
// Microsoft VisualC 2-11/net runtime
int __fastcall multi_check_pkt_valid(char *a1)
{
return *(_DWORD *)a1 == 0;
}
void __cdecl multi_mon_seeds()
{
unsigned int v0; // eax
int v1; // edx
int *v2; // ecx
int v3; // esi
v0 = _rotr(++sgdwGameLoops, 8);
v1 = 0;
v2 = &monster[0]._mAISeed;
do {
v3 = v1++ + v0;
*v2 = v3;
v2 += 57;
} while ((signed int)v2 < (signed int)&monster[MAXMONSTERS]._mAISeed);
}
void __cdecl multi_begin_timeout()
{
unsigned char bGroupPlayers; // bl
signed int v1; // eax
signed int nLowestActive; // esi
signed int nLowestPlayer; // edi
signed int v4; // eax
int v5; // edx
unsigned char v6; // [esp+Fh] [ebp-1h]
bGroupPlayers = 0;
#ifdef _DEBUG
if (sgbTimeout && !debug_mode_key_i)
#else
if (sgbTimeout)
#endif
{
v1 = GetTickCount() - sglTimeoutStart;
if (v1 <= 20000) {
if (v1 >= 10000) {
v6 = 0;
nLowestActive = -1;
nLowestPlayer = -1;
v4 = 0;
do {
v5 = player_state[v4];
if (v5 & 0x10000) {
if (nLowestPlayer == -1)
nLowestPlayer = v4;
if (v5 & 0x40000) {
++bGroupPlayers;
if (nLowestActive == -1)
nLowestActive = v4;
} else {
++v6;
}
}
++v4;
} while (v4 < MAX_PLRS);
if (bGroupPlayers >= v6 && (bGroupPlayers != v6 || nLowestPlayer == nLowestActive)) {
if (nLowestActive == myplr)
multi_check_drop_player();
} else {
gbGameDestroyed = 1;
}
}
} else {
gbRunGame = FALSE;
}
}
}
// 67862D: using guessed type char gbGameDestroyed;
// 678644: using guessed type int sglTimeoutStart;
// 679661: using guessed type char sgbTimeout;
void __cdecl multi_check_drop_player()
{
int v0; // esi
int v1; // eax
v0 = 0;
do {
v1 = player_state[v0];
if (!(v1 & 0x40000)) {
if (v1 & 0x10000)
SNetDropPlayer(v0, 0x40000006);
}
++v0;
} while (v0 < MAX_PLRS);
}
void __cdecl multi_process_network_packets()
{
//int v0; // eax
TPktHdr *v1; // ecx
TPktHdr *v2; // edi
int v3; // eax
BOOLEAN v4; // zf
unsigned char *v5; // esi
int v6; // ebx
int v7; // eax
int v8; // ecx
int v9; // eax
int v10; // eax
int v11; // esi
int v12; // eax
int v13; // ecx
int v14; // eax
//int v15; // eax
TPktHdr *pkt; // [esp+0h] [ebp-Ch]
int len; // [esp+4h] [ebp-8h]
char arglist[4]; // [esp+8h] [ebp-4h] /* fix, int */
multi_clear_left_tbl();
multi_process_tmsgs();
//_LOBYTE(v0) = SNetReceiveMessage((int *)arglist, (char **)&pkt, &len);
if (SNetReceiveMessage((int *)arglist, (char **)&pkt, &len)) {
do {
++pkt_counter;
multi_clear_left_tbl();
v1 = pkt;
v2 = pkt;
if ((unsigned int)len >= 0x13
&& *(_DWORD *)arglist < 4u
&& pkt->wCheck == 'ip'
&& (unsigned short)pkt->wLen == len) {
v3 = *(_DWORD *)arglist;
v4 = *(_DWORD *)arglist == myplr;
plr[v3]._pownerx = (unsigned char)pkt->px;
v5 = &v1->py;
plr[v3]._pownery = (unsigned char)v1->py;
if (!v4) {
v4 = gbBufferMsgs == 1;
plr[v3]._pHitPoints = v1->php;
plr[v3]._pMaxHP = v1->pmhp;
plr[v3]._pBaseStr = (unsigned char)v1->bstr;
plr[v3]._pBaseMag = (unsigned char)v1->bmag;
plr[v3]._pBaseDex = (unsigned char)v1->bdex;
if (!v4 && plr[v3].plractive && plr[v3]._pHitPoints) {
if (currlevel != plr[v3].plrlevel || plr[v3]._pLvlChanging) {
plr[v3].WorldX = (unsigned char)v1->px;
plr[v3].WorldY = (unsigned char)*v5;
plr[v3]._px = (unsigned char)v1->px;
plr[v3]._py = (unsigned char)*v5;
plr[v3]._ptargx = (unsigned char)v1->targx;
plr[v3]._ptargy = (unsigned char)v1->targy;
} else {
v6 = abs(plr[v3].WorldX - (unsigned char)v1->px);
v7 = abs(plr[*(_DWORD *)arglist].WorldY - (unsigned char)*v5);
if ((v6 > 3 || v7 > 3) && !dPlayer[(unsigned char)v2->px][(unsigned char)*v5]) {
FixPlrWalkTags(*(int *)arglist);
v8 = *(_DWORD *)arglist;
v9 = *(_DWORD *)arglist;
plr[v9]._poldx = plr[*(_DWORD *)arglist].WorldX;
plr[v9]._poldy = plr[v9].WorldY;
FixPlrWalkTags(v8);
v10 = *(_DWORD *)arglist;
plr[v10].WorldX = (unsigned char)v2->px;
plr[v10].WorldY = (unsigned char)*v5;
plr[v10]._px = (unsigned char)v2->px;
plr[v10]._py = (unsigned char)*v5;
dPlayer[plr[v10].WorldX][plr[v10].WorldY] = arglist[0] + 1;
}
v11 = abs(plr[*(_DWORD *)arglist]._px - plr[*(_DWORD *)arglist].WorldX);
v12 = abs(plr[*(_DWORD *)arglist]._py - plr[*(_DWORD *)arglist].WorldY);
v13 = *(_DWORD *)arglist;
if (v11 > 1 || v12 > 1) {
v14 = *(_DWORD *)arglist;
plr[v14]._px = plr[*(_DWORD *)arglist].WorldX;
plr[v14]._py = plr[v13].WorldY;
}
MakePlrPath(v13, (unsigned char)v2->targx, (unsigned char)v2->targy, 1u);
}
}
}
multi_handle_all_packets(*(int *)arglist, (TPkt *)&v2[1], len - 19);
}
//_LOBYTE(v15) = SNetReceiveMessage((int *)arglist, (char **)&pkt, &len);
} while (SNetReceiveMessage((int *)arglist, (char **)&pkt, &len));
}
if (SErrGetLastError() != STORM_ERROR_NO_MESSAGES_WAITING)
nthread_terminate_game("SNetReceiveMsg");
}
// 676194: using guessed type char gbBufferMsgs;
// 676198: using guessed type int pkt_counter;
void __fastcall multi_handle_all_packets(int players, TPkt *packet, int a3)
{
TCmd *v3; // esi
int i; // edi
int v5; // eax
v3 = (TCmd *)packet;
for (i = players; a3; a3 -= v5) {
v5 = ParseCmd(i, v3);
if (!v5)
break;
v3 += v5;
}
}
void __cdecl multi_process_tmsgs()
{
int v0; // eax
TPkt pkt; // [esp+0h] [ebp-200h]
while (1) {
v0 = tmsg_get((BYTE *)&pkt, 512);
if (!v0)
break;
multi_handle_all_packets(myplr, &pkt, v0);
}
}
void __fastcall multi_send_zero_packet(int pnum, char a2, void *pbSrc, int dwLen)
{
unsigned int v4; // edi
short v5; // si
unsigned short dwBody; // ax
TPkt pkt; // [esp+Ch] [ebp-208h]
int pnuma; // [esp+20Ch] [ebp-8h]
int v10; // [esp+210h] [ebp-4h]
v4 = dwLen;
_LOBYTE(v10) = a2;
pnuma = pnum;
v5 = 0;
while (v4) {
pkt.hdr.wCheck = 'ip';
pkt.body[0] = v10;
dwBody = gdwLargestMsgSize - 24;
pkt.hdr.px = 0;
pkt.hdr.py = 0;
pkt.hdr.targx = 0;
pkt.hdr.targy = 0;
pkt.hdr.php = 0;
pkt.hdr.pmhp = 0;
pkt.hdr.bstr = 0;
pkt.hdr.bmag = 0;
pkt.hdr.bdex = 0;
*(_WORD *)&pkt.body[1] = v5;
if (v4 < gdwLargestMsgSize - 24)
dwBody = v4;
*(_WORD *)&pkt.body[3] = dwBody;
memcpy(&pkt.body[5], pbSrc, dwBody);
pkt.hdr.wLen = *(_WORD *)&pkt.body[3] + 24;
if (!SNetSendMessage(pnuma, &pkt.hdr, *(unsigned short *)&pkt.body[3] + 24)) {
nthread_terminate_game("SNetSendMessage2");
return;
}
pbSrc = (char *)pbSrc + *(unsigned short *)&pkt.body[3];
v4 -= *(unsigned short *)&pkt.body[3];
v5 += *(_WORD *)&pkt.body[3];
}
}
// 67975C: using guessed type int gdwLargestMsgSize;
void __cdecl NetClose()
{
if (sgbNetInited) {
sgbNetInited = 0;
nthread_cleanup();
dthread_cleanup();
tmsg_cleanup();
multi_event_handler(0);
SNetLeaveGame(3);
msgcmd_cmd_cleanup();
if ((unsigned char)gbMaxPlayers > 1u)
Sleep(2000);
}
}
// 679660: using guessed type char gbMaxPlayers;
// 6796E8: using guessed type int sgbNetInited;
char __fastcall multi_event_handler(int a1)
{
int v1; // edi
void *(__stdcall * v2)(int, void(__stdcall *)(_SNETEVENT *)); // ebx
unsigned int v3; // esi
int v4; // eax
char *v5; // eax
v1 = a1;
v2 = SNetRegisterEventHandler;
if (!a1)
v2 = SNetUnregisterEventHandler;
v3 = 0;
do {
v4 = (int)v2(event_types[v3], multi_handle_events);
if (!v4 && v1) {
v5 = TraceLastError();
TermMsg("SNetRegisterEventHandler:\n%s", v5);
}
++v3;
} while (v3 < 3);
return v4;
}
void __stdcall multi_handle_events(_SNETEVENT *pEvt)
{
int v1; // ecx
int *v2; // eax
int *v3; // eax
switch (pEvt->eventid) {
case EVENT_TYPE_PLAYER_CREATE_GAME:
v3 = (int *)pEvt->data;
sgGameInitInfo.dwSeed = *v3;
_LOBYTE(sgGameInitInfo.bDiff) = *((_BYTE *)v3 + 4);
sgbPlayerTurnBitTbl[pEvt->playerid] = 1;
break;
case EVENT_TYPE_PLAYER_LEAVE_GAME:
v1 = 0;
sgbPlayerLeftGameTbl[pEvt->playerid] = 1;
sgbPlayerTurnBitTbl[pEvt->playerid] = 0;
v2 = (int *)pEvt->data;
if (v2 && pEvt->databytes >= 4u)
v1 = *v2;
sgdwPlayerLeftReasonTbl[pEvt->playerid] = v1;
if (v1 == 0x40000004)
gbSomebodyWonGameKludge = 1;
sgbSendDeltaTbl[pEvt->playerid] = 0;
dthread_remove_player(pEvt->playerid);
if (gbDeltaSender == pEvt->playerid)
gbDeltaSender = 4;
break;
case EVENT_TYPE_PLAYER_MESSAGE:
ErrorPlrMsg((char *)pEvt->data);
break;
}
}
// 6761B8: using guessed type char gbSomebodyWonGameKludge;
// 6796E4: using guessed type char gbDeltaSender;
int __fastcall NetInit(int bSinglePlayer, int *pfExitProgram)
{
int v2; // ebx
int v4; // eax
//int v5; // ecx
BOOLEAN v7; // zf
//int v9; // eax
//int v10; // eax
_SNETPROGRAMDATA ProgramData; // [esp+8h] [ebp-A8h]
_SNETUIDATA UiData; // [esp+44h] [ebp-6Ch]
_SNETPLAYERDATA a2; // [esp+94h] [ebp-1Ch]
int v14; // [esp+A4h] [ebp-Ch]
unsigned int len; // [esp+A8h] [ebp-8h]
int *a4; // [esp+ACh] [ebp-4h]
a4 = pfExitProgram;
v14 = bSinglePlayer;
v2 = 0;
while (1) {
*a4 = 0;
SetRndSeed(0);
sgGameInitInfo.dwSeed = time(NULL);
_LOBYTE(sgGameInitInfo.bDiff) = gnDifficulty;
memset(&ProgramData, 0, 0x3Cu);
ProgramData.size = 60;
ProgramData.programname = "Diablo Retail";
ProgramData.programdescription = gszVersionNumber;
ProgramData.programid = 'DRTL';
ProgramData.versionid = 42;
ProgramData.maxplayers = MAX_PLRS;
ProgramData.initdata = &sgGameInitInfo;
ProgramData.initdatabytes = 8;
ProgramData.optcategorybits = 15;
ProgramData.lcid = 1033; /* LANG_ENGLISH */
memset(&a2, 0, 0x10u);
a2.size = 16;
memset(&UiData, 0, 0x50u);
UiData.size = 80;
UiData.parentwindow = SDrawGetFrameWindow(NULL);
UiData.artcallback = (void(__cdecl *)())UiArtCallback;
UiData.createcallback = (void(__cdecl *)())UiCreateGameCallback;
UiData.drawdesccallback = (void(__cdecl *)())UiDrawDescCallback;
UiData.messageboxcallback = (void(__cdecl *)())UiMessageBoxCallback;
UiData.soundcallback = (void(__cdecl *)())UiSoundCallback;
UiData.authcallback = (void(__cdecl *)())UiAuthCallback;
UiData.getdatacallback = (void(__cdecl *)())UiGetDataCallback;
UiData.categorycallback = (void(__cdecl *)())UiCategoryCallback;
UiData.selectnamecallback = mainmenu_select_hero_dialog;
UiData.changenamecallback = (void(__cdecl *)())mainmenu_create_hero;
UiData.profilebitmapcallback = UiProfileDraw;
UiData.profilecallback = UiProfileCallback;
UiData.profilefields = UiProfileGetString();
memset(sgbPlayerTurnBitTbl, 0, 4u);
gbGameDestroyed = 0;
memset(sgbPlayerLeftGameTbl, 0, 4u);
memset(sgdwPlayerLeftReasonTbl, 0, 0x10u);
memset(sgbSendDeltaTbl, 0, 4u);
memset(plr, 0, 0x15360u);
memset(sgwPackPlrOffsetTbl, 0, 8u);
SNetSetBasePlayer(0);
if (v14)
v4 = multi_init_single(&ProgramData, &a2, &UiData);
else
v4 = multi_init_multi(&ProgramData, &a2, &UiData, a4);
if (!v4)
return 0;
sgbNetInited = 1;
sgbTimeout = 0;
delta_init();
InitPlrMsg();
multi_clear_pkt(pkdata_6761C0);
multi_clear_pkt(pkdata_678658);
dword_678628 = 0;
sync_clear_pkt();
nthread_start(sgbPlayerTurnBitTbl[myplr]);
dthread_start();
MI_Dummy(0); /* v5 */
sgdwGameLoops = 0;
sgbSentThisCycle = 0;
gbDeltaSender = myplr;
gbSomebodyWonGameKludge = 0;
nthread_send_and_recv_turn(0, 0);
SetupLocalCoords();
multi_send_pinfo(-2, CMD_SEND_PLRINFO);
gbActivePlayers = 1;
v7 = sgbPlayerTurnBitTbl[myplr] == 0;
plr[myplr].plractive = 1;
if (v7 || msg_wait_resync())
break;
NetClose();
byte_678640 = 0;
}
gnDifficulty = _LOBYTE(sgGameInitInfo.bDiff);
SetRndSeed(sgGameInitInfo.dwSeed);
do {
glSeedTbl[v2] = GetRndSeed();
gnLevelTypeTbl[v2] = InitNewSeed(v2);
++v2;
} while (v2 < 17);
//_LOBYTE(v9) = SNetGetGameInfo(GAMEINFO_NAME, szPlayerName, 128, len);
if (!SNetGetGameInfo(GAMEINFO_NAME, szPlayerName, 128, &len))
nthread_terminate_game("SNetGetGameInfo1");
//_LOBYTE(v10) = SNetGetGameInfo(GAMEINFO_PASSWORD, szPlayerDescript, 128, len);
if (!SNetGetGameInfo(GAMEINFO_PASSWORD, szPlayerDescript, 128, &len))
nthread_terminate_game("SNetGetGameInfo2");
return 1;
}
// 6761B8: using guessed type char gbSomebodyWonGameKludge;
// 678628: using guessed type int dword_678628;
// 67862D: using guessed type char gbGameDestroyed;
// 678640: using guessed type char byte_678640;
// 679661: using guessed type char sgbTimeout;
// 6796E4: using guessed type char gbDeltaSender;
// 6796E8: using guessed type int sgbNetInited;
void __fastcall multi_clear_pkt(char *a1)
{
*(_DWORD *)a1 = 0;
a1[4] = 0;
}
void __fastcall multi_send_pinfo(int pnum, char cmd)
{
char v2; // bl
int v3; // esi
PkPlayerStruct pkplr; // [esp+8h] [ebp-4F4h]
v2 = cmd;
v3 = pnum;
PackPlayer(&pkplr, myplr, 1);
dthread_send_delta(v3, v2, &pkplr, 1266);
}
int __fastcall InitNewSeed(int newseed)
{
int result; // eax
result = 0;
if (newseed) {
result = 1;
if (newseed < 1 || newseed > 4) {
if (newseed < 5 || newseed > 8) {
if (newseed < 9 || newseed > 12)
result = 4;
else
result = 3;
} else {
result = 2;
}
}
}
return result;
}
void __cdecl SetupLocalCoords()
{
int x; // ecx
int y; // edx
if (!leveldebug || (unsigned char)gbMaxPlayers > 1u) {
currlevel = 0;
leveltype = 0;
setlevel = 0;
}
x = 75;
y = 68;
#ifdef _DEBUG
if (debug_mode_key_inverted_v || debug_mode_key_d) {
x = 49;
y = 23;
}
#endif
x += plrxoff[myplr];
y += plryoff[myplr];
plr[myplr].WorldX = x;
plr[myplr].WorldY = y;
plr[myplr]._px = x;
plr[myplr]._py = y;
plr[myplr]._ptargx = x;
plr[myplr]._ptargy = y;
plr[myplr].plrlevel = currlevel;
plr[myplr]._pLvlChanging = 1;
plr[myplr].pLvlLoad = 0;
plr[myplr]._pmode = PM_NEWLVL;
plr[myplr].destAction = ACTION_NONE;
}
// 52572C: using guessed type int leveldebug;
// 5CF31D: using guessed type char setlevel;
// 679660: using guessed type char gbMaxPlayers;
int __fastcall multi_init_single(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info)
{
//int v3; // eax
int result; // eax
//int v5; // eax
char *v6; // eax
//_LOBYTE(v3) = SNetInitializeProvider(0, client_info, user_info, ui_info, &fileinfo);
if (SNetInitializeProvider(0, client_info, user_info, ui_info, &fileinfo)) {
ui_info = 0;
//_LOBYTE(v5) = SNetCreateGame("local", "local", "local", 0, (char *)&sgGameInitInfo.dwSeed, 8, 1, "local", "local", (int *)&ui_info);
if (!SNetCreateGame("local", "local", "local", 0, (char *)&sgGameInitInfo.dwSeed, 8, 1, "local", "local", (int *)&ui_info)) {
v6 = TraceLastError();
TermMsg("SNetCreateGame1:\n%s", v6);
}
myplr = 0;
gbMaxPlayers = 1;
result = 1;
} else {
SErrGetLastError();
result = 0;
}
return result;
}
// 679660: using guessed type char gbMaxPlayers;
int __fastcall multi_init_multi(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, int *a4)
{
_SNETPLAYERDATA *v4; // ebx
signed int i; // edi
int a6; // [esp+Ch] [ebp-Ch]
int a2; // [esp+10h] [ebp-8h]
int type; // [esp+14h] [ebp-4h]
v4 = user_info;
a2 = (int)client_info;
for (i = 1;; i = 0) {
type = 0;
if (byte_678640) {
if (!UiSelectProvider(0, (_SNETPROGRAMDATA *)a2, v4, ui_info, &fileinfo, &type)
&& (!i || SErrGetLastError() != STORM_ERROR_REQUIRES_UPGRADE || !multi_upgrade(a4))) {
return 0;
}
if (type == 'BNET')
plr[0].pBattleNet = 1;
}
multi_event_handler(1);
if (UiSelectGame(1, (_SNETPROGRAMDATA *)a2, v4, ui_info, &fileinfo, &a6))
break;
byte_678640 = 1;
}
if ((unsigned int)a6 >= MAX_PLRS)
return 0;
myplr = a6;
gbMaxPlayers = MAX_PLRS;
pfile_read_player_from_save();
if (type == 'BNET')
plr[myplr].pBattleNet = 1;
return 1;
}
// 678640: using guessed type char byte_678640;
// 679660: using guessed type char gbMaxPlayers;
int __fastcall multi_upgrade(int *a1)
{
int *v1; // esi
int result; // eax
int status; // [esp+4h] [ebp-4h]
v1 = a1;
SNetPerformUpgrade((unsigned long *)&status);
result = 1;
if (status && status != 1) {
if (status == 2) {
*v1 = 1;
} else if (status == -1) {
DrawDlg("Network upgrade failed");
}
result = 0;
}
return result;
}
void __fastcall multi_player_joins(int pnum, TCmdPlrInfoHdr *cmd, int a3)
{
int v3; // ebx
TCmdPlrInfoHdr *v4; // edi
short *v5; // esi
int v6; // esi
BOOLEAN v7; // zf
char *v8; // eax
int v9; // ST08_4
unsigned char *v10; // edx
int v11; // eax
int v12; // ecx
int v13; // eax
v3 = pnum;
v4 = cmd;
if (myplr != pnum) {
v5 = &sgwPackPlrOffsetTbl[pnum];
if (*v5 == cmd->wOffset || (*v5 = 0, !cmd->wOffset)) {
if (!a3 && !*v5) {
multi_send_pinfo(pnum, CMD_ACK_PLRINFO);
}
memcpy((char *)&netplr[v3] + (unsigned short)v4->wOffset, &v4[1], (unsigned short)v4->wBytes);
*v5 += v4->wBytes;
if (*v5 == 1266) {
*v5 = 0;
multi_player_left_msg(v3, 0);
v6 = v3;
plr[v3]._pGFXLoad = 0;
UnPackPlayer(&netplr[v3], v3, 1);
if (a3) {
++gbActivePlayers;
v7 = sgbPlayerTurnBitTbl[v3] == 0;
plr[v6].plractive = 1;
v8 = "Player '%s' (level %d) just joined the game";
if (v7)
v8 = "Player '%s' (level %d) is already in the game";
EventPlrMsg(v8, plr[v6]._pName, plr[v6]._pLevel);
LoadPlrGFX(v3, PFILE_STAND);
SyncInitPlr(v3);
if (plr[v6].plrlevel == currlevel) {
if (plr[v6]._pHitPoints >> 6 <= 0) {
plr[v6]._pgfxnum = 0;
LoadPlrGFX(v3, PFILE_DEATH);
v9 = plr[v6]._pDWidth;
v10 = plr[v6]._pDAnim[0];
plr[v6]._pmode = 8;
NewPlrAnim(v3, v10, plr[v6]._pDFrames, 1, v9);
v11 = plr[v6]._pAnimLen;
v12 = v11 - 1;
plr[v6]._pVar8 = 2 * v11;
v13 = plr[v6].WorldX;
plr[v6]._pAnimFrame = v12;
dFlags[v13][plr[v6].WorldY] |= DFLAG_DEAD_PLAYER;
} else {
StartStand(v3, 0);
}
}
}
}
}
}
}