#include "T2BitImage.h" #include "T2DLL.h" #include "T2FireWork.h" #include "T2SoundPlayer.h" T2FireWork::T2FireWork(int inWidth, int inHeight, CPalette* inPalette) { Sounds->AddSound("Firework:Don", SoundPriority_0, 1000, AfxGetResourceHandle()); RECT rect; rect.top = 0; rect.left = 0; rect.bottom = inHeight; rect.right = inWidth; mImage = new T2BitImage(rect); memset(mImage->mData, 0, mImage->mBitmap.header.biSizeImage); #define ALIGN_ROW_SIZE(s) ((((s) + 3) / 4) * 4) mRowSize = ALIGN_ROW_SIZE(inWidth); SetRect(&mRect, 0, 0, inWidth, inHeight); mIsActive = false; int i; for (i = 0; i < 5; i++) { for (int j = 0; j < 8; j++) { int r, g, b; if (i == 0) { r = ((j + 1) * 255) / 8; g = ((j + 1) * 255) / 8; b = ((j + 1) * 100) / 8; } else if (i == 1) { r = ((j + 1) * 255) / 8; g = ((j + 1) * 186) / 8; b = ((j + 1) * 100) / 8; } else if (i == 2) { r = ((j + 1) * 255) / 8; g = ((j + 1) * 50) / 8; b = ((j + 1) * 50) / 8; } else if (i == 3) { r = ((j + 1) * 80) / 8; g = ((j + 1) * 80) / 8; b = ((j + 1) * 255) / 8; } else if (i == 4) { r = ((j + 1) * 255) / 8; g = ((j + 1) * 255) / 8; b = ((j + 1) * 200) / 8; } mPalettes[i][j] = inPalette->GetNearestPaletteIndex(RGB(r, g, b)); } } for (i = 0; i < 20; i++) mUsed[i] = false; } T2FireWork::~T2FireWork() { delete mImage; for (int i = 0; i < 20; i++) { if (mUsed[i]) free(mStarInfo[i]); } } T2BitImage* T2FireWork::GetBitImage() { return mImage; } void T2FireWork::Start() { mIsActive = true; } void T2FireWork::Stop() { mIsActive = false; } BOOL T2FireWork::IsDisposable() { if (mIsActive) return false; for (int i = 0; i < 20; i++) { if (mUsed[i]) return false; } return true; } BOOL T2FireWork::Idle() { static DWORD lastUpdate; static DWORD counter; BOOL anyChange = false; DWORD now = GetTickCount(); int ind, ind2; if (mIsActive && lastUpdate != now) { if ((counter % 35) == 0 || (rand() % 80) == 0) { for (ind = 0; ind < 20; ind++) { if (!mUsed[ind]) { #pragma var_order(var24, var28, var2C, bufferSize, var34, var38) float var24 = (((rand() % 40) - 20) / 100.0f) + 0.0f; float var38 = var24; float var28 = int((var38 * 6.283186) / 0.18) / 4; int var34 = 1; for (float var2C = 0.0f; var2C <= var28; var2C += 1.0f) { #pragma var_order(var3C, var40, var44) float var3C = var38 * cos((var2C * 1.5707965) / var28); float var40 = int((var3C * 6.283186) / 0.095); for (float var44 = 0.0f; var44 < var40 || var40 == 0.0f; var44 += 1.0f) { var34++; if (var40 == 0.0f) break; } } #pragma var_order(var24, var28, var2C, bufferSize, var34, var38) mUsed[ind] = true; int bufferSize = (var34 + 2) * sizeof(FIREWORK_STARINFO); mStarInfo[ind] = (FIREWORK_STARINFO *) malloc(bufferSize); memset(mStarInfo[ind], 0, bufferSize); mStarInfo[ind]->m0 = (rand() % 200) / 100.0f - 1.0f; mStarInfo[ind]->m4 = (rand() % 400) / 200.0f + -9.5f - 2.0f; mStarInfo[ind]->m8 = ((mRect.right / 2) + (rand() % (mRect.right / 3))) - (mRect.right / 6); mStarInfo[ind]->mC = mRect.bottom; mStarInfo[ind]->m10 = 0.0f; mStarInfo[ind]->m14 = 0.01f; mStarInfo[ind]->m18 = 50.0f; mStarInfo[ind]->m1C = 15.0f; mStarInfo[ind]->m24 = var24; mStarInfo[ind]->mFlags = 0x101; break; } } } counter++; } lastUpdate = now; for (ind = 0; ind < 20; ind++) { if (mUsed[ind]) { FIREWORK_STARINFO *info = mStarInfo[ind]; BOOL changed = false; for (ind2 = 0; info[ind2].mFlags != 0; ind2++) { #pragma var_order(x, y, star, size, pixel) FIREWORK_STARINFO *star = info + ind2; int x, y, pixel, size; if (CalcStarData(star, star->m10 - star->m1C, &x, &y, &pixel, &size)) { PutDot(x, y, size, 0); changed = true; } if (CalcStarData(star, star->m10, &x, &y, &pixel, &size)) { PutDot(x, y, size, mPalettes[HIBYTE(pixel)][LOBYTE(pixel)]); changed = true; } star->m10 += 1.0f; } if (!(info->mFlags & 0x8000) && (info->m10 >= info->m18)) { #pragma var_order(var64, var68, var6C, var70, var74, origInfo, var7C, var80, var84, var88) Sounds->Play("Firework:Don", SoundMask_10, SoundFlags_10, NULL, PlayMode_2, 100); FIREWORK_STARINFO *origInfo = info; origInfo->mFlags |= 0x8000; unsigned short var88 = 0; float var74 = 10.0f; float var64 = 0.0f; float var6C = rand() % 10 + 25; float var84 = mStarInfo[ind]->m24; switch (rand() % 10) { case 0: var88 = 8; break; case 1: var88 = 0xC8; break; case 2: var88 = 0x84; break; case 3: var88 = 0x88; break; case 4: var88 = 4; break; case 5: var88 = 2; break; case 6: var88 = 0x10; break; case 7: case 8: var88 = 0x28; break; case 9: var88 = 0xD0; break; } float var68 = int((var84 * 6.283186) / 0.18) / 4; int var80 = 1; float var7C = mRect.bottom * 0.016; for (float var70 = 0.0f; var70 <= var68; var70 += 1.0f) { #pragma var_order(var8C, var90, var94) float var8C = var84 * cos((var70 * 1.5707965) / var68); float var90 = int((var8C * 6.283186) / 0.095); for (float var94 = 0.0f; var94 < var90 || var90 == 0.0f; var94 += 1.0f) { #pragma var_order(var98, var9C, varA0, varA4, varA8, varAC, varB0) float var98 = (var94 * 6.283186) / ((var90 != 0.0f) ? var90 : 1.0f); float varA0 = float(cos(var98)) * var8C * var7C; float varA4 = float(sin(var98)) * var8C * var7C; int var9C, varA8, varB0, varAC; CalcStarData(origInfo, origInfo->m10 - 1.0f, &var9C, &varA8, &varB0, &varAC); info[var80].m0 = varA0; info[var80].m4 = varA4; info[var80].m8 = var9C; info[var80].mC = varA8; info[var80].m10 = 0.0f; info[var80].m14 = var64; info[var80].m18 = var6C; info[var80].m1C = var74; info[var80].mFlags = var88; var80++; if (var90 == 0.0f) break; } } } anyChange |= changed; if (!changed) { free(mStarInfo[ind]); mUsed[ind] = false; } } } return anyChange; } BOOL T2FireWork::CalcStarData(FIREWORK_STARINFO* inInfo, float inTime, int* outX, int* outY, int* outPixel, int* outSize) { if (inTime >= 0.0f && inTime < inInfo->m18) { float blend = 0.01f; blend = 1.0f - (1.0f / ((inTime / 8.0f) + 1.0f)); float mult = inInfo->m0 * 30.0f; *outX = (mult * blend) + inInfo->m8; mult = inInfo->m4 * 30.0f; *outY = (mult * blend) + inInfo->mC + (inInfo->m14 * inTime * inTime); int group = 0; int color = 7; if (inInfo->mFlags & 2) group = 0; else if (inInfo->mFlags & 4) group = 1; else if (inInfo->mFlags & 8) group = 2; else if (inInfo->mFlags & 0x10) group = 3; else if (inInfo->mFlags & 1) group = 4; if (inInfo->mFlags & 0x20) { if ((inInfo->m18 / 2.0f) < inTime) group++; } else if (inInfo->mFlags & 0x40) { if ((inInfo->m18 - 2.0f) < inTime) group++; } while (group >= 5) group -= 5; if (inInfo->mFlags & 0x100) { color = (inTime * 10.0f) / inInfo->m18; if (color >= 8) color = 7; } else if (inInfo->mFlags & 0x200) { if ((inInfo->m18 / 2.0f) < inTime) color = ((inInfo->m18 - inTime) * 8.0f) / (inInfo->m18 / 2.0f); if (inTime >= 8.0f) inTime = 7.0f; } else { color = (((inTime * 8.0f) / 2.0f) / inInfo->m18) + 4.0f; } *outPixel = (group << 8) | color; if (inInfo->mFlags & 0x40) { if (inTime > (inInfo->m18 - 2.0f)) *outSize = 3; else *outSize = 1; } else { *outSize = 1; } return true; } return false; } void T2FireWork::PutDot(int inX, int inY, int inSize, unsigned char inCol) { RECT theDotRect, theSubRect; if (inSize == 1) SetRect(&theDotRect, inX, inY, inX + 1, inY + 1); else if (inSize == 2) SetRect(&theDotRect, inX, inY, inX + 2, inY + 2); else if (inSize == 3 || inSize == 4) SetRect(&theDotRect, inX - 1, inY - 1, inX + 2, inY + 2); SubtractRect(&theSubRect, &theDotRect, &mRect); if (!IsRectEmpty(&theSubRect)) return; int p = inX + (mRowSize * inY); unsigned char *theData = mImage->mData; if (inSize == 1) { theData[p] = inCol; } else if (inSize == 2) { theData[p] = inCol; theData[p + 1] = inCol; theData[p + mRowSize] = inCol; theData[p + mRowSize + 1] = inCol; } else if (inSize == 3) { theData[p - 1] = inCol; theData[p] = inCol; theData[p + 1] = inCol; theData[p - mRowSize] = inCol; theData[p + mRowSize] = inCol; } else if (inSize == 4) { theData[p - mRowSize - 1] = inCol; theData[p - mRowSize] = inCol; theData[p - mRowSize + 1] = inCol; theData[p - 1] = inCol; theData[p] = inCol; theData[p + 1] = inCol; theData[p + mRowSize - 1] = inCol; theData[p + mRowSize] = inCol; theData[p + mRowSize + 1] = inCol; } }