You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
6.9 KiB

/**
* @file sync.cpp
*
* Implementation of functionality for syncing game state with other players.
*/
#include <climits>
#include "gendung.h"
#include "monster.h"
#include "player.h"
8 years ago
namespace devilution {
namespace {
uint16_t sgnMonsterPriority[MAXMONSTERS];
int sgnMonsters;
uint16_t sgwLRU[MAXMONSTERS];
int sgnSyncItem;
int sgnSyncPInv;
8 years ago
void SyncOneMonster()
8 years ago
{
for (int i = 0; i < ActiveMonsterCount; i++) {
int m = ActiveMonsters[i];
sgnMonsterPriority[m] = Players[MyPlayerId].position.tile.ManhattanDistance(Monsters[m].position.tile);
if (Monsters[m]._msquelch == 0) {
sgnMonsterPriority[m] += 0x1000;
7 years ago
} else if (sgwLRU[m] != 0) {
sgwLRU[m]--;
8 years ago
}
}
}
void SyncMonsterPos(TSyncMonster *p, int ndx)
5 years ago
{
p->_mndx = ndx;
p->_mx = Monsters[ndx].position.tile.x;
p->_my = Monsters[ndx].position.tile.y;
5 years ago
p->_menemy = encode_enemy(ndx);
p->_mdelta = sgnMonsterPriority[ndx] > 255 ? 255 : sgnMonsterPriority[ndx];
5 years ago
sgnMonsterPriority[ndx] = 0xFFFF;
sgwLRU[ndx] = Monsters[ndx]._msquelch == 0 ? 0xFFFF : 0xFFFE;
5 years ago
}
bool SyncMonsterActive(TSyncMonster *p)
8 years ago
{
int ndx = -1;
uint32_t lru = 0xFFFFFFFF;
for (int i = 0; i < ActiveMonsterCount; i++) {
int m = ActiveMonsters[i];
if (sgnMonsterPriority[m] < lru && sgwLRU[m] < 0xFFFE) {
lru = sgnMonsterPriority[m];
ndx = ActiveMonsters[i];
8 years ago
}
}
7 years ago
if (ndx == -1) {
return false;
}
SyncMonsterPos(p, ndx);
return true;
8 years ago
}
bool SyncMonsterActive2(TSyncMonster *p)
8 years ago
{
int ndx = -1;
uint32_t lru = 0xFFFE;
for (int i = 0; i < ActiveMonsterCount; i++) {
if (sgnMonsters >= ActiveMonsterCount) {
sgnMonsters = 0;
}
int m = ActiveMonsters[sgnMonsters];
7 years ago
if (sgwLRU[m] < lru) {
lru = sgwLRU[m];
ndx = ActiveMonsters[sgnMonsters];
8 years ago
}
sgnMonsters++;
}
7 years ago
if (ndx == -1) {
return false;
}
SyncMonsterPos(p, ndx);
return true;
8 years ago
}
void SyncPlrInv(TSyncHeader *pHdr)
8 years ago
{
int ii;
ItemStruct *pItem;
if (ActiveItemCount > 0) {
if (sgnSyncItem >= ActiveItemCount) {
sgnSyncItem = 0;
}
ii = ActiveItems[sgnSyncItem++];
pHdr->bItemI = ii;
pHdr->bItemX = Items[ii].position.x;
pHdr->bItemY = Items[ii].position.y;
pHdr->wItemIndx = Items[ii].IDidx;
if (Items[ii].IDidx == IDI_EAR) {
pHdr->wItemCI = (Items[ii]._iName[7] << 8) | Items[ii]._iName[8];
pHdr->dwItemSeed = (Items[ii]._iName[9] << 24) | (Items[ii]._iName[10] << 16) | (Items[ii]._iName[11] << 8) | Items[ii]._iName[12];
pHdr->bItemId = Items[ii]._iName[13];
pHdr->bItemDur = Items[ii]._iName[14];
pHdr->bItemMDur = Items[ii]._iName[15];
pHdr->bItemCh = Items[ii]._iName[16];
pHdr->bItemMCh = Items[ii]._iName[17];
pHdr->wItemVal = (Items[ii]._iName[18] << 8) | ((Items[ii]._iCurs - ICURS_EAR_SORCERER) << 6) | Items[ii]._ivalue;
pHdr->dwItemBuff = (Items[ii]._iName[19] << 24) | (Items[ii]._iName[20] << 16) | (Items[ii]._iName[21] << 8) | Items[ii]._iName[22];
} else {
pHdr->wItemCI = Items[ii]._iCreateInfo;
pHdr->dwItemSeed = Items[ii]._iSeed;
pHdr->bItemId = Items[ii]._iIdentified ? 1 : 0;
pHdr->bItemDur = Items[ii]._iDurability;
pHdr->bItemMDur = Items[ii]._iMaxDur;
pHdr->bItemCh = Items[ii]._iCharges;
pHdr->bItemMCh = Items[ii]._iMaxCharges;
if (Items[ii].IDidx == IDI_GOLD) {
pHdr->wItemVal = Items[ii]._ivalue;
}
8 years ago
}
} else {
pHdr->bItemI = -1;
8 years ago
}
assert(sgnSyncPInv > -1 && sgnSyncPInv < NUM_INVLOC);
pItem = &Players[MyPlayerId].InvBody[sgnSyncPInv];
if (!pItem->isEmpty()) {
pHdr->bPInvLoc = sgnSyncPInv;
pHdr->wPInvIndx = pItem->IDidx;
pHdr->wPInvCI = pItem->_iCreateInfo;
pHdr->dwPInvSeed = pItem->_iSeed;
pHdr->bPInvId = pItem->_iIdentified ? 1 : 0;
} else {
pHdr->bPInvLoc = -1;
8 years ago
}
sgnSyncPInv++;
7 years ago
if (sgnSyncPInv >= NUM_INVLOC) {
8 years ago
sgnSyncPInv = 0;
}
8 years ago
}
} // namespace
uint32_t sync_all_monsters(const byte *pbBuf, uint32_t dwMaxLen)
8 years ago
{
if (ActiveMonsterCount < 1) {
5 years ago
return dwMaxLen;
}
if (dwMaxLen < sizeof(TSyncHeader) + sizeof(TSyncMonster)) {
5 years ago
return dwMaxLen;
}
auto *pHdr = (TSyncHeader *)pbBuf;
pbBuf += sizeof(TSyncHeader);
dwMaxLen -= sizeof(TSyncHeader);
5 years ago
pHdr->bCmd = CMD_SYNCDATA;
pHdr->bLevel = currlevel;
pHdr->wLen = 0;
SyncPlrInv(pHdr);
assert(dwMaxLen <= 0xffff);
SyncOneMonster();
for (int i = 0; i < ActiveMonsterCount && dwMaxLen >= sizeof(TSyncMonster); i++) {
bool sync = false;
5 years ago
if (i < 2) {
sync = SyncMonsterActive2((TSyncMonster *)pbBuf);
5 years ago
}
if (!sync) {
sync = SyncMonsterActive((TSyncMonster *)pbBuf);
5 years ago
}
if (!sync) {
break;
8 years ago
}
pbBuf += sizeof(TSyncMonster);
5 years ago
pHdr->wLen += sizeof(TSyncMonster);
dwMaxLen -= sizeof(TSyncMonster);
8 years ago
}
5 years ago
return dwMaxLen;
8 years ago
}
static void SyncMonster(int pnum, const TSyncMonster *p)
8 years ago
{
int ndx = p->_mndx;
if (Monsters[ndx]._mhitpoints <= 0) {
return;
}
uint32_t delta = Players[MyPlayerId].position.tile.ManhattanDistance(Monsters[ndx].position.tile);
7 years ago
if (delta > 255) {
delta = 255;
}
if (delta < p->_mdelta || (delta == p->_mdelta && pnum > MyPlayerId)) {
return;
}
if (Monsters[ndx].position.future.x == p->_mx && Monsters[ndx].position.future.y == p->_my) {
return;
}
if (Monsters[ndx]._mmode == MM_CHARGE || Monsters[ndx]._mmode == MM_STONE) {
return;
}
if (Monsters[ndx].position.tile.WalkingDistance({ p->_mx, p->_my }) <= 2) {
if (Monsters[ndx]._mmode < MM_WALK || Monsters[ndx]._mmode > MM_WALK3) {
Direction md = GetDirection(Monsters[ndx].position.tile, { p->_mx, p->_my });
7 years ago
if (DirOK(ndx, md)) {
M_ClearSquares(ndx);
dMonster[Monsters[ndx].position.tile.x][Monsters[ndx].position.tile.y] = ndx + 1;
M_WalkDir(ndx, md);
Monsters[ndx]._msquelch = UINT8_MAX;
8 years ago
}
}
7 years ago
} else if (dMonster[p->_mx][p->_my] == 0) {
M_ClearSquares(ndx);
dMonster[p->_mx][p->_my] = ndx + 1;
Monsters[ndx].position.tile = { p->_mx, p->_my };
decode_enemy(ndx, p->_menemy);
Direction md = GetDirection({ p->_mx, p->_my }, Monsters[ndx].enemyPosition);
M_StartStand(ndx, md);
Monsters[ndx]._msquelch = UINT8_MAX;
8 years ago
}
decode_enemy(ndx, p->_menemy);
8 years ago
}
uint32_t sync_update(int pnum, const byte *pbBuf)
5 years ago
{
uint16_t wLen;
5 years ago
auto *pHdr = (TSyncHeader *)pbBuf;
5 years ago
pbBuf += sizeof(*pHdr);
if (pHdr->bCmd != CMD_SYNCDATA) {
app_fatal("bad sync command");
}
assert(gbBufferMsgs != 2);
5 years ago
if (gbBufferMsgs == 1) {
return pHdr->wLen + sizeof(*pHdr);
}
if (pnum == MyPlayerId) {
5 years ago
return pHdr->wLen + sizeof(*pHdr);
}
for (wLen = pHdr->wLen; wLen >= sizeof(TSyncMonster); wLen -= sizeof(TSyncMonster)) {
if (currlevel == pHdr->bLevel) {
SyncMonster(pnum, (TSyncMonster *)pbBuf);
5 years ago
}
delta_sync_monster((TSyncMonster *)pbBuf, pHdr->bLevel);
pbBuf += sizeof(TSyncMonster);
}
assert(wLen == 0);
return pHdr->wLen + sizeof(*pHdr);
}
void sync_init()
8 years ago
{
sgnMonsters = 16 * MyPlayerId;
memset(sgwLRU, 255, sizeof(sgwLRU));
8 years ago
}
} // namespace devilution