#include "engine.h" #include "player.h" #include "anims.h" #include "status.h" #include "exhumed.h" #include "sequence.h" #include "init.h" #include "names.h" #include "items.h" #include "view.h" #include "trigdat.h" #include #include #include #include #include "typedefs.h" short nMaskY; static short nAnimsFree = 0; short statusmask[1600]; short message_timer = 0; char message_text[80]; int magicperline; int airperline; int healthperline; int nAirFrames; int nCounter; int nCounterDest; short nStatusSeqOffset; short nItemFrames; int laststatusx; int laststatusy; sshort nItemSeq; short nDigit[3]; short nMagicFrames; short nHealthLevel; short nItemFrame; short nMeterRange; short nMagicLevel; short nHealthFrame; short nMagicFrame; short statusx; short statusy; short nHealthFrames; short airframe; sshort nFirstAnim; sshort nLastAnim; short nItemAltSeq; short airpages = 0; short ammodelay = 3; short ammopages = 4; short nCounterBullet = -1; // 8 bytes struct statusAnim { short s1; short s2; sshort nPage; schar c1; schar c2; }; #define kMaxStatusAnims 50 statusAnim StatusAnim[kMaxStatusAnims]; uchar StatusAnimsFree[kMaxStatusAnims]; char StatusAnimFlags[kMaxStatusAnims]; short nItemSeqOffset[] = {91, 72, 76, 79, 68, 87, 83}; short word_9AD54[kMaxPlayers] = {0, 0, 0, 0, 0, 0, 0, 0}; int dword_9AD64[kMaxPlayers] = {0, 0, 0, 0, 0, 0, 0, 0}; void SetCounterDigits(); void SetItemSeq(); void SetItemSeq2(int nSeqOffset); int BuildStatusAnim(int val, int nFlags) { if (nAnimsFree <= 0) { return -1; } nAnimsFree--; uchar nStatusAnim = StatusAnimsFree[nAnimsFree]; StatusAnim[nStatusAnim].c1 = -1; StatusAnim[nStatusAnim].c2 = nLastAnim; if (nLastAnim < 0) { nFirstAnim = nStatusAnim; } else { StatusAnim[nLastAnim].c1 = nStatusAnim; } nLastAnim = nStatusAnim; StatusAnim[nStatusAnim].s1 = val; StatusAnim[nStatusAnim].s2 = 0; StatusAnimFlags[nStatusAnim] = nFlags; StatusAnim[nStatusAnim].nPage = numpages; return nStatusAnim; } void RefreshStatus() { short nLives = nPlayerLives[nLocalPlayer]; if (nLives < 0 || nLives > kMaxPlayerLives) { bail2dos("illegal value for nPlayerLives #%d\n", nLocalPlayer); } // draws the red dots that indicate the lives amount BuildStatusAnim(2 * nLives + 145, 0); ushort nKeys = PlayerList[nLocalPlayer].keys; int val = 37; for (int i = 0; i < 4; i++) { if (nKeys & 0x1000) { BuildStatusAnim(val, 0); } nKeys >>= 1; val += 2; } barpages = numpages; SetPlayerItem(nLocalPlayer, nPlayerItem[nLocalPlayer]); SetHealthFrame(0); SetMagicFrame(); SetAirFrame(); } void InitStatus() { nStatusSeqOffset = SeqOffsets[kSeqStatus]; nHealthFrames = SeqSize[nStatusSeqOffset + 1]; int nPicNum = seq_GetSeqPicnum(kSeqStatus, 1, 0); nMagicFrames = SeqSize[nStatusSeqOffset + 129]; nHealthFrame = 0; nMagicFrame = 0; nHealthLevel = 0; nMagicLevel = 0; nMeterRange = tilesizy[nPicNum]; magicperline = 1000 / nMeterRange; healthperline = 800 / nMeterRange; nAirFrames = SeqSize[nStatusSeqOffset + 133]; airperline = 100 / nAirFrames; nCounter = 0; nCounterDest = 0; memset(nDigit, 0, sizeof(nDigit)); SetCounter(0); SetHealthFrame(0); SetMagicFrame(); for (int i = 0; i < kMaxStatusAnims; i++) { StatusAnimsFree[i] = i; } nLastAnim = -1; nFirstAnim = -1; nItemSeq = -1; nAnimsFree = kMaxStatusAnims; statusx = nScreenWidth - 320; textpages = 0; message_timer = 0; statusy = nScreenHeight - 200; } void MoveStatusAnims() { // sshort nAnim = nFirstAnim; for (int i = nFirstAnim; i >= 0; i = StatusAnim[i].c1) { seq_MoveSequence(-1, nStatusSeqOffset + StatusAnim[i].s1, StatusAnim[i].s2); StatusAnim[i].s2++; short nSize = SeqSize[nStatusSeqOffset + StatusAnim[i].s1]; if (StatusAnim[i].s2 >= nSize) { if (StatusAnimFlags[i] & 0x10) { StatusAnim[i].s2 = 0; } else { StatusAnim[i].s2 = nSize - 1; } } } #if 0 while (nAnim != -1) { seq_MoveSequence(-1, nStatusSeqOffset + StatusAnim[nAnim].s1, StatusAnim[nAnim].s2); StatusAnim[nAnim].s2++; short nSize = SeqSize[nStatusSeqOffset + StatusAnim[nAnim].s1]; if (StatusAnim[nAnim].s2 >= nSize) { if (StatusAnimFlags[nAnim] & 0x10) StatusAnim[nAnim].s2 = 0; else StatusAnim[nAnim].s2 = nSize - 1; } nAnim = StatusAnim[nAnim].c1; } #endif } void DestroyStatusAnim(short nAnim) { short c1 = StatusAnim[nAnim].c1; short c2 = StatusAnim[nAnim].c2; if (c2 >= 0) { StatusAnim[c2].c1 = c1; } if (c1 >= 0) { StatusAnim[c1].c2 = c2; } if (nAnim == nFirstAnim) { nFirstAnim = c1; } if (nAnim == nLastAnim) { nLastAnim = c2; } StatusAnimsFree[nAnimsFree] = (uchar)nAnim; nAnimsFree++; } void DrawStatusAnims() { sshort nAnim = nFirstAnim; while (nAnim != -1) { int nextAnim = StatusAnim[nAnim].c1; int nSequence = nStatusSeqOffset + StatusAnim[nAnim].s1; seq_DrawStatusSequence(nSequence, StatusAnim[nAnim].s2, 0); if (StatusAnim[nAnim].s2 >= (SeqSize[nSequence] - 1)) { if (!(StatusAnimFlags[nAnim] & 0x10)) { StatusAnim[nAnim].nPage--; if (StatusAnim[nAnim].nPage <= 0) { DestroyStatusAnim(nAnim); } } } nAnim = nextAnim; } } void SetMagicFrame() { nMagicLevel = (1000 - PlayerList[nLocalPlayer].nMagic) / magicperline; if (nMagicLevel >= nMeterRange) { nMagicLevel = nMeterRange - 1; } if (nMagicLevel < 0) { nMagicLevel = 0; } SetItemSeq(); } void SetHealthFrame(short nVal) { nHealthLevel = (800 - PlayerList[nLocalPlayer].nHealth) / healthperline; if (nHealthLevel >= nMeterRange ) { nHealthLevel = nMeterRange - 1; } if (nHealthLevel < 0) { nHealthLevel = 0; } if (nVal < 0) { BuildStatusAnim(4, 0); } } void SetAirFrame() { airframe = PlayerList[nLocalPlayer].nAir / airperline; if (airframe < nAirFrames) { if (airframe < 0) { airframe = 0; } } else { airframe = nAirFrames - 1; } airpages = numpages; } void SetCounter(short nVal) { if (nVal <= 999) { if (nVal < 0) { nVal = 0; } } else { nVal = 999; } nCounterDest = nVal; } void SetCounterImmediate(short nVal) { SetCounter(nVal); nCounter = nCounterDest; SetCounterDigits(); } void SetCounterDigits() { nDigit[2] = 3 * (nCounter / 100 % 10); nDigit[1] = 3 * (nCounter / 10 % 10); nDigit[0] = 3 * (nCounter % 10); ammopages = numpages; } void SetItemSeq() { short nItem = nPlayerItem[nLocalPlayer]; if (nItem < 0) { nItemSeq = -1; return; } short nOffset = nItemSeqOffset[nItem]; SetItemSeq2(nOffset); } void SetItemSeq2(int nSeqOffset) { short nItem = nPlayerItem[nLocalPlayer]; if (nItemMagic[nItem] <= PlayerList[nLocalPlayer].nMagic) { nItemAltSeq = 0; } else { nItemAltSeq = 2; } nItemFrame = 0; nItemSeq = nSeqOffset + nItemAltSeq; nItemFrames = SeqSize[nItemSeq + nStatusSeqOffset]; } void SetPlayerItem(short nPlayer, short nItem) { nPlayerItem[nPlayer] = nItem; if (nPlayer == nLocalPlayer) { SetItemSeq(); if (nItem >= 0) { BuildStatusAnim((2 * PlayerList[nLocalPlayer].items[nItem]) + 156, 0); } } } void SetNextItem(int nPlayer) { short nItem = nPlayerItem[nPlayer]; int i; for (i = 6; i > 0; i--) { nItem++; if (nItem == 6) nItem = 0; if (PlayerList[nPlayer].items[nItem] != 0) break; } if (i > 0) { SetPlayerItem(nPlayer, nItem); } } void SetPrevItem(int nPlayer) { if (nPlayerItem[nPlayer] == -1) return; int nItem = nPlayerItem[nPlayer]; int i; for (i = 6; i > 0; i--) { nItem--; if (nItem < 0) nItem = 5; if (PlayerList[nPlayer].items[nItem] != 0) break; } if (i > 0) { SetPlayerItem(nPlayer, nItem); } } void MoveStatus() { if (nItemSeq >= 0) { nItemFrame++; if (nItemFrame >= nItemFrames) { if (nItemSeq == 67) { SetItemSeq(); } else { nItemSeq -= nItemAltSeq; if (nItemAltSeq || totalmoves & 0x1F) { if (nItemSeq < 2) { nItemAltSeq = 0; } } else { nItemAltSeq = 1; } nItemFrame = 0; nItemSeq += nItemAltSeq; nItemFrames = SeqSize[nStatusSeqOffset + nItemSeq]; } } } if (message_timer) { message_timer -= 4; if (message_timer <= 0) { if (screensize < nScreenWidth) { textpages = numpages; } message_timer = 0; } } MoveStatusAnims(); if (nCounter == nCounterDest) { nCounter = nCounterDest; ammopages = numpages; ammodelay = 3; return; } else { ammodelay--; if (ammodelay > 0) { return; } } ammopages = numpages; int eax = nCounterDest - nCounter; if (eax <= 0) { if (eax >= -30) { for (int i = 0; i < 3; i++) { nDigit[i]--; if (nDigit[i] < 0) { nDigit[i] += 30; } if (nDigit[i] < 27) { break; } } } else { nCounter += (nCounterDest - nCounter) >> 1; SetCounterDigits(); return; } } else { if (eax <= 30) { for (int i = 0; i < 3; i++) { nDigit[i]++; if (nDigit[i] <= 27) { break; } if (nDigit[i] >= 30) { nDigit[i] -= 30; } } } else { nCounter += (nCounterDest - nCounter) >> 1; SetCounterDigits(); return; } } if (!(nDigit[0] % 3)) { nCounter = nDigit[0] / 3 + 100 * (nDigit[2] / 3) + 10 * (nDigit[1] / 3); } eax = nCounterDest - nCounter; if (eax < 0) { eax = -eax; } ammodelay = 4 - (eax >> 1); if (ammodelay < 1) { ammodelay = 1; } } void UnMaskStatus() { for (int i = 0; i < nScreenWidth; i++) { startdmost[i] = nScreenHeight; } } void MaskStatus() { for (int i = 0; i < nScreenWidth; i++) { short bx = startdmost[i]; short cx = statusmask[i]; if (bx > cx) { startdmost[i] = cx; } } } void LoadStatus() { int i; short nSize; short tmp; short buffer[1024]; // memset(buffer, 0, sizeof(buffer)); // bjd - added by me for (i = 0; i < nScreenWidth; i++) { statusmask[i] = nScreenHeight; } nMaskY = nScreenHeight; int hStatus = kopen4load("status.msk", 1); if (!hStatus) { return; } kread(hStatus, &nSize, sizeof(nSize)); int nCount = nSize >> 1; kread(hStatus, &tmp, sizeof(tmp)); kread(hStatus, buffer, nSize); kclose(hStatus); short *pStatusMask = statusmask; for (i = 0; i < nCount; i++) { int v8 = nScreenHeight - ((nScreenHeight * buffer[i]) / 200); *pStatusMask++ = nScreenHeight - v8; if (bHiRes) { *pStatusMask++ = nScreenHeight - v8; } if (nScreenHeight - v8 < nMaskY) { nMaskY = nScreenHeight - v8; } } } void StatusMessage(int messageTime, const char *fmt, ...) { message_timer = messageTime; va_list args; va_start(args, fmt); vsprintf(message_text, fmt, args); if (screensize < nScreenWidth) { textpages = numpages; } } void DrawStatus() { char numberBuf[10] = {0}; char stringBuf[20] = {0}; char coordBuf[50] = {0}; // not sure of the size for this? if (!bFullScreen && nNetTime) { // bjd - commenting out this check seems to fix the black status bar at 320x200 resolution // if (bHiRes) { NoClip(); // } if (barpages > 0) { // draw the main bar itself seq_DrawStatusSequence(nStatusSeqOffset, 0, 0); barpages--; } seq_DrawStatusSequence(nStatusSeqOffset + 128, 0, 0); seq_DrawStatusSequence(nStatusSeqOffset + 127, 0, 0); seq_DrawStatusSequence(nStatusSeqOffset + 1, nHealthFrame, nHealthLevel); seq_DrawStatusSequence(nStatusSeqOffset + 129, nMagicFrame, nMagicLevel); nHealthFrame++; if (nHealthFrame >= nHealthFrames) { nHealthFrame = 0; } nMagicFrame++; if (nMagicFrame >= nMagicFrames) { nMagicFrame = 0; } seq_DrawStatusSequence(nStatusSeqOffset + 125, 0, 0); // draw ankh on health pool seq_DrawStatusSequence(nStatusSeqOffset + 130, 0, 0); // draw health pool frame (top) seq_DrawStatusSequence(nStatusSeqOffset + 131, 0, 0); // magic pool frame (bottom) if (nItemSeq >= 0) { seq_DrawStatusSequence(nItemSeq + nStatusSeqOffset, nItemFrame, 0); } // draws health level dots and other things DrawStatusAnims(); if (airpages) { seq_DrawStatusSequence(nStatusSeqOffset + 133, airframe, 0); airpages--; } // Draw compass seq_DrawStatusSequence(nStatusSeqOffset + 35, ((inita + 128) & kAngleMask) >> 8, 0); if (bCoordinates) { char *cFPS = itoa(lastfps, numberBuf, 10); printext(nScreenWidth - 20, nViewTop, cFPS, kTile159, -1); } if (ammopages) { ammopages--; seq_DrawStatusSequence(nStatusSeqOffset + 44, nDigit[2], 0); seq_DrawStatusSequence(nStatusSeqOffset + 45, nDigit[1], 0); seq_DrawStatusSequence(nStatusSeqOffset + 46, nDigit[0], 0); } // bjd - commenting out this check seems to fix the black status bar at 320x200 resolution // if (bHiRes) { Clip(); // } } if (nNetPlayerCount) { NoClip(); int shade; if (totalclock / kTimerTicks & 1) { shade = -100; } else { shade = 127; } int nTile = kTile3593; int x = 320 / (nTotalPlayers + 1); for (int i = 0; i < nTotalPlayers; i++) { int nScore = nPlayerScore[i]; if (word_9AD54[i] == nScore) { int v9 = dword_9AD64[i]; if (v9 && v9 <= totalclock) { dword_9AD64[i] = 0; } } else { word_9AD54[i] = nScore; dword_9AD64[i] = totalclock + 30; } overwritesprite(x, 7, nTile, 0, 3, kPalNormal); if (i != nLocalPlayer) { shade = -100; } sprintf(stringBuf, "%d", nPlayerScore[i]); int nStringLen = MyGetStringWidth(stringBuf); myprintext(x - (nStringLen / 2), 4, stringBuf, shade); x *= 2; nTile++; } if (nNetTime >= 0) { int y = nViewTop; if (nNetTime) { int v12 = (nNetTime + 29) / 30 % 60; int v13 = (nNetTime + 29) / 1800; nNetTime += 29; sprintf(stringBuf, "%d.%02d", v13, v12); if (bHiRes) { y = nViewTop / 2; } if (nViewTop <= 0) { y += 20; } else { y += 15; } nNetTime -= 29; } else { y = 100; strcpy(stringBuf, "GAME OVER"); } int nLenString = MyGetStringWidth(stringBuf); myprintext((320 - nLenString) / 2, y, stringBuf, 0); } Clip(); } if (bCoordinates) { int nSprite = PlayerList[nLocalPlayer].nSprite; int x = (nViewLeft + nViewRight) / 2; sprintf(coordBuf, "X %d", sprite[nSprite].x); printext(x, nViewTop + 1, coordBuf, kTile159, 255); sprintf(coordBuf, "Y %d", sprite[nSprite].y); printext(x, nViewTop + 10, coordBuf, kTile159, 255); } if (bHolly) { sprintf(message_text, "HOLLY: %s", sHollyStr); printext(0, 0, message_text, kTile159, 255); } else if (nSnakeCam < 0) { if (message_timer) { printext(0, 0, message_text, kTile159, 255); } } else { printext(0, 0, "S E R P E N T C A M", kTile159, 255); } }