Browse Source
Co-authored-by: qndel <stefan551@o2.pl> Co-authored-by: Stephen C. Wills <staphen@gmail.com>pull/5698/head
25 changed files with 387 additions and 137 deletions
Binary file not shown.
Binary file not shown.
@ -0,0 +1,198 @@
|
||||
#include "floatingnumbers.h" |
||||
|
||||
#include <ctime> |
||||
#include <deque> |
||||
#include <fmt/format.h> |
||||
#include <string> |
||||
|
||||
#include "engine/render/text_render.hpp" |
||||
#include "options.h" |
||||
|
||||
namespace devilution { |
||||
|
||||
namespace { |
||||
|
||||
struct FloatingNumber { |
||||
Point startPos; |
||||
Displacement startOffset; |
||||
Displacement endOffset; |
||||
std::string text; |
||||
uint32_t time; |
||||
uint32_t lastMerge; |
||||
UiFlags style; |
||||
DamageType type; |
||||
int value; |
||||
int index; |
||||
bool reverseDirection; |
||||
}; |
||||
|
||||
std::deque<FloatingNumber> FloatingQueue; |
||||
|
||||
void ClearExpiredNumbers() |
||||
{ |
||||
while (!FloatingQueue.empty()) { |
||||
FloatingNumber &num = FloatingQueue.front(); |
||||
if (num.time > SDL_GetTicks()) |
||||
break; |
||||
|
||||
FloatingQueue.pop_front(); |
||||
} |
||||
} |
||||
|
||||
GameFontTables GetGameFontSizeByDamage(int value) |
||||
{ |
||||
value >>= 6; |
||||
if (value >= 300) |
||||
return GameFont30; |
||||
if (value >= 100) |
||||
return GameFont24; |
||||
return GameFont12; |
||||
} |
||||
|
||||
UiFlags GetFontSizeByDamage(int value) |
||||
{ |
||||
value >>= 6; |
||||
if (value >= 300) |
||||
return UiFlags::FontSize30; |
||||
if (value >= 100) |
||||
return UiFlags::FontSize24; |
||||
return UiFlags::FontSize12; |
||||
} |
||||
|
||||
void UpdateFloatingData(FloatingNumber &num) |
||||
{ |
||||
num.text = fmt::format("{:d}", num.value >> 6); |
||||
if (num.value > 0 && num.value < 64) { |
||||
num.text = fmt::format("{:.2f}", num.value / 64.0); |
||||
} |
||||
|
||||
num.style &= ~(UiFlags::FontSize12 | UiFlags::FontSize24 | UiFlags::FontSize30); |
||||
num.style |= GetFontSizeByDamage(num.value); |
||||
|
||||
switch (num.type) { |
||||
case DamageType::Physical: |
||||
num.style |= UiFlags::ColorGold; |
||||
break; |
||||
case DamageType::Fire: |
||||
num.style |= UiFlags::ColorUiSilver; // UiSilver appears dark red ingame
|
||||
break; |
||||
case DamageType::Lightning: |
||||
num.style |= UiFlags::ColorBlue; |
||||
break; |
||||
case DamageType::Magic: |
||||
num.style |= UiFlags::ColorOrange; |
||||
break; |
||||
case DamageType::Acid: |
||||
num.style |= UiFlags::ColorYellow; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void AddFloatingNumber(Point pos, Displacement offset, DamageType type, int value, int index, bool damageToPlayer) |
||||
{ |
||||
// 45 deg angles to avoid jitter caused by px alignment
|
||||
Displacement goodAngles[] = { |
||||
{ 0, -140 }, |
||||
{ 100, -100 }, |
||||
{ -100, -100 }, |
||||
}; |
||||
|
||||
Displacement endOffset = goodAngles[rand() % 3]; |
||||
|
||||
if (damageToPlayer) |
||||
endOffset = -endOffset; |
||||
|
||||
for (auto &num : FloatingQueue) { |
||||
if (num.reverseDirection == damageToPlayer && num.type == type && num.index == index && (SDL_GetTicks() - static_cast<int>(num.lastMerge)) <= 100) { |
||||
num.value += value; |
||||
num.lastMerge = SDL_GetTicks(); |
||||
UpdateFloatingData(num); |
||||
return; |
||||
} |
||||
} |
||||
FloatingNumber num { |
||||
pos, offset, endOffset, "", SDL_GetTicks() + 2500, SDL_GetTicks(), UiFlags::Outlined, type, value, index, damageToPlayer |
||||
}; |
||||
UpdateFloatingData(num); |
||||
FloatingQueue.push_back(num); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
void AddFloatingNumber(DamageType damageType, const Monster &monster, int damage) |
||||
{ |
||||
if (!*sgOptions.Gameplay.enableFloatingNumbers) |
||||
return; |
||||
|
||||
Displacement offset = {}; |
||||
if (monster.isWalking()) { |
||||
offset = GetOffsetForWalking(monster.animInfo, monster.direction); |
||||
if (monster.mode == MonsterMode::MoveSideways) { |
||||
if (monster.direction == Direction::West) |
||||
offset -= Displacement { 64, 0 }; |
||||
else |
||||
offset += Displacement { 64, 0 }; |
||||
} |
||||
} |
||||
if (monster.animInfo.sprites) { |
||||
const ClxSprite sprite = monster.animInfo.currentSprite(); |
||||
offset.deltaY -= sprite.height() / 2; |
||||
} |
||||
|
||||
AddFloatingNumber(monster.position.tile, offset, damageType, damage, monster.getId(), false); |
||||
} |
||||
|
||||
void AddFloatingNumber(DamageType damageType, const Player &player, int damage) |
||||
{ |
||||
if (!*sgOptions.Gameplay.enableFloatingNumbers) |
||||
return; |
||||
|
||||
Displacement offset = {}; |
||||
if (player.isWalking()) { |
||||
offset = GetOffsetForWalking(player.AnimInfo, player._pdir); |
||||
if (player._pmode == PM_WALK_SIDEWAYS) { |
||||
if (player._pdir == Direction::West) |
||||
offset -= Displacement { 64, 0 }; |
||||
else |
||||
offset += Displacement { 64, 0 }; |
||||
} |
||||
} |
||||
|
||||
AddFloatingNumber(player.position.tile, offset, damageType, damage, player.getId(), true); |
||||
} |
||||
|
||||
void DrawFloatingNumbers(const Surface &out, Point viewPosition, Displacement offset) |
||||
{ |
||||
if (!*sgOptions.Gameplay.enableFloatingNumbers) |
||||
return; |
||||
|
||||
for (auto &floatingNum : FloatingQueue) { |
||||
Displacement worldOffset = viewPosition - floatingNum.startPos; |
||||
worldOffset = worldOffset.worldToScreen() + offset + Displacement { TILE_WIDTH / 2, -TILE_HEIGHT / 2 } + floatingNum.startOffset; |
||||
|
||||
if (*sgOptions.Graphics.zoom) { |
||||
worldOffset *= 2; |
||||
} |
||||
|
||||
Point screenPosition { worldOffset.deltaX, worldOffset.deltaY }; |
||||
|
||||
int lineWidth = GetLineWidth(floatingNum.text, GetGameFontSizeByDamage(floatingNum.value)); |
||||
screenPosition.x -= lineWidth / 2; |
||||
uint32_t timeLeft = floatingNum.time - SDL_GetTicks(); |
||||
float mul = 1 - (timeLeft / 2500.0f); |
||||
screenPosition += floatingNum.endOffset * mul; |
||||
|
||||
DrawString(out, floatingNum.text, Rectangle { screenPosition, { lineWidth, 0 } }, floatingNum.style); |
||||
} |
||||
|
||||
ClearExpiredNumbers(); |
||||
} |
||||
|
||||
void ClearFloatingNumbers() |
||||
{ |
||||
srand(time(nullptr)); |
||||
|
||||
FloatingQueue.clear(); |
||||
} |
||||
|
||||
} // namespace devilution
|
||||
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @file floatingnumbers.h |
||||
* |
||||
* Adds floating numbers QoL feature |
||||
*/ |
||||
#pragma once |
||||
|
||||
#include "engine/point.hpp" |
||||
#include "misdat.h" |
||||
#include "monster.h" |
||||
#include "player.h" |
||||
|
||||
namespace devilution { |
||||
|
||||
void AddFloatingNumber(DamageType damageType, const Monster &monster, int damage); |
||||
void AddFloatingNumber(DamageType damageType, const Player &player, int damage); |
||||
void DrawFloatingNumbers(const Surface &out, Point viewPosition, Displacement offset); |
||||
void ClearFloatingNumbers(); |
||||
|
||||
} // namespace devilution
|
||||
Loading…
Reference in new issue