mirror of
https://github.com/jmarshall23/Hellfire.git
synced 2026-08-12 07:50:53 +02:00
Initial commit.
This commit is contained in:
@@ -0,0 +1,470 @@
|
||||
/*-----------------------------------------------------------------------**
|
||||
** Diablo
|
||||
**
|
||||
** sync.cpp
|
||||
**
|
||||
** (C)1995 Condor, Inc. All rights reserved.
|
||||
**
|
||||
**-----------------------------------------------------------------------**
|
||||
** $Header: /Diablo/SYNC.CPP 3 2/10/97 6:23p Dbrevik2 $
|
||||
**-----------------------------------------------------------------------**
|
||||
**
|
||||
** File Routines
|
||||
**-----------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "diablo.h"
|
||||
#pragma hdrstop
|
||||
#include "sound.h"
|
||||
#include "msg.h"
|
||||
#include "multi.h"
|
||||
#include "gendung.h"
|
||||
#include "engine.h"
|
||||
#include "items.h"
|
||||
#include "player.h"
|
||||
#include "error.h"
|
||||
#include "debug.h"
|
||||
#include "monster.h"
|
||||
#include "monstint.h"
|
||||
#include "inv.h"
|
||||
|
||||
//******************************************************************
|
||||
// externs
|
||||
//******************************************************************
|
||||
void M_ClearSquares(int nMonster);
|
||||
void delta_sync_monster(const TSyncMonster * p,BYTE bLevel);
|
||||
|
||||
|
||||
//******************************************************************
|
||||
// private
|
||||
//******************************************************************
|
||||
static int sgnMonsters;
|
||||
static WORD sgwDelta[MAXMONSTERS];
|
||||
static WORD sgwLRU[MAXMONSTERS];
|
||||
static int sgnLRUScan;
|
||||
|
||||
#define LRU_NEVER 0xffff
|
||||
#define LRU_REINIT 0xfffe
|
||||
#define LRU_INIT 0xff
|
||||
|
||||
static int sgnSyncItem = 0;
|
||||
static int sgnSyncObj = 0;
|
||||
static int sgnSyncPInv = 0;
|
||||
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
static void prep_monster_list(void) {
|
||||
for (int i = 0; i < nummonsters; i++) {
|
||||
int mi = monstactive[i];
|
||||
sgwDelta[mi] = abs(plr[myplr]._px - monster[mi]._mx) +
|
||||
abs(plr[myplr]._py - monster[mi]._my);
|
||||
|
||||
// make all the squelched monsters particularly unattractive
|
||||
// make all the unsquelched monsters decrement their LRU
|
||||
// counters so that they will get sent eventually
|
||||
if (! monster[mi]._msquelch)
|
||||
sgwDelta[mi] += 0x1000;
|
||||
else if (sgwLRU[mi])
|
||||
sgwLRU[mi]--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
static void get_monster(TSyncMonster * p,int mi) {
|
||||
// get the true monster number
|
||||
// and save monster's parameters
|
||||
p->_mndx = mi;
|
||||
p->_mx = monster[mi]._mx;
|
||||
p->_my = monster[mi]._my;
|
||||
// encode player/monster enemy
|
||||
p->_menemy = encode_enemy(mi);
|
||||
p->_mdelta = sgwDelta[mi] > 0xff ? 0xff : sgwDelta[mi];
|
||||
// cant have this since menemy maybe a monster id
|
||||
//app_assert((DWORD) p->_menemy < MAX_PLRS);
|
||||
|
||||
// reset delta table so we don't find this monster again
|
||||
sgwDelta[mi] = 0xffff;
|
||||
|
||||
// reset LRU count so we don't resend this monster unnecessarily
|
||||
sgwLRU[mi] = monster[mi]._msquelch ? LRU_REINIT : LRU_NEVER;
|
||||
}
|
||||
|
||||
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
static BOOL get_best_monster(TSyncMonster * p) {
|
||||
// search all the monsters for the one closest to the player
|
||||
int nFound = -1;
|
||||
DWORD dwMin = 0xffffffff;
|
||||
for (int i = 0; i < nummonsters; i++) {
|
||||
int mi = monstactive[i];
|
||||
|
||||
// is this monster close to the local player?
|
||||
if (sgwDelta[mi] >= dwMin) continue;
|
||||
|
||||
// is this a monster which has already been sent LRU?
|
||||
if (sgwLRU[mi] >= LRU_REINIT) continue;
|
||||
|
||||
// found better candidate
|
||||
dwMin = sgwDelta[mi];
|
||||
nFound = mi;
|
||||
}
|
||||
if (nFound == -1) return FALSE;
|
||||
get_monster(p,nFound);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
static BOOL get_lru_monster(TSyncMonster * p) {
|
||||
// search all the monsters for the lowest LRU number
|
||||
int nFound = -1;
|
||||
DWORD dwMin = LRU_REINIT;
|
||||
for (int i = 0; i < nummonsters; i++,sgnLRUScan++) {
|
||||
if (sgnLRUScan >= nummonsters) sgnLRUScan = 0;
|
||||
int mi = monstactive[sgnLRUScan];
|
||||
|
||||
// is this a monster which hasn't been sent in a while?
|
||||
if (sgwLRU[mi] >= dwMin) continue;
|
||||
|
||||
dwMin = sgwLRU[mi];
|
||||
nFound = mi;
|
||||
}
|
||||
if (nFound == -1) return FALSE;
|
||||
get_monster(p,nFound);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
static void FillHeaderSync(TSyncHeader * pHdr)
|
||||
{
|
||||
// Fill one item
|
||||
int ii;
|
||||
if (numitems > 0) {
|
||||
if (sgnSyncItem >= numitems) sgnSyncItem = 0;
|
||||
ii = itemactive[sgnSyncItem++];
|
||||
pHdr->bItemI = ii;
|
||||
pHdr->bItemX = item[ii]._ix;
|
||||
pHdr->bItemY = item[ii]._iy;
|
||||
pHdr->wItemIndx = item[ii].IDidx;
|
||||
if (item[ii].IDidx == IDI_EAR) {
|
||||
pHdr->wItemCI = (item[ii]._iName[7] << 8) | item[ii]._iName[8];
|
||||
pHdr->dwItemSeed = (item[ii]._iName[9] << 24) |
|
||||
(item[ii]._iName[10] << 16) |
|
||||
(item[ii]._iName[11] << 8) |
|
||||
item[ii]._iName[12];
|
||||
pHdr->bItemId = item[ii]._iName[13];
|
||||
pHdr->bItemDur = item[ii]._iName[14];
|
||||
pHdr->bItemMDur = item[ii]._iName[15];
|
||||
pHdr->bItemCh = item[ii]._iName[16];
|
||||
pHdr->bItemMCh = item[ii]._iName[17];
|
||||
pHdr->wItemVal = (item[ii]._iName[18] << 8) | ((item[ii]._iCurs - ITEM_EAR1) << 6) | item[ii]._ivalue;
|
||||
pHdr->dwItemBuff = (item[ii]._iName[19] << 24) |
|
||||
(item[ii]._iName[20] << 16) |
|
||||
(item[ii]._iName[21] << 8) |
|
||||
item[ii]._iName[22];
|
||||
} else {
|
||||
pHdr->wItemCI = item[ii]._iCreateInfo;
|
||||
pHdr->dwItemSeed = item[ii]._iSeed;
|
||||
pHdr->bItemId = item[ii]._iIdentified;
|
||||
pHdr->bItemDur = item[ii]._iDurability;
|
||||
pHdr->bItemMDur = item[ii]._iMaxDur;
|
||||
pHdr->bItemCh = item[ii]._iCharges;
|
||||
pHdr->bItemMCh = item[ii]._iMaxCharges;
|
||||
if (item[ii].IDidx == IDI_GOLD) pHdr->wItemVal = item[ii]._ivalue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pHdr->bItemI = 0xff;
|
||||
}
|
||||
|
||||
// Fill with player inv info
|
||||
app_assert((DWORD) sgnSyncPInv < NUM_INVLOC);
|
||||
ItemStruct *itm = &plr[myplr].InvBody[sgnSyncPInv];
|
||||
if (itm->_itype != -1) {
|
||||
pHdr->bPInvLoc = sgnSyncPInv;
|
||||
pHdr->wPInvIndx = itm->IDidx;
|
||||
pHdr->wPInvCI = itm->_iCreateInfo;
|
||||
pHdr->dwPInvSeed = itm->_iSeed;
|
||||
// drb.patch1.start.02/10/97
|
||||
pHdr->bPInvId = itm->_iIdentified;
|
||||
// drb.patch1.end.02/10/97
|
||||
}
|
||||
else {
|
||||
pHdr->bPInvLoc = 0xff;
|
||||
}
|
||||
|
||||
// next item
|
||||
sgnSyncPInv++;
|
||||
if (sgnSyncPInv >= NUM_INVLOC)
|
||||
sgnSyncPInv = 0;
|
||||
}
|
||||
|
||||
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
DWORD sync_get(BYTE * pbBuf,DWORD dwMaxLen) {
|
||||
// if there are no monsters to sync, exit
|
||||
if (nummonsters < 1) return dwMaxLen;
|
||||
|
||||
// is there enough space for at header + one monster sync
|
||||
if (dwMaxLen < sizeof(TSyncMonster) + sizeof(TSyncHeader))
|
||||
return dwMaxLen;
|
||||
|
||||
// setup header
|
||||
TSyncHeader * pHdr = (TSyncHeader *) pbBuf;
|
||||
pbBuf += sizeof(TSyncHeader);
|
||||
dwMaxLen -= sizeof(TSyncHeader);
|
||||
pHdr->bCmd = CMD_SYNCDATA;
|
||||
pHdr->bLevel = currlevel;
|
||||
pHdr->wLen = 0;
|
||||
// Put one object, one item and one plr inv item into sync packets
|
||||
FillHeaderSync(pHdr);
|
||||
|
||||
// make sure we don't overrun header maximum length
|
||||
app_assert(dwMaxLen <= 0xffff);
|
||||
|
||||
prep_monster_list();
|
||||
for (int nMonsters = 0; nMonsters < nummonsters; nMonsters++) {
|
||||
if (dwMaxLen < sizeof(TSyncMonster)) break;
|
||||
|
||||
BOOL bGotOne = FALSE;
|
||||
if (nMonsters < 2) bGotOne = get_lru_monster((TSyncMonster *) pbBuf);
|
||||
if (! bGotOne) bGotOne = get_best_monster((TSyncMonster *) pbBuf);
|
||||
if (! bGotOne) break;
|
||||
|
||||
pbBuf += sizeof(TSyncMonster);
|
||||
pHdr->wLen += sizeof(TSyncMonster);
|
||||
dwMaxLen -= sizeof(TSyncMonster);
|
||||
}
|
||||
|
||||
// return bytes left in buffer
|
||||
return dwMaxLen;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*
|
||||
**-----------------------------------------------------------------------*
|
||||
|
||||
byte monstupdate[MAXMONSTERS];
|
||||
|
||||
void DaveMonstMap(BOOL initupdate, int pnum)
|
||||
{
|
||||
int i,j,m;
|
||||
char tempstr[512], tempstr2[256];
|
||||
|
||||
if (initupdate)
|
||||
for (i = 0; i < MAXMONSTERS; i++) monstupdate[i] = 0;
|
||||
|
||||
for (j = 0; j < DMAXY; j++) {
|
||||
for (i = 0; i < DMAXX; i++) {
|
||||
if (dFlags[i][j] & BFLAG_MONSTLR) {
|
||||
if (dMonster[i-1][j] != dMonster[i][j-1]) {
|
||||
sprintf(tempstr, "Error in map @ %i,%i x-1,j = %i, x,j-1 = %i\n", i, j, dMonster[i-1][j], dMonster[i][j-1]);
|
||||
if (dMonster[i-1][j] == 0) sprintf(tempstr2, "Null monster\n @ %i,%i", i-1, j);
|
||||
else {
|
||||
if (dMonster[i-1][j] > 0) m = dMonster[i-1][j] - 1;
|
||||
else m = -(dMonster[i-1][j] + 1);
|
||||
sprintf(tempstr2, "Monst %i xy = %i,%i oxy = %i,%i mode = %i Updated = %i\n",
|
||||
m, monster[m]._mx, monster[m]._my, monster[m]._moldx, monster[m]._moldy, monster[m]._mmode, monstupdate[m]);
|
||||
}
|
||||
strcat(tempstr, tempstr2);
|
||||
if (dMonster[i][j-1] == 0) sprintf(tempstr2, "Null monster @ %i,%i\n", i, j-1);
|
||||
else {
|
||||
if (dMonster[i][j-1] > 0) m = dMonster[i][j-1] - 1;
|
||||
else m = -(dMonster[i][j-1] + 1);
|
||||
sprintf(tempstr2, "Monst %i xy = %i,%i oxy = %i,%i mode = %i Updated = %i\n",
|
||||
m, monster[m]._mx, monster[m]._my, monster[m]._moldx, monster[m]._moldy, monster[m]._mmode, monstupdate[m]);
|
||||
}
|
||||
strcat(tempstr, tempstr2);
|
||||
sprintf(tempstr2, "Info from plr %i = %s", pnum, plr[pnum]._pName);
|
||||
strcat(tempstr, tempstr2);
|
||||
app_fatal(tempstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
static void sync_monster(int pnum,const TSyncMonster * p) {
|
||||
|
||||
// get monster index
|
||||
int ndx = p->_mndx;
|
||||
|
||||
// did I just kill this monster?
|
||||
if (monster[ndx]._mhitpoints <= 0) return;
|
||||
|
||||
// check for valid index
|
||||
for (int i = 0; i < nummonsters && monstactive[i] != ndx; i++);
|
||||
//app_assert(i < nummonsters);
|
||||
|
||||
// calc distance I think he is from me
|
||||
DWORD delta =
|
||||
abs(plr[myplr]._px - monster[ndx]._mx) +
|
||||
abs(plr[myplr]._py - monster[ndx]._my);
|
||||
if (delta > 0xff) delta = 0xff;
|
||||
|
||||
// if my delta is less than the other player's delta, use mine
|
||||
if (delta < p->_mdelta) return;
|
||||
// if the deltas are the same use the lowest player num
|
||||
else if ((delta == p->_mdelta) && (pnum > myplr)) return;
|
||||
|
||||
// if the monster is going to be there soon, don't do anything
|
||||
if (monster[ndx]._mfutx == p->_mx && monster[ndx]._mfuty == p->_my) return;
|
||||
|
||||
// Snake crash fix. Don't mess with missile monsters while they are warping
|
||||
if (monster[ndx]._mmode == MM_MISSILE) return;
|
||||
// Don't mess with stone cursed monsters
|
||||
if (monster[ndx]._mmode == MM_STONE) return;
|
||||
|
||||
// if the monster is far away, jump him into position
|
||||
int mdx = abs(monster[ndx]._mx - p->_mx);
|
||||
int mdy = abs(monster[ndx]._my - p->_my);
|
||||
if (mdx > 2 || mdy > 2) {
|
||||
if (! dMonster[p->_mx][p->_my]) {
|
||||
// remove where monster is now
|
||||
M_ClearSquares(ndx);
|
||||
|
||||
// put him in new location
|
||||
dMonster[p->_mx][p->_my] = ndx + 1;
|
||||
monster[ndx]._mx = p->_mx;
|
||||
monster[ndx]._my = p->_my;
|
||||
decode_enemy(ndx, p->_menemy);
|
||||
M_StartStand(ndx, GetDirection(p->_mx,p->_my, monster[ndx]._menemyx, monster[ndx]._menemyy));
|
||||
|
||||
// make sure he's awake
|
||||
monster[ndx]._msquelch = 255;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if the monster is not already on the way to a nearby
|
||||
// square, start him immediately on his way
|
||||
if ((monster[ndx]._mmode < MM_WALK) || (monster[ndx]._mmode > MM_WALK3)) {
|
||||
int md = GetDirection(monster[ndx]._mx, monster[ndx]._my, p->_mx, p->_my);
|
||||
|
||||
if (DirOK(ndx, md)) {
|
||||
// remove where monster is now
|
||||
M_ClearSquares(ndx);
|
||||
|
||||
// make monster walk into square where he should be
|
||||
dMonster[monster[ndx]._mx][monster[ndx]._my] = ndx + 1;
|
||||
M_WalkDir(ndx, md);
|
||||
|
||||
// make sure he's awake
|
||||
monster[ndx]._msquelch = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sync enemy
|
||||
// cant have this since menemy maybe a monster id
|
||||
//app_assert((DWORD) p->_menemy < MAX_PLRS);
|
||||
decode_enemy(ndx, p->_menemy);
|
||||
}
|
||||
|
||||
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
static void UpdateHeaderSync(int pnum, const TSyncHeader * pHdr)
|
||||
{
|
||||
// Fill one item
|
||||
if (pHdr->bItemI != 0xff) {
|
||||
int ii = pHdr->bItemI;
|
||||
if ((pHdr->wItemIndx != item[ii].IDidx) ||
|
||||
(pHdr->wItemCI != item[ii]._iCreateInfo) ||
|
||||
(pHdr->dwItemSeed != item[ii]._iSeed)) {
|
||||
ii = FindGetItem(pHdr->wItemIndx, pHdr->wItemCI, pHdr->dwItemSeed);
|
||||
if (ii == -1) {
|
||||
SyncPutItem(pnum,
|
||||
pHdr->bItemX,
|
||||
pHdr->bItemY,
|
||||
pHdr->wItemIndx,
|
||||
pHdr->wItemCI,
|
||||
pHdr->dwItemSeed,
|
||||
pHdr->bItemId,
|
||||
pHdr->bItemDur,
|
||||
pHdr->bItemMDur,
|
||||
pHdr->bItemCh,
|
||||
pHdr->bItemMCh,
|
||||
pHdr->wItemVal,
|
||||
pHdr->dwItemBuff,
|
||||
pHdr->wPLToHit,
|
||||
pHdr->wMaxDam,
|
||||
pHdr->bMinStr,
|
||||
pHdr->bMinMag,
|
||||
pHdr->bMinDex,
|
||||
pHdr->bAC
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fill with player inv info
|
||||
if (pHdr->bPInvLoc != 0xff) {
|
||||
ItemStruct *itm = &plr[myplr].InvBody[pHdr->bPInvLoc];
|
||||
if ((pHdr->wPInvIndx != itm->IDidx) ||
|
||||
(pHdr->wPInvCI != itm->_iCreateInfo) ||
|
||||
// drb.patch1.start.02/10/97
|
||||
// (pHdr->dwPInvSeed != itm->_iSeed)) {
|
||||
(pHdr->dwPInvSeed != itm->_iSeed) ||
|
||||
(pHdr->bPInvId != itm->_iIdentified)) {
|
||||
// SyncInvPaste(pnum, pHdr->bPInvLoc, pHdr->wPInvIndx, pHdr->wPInvCI, pHdr->dwPInvSeed,);
|
||||
SyncInvPaste(pnum, pHdr->bPInvLoc, pHdr->wPInvIndx, pHdr->wPInvCI, pHdr->dwPInvSeed, pHdr->bPInvId);
|
||||
// drb.patch1.end.02/10/97
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
DWORD sync_update(int pnum,const BYTE * pbBuf) {
|
||||
const TSyncHeader * pHdr = (const TSyncHeader *) pbBuf;
|
||||
pbBuf += sizeof(TSyncHeader);
|
||||
|
||||
// make sure we have a valid sync record
|
||||
if (pHdr->bCmd != CMD_SYNCDATA)
|
||||
app_fatal("bad sync command");
|
||||
|
||||
// don't resync while we're in buffer mode
|
||||
app_assert(gbBufferMsgs != BUFFER_PROCESS);
|
||||
if (gbBufferMsgs == BUFFER_ON)
|
||||
return pHdr->wLen + sizeof(TSyncHeader);
|
||||
|
||||
// we don't resync using our own information
|
||||
if (pnum == myplr) return pHdr->wLen + sizeof(TSyncHeader);
|
||||
|
||||
// Make sure we are in sync with others on the level
|
||||
//if (currlevel == pHdr->bLevel) UpdateHeaderSync(pnum, pHdr);
|
||||
|
||||
WORD wLen = pHdr->wLen;
|
||||
while (wLen >= sizeof(TSyncMonster)) {
|
||||
if (currlevel == pHdr->bLevel)
|
||||
sync_monster(pnum,(const TSyncMonster *) pbBuf);
|
||||
delta_sync_monster((const TSyncMonster *) pbBuf,pHdr->bLevel);
|
||||
pbBuf += sizeof(TSyncMonster);
|
||||
wLen -= sizeof(TSyncMonster);
|
||||
}
|
||||
|
||||
// make sure we used all the bytes
|
||||
app_assert(wLen == 0);
|
||||
|
||||
// return true number of bytes in our sync section
|
||||
return pHdr->wLen + sizeof(TSyncHeader);
|
||||
}
|
||||
|
||||
|
||||
//******************************************************************
|
||||
//******************************************************************
|
||||
void sync_init() {
|
||||
// don't let all the players start scanning in the same location.
|
||||
// if each player is scanning from a different location, it is
|
||||
// more likely that multiple monsters can be synced every turn
|
||||
sgnLRUScan = myplr * 16;
|
||||
FillMemory(sgwLRU,sizeof sgwLRU,LRU_INIT);
|
||||
}
|
||||
Reference in New Issue
Block a user