diff --git a/TR5Main/Game/effect2.cpp b/TR5Main/Game/effect2.cpp index 6b1e03538..ca49fe1a3 100644 --- a/TR5Main/Game/effect2.cpp +++ b/TR5Main/Game/effect2.cpp @@ -2,7 +2,7 @@ #include "draw.h" #include "tomb4fx.h" #include "traps.h" - +#include "math.h" #include "..\Scripting\GameFlowScript.h" //long wibble; @@ -1001,37 +1001,68 @@ void TriggerSuperJetFlame(ITEM_INFO* item, int yvel, int deadly)//32EAC, 333AC ( } } -void SetupSplash(SPLASH_SETUP* setup) +void SetupSplash(const SPLASH_SETUP* const setup) { + constexpr size_t NUM_SPLASHES = 4; + int numSplashesSetup = 0; + float splashVelocity; for (int i = 0; i < MAX_SPLASH; i++) { - SPLASH_STRUCT* splash = &Splashes[i]; - - if (!(splash->flags & 1)) + SPLASH_STRUCT& splash = Splashes[i]; + if (!splash.isActive) { - splash->flags = 1; - splash->x = setup->x; - splash->y = setup->y; - splash->z = setup->z; - splash->life = 62; - splash->innerRad = setup->innerRad; - splash->innerSize = setup->innerSize; - splash->innerRadVel = setup->innerRadVel; - splash->innerYVel = setup->innerYVel; - splash->innerY = setup->innerYVel >> 2; - splash->middleRad = setup->middleRad; - splash->middleSize = setup->middleSize; - splash->middleRadVel = setup->middleRadVel; - splash->middleYVel = setup->middleYVel; - splash->middleY = setup->middleYVel >> 2; - splash->outerRad = setup->outerRad; - splash->outerSize = setup->outerSize; - splash->outerRadVel = setup->outerRadVel; + if (numSplashesSetup == 0) { + splash.isActive = true; + splash.x = setup->x; + splash.y = setup->y; + splash.z = setup->z; + splash.life = 62; + splash.isRipple = false; + splash.innerRad = setup->innerRadius; + splashVelocity = setup->splashPower / 16; + splash.innerRadVel = splashVelocity; + splash.heightSpeed = setup->splashPower * 1.5f; + splash.height = 0; + splash.heightVel = -16; + splash.outerRad = setup->innerRadius / 6; + splash.outerRadVel = splashVelocity *2; + splash.spriteSequenceStart = 8; //Splash Texture + numSplashesSetup++; + } + else { + float thickness = frandMinMax(128,256); + splash.isActive = true; + splash.x = setup->x; + splash.y = setup->y; + splash.z = setup->z; + splash.isRipple = true; + float vel = (splashVelocity/2) + frandMinMax(3,16); + float innerRadius = 0; + splash.innerRad = innerRadius; + splash.innerRadVel = vel; + splash.outerRad = innerRadius + thickness; + splash.outerRadVel = vel; + splash.heightSpeed = 128; + splash.height = 0; + splash.heightVel = -16; + float t = vel / (splashVelocity / 2) + 16; + t = fmax(0, fmin(t, 1)); + splash.life = lerp(48, 70, t); + splash.spriteSequenceStart = 4; //Splash Texture + splash.spriteSequenceEnd = 7; //Splash Texture + splash.animationSpeed = frandMinMax(0.05f, 0.15f); - break; + numSplashesSetup++; + } + if (numSplashesSetup == NUM_SPLASHES) { + break; + } + continue; } } + + SoundEffect(SFX_LARA_SPLASH, (PHD_3DPOS*)setup, 0); } @@ -1039,60 +1070,30 @@ void UpdateSplashes() { for (int i = 0; i < MAX_SPLASH; i++) { - SPLASH_STRUCT* splash = &Splashes[i]; - - if (splash->flags & 1) - { - splash->innerRad += splash->innerRadVel >> 5; - splash->innerSize += splash->innerRadVel >> 6; - splash->innerRadVel -= (splash->innerRadVel >> 6); - - splash->middleRad += splash->middleRadVel >> 5; - splash->middleSize += splash->middleRadVel >> 6; - splash->middleRadVel -= splash->middleRadVel >> 6; - - splash->outerRad += splash->outerRadVel >> 5; - splash->outerSize += splash->outerRadVel >> 6; - splash->outerRadVel -= splash->outerRadVel >> 6; - - splash->innerY += splash->innerYVel >> 4; - splash->innerYVel += 1024; - - if (splash->innerYVel > 16384) - splash->innerYVel = 16384; - - if (splash->innerY < 0) - { - if (splash->innerY < -28672) - splash->innerY = -28672; + SPLASH_STRUCT& splash = Splashes[i]; + if (splash.isActive) { + splash.life--; + if (splash.life <= 0) { + splash.isActive = false; } - else - { - splash->innerY = 0; - splash->flags |= 4; - splash->life -= 2; - - if (splash->life == 0) - splash->flags = 0; + splash.heightSpeed += splash.heightVel; + splash.height += splash.heightSpeed; + if (splash.height < 0) { + splash.height = 0; + if (!splash.isRipple) { + splash.isActive = false; + } } - - splash->middleY += splash->middleYVel >> 4; - splash->middleYVel += 896; - - if (splash->middleYVel > 16384) - splash->middleYVel = 16384; - - if (splash->middleY < 0) - { - if (splash->middleY < -28672) - splash->middleY = -28672; - } - else - { - splash->middleY = 0; - splash->flags |= 8; + splash.innerRad += splash.innerRadVel; + splash.outerRad += splash.outerRadVel; + splash.animationPhase += splash.animationSpeed; + short sequenceLength = splash.spriteSequenceEnd - splash.spriteSequenceStart; + if (splash.animationPhase > sequenceLength) { + splash.animationPhase = fmod(splash.animationPhase, sequenceLength); } } + + } for (int i = 0; i < MAX_RIPPLES; i++) @@ -1389,17 +1390,8 @@ void WadeSplash(ITEM_INFO* item, int wh, int wd) SplashSetup.y = wh; SplashSetup.x = item->pos.xPos; SplashSetup.z = item->pos.zPos; - SplashSetup.innerRad = 16; - SplashSetup.innerSize = 12; - SplashSetup.innerRadVel = 160; - SplashSetup.innerYVel = -72 * item->fallspeed; - SplashSetup.middleRad = 24; - SplashSetup.middleSize = 24; - SplashSetup.middleRadVel = 224; - SplashSetup.middleYVel = -36 * item->fallspeed; - SplashSetup.outerRad = 32; - SplashSetup.outerSize = 32; - SplashSetup.outerRadVel = 272; + SplashSetup.innerRadius = 16; + SplashSetup.splashPower = item->speed; SetupSplash(&SplashSetup); SplashCount = 16; } @@ -1421,17 +1413,8 @@ void Splash(ITEM_INFO* item) SplashSetup.y = wh; SplashSetup.x = item->pos.xPos; SplashSetup.z = item->pos.zPos; - SplashSetup.innerRad = 32; - SplashSetup.innerSize = 8; - SplashSetup.innerRadVel = 320; - SplashSetup.innerYVel = -40 * item->fallspeed; - SplashSetup.middleRad = 48; - SplashSetup.middleSize = 32; - SplashSetup.middleRadVel = 480; - SplashSetup.middleYVel = -20 * item->fallspeed; - SplashSetup.outerRad = 32; - SplashSetup.outerSize = 128; - SplashSetup.outerRadVel = 544; + SplashSetup.splashPower = item->fallspeed; + SplashSetup.innerRadius = 64; SetupSplash(&SplashSetup); } } @@ -1952,5 +1935,4 @@ void Inject_Effect2() INJECT(0x00431530, ClearDynamicLights); INJECT(0x00432A30, WadeSplash); INJECT(0x00432900, Splash); - INJECT(0x00430620, SetupSplash); } \ No newline at end of file diff --git a/TR5Main/Game/effect2.h b/TR5Main/Game/effect2.h index 23f279878..aed2d34b1 100644 --- a/TR5Main/Game/effect2.h +++ b/TR5Main/Game/effect2.h @@ -23,7 +23,7 @@ //#define ControlWaterfallMist ((void (__cdecl*)(short)) 0x00432CA0) //#define TriggerRicochetSparks ((void (__cdecl*)(GAME_VECTOR*, short, int, int)) 0x0042F060) -extern SPLASH_STRUCT Splashes[4]; +extern SPLASH_STRUCT Splashes[MAX_SPLASH]; extern RIPPLE_STRUCT Ripples[32]; extern int DeadlyBounds[6]; extern SPARKS Sparks[1024]; @@ -43,7 +43,7 @@ void TriggerExplosionSmokeEnd(int x, int y, int z, int uw); void TriggerExplosionSmoke(int x, int y, int z, int uw); void TriggerFireFlame(int x, int y, int z, int fxObj, int type); void TriggerSuperJetFlame(ITEM_INFO* item, int yvel, int deadly); -void SetupSplash(SPLASH_SETUP* setup); +void SetupSplash(const SPLASH_SETUP* const setup); void UpdateSplashes(); void SetupRipple(int x, int y, int z, char size, char flags); void TriggerUnderwaterBlood(int x, int y, int z, int sizeme); @@ -59,6 +59,4 @@ void GrenadeExplosionEffects(int x, int y, int z, short roomNumber); void TriggerMetalSparks(int x, int y, int z, int xv, int yv, int zv, int additional); void WadeSplash(ITEM_INFO* item, int wh, int wd); void Splash(ITEM_INFO* item); -void SetupSplash(SPLASH_SETUP* setup); - void Inject_Effect2(); \ No newline at end of file diff --git a/TR5Main/Game/lara1gun.cpp b/TR5Main/Game/lara1gun.cpp index 58e6576a8..e9baa5509 100644 --- a/TR5Main/Game/lara1gun.cpp +++ b/TR5Main/Game/lara1gun.cpp @@ -1442,18 +1442,8 @@ void TriggerUnderwaterExplosion(ITEM_INFO* item) SplashSetup.y = wh; SplashSetup.x = item->pos.xPos; SplashSetup.z = item->pos.zPos; - SplashSetup.innerRadVel = 160; - SplashSetup.middleRadVel = 224; - SplashSetup.outerRadVel = 272; - SplashSetup.innerRad = (2048 - dy) >> 6 + 16; - SplashSetup.innerSize = (2048 - dy) >> 6 + 12; - SplashSetup.innerYVel = 8 * (-512 - (2048 - dy)); - SplashSetup.middleRad = (2048 - dy) >> 6 + 24; - SplashSetup.middleSize = (2048 - dy) >> 6 + 24; - SplashSetup.middleYVel = 4 * (-768 - (2048 - dy)); - SplashSetup.outerRad = (2048 - dy) >> 6 + 32; - SplashSetup.outerSize = (2048 - dy) >> 6 + 32; - + SplashSetup.innerRadius = 160; + SplashSetup.splashPower = 2048 - dy; SetupSplash(&SplashSetup); } } diff --git a/TR5Main/Game/laramisc.cpp b/TR5Main/Game/laramisc.cpp index 3560f17a5..b2375c8e7 100644 --- a/TR5Main/Game/laramisc.cpp +++ b/TR5Main/Game/laramisc.cpp @@ -7,6 +7,7 @@ #include "laraswim.h" #include "larasurf.h" #include "effect2.h" +#include "misc.h" extern LaraExtraInfo g_LaraExtra; extern GameFlow* g_GameFlow; @@ -137,7 +138,7 @@ void LaraControl(short itemNumber)//4A838, 4AC9C Lara.isDucked = 0; - bool isWater = Rooms[item->roomNumber].flags & ENV_FLAG_WATER; + bool isWater = Rooms[item->roomNumber].flags & (ENV_FLAG_WATER|ENV_FLAG_SWAMP); int wd = GetWaterDepth(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber); int wh = GetWaterHeight(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber); @@ -162,10 +163,22 @@ void LaraControl(short itemNumber)//4A838, 4AC9C { Lara.waterStatus = LW_WADE; if (!(item->gravityStatus)) + { item->goalAnimState = STATE_LARA_STOP; + } + else if (isWater & ENV_FLAG_SWAMP) + { + if (item->currentAnimState == STATE_LARA_SWANDIVE_BEGIN || item->currentAnimState == STATE_LARA_SWANDIVE_END) // Is Lara swan-diving? + item->pos.yPos = wh + 1000; + + item->goalAnimState = STATE_LARA_WADE_FORWARD; + item->currentAnimState = STATE_LARA_WADE_FORWARD; + item->animNumber = ANIMATION_LARA_WADE; + item->frameNumber = GF(ANIMATION_LARA_WADE, 0); + } } } - else if (isWater) + else if (!(isWater & ENV_FLAG_SWAMP)) { Lara.air = 1800; Lara.waterStatus = LW_UNDERWATER; @@ -388,7 +401,7 @@ void LaraControl(short itemNumber)//4A838, 4AC9C Camera.targetElevation = -ANGLE(22); if (hfw >= 256) { - if (hfw > 730) + if (hfw > 730 && !(isWater & ENV_FLAG_SWAMP)) { Lara.waterStatus = LW_SURFACE; item->pos.yPos += 1 - hfw; @@ -471,7 +484,20 @@ void LaraControl(short itemNumber)//4A838, 4AC9C { case LW_ABOVE_WATER: case LW_WADE: - if (Lara.gassed) + if (Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP && Lara.waterSurfaceDist < -775) + { + if (item->hitPoints >= 0) + { + Lara.air -= 6; + + if (Lara.air < 0) + { + Lara.air = -1; + item->hitPoints -= 10; + } + } + } + else if (Lara.gassed) { if (item->hitPoints >= 0 && --Lara.air < 0) { @@ -483,10 +509,14 @@ void LaraControl(short itemNumber)//4A838, 4AC9C } else if (Lara.air < 1800 && item->hitPoints >= 0) { - Lara.air += 10; - if (Lara.air > 1800) - Lara.air = 1800; - } + /* lara is not equipped with any vehicle */ + if (g_LaraExtra.Vehicle == NO_ITEM) // only for the upv !! + { + Lara.air += 10; + if (Lara.air > 1800) + Lara.air = 1800; + } + } LaraAboveWater(item, &coll); break; @@ -832,8 +862,8 @@ void AnimateLara(ITEM_INFO* item) flags = cmd[1] & 0xC000; if (flags == SFX_LANDANDWATER || - (flags == SFX_LANDONLY && (Lara.waterSurfaceDist >= 0 || Lara.waterSurfaceDist == NO_HEIGHT)) || - (flags == SFX_WATERONLY && Lara.waterSurfaceDist < 0 && Lara.waterSurfaceDist != NO_HEIGHT /*&& !(Rooms[lara_item->room_number].flags & SWAMP)*/)) + (flags == SFX_LANDONLY && (Lara.waterSurfaceDist >= 0 || Lara.waterSurfaceDist == NO_HEIGHT)) || + (flags == SFX_WATERONLY && Lara.waterSurfaceDist < 0 && Lara.waterSurfaceDist != NO_HEIGHT && !(Rooms[LaraItem->roomNumber].flags & ENV_FLAG_SWAMP))) { SoundEffect(cmd[1] & 0x3FFF, &item->pos, 2); } @@ -864,75 +894,57 @@ void AnimateLara(ITEM_INFO* item) int lateral = anim->Xvelocity; if (anim->Xacceleration) lateral += anim->Xacceleration * (item->frameNumber - anim->frameBase); - lateral >>= 16; - if (item->gravityStatus) + if (item->gravityStatus) // If gravity ON (Do Up/Down movement) { - int velocity = (anim->velocity + anim->acceleration * (item->frameNumber - anim->frameBase - 1)); - item->speed -= velocity >> 16; - item->speed += (velocity + anim->acceleration) >> 16; - item->fallspeed += (item->fallspeed >= 128 ? 1 : 6); - item->pos.yPos += item->fallspeed; + if (Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP) + { + item->speed -= item->speed >> 3; + if (abs(item->speed) < 8) + { + item->speed = 0; + item->gravityStatus = false; + } + if (item->fallspeed > 128) + item->fallspeed >>= 1; + item->fallspeed -= item->fallspeed >> 2; + if (item->fallspeed < 4) + item->fallspeed = 4; + item->pos.yPos += item->fallspeed; + } + else + { + int velocity = (anim->velocity + anim->acceleration * (item->frameNumber - anim->frameBase - 1)); + item->speed -= velocity >> 16; + item->speed += (velocity + anim->acceleration) >> 16; + item->fallspeed += (item->fallspeed >= 128 ? 1 : GRAVITY); + item->pos.yPos += item->fallspeed; + } } - else + else // if on the Ground... { - int velocity = anim->velocity; - if (anim->acceleration) - velocity += anim->acceleration * (item->frameNumber - anim->frameBase); + int velocity; + + if (Lara.waterStatus == LW_WADE && Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP) + { + velocity = anim->velocity >> 1; + if (anim->acceleration) + velocity += anim->acceleration * (item->frameNumber - anim->frameBase) >> 2; + } + else + { + velocity = anim->velocity; + if (anim->acceleration) + velocity += anim->acceleration * (item->frameNumber - anim->frameBase); + } + item->speed = velocity >> 16; } /*if (lara.RopePtr != -1) result = j_SomeRopeCollisionFunc(item);*/ - /* - if ( !item->gravity_status ) // Calculate absolute new velocities - { // if on the Ground... - if (lara.water_status==LARA_WADE && (room[item->room_number].flags & SWAMP)) - { - speed = anim->velocity>>1; - if ( anim->acceleration ) - speed += (anim->acceleration * (item->frame_number - anim->frame_base))>>2; - item->speed = (sint16)(speed >> 16); - } - else - { - speed = anim->velocity; - if ( anim->acceleration ) - speed += anim->acceleration * (item->frame_number - anim->frame_base); - item->speed = (sint16)(speed >> 16); - } - } - else // If gravity ON - { // do Up/down movement - if (room[item->room_number].flags & SWAMP) - { - item->speed -= item->speed>>3; - if (abs(item->speed)<8) - { - item->speed = 0; - item->gravity_status = 0; - } - if (item->fallspeed > 128) - item->fallspeed >>= 1; - item->fallspeed -= item->fallspeed>>2; - if (item->fallspeed < 4) - item->fallspeed = 4; - item->pos.y_pos += item->fallspeed; - } - else - { - speed = anim->velocity + anim->acceleration * (item->frame_number - anim->frame_base - 1); - item->speed -= (sint16)(speed>>16); - speed += anim->acceleration; - item->speed += (sint16)(speed>>16); - item->fallspeed += (item->fallspeedpos.y_pos += item->fallspeed; - } - } - */ - if (!Lara.isMoving) { item->pos.xPos += item->speed * SIN(Lara.moveAngle) >> W2V_SHIFT; diff --git a/TR5Main/Game/tomb4fx.cpp b/TR5Main/Game/tomb4fx.cpp index 5ee04fbf7..861b5c24e 100644 --- a/TR5Main/Game/tomb4fx.cpp +++ b/TR5Main/Game/tomb4fx.cpp @@ -439,32 +439,33 @@ void UpdateSmoke() int dl = ((spark->sLife - spark->life) << 16) / spark->sLife; - spark->yVel += spark->gravity; - - if (spark->maxYvel) + spark->yVel -= spark->gravity.to_float(); + + if (spark->maxYvel != 0) { - if ((spark->yVel < 0 && spark->yVel < (spark->maxYvel << 5)) || - (spark->yVel > 0 && spark->yVel > (spark->maxYvel << 5))) - spark->yVel = spark->maxYvel << 5; - } - - if (spark->friction & 0xF) - { - spark->xVel -= spark->xVel >> (spark->friction & 0xF); - spark->zVel -= spark->zVel >> (spark->friction & 0xF); + if (spark->yVel < 0) { + if (-spark->yVel.to_float() > (spark->maxYvel)) { + spark->yVel = -spark->maxYvel.to_float(); + } + } + else { + if (spark->yVel.to_float() > (spark->maxYvel)) { + spark->yVel = spark->maxYvel.to_float(); + } + } } - if (spark->friction & 0xF0) - spark->yVel -= spark->yVel >> (spark->friction >> 4); - - spark->x += spark->xVel >> 5; - spark->y += spark->yVel >> 5; - spark->z += spark->zVel >> 5; + spark->xVel -= spark->xVel * spark->friction.to_float(); + spark->zVel -= spark->zVel * spark->friction.to_float(); + spark->yVel -= spark->yVel * spark->friction.to_float(); + spark->x += spark->xVel.to_float(); + spark->y += spark->yVel.to_float(); + spark->z += spark->zVel.to_float(); if (spark->flags & SP_WIND) { spark->x += SmokeWindX >> 1; - spark->z += SmokeWindZ >> 1; + spark->z += SmokeWindZ>>1; } spark->size = spark->sSize + (dl * (spark->dSize - spark->sSize) >> 16); @@ -519,9 +520,10 @@ void TriggerGunSmoke(int x, int y, int z, short xv, short yv, short zv, byte ini } else { - spark->xVel = ((GetRandomControl() & 511) - 256) >> 1; - spark->yVel = ((GetRandomControl() & 511) - 256) >> 1; - spark->zVel = ((GetRandomControl() & 511) - 256) >> 1; + float f = (frand() * 6) - 3; + spark->xVel = (frand() * 6) - 3; + spark->yVel = (frand() * 6) - 3; + spark->zVel = (frand() * 6) - 3; } spark->friction = 4; @@ -548,9 +550,9 @@ void TriggerGunSmoke(int x, int y, int z, short xv, short yv, short zv, byte ini { spark->flags = 0; } - - spark->gravity = -(GetRandomControl() & 1) - 2; - spark->maxYvel = -(GetRandomControl() & 1) - 2; + float gravity = frand() * 1.25f; + spark->gravity = gravity; + spark->maxYvel = frand() * 16; byte size = ((GetRandomControl() & 0x0F) + 24); // -TriggerGunSmoke_SubFunction(weaponType); @@ -942,9 +944,9 @@ void UpdateGunShells() gs->pos.yRot += gs->speed * ANGLE(1); gs->pos.zRot += ANGLE(23); - gs->pos.xPos += gs->speed * 2 * SIN(gs->dirXrot) >> W2V_SHIFT; + gs->pos.xPos += gs->speed * SIN(gs->dirXrot) >> W2V_SHIFT; gs->pos.yPos += gs->fallspeed; - gs->pos.zPos += gs->speed * 2 * COS(gs->dirXrot) >> W2V_SHIFT; + gs->pos.zPos += gs->speed * COS(gs->dirXrot) >> W2V_SHIFT; FLOOR_INFO* floor = GetFloor(gs->pos.xPos, gs->pos.yPos, gs->pos.zPos, &gs->roomNumber); if (Rooms[gs->roomNumber].flags & ENV_FLAG_WATER @@ -1072,12 +1074,12 @@ void CreateBubble(PHD_VECTOR * pos, short roomNum, int unk1, int unk2, int flags BUBBLE_STRUCT* bubble = &Bubbles[GetFreeBubble()]; bubble->pos = *pos; bubble->roomNumber = roomNum; - bubble->speed = GetRandomControl() + 64; + bubble->speed = frand(); bubble->shade = 0; - int size = 2 * (unk1 + (unk2 & GetRandomControl())); + int size = rand() % 4 + 6; bubble->size = size; bubble->dsize = 16 * size; - bubble->vel = (GetRandomControl() & 0x1F) + 32; + bubble->vel = (frand()*0.8f)+0.2f; bubble->flags = flags; bubble->xVel = xv; bubble->yVel = yv; @@ -1125,24 +1127,24 @@ void UpdateBubbles() if (bubble->size) { - bubble->speed += bubble->vel; + bubble->speed += bubble->vel.to_float(); bubble->yRot += 6; - bubble->pos.y -= bubble->speed >> 8; + bubble->pos.y -= bubble->speed.to_float(); if (bubble->flags & 1) { - bubble->pos.x += bubble->xVel >> 4; - bubble->pos.y += bubble->yVel >> 4; - bubble->pos.z += bubble->zVel >> 4; + bubble->pos.x += bubble->xVel.to_float(); + bubble->pos.y += bubble->yVel.to_float(); + bubble->pos.z += bubble->zVel.to_float(); - bubble->xVel -= (bubble->xVel >> 3); - bubble->yVel -= (bubble->yVel >> 3); - bubble->zVel -= (bubble->zVel >> 3); + bubble->xVel -= (bubble->xVel.to_float()/2.0f); + bubble->yVel -= (bubble->yVel.to_float()/2.0f); + bubble->zVel -= (bubble->zVel.to_float()/2.0f); } else { - bubble->pos.x += SIN(bubble->yRot) >> W2V_SHIFT; - bubble->pos.z += COS(bubble->yRot) >> W2V_SHIFT; + bubble->pos.x += sin(bubble->yRot)*5; + bubble->pos.z += cos(bubble->yRot)*5; } short roomNumber = bubble->roomNumber; @@ -1910,16 +1912,6 @@ void TriggerSmallSplash(int x, int y, int z, int num)// (F) } } -void SetFadeClip(short height, short speed) -{ - /*__int16 result; // ax - - result = a1; - DestFadeScreenHeight = a1; - FadeClipSpeed = a2; - return result;*/ -} - void Inject_Tomb4FX() { INJECT(0x004827E0, TriggerBlood); diff --git a/TR5Main/Global/constants.h b/TR5Main/Global/constants.h index c2e160d6b..522056eed 100644 --- a/TR5Main/Global/constants.h +++ b/TR5Main/Global/constants.h @@ -69,7 +69,7 @@ #define MAX_DRIPS 32 #define MAX_BUBBLES 40 #define MAX_DYNAMICS 64 -#define MAX_SPLASH 4 +constexpr auto MAX_SPLASH = 8; #define MAX_RIPPLES 32 #define MAX_CAMERA 18 #define MAX_SHOCKWAVE 16 diff --git a/TR5Main/Global/math.cpp b/TR5Main/Global/math.cpp index 35fc6dd9f..36ef8d1d3 100644 --- a/TR5Main/Global/math.cpp +++ b/TR5Main/Global/math.cpp @@ -12,3 +12,19 @@ float ANGLEF(short angle) { return TR_ANGLE_TO_DEGREES(angle); } + + +const float frand() { + int randValue = rand(); + float result = randValue / (float)RAND_MAX; + return result; +} + +const float frandMinMax(float min, float max) +{ + return frand()* (max - min) + min; +} + +const float lerp(float v0, float v1, float t) { + return (1 - t) * v0 + t * v1; +} diff --git a/TR5Main/Global/math.h b/TR5Main/Global/math.h index 0ebbef982..ec3afef43 100644 --- a/TR5Main/Global/math.h +++ b/TR5Main/Global/math.h @@ -24,4 +24,10 @@ #define COS(x) (4 * rcossin_tbl[((int(x) >> 3) & 8190) + 1]) short ANGLE(double angle); -float ANGLEF(short angle); \ No newline at end of file +float ANGLEF(short angle); +// returns a float between 0-1 +const float frand(); + +const float frandMinMax(float min, float max); + +const float lerp(float v0, float v1, float t); \ No newline at end of file diff --git a/TR5Main/Global/types.h b/TR5Main/Global/types.h index bd9e58bfc..699e8030c 100644 --- a/TR5Main/Global/types.h +++ b/TR5Main/Global/types.h @@ -2,6 +2,7 @@ #include #include "enums.h" +#include #pragma pack(push, 1) typedef enum TYPE_ZONE { @@ -1012,39 +1013,38 @@ struct BUBBLE_STRUCT { PHD_VECTOR pos; // size=12, offset=0 short roomNumber; // size=0, offset=12 - short speed; // size=0, offset=14 + numeric::Fixed<9, 7> speed; // size=0, offset=14 short size; // size=0, offset=16 short dsize; // size=0, offset=18 unsigned char shade; // size=0, offset=20 - unsigned char vel; // size=0, offset=21 + numeric::Fixed<4, 4> vel; // size=0, offset=21 unsigned char yRot; // size=0, offset=22 byte flags; // size=0, offset=23 - short xVel; // size=0, offset=24 - short yVel; // size=0, offset=26 - short zVel; // size=0, offset=28 + numeric::Fixed<6,2> xVel; // size=0, offset=24 + numeric::Fixed<6, 2> yVel; // size=0, offset=26 + numeric::Fixed<6, 2> zVel; // size=0, offset=28 short pad; // size=0, offset=30 }; struct SPLASH_STRUCT { - int x; // size=0, offset=0 - int y; // size=0, offset=4 - int z; // size=0, offset=8 - short innerRad; // size=0, offset=12 - short innerSize; // size=0, offset=14 - short innerRadVel; // size=0, offset=16 - short innerYVel; // size=0, offset=18 - short innerY; // size=0, offset=20 - short middleRad; // size=0, offset=22 - short middleSize; // size=0, offset=24 - short middleRadVel; // size=0, offset=26 - short middleYVel; // size=0, offset=28 - short middleY; // size=0, offset=30 - short outerRad; // size=0, offset=32 - short outerSize; // size=0, offset=34 - short outerRadVel; // size=0, offset=36 - byte flags; // size=0, offset=38 - unsigned char life; // size=0, offset=39 + float x; + float y; + float z; + float innerRad; + float innerRadVel; + float heightVel; + float heightSpeed; + float height; + float outerRad; + float outerRadVel; + float animationSpeed; + float animationPhase; + short spriteSequenceStart; + short spriteSequenceEnd; + unsigned short life; + bool isRipple; + bool isActive; }; struct DRIP_STRUCT @@ -1077,23 +1077,11 @@ struct RIPPLE_STRUCT struct SPLASH_SETUP { - int x; // size=0, offset=0 - int y; // size=0, offset=4 - int z; // size=0, offset=8 - short innerRad; // size=0, offset=12 - short innerSize; // size=0, offset=14 - short innerRadVel; // size=0, offset=16 - short innerYVel; // size=0, offset=18 - short pad1; // size=0, offset=20 - short middleRad; // size=0, offset=22 - short middleSize; // size=0, offset=24 - short middleRadVel; // size=0, offset=26 - short middleYVel; // size=0, offset=28 - short pad2; // size=0, offset=30 - short outerRad; // size=0, offset=32 - short outerSize; // size=0, offset=34 - short outerRadVel; // size=0, offset=36 - short pad3; // size=0, offset=38 + float x; + float y; + float z; + float splashPower; + float innerRadius; }; struct FIRE_LIST @@ -1146,20 +1134,20 @@ struct SMOKE_SPARKS int x; // size=0, offset=0 int y; // size=0, offset=4 int z; // size=0, offset=8 - short xVel; // size=0, offset=12 - short yVel; // size=0, offset=14 - short zVel; // size=0, offset=16 - short gravity; // size=0, offset=18 + numeric::Fixed<12 ,4> xVel; // size=0, offset=12 + numeric::Fixed<12, 4> yVel; // size=0, offset=14 + numeric::Fixed<12, 4> zVel; // size=0, offset=16 + numeric::Fixed<8, 8> gravity; // size=0, offset=18 short rotAng; // size=0, offset=20 short flags; // size=0, offset=22 byte sSize; // size=0, offset=24 byte dSize; // size=0, offset=25 byte size; // size=0, offset=26 - byte friction; // size=0, offset=27 + numeric::Fixed<2,6> friction; // size=0, offset=27 byte scalar; // size=0, offset=28 byte def; // size=0, offset=29 byte rotAdd; // size=0, offset=30 - byte maxYvel; // size=0, offset=31 + numeric::Fixed<4, 4> maxYvel; // size=0, offset=31 byte on; // size=0, offset=32 byte sShade; // size=0, offset=33 byte dShade; // size=0, offset=34 diff --git a/TR5Main/Libs/fixedpoint/fixed_point.h b/TR5Main/Libs/fixedpoint/fixed_point.h new file mode 100644 index 000000000..d3c348da4 --- /dev/null +++ b/TR5Main/Libs/fixedpoint/fixed_point.h @@ -0,0 +1,574 @@ +// From: https://github.com/eteran/cpp-utilities/blob/master/fixed/include/eteran/cpp-utilities/Fixed.h +// See also: http://stackoverflow.com/questions/79677/whats-the-best-way-to-do-fixed-point-math +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Evan Teran + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef FIXED_H_ +#define FIXED_H_ + +#if __cplusplus >= 201402L +#define CONSTEXPR14 constexpr +#else +#define CONSTEXPR14 +#endif + + +#include +#include +#include // for size_t +#include +#include + +namespace numeric { + + template + class Fixed; + + namespace detail { + + // helper templates to make magic with types :) + // these allow us to determine resonable types from + // a desired size, they also let us infer the next largest type + // from a type which is nice for the division op + template + struct type_from_size { + static constexpr bool is_specialized = false; + }; + +#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__) + template <> + struct type_from_size<128> { + static constexpr bool is_specialized = true; + static constexpr size_t size = 128; + + using value_type = __int128; + using unsigned_type = unsigned __int128; + using signed_type = __int128; + using next_size = type_from_size<256>; + }; +#endif + + template <> + struct type_from_size<64> { + static constexpr bool is_specialized = true; + static constexpr size_t size = 64; + + using value_type = int64_t; + using unsigned_type = std::make_unsigned::type; + using signed_type = std::make_signed::type; + using next_size = type_from_size<128>; + }; + + template <> + struct type_from_size<32> { + static constexpr bool is_specialized = true; + static constexpr size_t size = 32; + + using value_type = int32_t; + using unsigned_type = std::make_unsigned::type; + using signed_type = std::make_signed::type; + using next_size = type_from_size<64>; + }; + + template <> + struct type_from_size<16> { + static constexpr bool is_specialized = true; + static constexpr size_t size = 16; + + using value_type = int16_t; + using unsigned_type = std::make_unsigned::type; + using signed_type = std::make_signed::type; + using next_size = type_from_size<32>; + }; + + template <> + struct type_from_size<8> { + static constexpr bool is_specialized = true; + static constexpr size_t size = 8; + + using value_type = int8_t; + using unsigned_type = std::make_unsigned::type; + using signed_type = std::make_signed::type; + using next_size = type_from_size<16>; + }; + + // this is to assist in adding support for non-native base + // types (for adding big-int support), this should be fine + // unless your bit-int class doesn't nicely support casting + template + constexpr B next_to_base(N rhs) { + return static_cast(rhs); + } + + struct divide_by_zero : std::exception { + }; + + template + CONSTEXPR14 Fixed divide(Fixed numerator, Fixed denominator, Fixed& remainder, typename std::enable_if::next_size::is_specialized>::type * = nullptr) { + + using next_type = typename Fixed::next_type; + using base_type = typename Fixed::base_type; + constexpr size_t fractional_bits = Fixed::fractional_bits; + + next_type t(numerator.to_raw()); + t <<= fractional_bits; + + Fixed quotient; + + quotient = Fixed::from_base(next_to_base(t / denominator.to_raw())); + remainder = Fixed::from_base(next_to_base(t % denominator.to_raw())); + + return quotient; + } + + template + CONSTEXPR14 Fixed divide(Fixed numerator, Fixed denominator, Fixed & remainder, typename std::enable_if::next_size::is_specialized>::type * = nullptr) { + + // NOTE(eteran): division is broken for large types :-( + // especially when dealing with negative quantities + + using base_type = typename Fixed::base_type; + using unsigned_type = typename Fixed::unsigned_type; + + constexpr int bits = Fixed::total_bits; + + if (denominator == 0) { + throw divide_by_zero(); + } + else { + + int sign = 0; + + Fixed quotient; + + if (numerator < 0) { + sign ^= 1; + numerator = -numerator; + } + + if (denominator < 0) { + sign ^= 1; + denominator = -denominator; + } + + base_type n = numerator.to_raw(); + base_type d = denominator.to_raw(); + base_type x = 1; + base_type answer = 0; + + // egyptian division algorithm + while ((n >= d) && (((d >> (bits - 1)) & 1) == 0)) { + x <<= 1; + d <<= 1; + } + + while (x != 0) { + if (n >= d) { + n -= d; + answer += x; + } + + x >>= 1; + d >>= 1; + } + + unsigned_type l1 = n; + unsigned_type l2 = denominator.to_raw(); + + // calculate the lower bits (needs to be unsigned) + // unfortunately for many fractions this overflows the type still :-/ + const unsigned_type lo = (static_cast(n) << F) / denominator.to_raw(); + + quotient = Fixed::from_base((answer << F) | lo); + remainder = n; + + if (sign) { + quotient = -quotient; + } + + return quotient; + } + } + + // this is the usual implementation of multiplication + template + CONSTEXPR14 Fixed multiply(Fixed lhs, Fixed rhs, typename std::enable_if::next_size::is_specialized>::type * = nullptr) { + + using next_type = typename Fixed::next_type; + using base_type = typename Fixed::base_type; + + constexpr size_t fractional_bits = Fixed::fractional_bits; + + next_type t(static_cast(lhs.to_raw()) * static_cast(rhs.to_raw())); + t >>= fractional_bits; + + return Fixed::from_base(next_to_base(t)); + } + + // this is the fall back version we use when we don't have a next size + // it is slightly slower, but is more robust since it doesn't + // require and upgraded type + template + CONSTEXPR14 Fixed multiply(Fixed lhs, Fixed rhs, typename std::enable_if::next_size::is_specialized>::type * = nullptr) { + + using base_type = typename Fixed::base_type; + + constexpr size_t fractional_bits = Fixed::fractional_bits; + constexpr base_type integer_mask = Fixed::integer_mask; + constexpr base_type fractional_mask = Fixed::fractional_mask; + + // more costly but doesn't need a larger type + constexpr base_type a_hi = (lhs.to_raw() & integer_mask) >> fractional_bits; + constexpr base_type b_hi = (rhs.to_raw() & integer_mask) >> fractional_bits; + constexpr base_type a_lo = (lhs.to_raw() & fractional_mask); + constexpr base_type b_lo = (rhs.to_raw() & fractional_mask); + + constexpr base_type x1 = a_hi * b_hi; + constexpr base_type x2 = a_hi * b_lo; + constexpr base_type x3 = a_lo * b_hi; + constexpr base_type x4 = a_lo * b_lo; + + return Fixed::from_base((x1 << fractional_bits) + (x3 + x2) + (x4 >> fractional_bits)); + } + } + + template + class Fixed { + static_assert(detail::type_from_size::is_specialized, "invalid combination of sizes"); + + public: + static constexpr size_t fractional_bits = F; + static constexpr size_t integer_bits = I; + static constexpr size_t total_bits = I + F; + + using base_type_info = detail::type_from_size; + + using base_type = typename base_type_info::value_type; + using next_type = typename base_type_info::next_size::value_type; + using unsigned_type = typename base_type_info::unsigned_type; + + public: +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverflow" +#endif + static constexpr base_type fractional_mask = ~(static_cast(~base_type(0)) << fractional_bits); + static constexpr base_type integer_mask = ~fractional_mask; +#ifdef __GNUC__ +#pragma GCC diagnostic push +#endif + + public: + static constexpr base_type one = base_type(1) << fractional_bits; + + public: // constructors + Fixed() = default; + Fixed(const Fixed&) = default; + Fixed & operator=(const Fixed&) = default; + + template + constexpr Fixed(Number n, typename std::enable_if::value>::type * = nullptr) : data_(static_cast(n * one)) { + } + + public: // conversion + template + CONSTEXPR14 explicit Fixed(Fixed other) { + static_assert(I2 <= I && F2 <= F, "Scaling conversion can only upgrade types"); + using T = Fixed; + + const base_type fractional = (other.data_ & T::fractional_mask); + const base_type integer = (other.data_ & T::integer_mask) >> T::fractional_bits; + data_ = (integer << fractional_bits) | (fractional << (fractional_bits - T::fractional_bits)); + } + + private: + // this makes it simpler to create a fixed point object from + // a native type without scaling + // use "Fixed::from_base" in order to perform this. + struct NoScale {}; + + constexpr Fixed(base_type n, const NoScale&) : data_(n) { + } + + public: + constexpr static Fixed from_base(base_type n) { + return Fixed(n, NoScale()); + } + + public: // comparison operators + constexpr bool operator==(Fixed rhs) const { + return data_ == rhs.data_; + } + + constexpr bool operator!=(Fixed rhs) const { + return data_ != rhs.data_; + } + + constexpr bool operator<(Fixed rhs) const { + return data_ < rhs.data_; + } + + constexpr bool operator>(Fixed rhs) const { + return data_ > rhs.data_; + } + + constexpr bool operator<=(Fixed rhs) const { + return data_ <= rhs.data_; + } + + constexpr bool operator>=(Fixed rhs) const { + return data_ >= rhs.data_; + } + + public: // unary operators + constexpr bool operator!() const { + return !data_; + } + + constexpr Fixed operator~() const { + // NOTE(eteran): this will often appear to "just negate" the value + // that is not an error, it is because -x == (~x+1) + // and that "+1" is adding an infinitesimally small fraction to the + // complimented value + return Fixed::from_base(~data_); + } + + constexpr Fixed operator-() const { + return Fixed::from_base(-data_); + } + + constexpr Fixed operator+() const { + return Fixed::from_base(+data_); + } + + CONSTEXPR14 Fixed& operator++() { + data_ += one; + return *this; + } + + CONSTEXPR14 Fixed& operator--() { + data_ -= one; + return *this; + } + + CONSTEXPR14 Fixed operator++(int) { + Fixed tmp(*this); + data_ += one; + return tmp; + } + + CONSTEXPR14 Fixed operator--(int) { + Fixed tmp(*this); + data_ -= one; + return tmp; + } + + public: // basic math operators + CONSTEXPR14 Fixed& operator+=(Fixed n) { + data_ += n.data_; + return *this; + } + + CONSTEXPR14 Fixed& operator-=(Fixed n) { + data_ -= n.data_; + return *this; + } + + CONSTEXPR14 Fixed& operator*=(Fixed n) { + return assign(detail::multiply(*this, n)); + } + + CONSTEXPR14 Fixed& operator/=(Fixed n) { + Fixed temp; + return assign(detail::divide(*this, n, temp)); + } + + private: + CONSTEXPR14 Fixed& assign(Fixed rhs) { + data_ = rhs.data_; + return *this; + } + + public: // binary math operators, effects underlying bit pattern since these + // don't really typically make sense for non-integer values + CONSTEXPR14 Fixed& operator&=(Fixed n) { + data_ &= n.data_; + return *this; + } + + CONSTEXPR14 Fixed& operator|=(Fixed n) { + data_ |= n.data_; + return *this; + } + + CONSTEXPR14 Fixed& operator^=(Fixed n) { + data_ ^= n.data_; + return *this; + } + + template ::value>::type> + CONSTEXPR14 Fixed & operator>>=(Integer n) { + data_ >>= n; + return *this; + } + + template ::value>::type> + CONSTEXPR14 Fixed & operator<<=(Integer n) { + data_ <<= n; + return *this; + } + + public: // conversion to basic types + constexpr int to_int() const { + return (data_ & integer_mask) >> fractional_bits; + } + + constexpr unsigned int to_uint() const { + return (data_ & integer_mask) >> fractional_bits; + } + + constexpr float to_float() const { + return static_cast(data_) / Fixed::one; + } + + constexpr double to_double() const { + return static_cast(data_) / Fixed::one; + } + + constexpr base_type to_raw() const { + return data_; + } + + public: + CONSTEXPR14 void swap(Fixed & rhs) { + using std::swap; + swap(data_, rhs.data_); + } + + public: + base_type data_ = 0; + }; + + // if we have the same fractional portion, but differing integer portions, we trivially upgrade the smaller type + template + CONSTEXPR14 typename std::conditional= I2, Fixed, Fixed>::type operator+(Fixed lhs, Fixed rhs) { + + using T = typename std::conditional< + I1 >= I2, + Fixed, + Fixed + >::type; + + const T l = T::from_base(lhs.to_raw()); + const T r = T::from_base(rhs.to_raw()); + return l + r; + } + + template + CONSTEXPR14 typename std::conditional= I2, Fixed, Fixed>::type operator-(Fixed lhs, Fixed rhs) { + + using T = typename std::conditional< + I1 >= I2, + Fixed, + Fixed + >::type; + + const T l = T::from_base(lhs.to_raw()); + const T r = T::from_base(rhs.to_raw()); + return l - r; + } + + template + CONSTEXPR14 typename std::conditional= I2, Fixed, Fixed>::type operator*(Fixed lhs, Fixed rhs) { + + using T = typename std::conditional< + I1 >= I2, + Fixed, + Fixed + >::type; + + const T l = T::from_base(lhs.to_raw()); + const T r = T::from_base(rhs.to_raw()); + return l * r; + } + + template + CONSTEXPR14 typename std::conditional= I2, Fixed, Fixed>::type operator/(Fixed lhs, Fixed rhs) { + + using T = typename std::conditional< + I1 >= I2, + Fixed, + Fixed + >::type; + + const T l = T::from_base(lhs.to_raw()); + const T r = T::from_base(rhs.to_raw()); + return l / r; + } + + template + std::ostream& operator<<(std::ostream & os, Fixed f) { + os << f.to_double(); + return os; + } + + // basic math operators + template CONSTEXPR14 Fixed operator+(Fixed lhs, Fixed rhs) { lhs += rhs; return lhs; } + template CONSTEXPR14 Fixed operator-(Fixed lhs, Fixed rhs) { lhs -= rhs; return lhs; } + template CONSTEXPR14 Fixed operator*(Fixed lhs, Fixed rhs) { lhs *= rhs; return lhs; } + template CONSTEXPR14 Fixed operator/(Fixed lhs, Fixed rhs) { lhs /= rhs; return lhs; } + + template ::value>::type> CONSTEXPR14 Fixed operator+(Fixed lhs, Number rhs) { lhs += Fixed(rhs); return lhs; } + template ::value>::type> CONSTEXPR14 Fixed operator-(Fixed lhs, Number rhs) { lhs -= Fixed(rhs); return lhs; } + template ::value>::type> CONSTEXPR14 Fixed operator*(Fixed lhs, Number rhs) { lhs *= Fixed(rhs); return lhs; } + template ::value>::type> CONSTEXPR14 Fixed operator/(Fixed lhs, Number rhs) { lhs /= Fixed(rhs); return lhs; } + + template ::value>::type> CONSTEXPR14 Fixed operator+(Number lhs, Fixed rhs) { Fixed tmp(lhs); tmp += rhs; return tmp; } + template ::value>::type> CONSTEXPR14 Fixed operator-(Number lhs, Fixed rhs) { Fixed tmp(lhs); tmp -= rhs; return tmp; } + template ::value>::type> CONSTEXPR14 Fixed operator*(Number lhs, Fixed rhs) { Fixed tmp(lhs); tmp *= rhs; return tmp; } + template ::value>::type> CONSTEXPR14 Fixed operator/(Number lhs, Fixed rhs) { Fixed tmp(lhs); tmp /= rhs; return tmp; } + + // shift operators + template ::value>::type> CONSTEXPR14 Fixed operator<<(Fixed lhs, Integer rhs) { lhs <<= rhs; return lhs; } + template ::value>::type> CONSTEXPR14 Fixed operator>>(Fixed lhs, Integer rhs) { lhs >>= rhs; return lhs; } + + // comparison operators + template ::value>::type> constexpr bool operator>(Fixed lhs, Number rhs) { return lhs > Fixed(rhs); } + template ::value>::type> constexpr bool operator<(Fixed lhs, Number rhs) { return lhs < Fixed(rhs); } + template ::value>::type> constexpr bool operator>=(Fixed lhs, Number rhs) { return lhs >= Fixed(rhs); } + template ::value>::type> constexpr bool operator<=(Fixed lhs, Number rhs) { return lhs <= Fixed(rhs); } + template ::value>::type> constexpr bool operator==(Fixed lhs, Number rhs) { return lhs == Fixed(rhs); } + template ::value>::type> constexpr bool operator!=(Fixed lhs, Number rhs) { return lhs != Fixed(rhs); } + + template ::value>::type> constexpr bool operator>(Number lhs, Fixed rhs) { return Fixed(lhs) > rhs; } + template ::value>::type> constexpr bool operator<(Number lhs, Fixed rhs) { return Fixed(lhs) < rhs; } + template ::value>::type> constexpr bool operator>=(Number lhs, Fixed rhs) { return Fixed(lhs) >= rhs; } + template ::value>::type> constexpr bool operator<=(Number lhs, Fixed rhs) { return Fixed(lhs) <= rhs; } + template ::value>::type> constexpr bool operator==(Number lhs, Fixed rhs) { return Fixed(lhs) == rhs; } + template ::value>::type> constexpr bool operator!=(Number lhs, Fixed rhs) { return Fixed(lhs) != rhs; } +} + +#undef CONSTEXPR14 + +#endif \ No newline at end of file diff --git a/TR5Main/Objects/Vehicles/quad.cpp b/TR5Main/Objects/Vehicles/quad.cpp index cdce24228..0881891e4 100644 --- a/TR5Main/Objects/Vehicles/quad.cpp +++ b/TR5Main/Objects/Vehicles/quad.cpp @@ -922,7 +922,7 @@ void AnimateQuadBike(ITEM_INFO* item, int collide, int dead) break; } - if (Rooms[item->roomNumber].flags & ENV_FLAG_WATER) + if (Rooms[item->roomNumber].flags & (ENV_FLAG_WATER | ENV_FLAG_SWAMP)) { LaraItem->goalAnimState = QUAD_STATE_FALLOFF; LaraItem->hitPoints = 0; diff --git a/TR5Main/Renderer/Renderer11.cpp b/TR5Main/Renderer/Renderer11.cpp index 619156790..2798c701b 100644 --- a/TR5Main/Renderer/Renderer11.cpp +++ b/TR5Main/Renderer/Renderer11.cpp @@ -2706,15 +2706,19 @@ void Renderer11::DrawDashBar() void Renderer11::DrawHealthBar(int percentual) { - int color2 = 0xA00000; + int color2; if (Lara.poisoned || Lara.gassed) color2 = 0xA0A000; + else + color2 = 0xA00000; drawBar(20, 32, 150, 12, percentual, 0xA00000, color2); } void Renderer11::DrawAirBar(int percentual) { - drawBar(20, 10, 150, 12, percentual, 0x0000A0, 0x0050A0); + /* Draw the air bar only if lara is not one a swamp room */ + if (!(Rooms[LaraItem->roomNumber].flags & ENV_FLAG_SWAMP)) + drawBar(20, 10, 150, 12, percentual, 0x0000A0, 0x0050A0); } void Renderer11::ClearDynamicLights() @@ -4916,104 +4920,51 @@ void Renderer11::drawBubbles() void Renderer11::drawSplahes() { + constexpr size_t NUM_POINTS = 12; for (int i = 0; i < MAX_SPLASH; i++) { - SPLASH_STRUCT* splash = &Splashes[i]; - if (splash->flags & 1) + SPLASH_STRUCT& splash = Splashes[i]; + if (splash.isActive) { - byte color = (splash->life >= 32 ? 255 : splash->life << 5); - - // Inner circle - float angle = PI / 16.0f; - float c = cos(angle); - float s = sin(angle); - float dx = splash->innerRad * c; - float dz = splash->innerRad * s; - float x1 = splash->x + dx; - float z1 = splash->z + dz; - angle -= PI / 4.0f; - - for (int j = 0; j < 8; j++) - { - c = cos(angle); - s = sin(angle); - dx = splash->innerRad * c; - dz = splash->innerRad * s; - float x2 = splash->x + dx; - float z2 = splash->z + dz; - angle -= PI / 4.0f; - - addSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_SPLASH1], - x1, splash->y + splash->innerY, z1, - x2, splash->y + splash->innerY, z2, - x2, splash->y, z2, - x1, splash->y, z1, - color, color, color, 0, 1, 0, 0, BLENDMODE_ALPHABLEND); - - x1 = x2; - z1 = z2; + constexpr float alpha = 360 / NUM_POINTS; + byte color = (splash.life >= 32 ? 255 : (byte)((splash.life / 32.0f) * 255)); + if (!splash.isRipple) { + if (splash.heightSpeed < 0 && splash.height < 1024) { + float multiplier = splash.height / 1024.0f; + color = (float)color*multiplier; + } } - - // Medium circle - angle = PI / 16.0f; - c = cos(angle); - s = sin(angle); - dx = splash->middleRad * c; - dz = splash->middleRad * s; - x1 = splash->x + dx; - z1 = splash->z + dz; - angle -= PI / 4.0f; - - for (int j = 0; j < 8; j++) - { - c = cos(angle); - s = sin(angle); - dx = splash->middleRad * c; - dz = splash->middleRad * s; - float x2 = splash->x + dx; - float z2 = splash->z + dz; - angle -= PI / 4.0f; - - addSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_SPLASH], - x1, splash->y + splash->middleY, z1, - x2, splash->y + splash->middleY, z2, - x2, splash->y, z2, - x1, splash->y, z1, - color, color, color, 0, 1, 0, 0, BLENDMODE_ALPHABLEND); - - x1 = x2; - z1 = z2; - } - - // Large circle - angle = PI / 16.0f; - c = cos(angle); - s = sin(angle); - dx = splash->outerRad * c; - dz = splash->outerRad * s; - x1 = splash->x + dx; - z1 = splash->z + dz; - angle -= PI / 4.0f; - - for (int j = 0; j < 8; j++) - { - c = cos(angle); - s = sin(angle); - dx = splash->outerRad * c; - dz = splash->outerRad * s; - float x2 = splash->x + dx; - float z2 = splash->z + dz; - angle -= PI / 4.0f; - - addSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_SPLASH], - x1, splash->y - splash->outerSize, z1, - x2, splash->y - splash->outerSize, z2, - x2, splash->y, z2, - x1, splash->y, z1, - color, color, color, 0, 1, 0, 0, BLENDMODE_ALPHABLEND); - - x1 = x2; - z1 = z2; + float innerRadius = splash.innerRad; + float outerRadius = splash.outerRad; + float xInner; + float zInner; + float xOuter; + float zOuter; + float x2Inner; + float z2Inner; + float x2Outer; + float z2Outer; + float yInner = splash.y; + float yOuter = splash.y - splash.height; + for (int i = 0; i < NUM_POINTS; i++) { + xInner = innerRadius * sin(alpha * i * PI / 180); + zInner = innerRadius * cos(alpha * i * PI / 180); + xOuter = outerRadius * sin(alpha * i * PI / 180); + zOuter = outerRadius * cos(alpha * i * PI / 180); + xInner += splash.x; + zInner += splash.z; + xOuter += splash.x; + zOuter += splash.z; + int j = (i + 1) % NUM_POINTS; + x2Inner = innerRadius * sin(alpha * j * PI / 180); + x2Inner += splash.x; + z2Inner = innerRadius * cos(alpha * j * PI / 180); + z2Inner += splash.z; + x2Outer = outerRadius * sin(alpha * j * PI / 180); + x2Outer += splash.x; + z2Outer = outerRadius * cos(alpha * j * PI / 180); + z2Outer += splash.z; + addSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + splash.spriteSequenceStart + (int)splash.animationPhase], xOuter, yOuter, zOuter, x2Outer, yOuter, z2Outer, x2Inner, yInner, z2Inner, xInner, yInner, zInner, color, color, color, 0, 1, 0, 0, BLENDMODE_ALPHABLEND); } } } @@ -7006,7 +6957,7 @@ void Renderer11::drawUnderwaterDust() dust->Life++; byte color = (dust->Life > 16 ? 32 - dust->Life : dust->Life) * 4; - addSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], dust->X, dust->Y, dust->Z, color, color, color, 0.0f, 1.0f, UNDERWATER_DUST_PARTICLES_SIZE, UNDERWATER_DUST_PARTICLES_SIZE, BLENDMODE_ALPHABLEND); + addSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], dust->X, dust->Y, dust->Z, color, color, color, 0.0f, 1.0f, 12, 12, BLENDMODE_ALPHABLEND); if (dust->Life >= 32) dust->Reset = true; diff --git a/TR5Main/TR5Main.vcxproj b/TR5Main/TR5Main.vcxproj index ae9c7c154..0c03af442 100644 --- a/TR5Main/TR5Main.vcxproj +++ b/TR5Main/TR5Main.vcxproj @@ -65,9 +65,11 @@ true _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;TR5MAIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) false - $(SolutionDir)TR5Main\Libs\sol2;%(AdditionalIncludeDirectories) + $(SolutionDir)TR5Main\Libs\fixedpoint;$(SolutionDir)TR5Main\Libs\sol2;%(AdditionalIncludeDirectories) MultiThreadedDebugDLL false + true + false Windows @@ -94,7 +96,8 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts" true _CRT_SECURE_NO_WARNINGS;WIN32;_RELEASE;TR5MAIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true - %(AdditionalIncludeDirectories) + $(SolutionDir)TR5Main\Libs\fixedpoint;$(SolutionDir)TR5Main\Libs\sol2;%(AdditionalIncludeDirectories) + true Windows @@ -115,6 +118,7 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts" + diff --git a/TR5Main/TR5Main.vcxproj.filters b/TR5Main/TR5Main.vcxproj.filters index a319b54b9..5e11ee631 100644 --- a/TR5Main/TR5Main.vcxproj.filters +++ b/TR5Main/TR5Main.vcxproj.filters @@ -300,6 +300,9 @@ File di intestazione + + File di intestazione +