Missiles _mimfnum is being used for a lot more then just directions and can also be a 16 degree direction so can't apply enum verbs and restricitons to it in most cases. This in turns also affects SetMissDir and some other functions that have to stay int.
296 lines
6.9 KiB
C++
296 lines
6.9 KiB
C++
/**
|
|
* @file sync.cpp
|
|
*
|
|
* Implementation of functionality for syncing game state with other players.
|
|
*/
|
|
#include <limits.h>
|
|
|
|
#include "gendung.h"
|
|
#include "monster.h"
|
|
#include "player.h"
|
|
|
|
namespace devilution {
|
|
|
|
namespace {
|
|
|
|
Uint16 sgnMonsterPriority[MAXMONSTERS];
|
|
int sgnMonsters;
|
|
Uint16 sgwLRU[MAXMONSTERS];
|
|
int sgnSyncItem;
|
|
int sgnSyncPInv;
|
|
|
|
static void sync_one_monster()
|
|
{
|
|
int i, m;
|
|
|
|
for (i = 0; i < nummonsters; i++) {
|
|
m = monstactive[i];
|
|
sgnMonsterPriority[m] = abs(plr[myplr]._px - monster[m]._mx) + abs(plr[myplr]._py - monster[m]._my);
|
|
if (monster[m]._msquelch == 0) {
|
|
sgnMonsterPriority[m] += 0x1000;
|
|
} else if (sgwLRU[m] != 0) {
|
|
sgwLRU[m]--;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sync_monster_pos(TSyncMonster *p, int ndx)
|
|
{
|
|
p->_mndx = ndx;
|
|
p->_mx = monster[ndx]._mx;
|
|
p->_my = monster[ndx]._my;
|
|
p->_menemy = encode_enemy(ndx);
|
|
p->_mdelta = sgnMonsterPriority[ndx] > 255 ? 255 : sgnMonsterPriority[ndx];
|
|
|
|
sgnMonsterPriority[ndx] = 0xFFFF;
|
|
sgwLRU[ndx] = monster[ndx]._msquelch == 0 ? 0xFFFF : 0xFFFE;
|
|
}
|
|
|
|
static bool sync_monster_active(TSyncMonster *p)
|
|
{
|
|
int i, m, ndx;
|
|
Uint32 lru;
|
|
|
|
ndx = -1;
|
|
lru = 0xFFFFFFFF;
|
|
|
|
for (i = 0; i < nummonsters; i++) {
|
|
m = monstactive[i];
|
|
if (sgnMonsterPriority[m] < lru && sgwLRU[m] < 0xFFFE) {
|
|
lru = sgnMonsterPriority[m];
|
|
ndx = monstactive[i];
|
|
}
|
|
}
|
|
|
|
if (ndx == -1) {
|
|
return false;
|
|
}
|
|
|
|
sync_monster_pos(p, ndx);
|
|
return true;
|
|
}
|
|
|
|
static bool sync_monster_active2(TSyncMonster *p)
|
|
{
|
|
int i, m, ndx;
|
|
Uint32 lru;
|
|
|
|
ndx = -1;
|
|
lru = 0xFFFE;
|
|
|
|
for (i = 0; i < nummonsters; i++) {
|
|
if (sgnMonsters >= nummonsters) {
|
|
sgnMonsters = 0;
|
|
}
|
|
m = monstactive[sgnMonsters];
|
|
if (sgwLRU[m] < lru) {
|
|
lru = sgwLRU[m];
|
|
ndx = monstactive[sgnMonsters];
|
|
}
|
|
sgnMonsters++;
|
|
}
|
|
|
|
if (ndx == -1) {
|
|
return false;
|
|
}
|
|
|
|
sync_monster_pos(p, ndx);
|
|
return true;
|
|
}
|
|
|
|
static void SyncPlrInv(TSyncHeader *pHdr)
|
|
{
|
|
int ii;
|
|
ItemStruct *pItem;
|
|
|
|
if (numitems > 0) {
|
|
if (sgnSyncItem >= numitems) {
|
|
sgnSyncItem = 0;
|
|
}
|
|
ii = itemactive[sgnSyncItem++];
|
|
pHdr->bItemI = ii;
|
|
pHdr->bItemX = items[ii]._ix;
|
|
pHdr->bItemY = items[ii]._iy;
|
|
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;
|
|
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;
|
|
}
|
|
}
|
|
} else {
|
|
pHdr->bItemI = -1;
|
|
}
|
|
|
|
assert(sgnSyncPInv > -1 && sgnSyncPInv < NUM_INVLOC);
|
|
pItem = &plr[myplr].InvBody[sgnSyncPInv];
|
|
if (!pItem->isEmpty()) {
|
|
pHdr->bPInvLoc = sgnSyncPInv;
|
|
pHdr->wPInvIndx = pItem->IDidx;
|
|
pHdr->wPInvCI = pItem->_iCreateInfo;
|
|
pHdr->dwPInvSeed = pItem->_iSeed;
|
|
pHdr->bPInvId = pItem->_iIdentified;
|
|
} else {
|
|
pHdr->bPInvLoc = -1;
|
|
}
|
|
|
|
sgnSyncPInv++;
|
|
if (sgnSyncPInv >= NUM_INVLOC) {
|
|
sgnSyncPInv = 0;
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Uint32 sync_all_monsters(const Uint8 *pbBuf, Uint32 dwMaxLen)
|
|
{
|
|
TSyncHeader *pHdr;
|
|
int i;
|
|
bool sync;
|
|
|
|
if (nummonsters < 1) {
|
|
return dwMaxLen;
|
|
}
|
|
if (dwMaxLen < sizeof(*pHdr) + sizeof(TSyncMonster)) {
|
|
return dwMaxLen;
|
|
}
|
|
|
|
pHdr = (TSyncHeader *)pbBuf;
|
|
pbBuf += sizeof(*pHdr);
|
|
dwMaxLen -= sizeof(*pHdr);
|
|
|
|
pHdr->bCmd = CMD_SYNCDATA;
|
|
pHdr->bLevel = currlevel;
|
|
pHdr->wLen = 0;
|
|
SyncPlrInv(pHdr);
|
|
assert(dwMaxLen <= 0xffff);
|
|
sync_one_monster();
|
|
|
|
for (i = 0; i < nummonsters && dwMaxLen >= sizeof(TSyncMonster); i++) {
|
|
sync = false;
|
|
if (i < 2) {
|
|
sync = sync_monster_active2((TSyncMonster *)pbBuf);
|
|
}
|
|
if (!sync) {
|
|
sync = sync_monster_active((TSyncMonster *)pbBuf);
|
|
}
|
|
if (!sync) {
|
|
break;
|
|
}
|
|
pbBuf += sizeof(TSyncMonster);
|
|
pHdr->wLen += sizeof(TSyncMonster);
|
|
dwMaxLen -= sizeof(TSyncMonster);
|
|
}
|
|
|
|
return dwMaxLen;
|
|
}
|
|
|
|
static void sync_monster(int pnum, const TSyncMonster *p)
|
|
{
|
|
int ndx, mdx, mdy;
|
|
Uint32 delta;
|
|
|
|
ndx = p->_mndx;
|
|
|
|
if (monster[ndx]._mhitpoints <= 0) {
|
|
return;
|
|
}
|
|
|
|
delta = abs(plr[myplr]._px - monster[ndx]._mx) + abs(plr[myplr]._py - monster[ndx]._my);
|
|
if (delta > 255) {
|
|
delta = 255;
|
|
}
|
|
|
|
if (delta < p->_mdelta || (delta == p->_mdelta && pnum > myplr)) {
|
|
return;
|
|
}
|
|
if (monster[ndx]._mfutx == p->_mx && monster[ndx]._mfuty == p->_my) {
|
|
return;
|
|
}
|
|
if (monster[ndx]._mmode == MM_CHARGE || monster[ndx]._mmode == MM_STONE) {
|
|
return;
|
|
}
|
|
|
|
mdx = abs(monster[ndx]._mx - p->_mx);
|
|
mdy = abs(monster[ndx]._my - p->_my);
|
|
if (mdx <= 2 && mdy <= 2) {
|
|
if (monster[ndx]._mmode < MM_WALK || monster[ndx]._mmode > MM_WALK3) {
|
|
direction md = GetDirection(monster[ndx]._mx, monster[ndx]._my, p->_mx, p->_my);
|
|
if (DirOK(ndx, md)) {
|
|
M_ClearSquares(ndx);
|
|
dMonster[monster[ndx]._mx][monster[ndx]._my] = ndx + 1;
|
|
M_WalkDir(ndx, md);
|
|
monster[ndx]._msquelch = UCHAR_MAX;
|
|
}
|
|
}
|
|
} else if (dMonster[p->_mx][p->_my] == 0) {
|
|
M_ClearSquares(ndx);
|
|
dMonster[p->_mx][p->_my] = ndx + 1;
|
|
monster[ndx]._mx = p->_mx;
|
|
monster[ndx]._my = p->_my;
|
|
decode_enemy(ndx, p->_menemy);
|
|
direction md = GetDirection(p->_mx, p->_my, monster[ndx]._menemyx, monster[ndx]._menemyy);
|
|
M_StartStand(ndx, md);
|
|
monster[ndx]._msquelch = UCHAR_MAX;
|
|
}
|
|
|
|
decode_enemy(ndx, p->_menemy);
|
|
}
|
|
|
|
Uint32 sync_update(int pnum, const Uint8 *pbBuf)
|
|
{
|
|
TSyncHeader *pHdr;
|
|
Uint16 wLen;
|
|
|
|
pHdr = (TSyncHeader *)pbBuf;
|
|
pbBuf += sizeof(*pHdr);
|
|
|
|
if (pHdr->bCmd != CMD_SYNCDATA) {
|
|
app_fatal("bad sync command");
|
|
}
|
|
|
|
assert(gbBufferMsgs != 2);
|
|
|
|
if (gbBufferMsgs == 1) {
|
|
return pHdr->wLen + sizeof(*pHdr);
|
|
}
|
|
if (pnum == myplr) {
|
|
return pHdr->wLen + sizeof(*pHdr);
|
|
}
|
|
|
|
for (wLen = pHdr->wLen; wLen >= sizeof(TSyncMonster); wLen -= sizeof(TSyncMonster)) {
|
|
if (currlevel == pHdr->bLevel) {
|
|
sync_monster(pnum, (TSyncMonster *)pbBuf);
|
|
}
|
|
delta_sync_monster((TSyncMonster *)pbBuf, pHdr->bLevel);
|
|
pbBuf += sizeof(TSyncMonster);
|
|
}
|
|
|
|
assert(wLen == 0);
|
|
|
|
return pHdr->wLen + sizeof(*pHdr);
|
|
}
|
|
|
|
void sync_init()
|
|
{
|
|
sgnMonsters = 16 * myplr;
|
|
memset(sgwLRU, 255, sizeof(sgwLRU));
|
|
}
|
|
|
|
} // namespace devilution
|