|
|
|
|
#include "diablo.h"
|
|
|
|
|
#include "../3rdParty/Storm/Source/storm.h"
|
|
|
|
|
#include "../DiabloUI/diabloui.h"
|
|
|
|
|
|
|
|
|
|
BOOLEAN gbSomebodyWonGameKludge; // weak
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
DWORD gdwHistTicks;
|
|
|
|
|
#endif
|
|
|
|
|
TBuffer sgHiPriBuf;
|
|
|
|
|
char szPlayerDescript[128];
|
|
|
|
|
WORD sgwPackPlrOffsetTbl[MAX_PLRS];
|
|
|
|
|
PkPlayerStruct netplr[MAX_PLRS];
|
|
|
|
|
BOOLEAN sgbPlayerTurnBitTbl[MAX_PLRS];
|
|
|
|
|
BOOLEAN sgbPlayerLeftGameTbl[MAX_PLRS];
|
|
|
|
|
int sgbSentThisCycle; // idb
|
|
|
|
|
BOOL gbShouldValidatePackage;
|
|
|
|
|
BYTE gbActivePlayers; // weak
|
|
|
|
|
BOOLEAN gbGameDestroyed;
|
|
|
|
|
BOOLEAN sgbSendDeltaTbl[MAX_PLRS];
|
|
|
|
|
_gamedata sgGameInitInfo;
|
|
|
|
|
char byte_678640; // weak
|
|
|
|
|
int sglTimeoutStart; // weak
|
|
|
|
|
int sgdwPlayerLeftReasonTbl[MAX_PLRS];
|
|
|
|
|
TBuffer sgLoPriBuf;
|
|
|
|
|
unsigned int sgdwGameLoops; // idb
|
|
|
|
|
BYTE gbMaxPlayers;
|
|
|
|
|
BOOLEAN sgbTimeout;
|
|
|
|
|
char szPlayerName[128];
|
|
|
|
|
BYTE gbDeltaSender;
|
|
|
|
|
BOOL sgbNetInited; // weak
|
|
|
|
|
int player_state[MAX_PLRS];
|
|
|
|
|
|
|
|
|
|
const int event_types[3] = {
|
|
|
|
|
EVENT_TYPE_PLAYER_LEAVE_GAME,
|
|
|
|
|
EVENT_TYPE_PLAYER_CREATE_GAME,
|
|
|
|
|
EVENT_TYPE_PLAYER_MESSAGE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
void __cdecl dumphist(const char *pszFmt, ...)
|
|
|
|
|
{
|
|
|
|
|
static FILE *sgpHistFile = NULL;
|
|
|
|
|
DWORD dwTicks;
|
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
|
|
va_start(va, pszFmt);
|
|
|
|
|
|
|
|
|
|
if (sgpHistFile == NULL) {
|
|
|
|
|
sgpHistFile = fopen("c:\\dumphist.txt", "wb");
|
|
|
|
|
if (sgpHistFile == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dwTicks = GetTickCount();
|
|
|
|
|
fprintf(sgpHistFile, "%4u.%02u ", (dwTicks - gdwHistTicks) / 1000, (dwTicks - gdwHistTicks) % 1000 / 10);
|
|
|
|
|
vfprintf(sgpHistFile, pszFmt, va);
|
|
|
|
|
fprintf(
|
|
|
|
|
sgpHistFile,
|
|
|
|
|
"\r\n (%d,%d)(%d,%d)(%d,%d)(%d,%d)\r\n",
|
|
|
|
|
plr[0].plractive,
|
|
|
|
|
player_state[0],
|
|
|
|
|
plr[1].plractive,
|
|
|
|
|
player_state[1],
|
|
|
|
|
plr[2].plractive,
|
|
|
|
|
player_state[2],
|
|
|
|
|
plr[3].plractive,
|
|
|
|
|
player_state[3]);
|
|
|
|
|
fflush(sgpHistFile);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void multi_msg_add(BYTE *pbMsg, BYTE bLen)
|
|
|
|
|
{
|
|
|
|
|
if (pbMsg && bLen) {
|
|
|
|
|
tmsg_add(pbMsg, bLen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NetSendLoPri(BYTE *pbMsg, BYTE bLen)
|
|
|
|
|
{
|
|
|
|
|
if (pbMsg && bLen) {
|
|
|
|
|
multi_copy_packet(&sgLoPriBuf, pbMsg, bLen);
|
|
|
|
|
multi_send_packet(pbMsg, bLen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_copy_packet(TBuffer *buf, void *packet, BYTE size)
|
|
|
|
|
{
|
|
|
|
|
BYTE *p;
|
|
|
|
|
|
|
|
|
|
if (buf->dwNextWriteOffset + size + 2 > 0x1000) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p = &buf->bData[buf->dwNextWriteOffset];
|
|
|
|
|
buf->dwNextWriteOffset += size + 1;
|
|
|
|
|
*p = size;
|
|
|
|
|
p++;
|
|
|
|
|
memcpy(p, packet, size);
|
|
|
|
|
p[size] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_send_packet(void *packet, BYTE dwSize)
|
|
|
|
|
{
|
|
|
|
|
TPkt pkt;
|
|
|
|
|
|
|
|
|
|
NetRecvPlrData(&pkt);
|
|
|
|
|
pkt.hdr.wLen = dwSize + 19;
|
|
|
|
|
memcpy(pkt.body, packet, dwSize);
|
|
|
|
|
if (!SNetSendMessage(myplr, &pkt.hdr, pkt.hdr.wLen))
|
|
|
|
|
nthread_terminate_game("SNetSendMessage0");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void 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 NetSendHiPri(BYTE *pbMsg, BYTE bLen)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *v5; // eax
|
|
|
|
|
BYTE *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(&sgHiPriBuf, pbMsg, bLen);
|
|
|
|
|
multi_send_packet(pbMsg, bLen);
|
|
|
|
|
}
|
|
|
|
|
if (!gbShouldValidatePackage) {
|
|
|
|
|
gbShouldValidatePackage = TRUE;
|
|
|
|
|
NetRecvPlrData(&pkt);
|
|
|
|
|
size = gdwNormalMsgSize - 19;
|
|
|
|
|
v5 = multi_recv_packet(&sgHiPriBuf, pkt.body, &size);
|
|
|
|
|
v6 = multi_recv_packet(&sgLoPriBuf, 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");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 679760: using guessed type int gdwNormalMsgSize;
|
|
|
|
|
|
|
|
|
|
BYTE *multi_recv_packet(TBuffer *packet, BYTE *body, int *size)
|
|
|
|
|
{
|
|
|
|
|
BYTE *src_ptr;
|
|
|
|
|
size_t chunk_size;
|
|
|
|
|
|
|
|
|
|
if (packet->dwNextWriteOffset != 0) {
|
|
|
|
|
src_ptr = packet->bData;
|
|
|
|
|
while (TRUE) {
|
|
|
|
|
if (*src_ptr == 0)
|
|
|
|
|
break;
|
|
|
|
|
chunk_size = *src_ptr;
|
|
|
|
|
if (chunk_size > *size)
|
|
|
|
|
break;
|
|
|
|
|
src_ptr++;
|
|
|
|
|
memcpy(body, src_ptr, chunk_size);
|
|
|
|
|
body += chunk_size;
|
|
|
|
|
src_ptr += chunk_size;
|
|
|
|
|
*size -= chunk_size;
|
|
|
|
|
}
|
|
|
|
|
memcpy(packet->bData, src_ptr, (packet->bData - src_ptr) + packet->dwNextWriteOffset + 1);
|
|
|
|
|
packet->dwNextWriteOffset += (packet->bData - src_ptr);
|
|
|
|
|
return body;
|
|
|
|
|
}
|
|
|
|
|
return body;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_send_msg_packet(int pmask, BYTE *a2, BYTE len)
|
|
|
|
|
{
|
|
|
|
|
DWORD v, p, t;
|
|
|
|
|
TPkt pkt;
|
|
|
|
|
|
|
|
|
|
NetRecvPlrData(&pkt);
|
|
|
|
|
t = len + 19;
|
|
|
|
|
pkt.hdr.wLen = t;
|
|
|
|
|
memcpy(pkt.body, a2, len);
|
|
|
|
|
for (v = 1, p = 0; p < MAX_PLRS; p++, v <<= 1) {
|
|
|
|
|
if (v & pmask) {
|
|
|
|
|
if (!SNetSendMessage(p, &pkt.hdr, t) && SErrGetLastError() != STORM_ERROR_INVALID_PLAYER) {
|
|
|
|
|
nthread_terminate_game("SNetSendMessage");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_msg_countdown()
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_PLRS; i++) {
|
|
|
|
|
if (player_state[i] & 0x20000) {
|
|
|
|
|
if (gdwMsgLenTbl[i] == 4)
|
|
|
|
|
multi_parse_turn(i, *(DWORD *)glpMsgTbl[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_parse_turn(int pnum, int turn)
|
|
|
|
|
{
|
|
|
|
|
DWORD absTurns;
|
|
|
|
|
|
|
|
|
|
if (turn >> 31)
|
|
|
|
|
multi_handle_turn_upper_bit(pnum);
|
|
|
|
|
absTurns = turn & 0x7FFFFFFF;
|
|
|
|
|
if (sgbSentThisCycle < gdwTurnsInTransit + absTurns) {
|
|
|
|
|
if (absTurns >= 0x7FFFFFFF)
|
|
|
|
|
absTurns &= 0xFFFF;
|
|
|
|
|
sgbSentThisCycle = absTurns + gdwTurnsInTransit;
|
|
|
|
|
sgdwGameLoops = 4 * absTurns * sgbNetUpdateRate;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_handle_turn_upper_bit(int pnum)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_PLRS; i++) {
|
|
|
|
|
if (player_state[i] & 0x10000 && i != pnum)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (myplr == i) {
|
|
|
|
|
sgbSendDeltaTbl[pnum] = TRUE;
|
|
|
|
|
} else if (myplr == pnum) {
|
|
|
|
|
gbDeltaSender = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_player_left(int pnum, int reason)
|
|
|
|
|
{
|
|
|
|
|
sgbPlayerLeftGameTbl[pnum] = TRUE;
|
|
|
|
|
sgdwPlayerLeftReasonTbl[pnum] = reason;
|
|
|
|
|
multi_clear_left_tbl();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_clear_left_tbl()
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_PLRS; i++) {
|
|
|
|
|
if (sgbPlayerLeftGameTbl[i]) {
|
|
|
|
|
if (gbBufferMsgs == 1)
|
|
|
|
|
msg_send_drop_pkt(i, sgdwPlayerLeftReasonTbl[i]);
|
|
|
|
|
else
|
|
|
|
|
multi_player_left_msg(i, 1);
|
|
|
|
|
|
|
|
|
|
sgbPlayerLeftGameTbl[i] = FALSE;
|
|
|
|
|
sgdwPlayerLeftReasonTbl[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_player_left_msg(int pnum, int left)
|
|
|
|
|
{
|
|
|
|
|
char *pszFmt;
|
|
|
|
|
|
|
|
|
|
if (plr[pnum].plractive) {
|
|
|
|
|
RemovePlrFromMap(pnum);
|
|
|
|
|
RemovePortalMissile(pnum);
|
|
|
|
|
DeactivatePortal(pnum);
|
|
|
|
|
RemovePlrPortal(pnum);
|
|
|
|
|
RemovePlrMissiles(pnum);
|
|
|
|
|
if (left) {
|
|
|
|
|
pszFmt = "Player '%s' just left the game";
|
|
|
|
|
switch (sgdwPlayerLeftReasonTbl[pnum]) {
|
|
|
|
|
case 0x40000004:
|
|
|
|
|
pszFmt = "Player '%s' killed Diablo and left the game!";
|
|
|
|
|
gbSomebodyWonGameKludge = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
case 0x40000006:
|
|
|
|
|
pszFmt = "Player '%s' dropped due to timeout";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
EventPlrMsg(pszFmt, plr[pnum]._pName);
|
|
|
|
|
}
|
|
|
|
|
plr[pnum].plractive = FALSE;
|
|
|
|
|
plr[pnum]._pName[0] = '\0';
|
|
|
|
|
gbActivePlayers--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_net_ping()
|
|
|
|
|
{
|
|
|
|
|
sgbTimeout = TRUE;
|
|
|
|
|
sglTimeoutStart = GetTickCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int multi_handle_delta()
|
|
|
|
|
{
|
|
|
|
|
int i, recieved;
|
|
|
|
|
|
|
|
|
|
if (gbGameDestroyed) {
|
|
|
|
|
gbRunGame = FALSE;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_PLRS; i++) {
|
|
|
|
|
if (sgbSendDeltaTbl[i]) {
|
|
|
|
|
sgbSendDeltaTbl[i] = FALSE;
|
|
|
|
|
DeltaExportData(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sgbSentThisCycle = nthread_send_and_recv_turn(sgbSentThisCycle, 1);
|
|
|
|
|
if (!nthread_recv_turns(&recieved)) {
|
|
|
|
|
multi_begin_timeout();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sgbTimeout = FALSE;
|
|
|
|
|
if (recieved) {
|
|
|
|
|
if (!gbShouldValidatePackage) {
|
|
|
|
|
NetSendHiPri(0, 0);
|
|
|
|
|
gbShouldValidatePackage = FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
gbShouldValidatePackage = FALSE;
|
|
|
|
|
if (!multi_check_pkt_valid(&sgHiPriBuf))
|
|
|
|
|
NetSendHiPri(0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
multi_mon_seeds();
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Microsoft VisualC 2-11/net runtime
|
|
|
|
|
int multi_check_pkt_valid(TBuffer *a1)
|
|
|
|
|
{
|
|
|
|
|
return a1->dwNextWriteOffset == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_mon_seeds()
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
DWORD l;
|
|
|
|
|
|
|
|
|
|
sgdwGameLoops++;
|
|
|
|
|
l = _rotr(sgdwGameLoops, 8);
|
|
|
|
|
for (i = 0; i < 200; i++)
|
|
|
|
|
monster[i]._mAISeed = l + i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_begin_timeout()
|
|
|
|
|
{
|
|
|
|
|
int i, nTicks, nState, nLowestActive, nLowestPlayer;
|
|
|
|
|
BYTE bGroupPlayers, bGroupCount;
|
|
|
|
|
|
|
|
|
|
if(!sgbTimeout) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
if(debug_mode_key_i) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
nTicks = GetTickCount() - sglTimeoutStart;
|
|
|
|
|
if(nTicks > 20000) {
|
|
|
|
|
gbRunGame = FALSE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(nTicks < 10000) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nLowestActive = -1;
|
|
|
|
|
nLowestPlayer = -1;
|
|
|
|
|
bGroupPlayers = 0;
|
|
|
|
|
bGroupCount = 0;
|
|
|
|
|
for(i = 0; i < MAX_PLRS; i++) {
|
|
|
|
|
nState = player_state[i];
|
|
|
|
|
if(nState & 0x10000) {
|
|
|
|
|
if(nLowestPlayer == -1) {
|
|
|
|
|
nLowestPlayer = i;
|
|
|
|
|
}
|
|
|
|
|
if(nState & 0x40000) {
|
|
|
|
|
bGroupPlayers++;
|
|
|
|
|
if(nLowestActive == -1) {
|
|
|
|
|
nLowestActive = i;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
bGroupCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// ASSERT: assert(bGroupPlayers);
|
|
|
|
|
/// ASSERT: assert(nLowestActive != -1);
|
|
|
|
|
/// ASSERT: assert(nLowestPlayer != -1);
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
dumphist(
|
|
|
|
|
"(%d) grp:%d ngrp:%d lowp:%d lowa:%d",
|
|
|
|
|
myplr,
|
|
|
|
|
bGroupPlayers,
|
|
|
|
|
bGroupCount,
|
|
|
|
|
nLowestPlayer,
|
|
|
|
|
nLowestActive);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if(bGroupPlayers < bGroupCount) {
|
|
|
|
|
gbGameDestroyed = TRUE;
|
|
|
|
|
} else if(bGroupPlayers == bGroupCount) {
|
|
|
|
|
if(nLowestPlayer != nLowestActive) {
|
|
|
|
|
gbGameDestroyed = TRUE;
|
|
|
|
|
} else if(nLowestActive == myplr) {
|
|
|
|
|
multi_check_drop_player();
|
|
|
|
|
}
|
|
|
|
|
} else if(nLowestActive == myplr) {
|
|
|
|
|
multi_check_drop_player();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 67862D: using guessed type char gbGameDestroyed;
|
|
|
|
|
// 678644: using guessed type int sglTimeoutStart;
|
|
|
|
|
// 679661: using guessed type char sgbTimeout;
|
|
|
|
|
|
|
|
|
|
void multi_check_drop_player()
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_PLRS; i++) {
|
|
|
|
|
if (!(player_state[i] & 0x40000) && player_state[i] & 0x10000) {
|
|
|
|
|
SNetDropPlayer(i, 0x40000006);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void 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 >= sizeof(TPktHdr)
|
|
|
|
|
&& *(_DWORD *)arglist < MAX_PLRS
|
|
|
|
|
&& 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 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 multi_process_tmsgs()
|
|
|
|
|
{
|
|
|
|
|
int cnt;
|
|
|
|
|
TPkt pkt;
|
|
|
|
|
|
|
|
|
|
while (cnt = tmsg_get((BYTE *)&pkt, 512)) {
|
|
|
|
|
multi_handle_all_packets(myplr, &pkt, cnt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_send_zero_packet(DWORD pnum, char a2, void *pbSrc, DWORD dwLen)
|
|
|
|
|
{
|
|
|
|
|
DWORD v5, dwBody;
|
|
|
|
|
TPkt pkt;
|
|
|
|
|
int t;
|
|
|
|
|
v5 = 0;
|
|
|
|
|
while (dwLen) {
|
|
|
|
|
pkt.hdr.wCheck = 'ip';
|
|
|
|
|
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;
|
|
|
|
|
pkt.body[0] = a2;
|
|
|
|
|
*(_WORD *)&pkt.body[1] = v5;
|
|
|
|
|
dwBody = gdwLargestMsgSize - 24;
|
|
|
|
|
if (dwLen < dwBody)
|
|
|
|
|
dwBody = dwLen;
|
|
|
|
|
*(_WORD *)&pkt.body[3] = dwBody;
|
|
|
|
|
memcpy(&pkt.body[5], pbSrc, *(_WORD *)&pkt.body[3]);
|
|
|
|
|
t = *(WORD *)&pkt.body[3] + 24;
|
|
|
|
|
pkt.hdr.wLen = t;
|
|
|
|
|
if (!SNetSendMessage(pnum, &pkt.hdr, t)) {
|
|
|
|
|
nthread_terminate_game("SNetSendMessage2");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pbSrc = (char *)pbSrc + *(WORD *)&pkt.body[3];
|
|
|
|
|
dwLen -= *(WORD *)&pkt.body[3];
|
|
|
|
|
v5 += *(_WORD *)&pkt.body[3];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 67975C: using guessed type int gdwLargestMsgSize;
|
|
|
|
|
|
|
|
|
|
void NetClose()
|
|
|
|
|
{
|
|
|
|
|
if (!sgbNetInited) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sgbNetInited = FALSE;
|
|
|
|
|
nthread_cleanup();
|
|
|
|
|
dthread_cleanup();
|
|
|
|
|
tmsg_cleanup();
|
|
|
|
|
multi_event_handler(FALSE);
|
|
|
|
|
SNetLeaveGame(3);
|
|
|
|
|
msgcmd_cmd_cleanup();
|
|
|
|
|
if (gbMaxPlayers > 1)
|
|
|
|
|
Sleep(2000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_event_handler(BOOL add)
|
|
|
|
|
{
|
|
|
|
|
DWORD i;
|
|
|
|
|
BOOL(STORMAPI * fn)
|
|
|
|
|
(int, SEVTHANDLER);
|
|
|
|
|
|
|
|
|
|
if (add)
|
|
|
|
|
fn = SNetRegisterEventHandler;
|
|
|
|
|
else
|
|
|
|
|
fn = SNetUnregisterEventHandler;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
|
if (!fn(event_types[i], multi_handle_events) && add) {
|
|
|
|
|
app_fatal("SNetRegisterEventHandler:\n%s", TraceLastError());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void __stdcall multi_handle_events(_SNETEVENT *pEvt)
|
|
|
|
|
{
|
|
|
|
|
DWORD LeftReason;
|
|
|
|
|
DWORD *data;
|
|
|
|
|
|
|
|
|
|
switch (pEvt->eventid) {
|
|
|
|
|
case EVENT_TYPE_PLAYER_CREATE_GAME:
|
|
|
|
|
data = (DWORD *)pEvt->data;
|
|
|
|
|
sgGameInitInfo.dwSeed = data[0];
|
|
|
|
|
sgGameInitInfo.bDiff = data[1];
|
|
|
|
|
sgbPlayerTurnBitTbl[pEvt->playerid] = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
case EVENT_TYPE_PLAYER_LEAVE_GAME:
|
|
|
|
|
sgbPlayerLeftGameTbl[pEvt->playerid] = TRUE;
|
|
|
|
|
sgbPlayerTurnBitTbl[pEvt->playerid] = FALSE;
|
|
|
|
|
LeftReason = 0;
|
|
|
|
|
data = (DWORD *)pEvt->data;
|
|
|
|
|
if (data && (DWORD)pEvt->databytes >= 4)
|
|
|
|
|
LeftReason = data[0];
|
|
|
|
|
sgdwPlayerLeftReasonTbl[pEvt->playerid] = LeftReason;
|
|
|
|
|
if (LeftReason == 0x40000004)
|
|
|
|
|
gbSomebodyWonGameKludge = TRUE;
|
|
|
|
|
sgbSendDeltaTbl[pEvt->playerid] = FALSE;
|
|
|
|
|
dthread_remove_player(pEvt->playerid);
|
|
|
|
|
|
|
|
|
|
if (gbDeltaSender == pEvt->playerid)
|
|
|
|
|
gbDeltaSender = MAX_PLRS;
|
|
|
|
|
break;
|
|
|
|
|
case EVENT_TYPE_PLAYER_MESSAGE:
|
|
|
|
|
ErrorPlrMsg((char *)pEvt->data);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL NetInit(BOOL bSinglePlayer, BOOL *pfExitProgram)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
_SNETPROGRAMDATA ProgramData;
|
|
|
|
|
_SNETUIDATA UiData;
|
|
|
|
|
_SNETPLAYERDATA plrdata;
|
|
|
|
|
unsigned int len;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
*pfExitProgram = FALSE;
|
|
|
|
|
SetRndSeed(0);
|
|
|
|
|
sgGameInitInfo.dwSeed = time(NULL);
|
|
|
|
|
sgGameInitInfo.bDiff = gnDifficulty;
|
|
|
|
|
memset(&ProgramData, 0, sizeof(ProgramData));
|
|
|
|
|
ProgramData.size = sizeof(ProgramData);
|
|
|
|
|
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(&plrdata, 0, sizeof(plrdata));
|
|
|
|
|
plrdata.size = sizeof(plrdata);
|
|
|
|
|
memset(&UiData, 0, sizeof(UiData));
|
|
|
|
|
UiData.size = sizeof(UiData);
|
|
|
|
|
UiData.parentwindow = SDrawGetFrameWindow(NULL);
|
|
|
|
|
UiData.artcallback = (void (*)())UiArtCallback;
|
|
|
|
|
UiData.createcallback = (void (*)())UiCreateGameCallback;
|
|
|
|
|
UiData.drawdesccallback = (void (*)())UiDrawDescCallback;
|
|
|
|
|
UiData.messageboxcallback = (void (*)())UiMessageBoxCallback;
|
|
|
|
|
UiData.soundcallback = (void (*)())UiSoundCallback;
|
|
|
|
|
UiData.authcallback = (void (*)())UiAuthCallback;
|
|
|
|
|
UiData.getdatacallback = (void (*)())UiGetDataCallback;
|
|
|
|
|
UiData.categorycallback = (void (*)())UiCategoryCallback;
|
|
|
|
|
UiData.selectnamecallback = mainmenu_select_hero_dialog;
|
|
|
|
|
UiData.changenamecallback = (void (*)())mainmenu_create_hero;
|
|
|
|
|
UiData.profilebitmapcallback = (void (*)())UiProfileDraw;
|
|
|
|
|
UiData.profilecallback = (void (*)())UiProfileCallback;
|
|
|
|
|
UiData.profilefields = UiProfileGetString();
|
|
|
|
|
memset(sgbPlayerTurnBitTbl, 0, sizeof(sgbPlayerTurnBitTbl));
|
|
|
|
|
gbGameDestroyed = FALSE;
|
|
|
|
|
memset(sgbPlayerLeftGameTbl, 0, sizeof(sgbPlayerLeftGameTbl));
|
|
|
|
|
memset(sgdwPlayerLeftReasonTbl, 0, sizeof(sgdwPlayerLeftReasonTbl));
|
|
|
|
|
memset(sgbSendDeltaTbl, 0, sizeof(sgbSendDeltaTbl));
|
|
|
|
|
memset(plr, 0, sizeof(plr));
|
|
|
|
|
memset(sgwPackPlrOffsetTbl, 0, sizeof(sgwPackPlrOffsetTbl));
|
|
|
|
|
SNetSetBasePlayer(0);
|
|
|
|
|
if (bSinglePlayer) {
|
|
|
|
|
if (!multi_init_single(&ProgramData, &plrdata, &UiData))
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
if (!multi_init_multi(&ProgramData, &plrdata, &UiData, pfExitProgram))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
gdwHistTicks = GetTickCount();
|
|
|
|
|
dumphist("(%d) new game started", myplr);
|
|
|
|
|
#endif
|
|
|
|
|
sgbNetInited = TRUE;
|
|
|
|
|
sgbTimeout = FALSE;
|
|
|
|
|
delta_init();
|
|
|
|
|
InitPlrMsg();
|
|
|
|
|
buffer_init(&sgHiPriBuf);
|
|
|
|
|
buffer_init(&sgLoPriBuf);
|
|
|
|
|
gbShouldValidatePackage = FALSE;
|
|
|
|
|
sync_init();
|
|
|
|
|
nthread_start(sgbPlayerTurnBitTbl[myplr]);
|
|
|
|
|
dthread_start();
|
|
|
|
|
tmsg_start();
|
|
|
|
|
sgdwGameLoops = 0;
|
|
|
|
|
sgbSentThisCycle = 0;
|
|
|
|
|
gbDeltaSender = myplr;
|
|
|
|
|
gbSomebodyWonGameKludge = FALSE;
|
|
|
|
|
nthread_send_and_recv_turn(0, 0);
|
|
|
|
|
SetupLocalCoords();
|
|
|
|
|
multi_send_pinfo(-2, CMD_SEND_PLRINFO);
|
|
|
|
|
gbActivePlayers = 1;
|
|
|
|
|
plr[myplr].plractive = TRUE;
|
|
|
|
|
if (sgbPlayerTurnBitTbl[myplr] == 0 || msg_wait_resync())
|
|
|
|
|
break;
|
|
|
|
|
NetClose();
|
|
|
|
|
byte_678640 = 0;
|
|
|
|
|
}
|
|
|
|
|
gnDifficulty = sgGameInitInfo.bDiff;
|
|
|
|
|
SetRndSeed(sgGameInitInfo.dwSeed);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 17; i++) {
|
|
|
|
|
glSeedTbl[i] = GetRndSeed();
|
|
|
|
|
gnLevelTypeTbl[i] = InitNewSeed(i);
|
|
|
|
|
}
|
|
|
|
|
if (!SNetGetGameInfo(GAMEINFO_NAME, szPlayerName, 128, &len))
|
|
|
|
|
nthread_terminate_game("SNetGetGameInfo1");
|
|
|
|
|
if (!SNetGetGameInfo(GAMEINFO_PASSWORD, szPlayerDescript, 128, &len))
|
|
|
|
|
nthread_terminate_game("SNetGetGameInfo2");
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void buffer_init(TBuffer *pBuf)
|
|
|
|
|
{
|
|
|
|
|
pBuf->dwNextWriteOffset = 0;
|
|
|
|
|
pBuf->bData[0] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void multi_send_pinfo(int pnum, char cmd)
|
|
|
|
|
{
|
|
|
|
|
PkPlayerStruct pkplr;
|
|
|
|
|
|
|
|
|
|
PackPlayer(&pkplr, myplr, TRUE);
|
|
|
|
|
dthread_send_delta(pnum, cmd, &pkplr, sizeof(pkplr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int InitNewSeed(int newseed)
|
|
|
|
|
{
|
|
|
|
|
if (newseed == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
if (newseed >= 1 && newseed <= 4)
|
|
|
|
|
return 1;
|
|
|
|
|
if (newseed >= 5 && newseed <= 8)
|
|
|
|
|
return 2;
|
|
|
|
|
if (newseed >= 9 && newseed <= 12)
|
|
|
|
|
return 3;
|
|
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetupLocalCoords()
|
|
|
|
|
{
|
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
|
|
if (!leveldebug || gbMaxPlayers > 1) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL multi_init_single(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info)
|
|
|
|
|
{
|
|
|
|
|
int unused;
|
|
|
|
|
|
|
|
|
|
if (!SNetInitializeProvider(0, client_info, user_info, ui_info, &fileinfo)) {
|
|
|
|
|
SErrGetLastError();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unused = 0;
|
|
|
|
|
if (!SNetCreateGame("local", "local", "local", 0, (char *)&sgGameInitInfo.dwSeed, 8, 1, "local", "local", &unused)) {
|
|
|
|
|
app_fatal("SNetCreateGame1:\n%s", TraceLastError());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
myplr = 0;
|
|
|
|
|
gbMaxPlayers = 1;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL multi_init_multi(_SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, int *pfExitProgram)
|
|
|
|
|
{
|
|
|
|
|
BOOL first;
|
|
|
|
|
int playerId;
|
|
|
|
|
int type;
|
|
|
|
|
|
|
|
|
|
for (first = TRUE;; first = FALSE) {
|
|
|
|
|
type = 0x00;
|
|
|
|
|
if (byte_678640) {
|
|
|
|
|
if (!UiSelectProvider(0, client_info, user_info, ui_info, &fileinfo, &type)
|
|
|
|
|
&& (!first || SErrGetLastError() != STORM_ERROR_REQUIRES_UPGRADE || !multi_upgrade(pfExitProgram))) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (type == 'BNET')
|
|
|
|
|
plr[0].pBattleNet = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
multi_event_handler(TRUE);
|
|
|
|
|
if (UiSelectGame(1, client_info, user_info, ui_info, &fileinfo, &playerId))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
byte_678640 = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((DWORD)playerId >= MAX_PLRS) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
myplr = playerId;
|
|
|
|
|
gbMaxPlayers = MAX_PLRS;
|
|
|
|
|
|
|
|
|
|
pfile_read_player_from_save();
|
|
|
|
|
|
|
|
|
|
if (type == 'BNET')
|
|
|
|
|
plr[myplr].pBattleNet = 1;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL multi_upgrade(int *pfExitProgram)
|
|
|
|
|
{
|
|
|
|
|
BOOL result;
|
|
|
|
|
int status;
|
|
|
|
|
|
|
|
|
|
SNetPerformUpgrade((LPDWORD)&status);
|
|
|
|
|
result = TRUE;
|
|
|
|
|
if (status && status != 1) {
|
|
|
|
|
if (status != 2) {
|
|
|
|
|
if (status == -1) {
|
|
|
|
|
DrawDlg("Network upgrade failed");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
*pfExitProgram = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void recv_plrinfo(int pnum, TCmdPlrInfoHdr *p, BOOL recv)
|
|
|
|
|
{
|
|
|
|
|
char *szEvent;
|
|
|
|
|
|
|
|
|
|
if (myplr == pnum) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/// ASSERT: assert((DWORD)pnum < MAX_PLRS);
|
|
|
|
|
|
|
|
|
|
if (sgwPackPlrOffsetTbl[pnum] != p->wOffset) {
|
|
|
|
|
sgwPackPlrOffsetTbl[pnum] = 0;
|
|
|
|
|
if (p->wOffset != 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!recv && sgwPackPlrOffsetTbl[pnum] == 0) {
|
|
|
|
|
multi_send_pinfo(pnum, CMD_ACK_PLRINFO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy((char *)&netplr[pnum] + p->wOffset, &p[1], p->wBytes); /* todo: cast? */
|
|
|
|
|
sgwPackPlrOffsetTbl[pnum] += p->wBytes;
|
|
|
|
|
if (sgwPackPlrOffsetTbl[pnum] != sizeof(*netplr)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sgwPackPlrOffsetTbl[pnum] = 0;
|
|
|
|
|
multi_player_left_msg(pnum, 0);
|
|
|
|
|
plr[pnum]._pGFXLoad = 0;
|
|
|
|
|
UnPackPlayer(&netplr[pnum], pnum, 1);
|
|
|
|
|
|
|
|
|
|
if (!recv) {
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
dumphist("(%d) received all %d plrinfo", myplr, pnum);
|
|
|
|
|
#endif
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
plr[pnum].plractive = TRUE;
|
|
|
|
|
gbActivePlayers++;
|
|
|
|
|
|
|
|
|
|
if (sgbPlayerTurnBitTbl[pnum] != 0) {
|
|
|
|
|
szEvent = "Player '%s' (level %d) just joined the game";
|
|
|
|
|
} else {
|
|
|
|
|
szEvent = "Player '%s' (level %d) is already in the game";
|
|
|
|
|
}
|
|
|
|
|
EventPlrMsg(szEvent, plr[pnum]._pName, plr[pnum]._pLevel);
|
|
|
|
|
|
|
|
|
|
LoadPlrGFX(pnum, PFILE_STAND);
|
|
|
|
|
SyncInitPlr(pnum);
|
|
|
|
|
|
|
|
|
|
if (plr[pnum].plrlevel == currlevel) {
|
|
|
|
|
if (plr[pnum]._pHitPoints >> 6 > 0) {
|
|
|
|
|
StartStand(pnum, 0);
|
|
|
|
|
} else {
|
|
|
|
|
plr[pnum]._pgfxnum = 0;
|
|
|
|
|
LoadPlrGFX(pnum, PFILE_DEATH);
|
|
|
|
|
plr[pnum]._pmode = PM_DEATH;
|
|
|
|
|
NewPlrAnim(pnum, plr[pnum]._pDAnim[0], plr[pnum]._pDFrames, 1, plr[pnum]._pDWidth);
|
|
|
|
|
plr[pnum]._pAnimFrame = plr[pnum]._pAnimLen - 1;
|
|
|
|
|
plr[pnum]._pVar8 = 2 * plr[pnum]._pAnimLen;
|
|
|
|
|
dFlags[plr[pnum].WorldX][plr[pnum].WorldY] |= BFLAG_DEAD_PLAYER;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
dumphist("(%d) making %d active -- recv_plrinfo", myplr, pnum);
|
|
|
|
|
#endif
|
|
|
|
|
}
|