#include "engine.h" #include "exhumed.h" #include "snake.h" #include "status.h" #include "player.h" #include "runlist.h" #include "sequence.h" #include "bullet.h" #include "input.h" #include "anims.h" #include "lighting.h" #include "sound.h" #include "move.h" #include "trigdat.h" #include "gun.h" #include #include #define kMaxSnakes 50 int nSnakeCount = 0; int nSnakesFree; short SnakeFree[kMaxSnakes]; short nPlayerSnake[kMaxPlayers]; Snake SnakeList[kMaxSnakes]; short nSnakePlayer[kMaxSnakes]; void InitSnakes() { nSnakeCount = 0; for (int i = 0; i < kMaxSnakes; i++) { SnakeFree[i] = i; } nSnakesFree = kMaxSnakes; memset(nPlayerSnake, 0, sizeof(nPlayerSnake)); } short GrabSnake() { nSnakesFree--; return SnakeFree[nSnakesFree]; } void DestroySnake(int nSnake) { short nRun = SnakeList[nSnake].nRun; runlist_SubRunRec(nRun); for (int i = 0; i < kSnakeSprites; i++) { short nSprite = SnakeList[nSnake].nSprites[i]; runlist_DoSubRunRec(sprite[nSprite].lotag - 1); runlist_DoSubRunRec(sprite[nSprite].owner); mydeletesprite(nSprite); } SnakeFree[nSnakesFree] = nSnake; nSnakesFree++; if (nSnake == nSnakeCam) { nSnakeCam = -1; if (!bFullScreen) { RefreshStatus(); } } } void ExplodeSnakeSprite(int nSprite, short nPlayer) { short nDamage = BulletInfo[kWeaponStaff].nDamage; if (nPlayerDouble[nPlayer] > 0) { nDamage *= 2; } // take a copy of this, to revert after call to runlist_RadialDamageEnemy() short nOwner = sprite[nSprite].owner; sprite[nSprite].owner = PlayerList[nPlayer].nSprite; runlist_RadialDamageEnemy(nSprite, nDamage, BulletInfo[kWeaponStaff].field_10); sprite[nSprite].owner = nOwner; BuildAnim(-1, 23, 0, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, sprite[nSprite].sectnum, 40, 4); AddFlash(sprite[nSprite].sectnum, sprite[nSprite].x, sprite[nSprite].y, sprite[nSprite].z, 128); StopSpriteSound(nSprite); } int BuildSnake(short nPlayer, short zVal) { if (!nSnakesFree) return -1; zVal -= 1280; short nPlayerSprite = PlayerList[nPlayer].nSprite; short nViewSect = nPlayerViewSect[nPlayer]; short nPic = seq_GetSeqPicnum(kSeqSnakBody, 0, 0); int x = sprite[nPlayerSprite].x; int y = sprite[nPlayerSprite].y; int z = (sprite[nPlayerSprite].z + zVal) - 2560; short nAngle = sprite[nPlayerSprite].ang; short hitsect, hitwall, hitsprite; int hitx, hity, hitz; short nSprite; hitscan(x, y, z, sprite[nPlayerSprite].sectnum, Sin(nAngle + 512), Sin(nAngle), 0, &hitsect, &hitwall, &hitsprite, &hitx, &hity, &hitz, CLIPMASK1); int nSqrt = ksqrt(((hity - y) * (hity - y)) + ((hitx - x) * (hitx - x))); if (nSqrt < sintable[512] >> 4) { BackUpBullet(&hitx, &hity, nAngle); nSprite = insertsprite(hitsect, 202); sprite[nSprite].x = hitx; sprite[nSprite].y = hity; sprite[nSprite].z = hitz; ExplodeSnakeSprite(nSprite, nPlayer); mydeletesprite(nSprite); return -1; } else { short nTarget; if (hitsprite < 0 || sprite[hitsprite].statnum < 90 || sprite[hitsprite].statnum > 199) { nTarget = sPlayerInput[nPlayer].nTarget; } else { nTarget = hitsprite; } short nSnake = GrabSnake(); // int var_40 = 0; uchar var_18 = 0; // var_40 + var_40; // CHECKME ?? // GrabTimeSlot(3); short var_24; for (int i = 0; i < kSnakeSprites; i++) { nSprite = insertsprite(nViewSect, 202); assert(nSprite >= 0 && nSprite < kMaxSprites); sprite[nSprite].owner = nPlayerSprite; sprite[nSprite].picnum = nPic; if (i != 0) { sprite[nSprite].x = sprite[var_24].x; sprite[nSprite].y = sprite[var_24].y; sprite[nSprite].z = sprite[var_24].z; sprite[nSprite].xrepeat = 40 - (var_18 + i); sprite[nSprite].yrepeat = 40 - (var_18 + i); } else { sprite[nSprite].x = sprite[nPlayerSprite].x; sprite[nSprite].y = sprite[nPlayerSprite].y; sprite[nSprite].z = sprite[nPlayerSprite].z + zVal; sprite[nSprite].xrepeat = 32; sprite[nSprite].yrepeat = 32; nViewSect = sprite[nSprite].sectnum; var_24 = nSprite; } sprite[nSprite].clipdist = 10; sprite[nSprite].cstat = 0; sprite[nSprite].shade = -64; sprite[nSprite].pal = 0; sprite[nSprite].xoffset = 0; sprite[nSprite].yoffset = 0; sprite[nSprite].ang = sprite[nPlayerSprite].ang; sprite[nSprite].xvel = 0; sprite[nSprite].yvel = 0; sprite[nSprite].zvel = 0; sprite[nSprite].hitag = 0; sprite[nSprite].extra = -1; sprite[nSprite].lotag = runlist_HeadRun() + 1; SnakeList[nSnake].nSprites[i] = nSprite; sprite[nSprite].owner = runlist_AddRunRec(sprite[nSprite].lotag - 1, ((nSnake << 8) | i) | 0x110000); var_18 += 2; // var_40++; } SnakeList[nSnake].nRun = runlist_AddRunRec(NewRun, nSnake | 0x110000); SnakeList[nSnake].c[1] = 2; SnakeList[nSnake].c[5] = 5; SnakeList[nSnake].c[2] = 4; SnakeList[nSnake].c[3] = 6; SnakeList[nSnake].c[4] = 7; SnakeList[nSnake].c[6] = 6; SnakeList[nSnake].c[7] = 7; SnakeList[nSnake].nEnemy = nTarget; SnakeList[nSnake].sC = 1200; SnakeList[nSnake].sE = 0; nSnakePlayer[nSnake] = nPlayer; nPlayerSnake[nPlayer] = nSnake; if (bSnakeCam) { if (nSnakeCam < 0) { nSnakeCam = nSnake; } } // TODO D3PlayFX(StaticSound[kSound6], var_24); } return nSprite; } int FindSnakeEnemy(short nSnake) { short nPlayer = nSnakePlayer[nSnake]; short nPlayerSprite = PlayerList[nPlayer].nSprite; short nSprite = SnakeList[nSnake].nSprites[0]; // CHECKME short nAngle = sprite[nSprite].ang; short nSector = sprite[nSprite].sectnum; int esi = 2048; int nEnemy = -1; for (int i = headspritesect[nSector]; i >= 0; i = nextspritesect[i]) { if (sprite[i].statnum >= 90 && sprite[i].statnum < 150 && sprite[i].cstat & 0x101) { if (i != nPlayerSprite && (!(sprite[i].cstat & 0x8000))) { int nAngle2 = (nAngle - GetAngleToSprite(nSprite, i)) & kAngleMask; if (nAngle2 < esi) { nEnemy = i; esi = nAngle2; } } } } if (nEnemy == -1) { SnakeList[nSnake].nEnemy--; if (SnakeList[nSnake].nEnemy < -25) { nEnemy = nPlayerSprite; SnakeList[nSnake].nEnemy = nPlayerSprite; } } else { SnakeList[nSnake].nEnemy = nEnemy; } return nEnemy; } void FuncSnake(int a, int nDamage, int nRun) { int nMessage = a & 0x7F0000; switch (nMessage) { default: { DebugOut("unknown msg %x for bullet\n", a & 0x7F0000); return; } case 0x90000: { short nSnake = RunData[nRun].nVal; short nSprite = a & 0xFFFF; if (nSnake & 0xFF) { seq_PlotSequence(nSprite, SeqOffsets[kSeqSnakBody], 0, 0); } else { seq_PlotSequence(nSprite, SeqOffsets[kSeqSnakehed], 0, 0); } tsprite[nSprite].owner = -1; return; } case 0xA0000: { return; } case 0x20000: { short nSnake = RunData[nRun].nVal; assert(nSnake >= 0 && nSnake < kMaxSnakes); short nSprite = SnakeList[nSnake].nSprites[0]; seq_MoveSequence(nSprite, SeqOffsets[kSeqSnakehed], 0); short nEnemySprite = SnakeList[nSnake].nEnemy; int nMov; int zVal; if (nEnemySprite >= 0 && (sprite[nEnemySprite].cstat & 0x101)) { zVal = sprite[nSprite].z; nMov = AngleChase(nSprite, nEnemySprite, 1200, SnakeList[nSnake].sE, 32); zVal = sprite[nSprite].z - zVal; } else { if (!(sprite[nEnemySprite].cstat & 0x101)) { SnakeList[nSnake].nEnemy = -1; } nMov = movesprite(nSprite, 600 * Sin(sprite[nSprite].ang + 512), 600 * Sin(sprite[nSprite].ang), Sin(SnakeList[nSnake].sE) >> 5, 0, 0, 1); FindSnakeEnemy(nSnake); zVal = 0; } if (nMov) { short nPlayer = nSnakePlayer[nSnake]; ExplodeSnakeSprite(SnakeList[nSnake].nSprites[0], nPlayer); nPlayerSnake[nPlayer] = -1; nSnakePlayer[nSnake] = -1; DestroySnake(nSnake); return; } else { short nAngle = sprite[nSprite].ang; int var_30 = -(64 * Sin(nAngle + 512)); int var_34 = -(64 * Sin(nAngle)); int var_40 = var_30 + (var_30 * 8); int var_4C = var_30 + (var_34 * 8); int var_20 = SnakeList[nSnake].sE; SnakeList[nSnake].sE = (SnakeList[nSnake].sE + 64) & 0x7FF; int var_28 = (nAngle + 512) & kAngleMask; short nSector = sprite[nSprite].sectnum; int x = sprite[nSprite].x; int y = sprite[nSprite].y; int z = sprite[nSprite].z; int ebp = -(zVal * 7); int var_18 = var_28; for (int i = 7; i > 0; i--) { int nSprite2 = SnakeList[nSnake].nSprites[i]; sprite[nSprite2].ang = nAngle; sprite[nSprite2].x = x; sprite[nSprite2].y = y; sprite[nSprite2].z = z; mychangespritesect(nSprite2, nSector); var_40 = var_40 - var_30; var_4C = var_4C - var_34; ebp += zVal; int eax = Sin(var_20) * SnakeList[nSnake].c[i]; eax >>= 9; int ecx = eax * Sin(var_28 + 512); eax = sintable[var_18] * eax; movesprite(nSprite2, var_40 + ecx, var_4C + eax, ebp, 0, 0, CLIPMASK1); var_20 = (var_20 + 128) & kAngleMask; } } } } }