diff --git a/Content/Metadata/UI/HUD.res b/Content/Metadata/UI/HUD.res index fbb75a61..c30a6964 100644 --- a/Content/Metadata/UI/HUD.res +++ b/Content/Metadata/UI/HUD.res @@ -146,6 +146,10 @@ "Path": "Pickup/food_pizza.aura", "States": [ 73 ] }, + "PickupCarrot": { + "Path": "Pickup/carrot_full.aura", + "States": [ 74 ] + }, "BossHealthBar": { "Path": "UI/boss_health_bar.aura", diff --git a/Sources/Jazz2/Actors/Enemies/Dragon.cpp b/Sources/Jazz2/Actors/Enemies/Dragon.cpp index 791d425f..6179a788 100644 --- a/Sources/Jazz2/Actors/Enemies/Dragon.cpp +++ b/Sources/Jazz2/Actors/Enemies/Dragon.cpp @@ -130,7 +130,7 @@ namespace Jazz2::Actors::Enemies { SetState(ActorState::IsInvulnerable, true); SetState(ActorState::CanBeFrozen | ActorState::ApplyGravitation, false); - // Collide with player ammo if Reforged Mode is enabled + // Collide with player ammo if Reforged CanCollideWithAmmo = _levelHandler->IsReforged(); SetFacingLeft(details.Params[0] != 0); diff --git a/Sources/Jazz2/Actors/Player.cpp b/Sources/Jazz2/Actors/Player.cpp index 49a5e7e8..1be006ee 100644 --- a/Sources/Jazz2/Actors/Player.cpp +++ b/Sources/Jazz2/Actors/Player.cpp @@ -60,7 +60,7 @@ namespace Jazz2::Actors _inIdleTransition(false), _inLedgeTransition(false), _carryingObject(nullptr), _canDoubleJump(true), - _lives(0), _coins(0), _coinsCheckpoint(0), _foodEaten(0), _score(0), + _lives(0), _coins(0), _coinsCheckpoint(0), _foodEaten(0), _foodEatenCheckpoint(0), _score(0), _checkpointLight(1.0f), _sugarRushLeft(0.0f), _sugarRushStarsTime(0.0f), _shieldSpawnTime(ShieldDisabled), @@ -277,6 +277,9 @@ namespace Jazz2::Actors int areaWaterBlock = -1; OnHandleAreaEvents(timeMult, areaWeaponAllowed, areaWaterBlock); + // Force collisions every frame even if player doesn't move + SetState(ActorState::IsDirty, true); + // Invulnerability if (_invulnerableTime > 0.0f) { _invulnerableTime -= timeMult; @@ -613,7 +616,7 @@ namespace Jazz2::Actors if (_dizzyTime > 0.0f || _playerType == PlayerType::Frog) { _speed.X = std::clamp(_speed.X + acceleration * timeMult * (IsFacingLeft() ? -1 : 1), -MaxDizzySpeed * playerMovementVelocity, MaxDizzySpeed * playerMovementVelocity); } else if (_inShallowWater != -1 && _levelHandler->IsReforged() && _playerType != PlayerType::Lori) { - // Use lower speed in shallow water if Reforged Mode is enabled + // Use lower speed in shallow water if Reforged // Also, exclude Lori, because she can't ledge climb or double jump (rescue/01_colon1) _speed.X = std::clamp(_speed.X + acceleration * timeMult * (IsFacingLeft() ? -1 : 1), -MaxShallowWaterSpeed * playerMovementVelocity, MaxShallowWaterSpeed * playerMovementVelocity); } else { @@ -2437,6 +2440,11 @@ namespace Jazz2::Actors _lives--; } + // Revert food eaten only if Reforged + if (_levelHandler->IsReforged()) { + _foodEaten = _foodEatenCheckpoint; + } + // Revert coins, gems, ammo and weapon upgrades _coins = _coinsCheckpoint; _gems = _gemsCheckpoint; @@ -3009,6 +3017,7 @@ namespace Jazz2::Actors _lives = (std::int32_t)carryOver.Lives; _score = carryOver.Score; _foodEaten = (std::int32_t)carryOver.FoodEaten; + _foodEatenCheckpoint = _foodEaten; _currentWeapon = carryOver.CurrentWeapon; std::memcpy(_weaponAmmo, carryOver.Ammo, sizeof(_weaponAmmo)); @@ -3080,6 +3089,7 @@ namespace Jazz2::Actors _coins = src.ReadVariableInt32(); _coinsCheckpoint = _coins; _foodEaten = src.ReadVariableInt32(); + _foodEatenCheckpoint = _foodEaten; _score = src.ReadVariableInt32(); _gems = src.ReadVariableInt32(); _gemsCheckpoint = _gems; @@ -3111,7 +3121,7 @@ namespace Jazz2::Actors dest.WriteValue(_checkpointLight); dest.WriteVariableInt32(_lives); dest.WriteVariableInt32(_coinsCheckpoint); - dest.WriteVariableInt32(_foodEaten); + dest.WriteVariableInt32(_foodEatenCheckpoint); dest.WriteVariableInt32(_score); dest.WriteVariableInt32(_gemsCheckpoint); dest.WriteVariableInt32(countof(_weaponAmmoCheckpoint)); @@ -3803,6 +3813,7 @@ namespace Jazz2::Actors _checkpointPos = Vector2f(pos.X, pos.Y - 20.0f); _checkpointLight = ambientLight; + _foodEatenCheckpoint = _foodEaten; _coinsCheckpoint = _coins; _gemsCheckpoint = _gems; diff --git a/Sources/Jazz2/Actors/Player.h b/Sources/Jazz2/Actors/Player.h index 55255d1d..74cccfd4 100644 --- a/Sources/Jazz2/Actors/Player.h +++ b/Sources/Jazz2/Actors/Player.h @@ -224,7 +224,7 @@ namespace Jazz2::Actors float _springCooldown; std::shared_ptr _copterSound; - std::int32_t _lives, _coins, _coinsCheckpoint, _foodEaten, _score; + std::int32_t _lives, _coins, _coinsCheckpoint, _foodEaten, _foodEatenCheckpoint, _score; Vector2f _checkpointPos; float _checkpointLight; diff --git a/Sources/Jazz2/UI/HUD.cpp b/Sources/Jazz2/UI/HUD.cpp index e58de801..d687719b 100644 --- a/Sources/Jazz2/UI/HUD.cpp +++ b/Sources/Jazz2/UI/HUD.cpp @@ -59,6 +59,7 @@ namespace Jazz2::UI static constexpr AnimState PickupGem = (AnimState)71; static constexpr AnimState PickupCoin = (AnimState)72; static constexpr AnimState PickupFood = (AnimState)73; + static constexpr AnimState PickupCarrot = (AnimState)74; static constexpr AnimState BossHealthBar = (AnimState)74; static constexpr AnimState WeaponWheel = (AnimState)80; static constexpr AnimState WeaponWheelInner = (AnimState)81; @@ -463,19 +464,9 @@ namespace Jazz2::UI std::int32_t charOffsetShadow = 0; if (PreferencesCache::EnableReforgedHUD) { - for (std::int32_t i = 0; i < player->_health; i++) { - stringBuffer[i] = '|'; - } - stringBuffer[player->_health] = '\0'; - if (player->_lives > 0) { if (shouldDrawHealth) { - _smallFont->DrawString(this, stringBuffer, charOffsetShadow, adjustedView.X + 36.0f - 3.0f - 0.5f, bottom - 17.0f + 0.5f, FontShadowLayer, - Alignment::BottomLeft, Colorf(0.0f, 0.0f, 0.0f, 0.42f), 0.7f, 0.0f, 0.0f, 0.0f, 0.0f, 1.1f); - _smallFont->DrawString(this, stringBuffer, charOffsetShadow, adjustedView.X + 36.0f - 3.0f + 0.5f, bottom - 17.0f - 0.5f, FontShadowLayer, - Alignment::BottomLeft, Colorf(0.0f, 0.0f, 0.0f, 0.42f), 0.7f, 0.0f, 0.0f, 0.0f, 0.0f, 1.1f); - _smallFont->DrawString(this, stringBuffer, charOffset, adjustedView.X + 36.0f - 3.0f, bottom - 17.0f, FontLayer, - Alignment::BottomLeft, Font::RandomColor, 0.7f, 0.0f, 0.0f, 0.0f, 0.0f, 1.1f); + DrawHealthCarrots(adjustedView.X + 24.0f, bottom - 30.0f, player->_health); } if (shouldDrawLives) { @@ -496,12 +487,7 @@ namespace Jazz2::UI } } else { if (shouldDrawHealth) { - _smallFont->DrawString(this, stringBuffer, charOffsetShadow, adjustedView.X + 36.0f - 3.0f - 0.5f, bottom - 4.0f + 0.5f, FontShadowLayer, - Alignment::BottomLeft, Colorf(0.0f, 0.0f, 0.0f, 0.42f), 0.7f, 0.0f, 0.0f, 0.0f, 0.0f, 1.1f); - _smallFont->DrawString(this, stringBuffer, charOffsetShadow, adjustedView.X + 36.0f - 3.0f + 0.5f, bottom - 4.0f - 0.5f, FontShadowLayer, - Alignment::BottomLeft, Colorf(0.0f, 0.0f, 0.0f, 0.42f), 0.7f, 0.0f, 0.0f, 0.0f, 0.0f, 1.1f); - _smallFont->DrawString(this, stringBuffer, charOffset, adjustedView.X + 36.0f - 3.0f, bottom - 4.0f, FontLayer, - Alignment::BottomLeft, Font::RandomColor, 0.7f, 0.0f, 0.0f, 0.0f, 0.0f, 1.1f); + DrawHealthCarrots(adjustedView.X + 24.0f, bottom - 20.0f, player->_health); } } } else { @@ -531,6 +517,80 @@ namespace Jazz2::UI } } + void HUD::DrawHealthCarrots(float x, float y, std::int32_t health) + { + constexpr Colorf CarrotShadowColor = Colorf(0.0f, 0.0f, 0.0f, 0.5f); + + std::int32_t lastCarrotIdx = 0; + float lastCarrotOffset = 0.0f; + float scale = 0.5f; + float angleBase1 = sinf(AnimTime * 10.0f) * fDegToRad; + float angleBase2 = sinf(AnimTime * 12.0f + 3.0f) * fDegToRad; + float angleBase3 = sinf(AnimTime * 11.0f + 7.0f) * fDegToRad; + + // Limit frame rate of carrot movement + angleBase1 = std::round(angleBase1 * 3.0f * fRadToDeg) / (3.0f * RadToDeg); + angleBase2 = std::round(angleBase2 * 3.0f * fRadToDeg) / (3.0f * RadToDeg); + angleBase3 = std::round(angleBase3 * 3.0f * fRadToDeg) / (3.0f * RadToDeg); + + if (health >= 1) { + float angle = angleBase1 * (health > 1 ? -6.0f : -14.0f) + 0.2f; + DrawElement(PickupCarrot, 1, x + 1.0f - 1.0f, y + 2.0f + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 1, x + 1.0f + 1.0f, y + 2.0f + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 1, x + 1.0f, y + 2.0f, FontLayer + lastCarrotIdx * 2 + 1, Alignment::Left, Colorf::White, scale, scale, false, angle); + lastCarrotIdx++; + lastCarrotOffset = 7.0f; + } + if (health >= 3) { + float angle = angleBase3 * 10.0f; + lastCarrotOffset -= 1.0f; + DrawElement(PickupCarrot, 2, x + lastCarrotOffset - 1.0f, y + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 2, x + lastCarrotOffset + 1.0f, y + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 2, x + lastCarrotOffset, y, FontLayer + lastCarrotIdx * 2 + 1, Alignment::Left, Colorf::White, scale, scale, false, angle); + lastCarrotIdx++; + lastCarrotOffset += 6.0f; + } + if (health >= 2) { + float angle = angleBase2 * -6.0f + 0.2f; + DrawElement(PickupCarrot, 2, x + lastCarrotOffset - 1.0f, y + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 2, x + lastCarrotOffset + 1.0f, y + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 2, x + lastCarrotOffset, y, FontLayer + lastCarrotIdx * 2 + 1, Alignment::Left, Colorf::White, scale, scale, false, angle); + lastCarrotIdx++; + lastCarrotOffset = 17.0f; + } + if (health >= 6) { + for (std::int32_t i = 0; i < health - 5; i++) { + float angle = ((i % 3) == 1 ? angleBase2 : angleBase3) * (4.0f + ((i * 7) % 6)); + if ((i % 2) == 1) { + angle = -angle; + } + + DrawElement(PickupCarrot, 2, x + lastCarrotOffset - 1.0f, y + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 2, x + lastCarrotOffset + 1.0f, y + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 2, x + lastCarrotOffset, y, FontLayer + lastCarrotIdx * 2 + 1, Alignment::Left, Colorf::White, scale, scale, false, angle); + lastCarrotIdx++; + lastCarrotOffset += 5.0f; + } + } + if (health >= 5) { + float angle = angleBase1 * 10.0f; + lastCarrotOffset -= 1.0f; + DrawElement(PickupCarrot, 3, x + lastCarrotOffset - 1.0f, y + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 3, x + lastCarrotOffset + 1.0f, y + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 3, x + lastCarrotOffset, y, FontLayer + lastCarrotIdx * 2 + 1, Alignment::Left, Colorf::White, scale, scale, false, angle); + lastCarrotIdx++; + lastCarrotOffset += 5.0f; + } + if (health >= 4) { + float angle = angleBase2 * -6.0f - 0.4f; + lastCarrotOffset -= 2.0f; + DrawElement(PickupCarrot, 5, x + lastCarrotOffset - 1.0f, y + 2.0f + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 5, x + lastCarrotOffset + 1.0f, y + 2.0f + 1.0f, FontLayer + lastCarrotIdx * 2, Alignment::Left, CarrotShadowColor, scale, scale, false, angle); + DrawElement(PickupCarrot, 5, x + lastCarrotOffset, y + 2.0f, FontLayer + lastCarrotIdx * 2 + 1, Alignment::Left, Colorf::White, scale, scale, false, angle); + lastCarrotIdx++; + } + } + void HUD::DrawScore(const Rectf& view, Actors::Player* player) { #if defined(WITH_ANGELSCRIPT) @@ -692,10 +752,11 @@ namespace Jazz2::UI alpha = 1.0f; } + float alpha2 = alpha * alpha; DrawElement(PickupCoin, -1, ViewSize.X * 0.5f, ViewSize.Y * 0.92f + 2.5f + offset, ShadowLayer, Alignment::Right, Colorf(0.0f, 0.0f, 0.0f, 0.2f * alpha), 0.8f, 0.8f); DrawElement(PickupCoin, -1, ViewSize.X * 0.5f, ViewSize.Y * 0.92f + offset, MainLayer, - Alignment::Right, Colorf(1.0f, 1.0f, 1.0f, alpha * alpha), 0.8f, 0.8f); + Alignment::Right, Colorf(1.0f, 1.0f, 1.0f, alpha2), 0.8f, 0.8f); char stringBuffer[32]; snprintf(stringBuffer, countof(stringBuffer), "x%i", _coins); @@ -705,7 +766,7 @@ namespace Jazz2::UI Alignment::Left, Colorf(0.0f, 0.0f, 0.0f, 0.3f * alpha), 1.0f, 0.0f, 0.0f, 0.0f); Colorf fontColor = Font::DefaultColor; - fontColor.SetAlpha(alpha); + fontColor.SetAlpha(alpha2); _smallFont->DrawString(this, stringBuffer, charOffset, ViewSize.X * 0.5f, ViewSize.Y * 0.92f + offset, FontLayer, Alignment::Left, fontColor, 1.0f, 0.0f, 0.0f, 0.0f); @@ -738,11 +799,11 @@ namespace Jazz2::UI alpha = 1.0f; } - float animAlpha = alpha * alpha; + float alpha2 = alpha * alpha; DrawElement(PickupGem, -1, ViewSize.X * 0.5f, ViewSize.Y * 0.92f + 2.5f + offset, ShadowLayer, Alignment::Right, - Colorf(0.0f, 0.0f, 0.0f, 0.4f * animAlpha), 0.8f, 0.8f); + Colorf(0.0f, 0.0f, 0.0f, 0.4f * alpha2), 0.8f, 0.8f); DrawElement(PickupGem, -1, ViewSize.X * 0.5f, ViewSize.Y * 0.92f + offset, MainLayer, Alignment::Right, - Colorf(1.0f, 1.0f, 1.0f, 0.8f * animAlpha), 0.8f, 0.8f); + Colorf(1.0f, 1.0f, 1.0f, 0.8f * alpha2), 0.8f, 0.8f); char stringBuffer[32]; snprintf(stringBuffer, countof(stringBuffer), "x%i", _gems); @@ -752,7 +813,7 @@ namespace Jazz2::UI Alignment::Left, Colorf(0.0f, 0.0f, 0.0f, 0.3f * alpha), 1.0f, 0.0f, 0.0f, 0.0f); Colorf fontColor = Font::DefaultColor; - fontColor.SetAlpha(alpha); + fontColor.SetAlpha(alpha2); _smallFont->DrawString(this, stringBuffer, charOffset, ViewSize.X * 0.5f, ViewSize.Y * 0.92f + offset, FontLayer, Alignment::Left, fontColor, 1.0f, 0.0f, 0.0f, 0.0f); diff --git a/Sources/Jazz2/UI/HUD.h b/Sources/Jazz2/UI/HUD.h index 5790686e..697601a3 100644 --- a/Sources/Jazz2/UI/HUD.h +++ b/Sources/Jazz2/UI/HUD.h @@ -114,6 +114,7 @@ namespace Jazz2::UI float _touchButtonsTimer; void DrawHealth(const Rectf& view, const Rectf& adjustedView, Actors::Player* player); + void DrawHealthCarrots(float x, float y, std::int32_t health); void DrawScore(const Rectf& view, Actors::Player* player); void DrawWeaponAmmo(const Rectf& adjustedView, Actors::Player* player); void DrawActiveBoss(const Rectf& adjustedView);