diff --git a/lib/netplay/netlog.c b/lib/netplay/netlog.c index 370d729b7..f04d8e984 100644 --- a/lib/netplay/netlog.c +++ b/lib/netplay/netlog.c @@ -100,8 +100,6 @@ BOOL NETstopLogging(void) PHYSFS_write(pFileHandle, buf, strlen(buf), 1); snprintf(buf, sizeof(buf), "sent/unsent Ping %"PRIu64" / %"PRIu64"\n", sync_counter.sentPing, sync_counter.unsentPing); PHYSFS_write(pFileHandle, buf, strlen(buf), 1); - snprintf(buf, sizeof(buf), "sent/unsent isMPDirtyBit %"PRIu64" / %"PRIu64"\n", sync_counter.sentisMPDirtyBit, sync_counter.unsentisMPDirtyBit); - PHYSFS_write(pFileHandle, buf, strlen(buf), 1); PHYSFS_write(pFileHandle, dash_line, strlen(dash_line), 1); if (!PHYSFS_close(pFileHandle)) diff --git a/lib/netplay/netplay.h b/lib/netplay/netplay.h index a5760cc0f..5ed2d0735 100644 --- a/lib/netplay/netplay.h +++ b/lib/netplay/netplay.h @@ -188,8 +188,6 @@ typedef struct { uint64_t unsentScoreCheck; uint64_t sentPing; uint64_t unsentPing; - uint64_t sentisMPDirtyBit; - uint64_t unsentisMPDirtyBit; } SYNC_COUNTER; typedef struct diff --git a/lib/netplay/nettypes.cpp b/lib/netplay/nettypes.cpp index 210801a9c..03fc3fc63 100644 --- a/lib/netplay/nettypes.cpp +++ b/lib/netplay/nettypes.cpp @@ -34,6 +34,7 @@ #include "nettypes.h" #include "netqueue.h" #include "netlog.h" +#include "src/order.h" #include /// There is a game queue representing each player. The game queues are synchronised among all players, so that all players process the same game queue @@ -561,6 +562,28 @@ void NETVector3uw(Vector3uw *vp) queueAuto(*vp); } +void NETPACKAGED_CHECK(PACKAGED_CHECK *v) +{ + queueAuto(v->player); + queueAuto(v->droidID); + queueAuto(v->order); + queueAuto(v->secondaryOrder); + queueAuto(v->body); + queueAuto(v->direction); + queueAuto(v->experience); + queueAuto(v->sMoveX); + queueAuto(v->sMoveY); + if (v->order == DORDER_ATTACK) + { + queueAuto(v->targetID); + } + else if (v->order == DORDER_MOVE) + { + queueAuto(v->orderX); + queueAuto(v->orderY); + } +} + typedef enum { test_a, diff --git a/lib/netplay/nettypes.h b/lib/netplay/nettypes.h index e2a340bbf..56f83838e 100644 --- a/lib/netplay/nettypes.h +++ b/lib/netplay/nettypes.h @@ -125,6 +125,24 @@ do \ void NETVector3uw(Vector3uw* vp); +typedef struct PackagedCheck +{ + uint32_t gameTime; ///< Game time that this synch check was made. Not touched by NETPACKAGED_CHECK(). + uint8_t player; + uint32_t droidID; + int32_t order; + uint32_t secondaryOrder; + uint32_t body; + float direction; + float experience; + float sMoveX; + float sMoveY; + uint32_t targetID; ///< Defined iff order == DORDER_ATTACK. + uint16_t orderX; ///< Defined iff order == DORDER_MOVE. + uint16_t orderY; ///< Defined iff order == DORDER_MOVE. +} PACKAGED_CHECK; +void NETPACKAGED_CHECK(PACKAGED_CHECK *v); + void NETtest(void); #ifdef __cplusplus diff --git a/src/droid.c b/src/droid.c index 0af6ac898..e895d4f1b 100644 --- a/src/droid.c +++ b/src/droid.c @@ -2700,6 +2700,8 @@ void droidSetBits(DROID_TEMPLATE *pTemplate,DROID *psDroid) psDroid->asBits[COMP_ECM].nStat = pTemplate->asParts[COMP_ECM]; psDroid->asBits[COMP_REPAIRUNIT].nStat = pTemplate->asParts[COMP_REPAIRUNIT]; psDroid->asBits[COMP_CONSTRUCT].nStat = pTemplate->asParts[COMP_CONSTRUCT]; + + psDroid->gameCheckDroid = NULL; } diff --git a/src/droiddef.h b/src/droiddef.h index 123182eb6..3c1159ace 100644 --- a/src/droiddef.h +++ b/src/droiddef.h @@ -209,6 +209,9 @@ typedef struct DROID /* anim data */ ANIM_OBJECT *psCurAnim; SDWORD iAudioID; + + // Synch checking + void * gameCheckDroid; ///< Last PACKAGED_CHECK, for synchronisation use only (see multisync.c). TODO Make synch perfect, so that this isn't needed at all. } WZ_DECL_MAY_ALIAS DROID; #ifdef __cplusplus diff --git a/src/fpath.c b/src/fpath.c index 73c404065..5685bfd40 100644 --- a/src/fpath.c +++ b/src/fpath.c @@ -522,8 +522,8 @@ static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int sta goto ok; } } - // This should never happen, but apparently does. Is psMove->Status == MOVEWAITROUTE getting synched, or something ridiculous like that? - debug(LOG_ERROR, "Waiting for fpath result of droid %u, but the job doesn't exist. This may cause synch errors.", id); + // This should never happen, but apparently did. Probably fixed in svn -r9788, so shouldn't ever happen again. + ASSERT(false, "Waiting for fpath result of droid %u, but the job doesn't exist. This may cause synch errors.", id); wzMutexUnlock(fpathMutex); return FPR_FAILED; diff --git a/src/multiplay.c b/src/multiplay.c index 3dfa5f6fc..234627d13 100644 --- a/src/multiplay.c +++ b/src/multiplay.c @@ -72,7 +72,6 @@ // //////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////// // globals. -bool isMPDirtyBit = false; // When we are forced to use turnOffMultiMsg() we set this BOOL bMultiPlayer = false; // true when more than 1 player. BOOL bMultiMessages = false; // == bMultiPlayer unless multimessages are disabled BOOL openchannels[MAX_PLAYERS]={true}; @@ -124,16 +123,12 @@ void turnOffMultiMsg(BOOL bDoit) } bMultiMessages = !bDoit; - if (bDoit) - { - isMPDirtyBit = true; - } return; } // //////////////////////////////////////////////////////////////////////////// -// throw a pary when you win! +// throw a party when you win! BOOL multiplayerWinSequence(BOOL firstCall) { static Vector3i pos; diff --git a/src/multiplay.h b/src/multiplay.h index 3e5a7bc91..b2767ee6c 100644 --- a/src/multiplay.h +++ b/src/multiplay.h @@ -228,7 +228,6 @@ extern void startMultiplayerGame (void); extern void resetReadyStatus (bool bSendOptions); extern BOOL bPlayerReadyGUI[MAX_PLAYERS]; -extern bool isMPDirtyBit; #ifdef __cplusplus } diff --git a/src/multisync.c b/src/multisync.c index 2f550c7a0..7af00ae07 100644 --- a/src/multisync.c +++ b/src/multisync.c @@ -51,32 +51,15 @@ #include "multistat.h" #include "power.h" // for power checks #include "multirecv.h" +#include "random.h" // //////////////////////////////////////////////////////////////////////////// // function definitions static BOOL sendStructureCheck (void); //Structure -static void packageCheck (const DROID* pD); +static PACKAGED_CHECK packageCheck(const DROID *pD); static BOOL sendDroidCheck (void); //droids -static void highLevelDroidUpdate(DROID *psDroid, - float fx, - float fy, - UDWORD state, - UDWORD order, - BASE_OBJECT *psTarget, - float experience); - - -static void onscreenUpdate (DROID *pDroid,UDWORD dam, // the droid and its damage - UWORD dir, // direction it should facing - DROID_ORDER order); // what it should be doing - -static void offscreenUpdate (DROID *pDroid,UDWORD dam, - float fx,float fy, - UWORD dir, - DROID_ORDER order); - static BOOL sendPowerCheck(void); static UDWORD averagePing(void); @@ -91,8 +74,6 @@ static UDWORD averagePing(void); #define POWER_FREQUENCY MP_FPS_LOCK * 14 // how often to send power levels #define SCORE_FREQUENCY MP_FPS_LOCK * 2400 // how often to update global score. -#define SYNC_PANIC 40000 // maximum time before doing a dirty fix. [not even used!] - static UDWORD PingSend[MAX_PLAYERS]; //stores the time the ping was called. // //////////////////////////////////////////////////////////////////////////// @@ -132,15 +113,7 @@ BOOL sendCheck(void) // send Checks. note each send has it's own send criteria, so might not send anything. // Priority is droids -> structures -> power -> score -> ping - if(okToSend()) - { - sendDroidCheck(); - sync_counter.sentDroidCheck++; - } - else - { - sync_counter.unsentDroidCheck++; - } + sendDroidCheck(); if(okToSend()) { sendStructureCheck(); @@ -179,16 +152,6 @@ BOOL sendCheck(void) sync_counter.unsentPing++; } - if (isMPDirtyBit) - { - sync_counter.sentisMPDirtyBit++; - } - else - { - sync_counter.unsentisMPDirtyBit++; - } - // FIXME: reset flag--For now, we always do this since we have no way of knowing which routine(s) we had to set this flag - isMPDirtyBit = false; return true; } @@ -196,54 +159,37 @@ BOOL sendCheck(void) // pick a droid to send, NULL otherwise. static DROID* pickADroid(void) { - DROID* pD = NULL; // current droid we're checking - unsigned int i; - static UDWORD droidnum=0; // how far down the playerlist to go. - static UDWORD player=0; // current player we're checking - static UDWORD maxtrys=0; + DROID *pD, *ret; + unsigned player = MAX_PLAYERS; + unsigned i; - // Don't send stuff that isn't our problem - while (!myResponsibility(player)) + // Pick a random player who has at least one droid. + for (i = 0; i < 200; ++i) { - player = (player + 1) % MAX_PLAYERS; - droidnum = 0; - - // Bail out if we've tried for each available player already - if (++maxtrys >= MAX_PLAYERS) + unsigned p = gameRand(MAX_PLAYERS); + if (apsDroidLists[p] != NULL) { - maxtrys = 0; - return NULL; + player = p; + break; } } - // Find the 'droidnum'th droid for the current player - for (i = 0, pD = apsDroidLists[player]; - i < droidnum && pD != NULL; - ++i, pD = pD->psNext) - {} - - // If we've already dealt with the last droid for this player - if (pD == NULL) // droid is no longer there or list end. + if (player == MAX_PLAYERS) { - // Deal with the next player now - player = (player + 1) % MAX_PLAYERS; - droidnum = 0; - - // Bail out if we've tried for each available player already - if (++maxtrys >= MAX_PLAYERS) - { - maxtrys = 0; - return NULL; - } - - // Invoke ourselves to pick a droid from the next player - return pickADroid(); + return NULL; // No players have any droids, with high probability... } - ++droidnum; - maxtrys = 0; + // O(n) where n is number of droids. Slow, but hard to beat on a linked list. (One call of a pick n droids function would be just as fast.) + i = 0; + for (pD = apsDroidLists[player]; pD != NULL; pD = pD->psNext) + { + if (gameRand(++i) == 0) + { + ret = pD; + } + } - return pD; + return ret; } /** Force a droid to be synced @@ -253,6 +199,7 @@ static DROID* pickADroid(void) BOOL ForceDroidSync(const DROID* droidToSend) { uint8_t count = 1; // *always* one + PACKAGED_CHECK pc = packageCheck(droidToSend); ASSERT(droidToSend != NULL, "NULL pointer passed"); @@ -260,7 +207,8 @@ BOOL ForceDroidSync(const DROID* droidToSend) NETbeginEncode(NETgameQueue(selectedPlayer), GAME_CHECK_DROID); NETuint8_t(&count); - packageCheck(droidToSend); + NETuint32_t(&gameTime); // Send game time. + NETPACKAGED_CHECK(&pc); return NETend(); } @@ -271,15 +219,15 @@ static BOOL sendDroidCheck(void) DROID *pD, **ppD; uint8_t i, count; static UDWORD lastSent = 0; // Last time a struct was sent. - UDWORD toSend = 6; + UDWORD toSend = 12; if (lastSent > gameTime) { lastSent= 0; } - // Only send a struct send if not done recently or if isMPDirtyBit is set - if (gameTime - lastSent < DROID_FREQUENCY && !isMPDirtyBit) + // Only send a struct send if not done recently + if (gameTime - lastSent < DROID_FREQUENCY) { return true; } @@ -296,25 +244,29 @@ static BOOL sendDroidCheck(void) { pD = pickADroid(); - // If the droid is valid add it to the list - if (pD) + if (pD == NULL || (pD->gameCheckDroid != NULL && ((PACKAGED_CHECK *)pD->gameCheckDroid)->gameTime + 5000 > gameTime)) + { + continue; // Didn't find a droid, or droid was synched recently. + } + + // If the droid is ours add it to the list + if (myResponsibility(pD->player)) { ppD[count++] = pD; } - // All droids are synced! (We're done.) - else - { - break; - } + free(pD->gameCheckDroid); + pD->gameCheckDroid = (PACKAGED_CHECK *)malloc(sizeof(PACKAGED_CHECK)); + *(PACKAGED_CHECK *)pD->gameCheckDroid = packageCheck(pD); } // Send the number of droids to expect NETuint8_t(&count); + NETuint32_t(&gameTime); // Send game time. // Add the droids to the packet for (i = 0; i < count; i++) { - packageCheck(ppD[i]); + NETPACKAGED_CHECK((PACKAGED_CHECK *)ppD[i]->gameCheckDroid); } return NETend(); @@ -322,57 +274,30 @@ static BOOL sendDroidCheck(void) // //////////////////////////////////////////////////////////////////////////// // Send a Single Droid Check message -static void packageCheck(const DROID* pD) +static PACKAGED_CHECK packageCheck(const DROID *pD) { - // Copy these variables so that we don't have to violate pD's constness - uint8_t player = pD->player; - uint32_t droidID = pD->id; - int32_t order = pD->order; - uint32_t secondaryOrder = pD->secondaryOrder; - uint32_t body = pD->body; - float direction = pD->direction; - float experience = pD->experience; - float sMoveX = pD->sMove.fx; - float sMoveY = pD->sMove.fy; - - // Send the player to which the droid belongs - NETuint8_t(&player); - - // Now the droid's ID - NETuint32_t(&droidID); - - // The droid's order - NETint32_t(&order); - - // The droids secondary order - NETuint32_t(&secondaryOrder); - - // Droid's current HP - NETuint32_t(&body); - - // Direction it is going in - NETfloat(&direction); - - NETfloat(&sMoveX); - NETfloat(&sMoveY); + PACKAGED_CHECK pc; + pc.gameTime = gameTime; + pc.player = pD->player; + pc.droidID = pD->id; + pc.order = pD->order; + pc.secondaryOrder = pD->secondaryOrder; + pc.body = pD->body; + pc.direction = pD->direction; + pc.experience = pD->experience; + pc.sMoveX = pD->sMove.fx; + pc.sMoveY = pD->sMove.fy; if (pD->order == DORDER_ATTACK) { - uint32_t targetID = pD->psTarget->id; - - NETuint32_t(&targetID); + pc.targetID = pD->psTarget->id; } else if (pD->order == DORDER_MOVE) { - uint16_t orderX = pD->orderX; - uint16_t orderY = pD->orderY; - - NETuint16_t(&orderX); - NETuint16_t(&orderY); + pc.orderX = pD->orderX; + pc.orderY = pD->orderY; } - - // Last send the droid's experience - NETfloat(&experience); + return pc; } @@ -382,114 +307,99 @@ BOOL recvDroidCheck(NETQUEUE queue) { uint8_t count; int i; + uint32_t synchTime; NETbeginDecode(queue, GAME_CHECK_DROID); // Get the number of droids to expect NETuint8_t(&count); + NETuint32_t(&synchTime); // Get game time. for (i = 0; i < count; i++) { - DROID *pD; - BASE_OBJECT *psTarget = NULL; - float fx = 0, fy = 0; - DROID_ORDER order = 0; - BOOL onscreen; - uint8_t player; - float direction, experience; - uint16_t tx, ty; - uint32_t ref, body, target = 0, secondaryOrder; + DROID * pD; + PACKAGED_CHECK pc, pc2; - // Fetch the player - NETuint8_t(&player); - - // Fetch the droid being checked - NETuint32_t(&ref); - - // The droid's order - NETenum(&order); - - // Secondary order - NETuint32_t(&secondaryOrder); - - // HP - NETuint32_t(&body); - - // Direction - NETfloat(&direction); - - // Fractional move - NETfloat(&fx); - NETfloat(&fy); - - // Find out what the droid is aiming at - if (order == DORDER_ATTACK) - { - NETuint32_t(&target); - } - // Else if the droid is moving where to - else if (order == DORDER_MOVE) - { - NETuint16_t(&tx); - NETuint16_t(&ty); - } - - // Get the droid's experience - NETfloat(&experience); - - /* - * Post processing - */ + NETPACKAGED_CHECK(&pc); // Find the droid in question - if (!IdToDroid(ref, player, &pD)) + if (!IdToDroid(pc.droidID, pc.player, &pD)) { - NETlogEntry("Recvd Unknown droid info. val=player",0,player); - debug(LOG_SYNC, "Received checking info for an unknown (as yet) droid. player:%d ref:%d", player, ref); + NETlogEntry("Recvd Unknown droid info. val=player", 0, pc.player); + debug(LOG_SYNC, "Received checking info for an unknown (as yet) droid. player:%d ref:%d", pc.player, pc.droidID); continue; } - // If there is a target find it - if (target) + if (pD->gameCheckDroid == NULL || ((PACKAGED_CHECK *)pD->gameCheckDroid)->gameTime != synchTime) { - psTarget = IdToPointer(target, ANYPLAYER); + debug(LOG_SYNC, "We got a droid %u synch, but we didn't choose the same droid to synch.", pc.droidID); + continue; // Can't synch, since we didn't save data to be able to calculate a delta. } - /* - * Decide how best to sync the droid. If it is onscreen and visible - * and the player who owns the droid has a low ping then do an - * onscreen update, otherwise do an offscreen one. - */ - /*if (droidOnScreen(pD, 0) - && ingame.PingTimes[player] < PING_LIMIT) - { - onscreen = true; - } - else - { - onscreen = false; - }*/ - onscreen = true; // Pick anything. Just be consistent instead of depending on random non-synchronised things. Maybe delete this entire function. + pc2 = *(PACKAGED_CHECK *)pD->gameCheckDroid; - // Update the droid - if (onscreen || isVtolDroid(pD)) +#define MERGECOPY(x, y, z1, z2) if (pc.y != pc2.y) { debug(LOG_SYNC, "Droid %u out of synch, changing "#x" from %"z1" to %"z2".", pc.droidID, x, pc.y); x = pc.y; } +#define MERGEDELTA(x, y, z1, z2) if (pc.y != pc2.y) { debug(LOG_SYNC, "Droid %u out of synch, changing "#x" from %"z1" to %"z2".", pc.droidID, x, x + pc.y - pc2.y); x += pc.y - pc2.y; } + // player not synched here... + MERGEDELTA(pD->pos.x, sMoveX, "d", "f"); + MERGEDELTA(pD->pos.y, sMoveY, "d", "f"); // Apparently the old off-screen update set both pos.[xy] and sMove.f[xy] to the received sMove.f[xy], so doing the same. + MERGEDELTA(pD->sMove.fx, sMoveX, "f", "f"); + MERGEDELTA(pD->sMove.fy, sMoveY, "f", "f"); + MERGEDELTA(pD->direction, direction, "f", "f"); + pD->direction += pD->direction < 0 ? 360 : pD->direction >= 360 ? -360 : 0; + MERGEDELTA(pD->body, body, "u", "u"); + MERGEDELTA(pD->experience, experience, "f", "f"); + + if (pc.sMoveX != pc2.sMoveX || pc.sMoveY != pc2.sMoveY) { - onscreenUpdate(pD, body, direction, order); - } - else - { - offscreenUpdate(pD, body, fx, fy, direction, order); + // snap droid(if on ground) to terrain level at x,y. + if ((asPropulsionStats + pD->asBits[COMP_PROPULSION].nStat)->propulsionType != PROPULSION_TYPE_LIFT) // if not airborne. + { + pD->pos.z = map_Height(pD->pos.x, pD->pos.y); + } } -// debug(LOG_SYNC, "difference in position for droid %d; was (%g, %g); did %s update", (int)pD->id, -// fx - pD->sMove.fx, fy - pD->sMove.fy, onscreen ? "onscreen" : "offscreen"); - - // Update the higher level stuff - if (!isVtolDroid(pD)) + // Doesn't cover all cases, but at least doesn't actively break stuff randomly. + switch (pc.order) { - highLevelDroidUpdate(pD, fx, fy, secondaryOrder, order, psTarget, experience); + case DORDER_MOVE: + if (pc.order != pc2.order || pc.orderX != pc2.orderX || pc.orderY != pc2.orderY) + { + debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s(%d, %d).", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.orderX, pc.orderY); + // reroute the droid. + turnOffMultiMsg(true); + orderDroidLoc(pD, pc.order, pc.orderX, pc.orderY); + turnOffMultiMsg(false); + } + break; + case DORDER_ATTACK: + if (pc.order != pc2.order || pc.targetID != pc2.targetID) + { + debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s(%u).", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order), pc.targetID); + // remote droid is attacking, not here tho! + turnOffMultiMsg(true); + orderDroidObj(pD, pc.order, IdToPointer(pc.targetID, ANYPLAYER)); + turnOffMultiMsg(false); + } + break; + case DORDER_NONE: + case DORDER_GUARD: + if (pc.order != pc2.order) + { + debug(LOG_SYNC, "Droid %u out of synch, changing order from %s to %s.", pc.droidID, getDroidOrderName(pc2.order), getDroidOrderName(pc.order)); + turnOffMultiMsg(true); + moveStopDroid(pD); + turnOffMultiMsg(false); + } + break; + default: + break; // Don't know what to do, but at least won't be actively breaking anything. } + MERGECOPY(pD->secondaryOrder, secondaryOrder, "u", "u"); // The old code set this after changing orders, so doing that in case. +#undef MERGECOPY +#undef MERGEDELTA + // ...and repeat! } @@ -498,133 +408,6 @@ BOOL recvDroidCheck(NETQUEUE queue) return true; } -// //////////////////////////////////////////////////////////////////////////// - -// //////////////////////////////////////////////////////////////////////////// -// higher order droid updating. Works mainly at the order level. comes after the main sync. -static void highLevelDroidUpdate(DROID *psDroid, float fx, float fy, - UDWORD state, UDWORD order, - BASE_OBJECT *psTarget,float experience) -{ - // update kill rating. - psDroid->experience = experience; - - // remote droid is attacking, not here tho! - if(order == DORDER_ATTACK && psDroid->order != DORDER_ATTACK && psTarget) - { - turnOffMultiMsg(true); - orderDroidObj(psDroid, DORDER_ATTACK, psTarget); - turnOffMultiMsg(false); - } - - // secondary orders. - if(psDroid->secondaryOrder != state) - { - psDroid->secondaryOrder = state; - } - - // see how well the sync worked, optionally update. - // offscreen updates will make this ok each time. - if (psDroid->order == DORDER_NONE && order == DORDER_NONE) - { - if( (fabs(fx - psDroid->sMove.fx)>(TILE_UNITS*2)) // if more than 2 tiles wrong. - ||(fabs(fy - psDroid->sMove.fy)>(TILE_UNITS*2)) ) - { - turnOffMultiMsg(true); - debug(LOG_SYNC, "Move order from %d,%d to %d,%d", (int)psDroid->pos.x, (int)psDroid->pos.y, (int)fx, (int)fy); - orderDroidLoc(psDroid, DORDER_MOVE, fx, fy); - turnOffMultiMsg(false); - } - } -} - -// //////////////////////////////////////////////////////////////////////////// -// droid on screen needs modifying -static void onscreenUpdate(DROID *psDroid, - UDWORD dam, - UWORD dir, - DROID_ORDER order) -{ - BASE_OBJECT *psClickedOn; - BOOL bMouseOver = false; - - psClickedOn = mouseTarget(); - if( psClickedOn != NULL && psClickedOn->type == OBJ_DROID) - { - if(psClickedOn->id == psDroid->id && mouseDown(MOUSE_RMB)) - { - bMouseOver = true; // override, so you dont see the updates. - } - } - - if(!bMouseOver) - { - psDroid->body = dam; // update damage - } - -// if(psDroid->order == DORDER_NONE || (psDroid->order == DORDER_GUARD && psDroid->action == DACTION_NONE) ) -// { -// psDroid->direction = dir %360; //update rotation -// } - - return; -} - -// //////////////////////////////////////////////////////////////////////////// -// droid offscreen needs modyfying. -static void offscreenUpdate(DROID *psDroid, - UDWORD dam, - float fx, - float fy, - UWORD dir, - DROID_ORDER order) -{ - PROPULSION_STATS *psPropStats; - - if (fabs((float)psDroid->pos.x - fx) > TILE_UNITS || fabs((float)psDroid->pos.y - fy) > TILE_UNITS) - { - debug(LOG_SYNC, "Moving droid %d from (%u,%u) to (%u,%u) (has order %s)", - (int)psDroid->id, psDroid->pos.x, psDroid->pos.y, (UDWORD)fx, (UDWORD)fy, getDroidOrderName(order)); - } - - psDroid->pos.x = fx; // update x - psDroid->pos.y = fy; // update y - psDroid->sMove.fx = fx; - psDroid->sMove.fy = fy; - psDroid->direction = dir % 360; // update rotation - psDroid->body = dam; // update damage - - // stage one, update the droid's position & info, LOW LEVEL STUFF. - if( order == DORDER_ATTACK - || order == DORDER_MOVE - || order == DORDER_RTB - || order == DORDER_RTR) // move order - { - // reroute the droid. - turnOffMultiMsg(true); - moveDroidTo(psDroid, psDroid->sMove.DestinationX,psDroid->sMove.DestinationY); - turnOffMultiMsg(false); - } - - // stop droid if remote droid has stopped. - if ((order == DORDER_NONE || order == DORDER_GUARD) - && !(psDroid->order == DORDER_NONE || psDroid->order == DORDER_GUARD)) - { - turnOffMultiMsg(true); - moveStopDroid(psDroid); - turnOffMultiMsg(false); - } - - // snap droid(if on ground) to terrain level at x,y. - psPropStats = asPropulsionStats + psDroid->asBits[COMP_PROPULSION].nStat; - ASSERT( psPropStats != NULL, "offscreenUpdate: invalid propulsion stats pointer" ); - if( psPropStats->propulsionType != PROPULSION_TYPE_LIFT ) // if not airborne. - { - psDroid->pos.z = map_Height(psDroid->pos.x, psDroid->pos.y); - } - return; -} - // //////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////// @@ -698,8 +481,8 @@ static BOOL sendStructureCheck(void) { lastSent = 0; } - // Only send a struct send if not done recently or if isMPDirtyBit is set - if ((gameTime - lastSent) < STRUCT_FREQUENCY && !isMPDirtyBit) + // Only send a struct send if not done recently + if ((gameTime - lastSent) < STRUCT_FREQUENCY) { return true; } @@ -927,8 +710,8 @@ static BOOL sendPowerCheck() lastsent = 0; } - // Only send if not done recently or if isMPDirtyBit is set - if (gameTime - lastsent < POWER_FREQUENCY && !isMPDirtyBit) + // Only send if not done recently + if (gameTime - lastsent < POWER_FREQUENCY) { return true; } diff --git a/src/objmem.c b/src/objmem.c index 679cbffe4..4b4ea8c30 100644 --- a/src/objmem.c +++ b/src/objmem.c @@ -499,6 +499,7 @@ void killDroid(DROID *psDel) { removeObjectFromFuncList(apsSensorList, (BASE_OBJECT*)psDel, 0); } + free(psDel->gameCheckDroid); destroyObject((BASE_OBJECT**)apsDroidLists, (BASE_OBJECT*)psDel); }