From 1af3d499f5ebad602689e78cd86f8b9b4813f2e6 Mon Sep 17 00:00:00 2001 From: NY00123 Date: Thu, 13 Jun 2024 21:20:39 +0300 Subject: [PATCH] Blood: Calculate XSPRITE checksums in a cross-platform manner. The way it's done should theoretically match DOS v1.21, short of the value of aiState depending on the exe's layout (but possibly always being 0 for player sprites). --- source/blood/src/db.cpp | 38 ++++++++++++++++++++++++++++++++++++ source/blood/src/db.h | 2 ++ source/blood/src/network.cpp | 10 ++-------- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/source/blood/src/db.cpp b/source/blood/src/db.cpp index 62642dcd19..3e4d5f697b 100644 --- a/source/blood/src/db.cpp +++ b/source/blood/src/db.cpp @@ -156,6 +156,44 @@ const char *gWeaponText[] = { +uint32_t XSPRITE::CalcChecksum(void) +{ + // This was originally written to calculate the checksum + // the way OUWB v1.21 does. Therefore, certain bits may + // be skipped or calculated in a different order. + uint32_t sum = 0; + sum += (reference&16383) | ((state&1)<<14) | ((busy&131071)<<15); + sum += (txID&1023) | ((rxID&1023)<<10) | ((command&255)<<20) | + ((triggerOn&1)<<28) | ((triggerOff&1)<<29) | ((wave&3)<<30); + sum += (busyTime&4095) | ((waitTime&4095)<<12) | + ((restState&1)<<24) | ((Interrutable&1)<<25) | + ((unused1&3)<<26) | ((respawnPending&3)<<28) | + ((unused2&1)<<30) | ((lT&1)<<31); + sum += (dropMsg&255) | ((Decoupled&1)<<8) | + ((triggerOnce&1)<<9) | ((isTriggered&1)<<10) | + ((key&7)<<11) | ((Push&1)<<14) | ((Vector&1)<<15) | + ((Impact&1)<<16) | ((Pickup&1)<<17) | ((Touch&1)<<18) | + ((Sight&1)<<19) | ((Proximity&1)<<20) | + ((unused3&3)<<21) | ((lSkill&31)<<23) | + ((lS&1)<<28) | ((lB&1)<<29) | ((lC&1)<<30) | ((DudeLockout&1)<<31); + sum += (data1&65535) | ((data2&65535)<<16); + sum += (data3&65535) | ((goalAng&2047)<<16) | ((dodgeDir&3)<<27) | + ((locked&1)<<29) | ((medium&3)<<30); + sum += (respawn&3) | ((data4&65535)<<2) | + ((unused4&63)<<18) | ((lockMsg&255)<<24); + sum += (health&4095) | ((dudeDeaf&1)<<12) | ((dudeAmbush&1)<<13) | + ((dudeGuard&1)<<14) | ((dudeFlag4&1)<<15) | ((target&65535)<<16); + sum += targetX&0xFFFFFFFF; + sum += targetY&0xFFFFFFFF; + sum += targetZ&0xFFFFFFFF; + sum += (burnTime&65535) | ((burnSource&65535)<<16); + sum += (height&65535) | ((stateTimer&65535)<<16); + // aiState is a state pointer. Exact pointer values depend on exe layout. + // For player sprites, it is apparently always set to 0. + sum += aiState ? (((uintptr_t)aiState)&0xFFFFFFFF) : 0; + return sum; +} + void dbCrypt(char *pPtr, int nLength, int nKey) { for (int i = 0; i < nLength; i++) diff --git a/source/blood/src/db.h b/source/blood/src/db.h index 69b4d15ce2..6e3843246d 100644 --- a/source/blood/src/db.h +++ b/source/blood/src/db.h @@ -122,6 +122,8 @@ struct XSPRITE { #endif signed int scale; // used for scaling SEQ size on sprites + // Calculates checksum for multiplayer games. Certain bits might be skipped. + uint32_t CalcChecksum(void); }; struct XSECTOR { diff --git a/source/blood/src/network.cpp b/source/blood/src/network.cpp index ad4e56b5b7..8dca8749f0 100644 --- a/source/blood/src/network.cpp +++ b/source/blood/src/network.cpp @@ -259,14 +259,8 @@ void CalcGameChecksum(void) sum += *pBuffer++; } gChecksum[2] ^= sum; - pBuffer = (int*)gPlayer[p].pXSprite; - sum = 0; - length = sizeof(XSPRITE)/4; - while (length--) - { - sum += *pBuffer++; - } - gChecksum[3] ^= sum; + + gChecksum[3] ^= gPlayer[p].pXSprite->CalcChecksum(); } }