feat: Add bonus flash effect for player pickups and update rendering logic
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -483,16 +483,16 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
|
||||
final int color = isPushwall
|
||||
? pushwallColor
|
||||
: objTile == MapObject.normalExitTrigger
|
||||
? normalExitColor
|
||||
: objTile == MapObject.secretExitTrigger
|
||||
? secretExitColor
|
||||
: objTile == MapObject.goldKey
|
||||
? goldKeyColor
|
||||
: objTile == MapObject.silverKey
|
||||
? silverKeyColor
|
||||
: (wallTile == 0
|
||||
? floorColor
|
||||
: (wallTile >= 90 ? doorColor : wallColor));
|
||||
? normalExitColor
|
||||
: objTile == MapObject.secretExitTrigger
|
||||
? secretExitColor
|
||||
: objTile == MapObject.goldKey
|
||||
? goldKeyColor
|
||||
: objTile == MapObject.silverKey
|
||||
? silverKeyColor
|
||||
: (wallTile == 0
|
||||
? floorColor
|
||||
: (wallTile >= 90 ? doorColor : wallColor));
|
||||
_fillMapRect(
|
||||
mapStartX + (x * tileSize),
|
||||
mapStartY + (y * tileSize),
|
||||
@@ -2094,11 +2094,19 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
|
||||
|
||||
@override
|
||||
dynamic finalizeFrame() {
|
||||
if (engine.difficulty != null && engine.player.damageFlash > 0.0) {
|
||||
if (_usesTerminalLayout) {
|
||||
_applyDamageFlashToScene();
|
||||
} else {
|
||||
_applyDamageFlash();
|
||||
if (engine.difficulty != null) {
|
||||
if (engine.player.damageFlash > 0.0) {
|
||||
if (_usesTerminalLayout) {
|
||||
_applyDamageFlashToScene();
|
||||
} else {
|
||||
_applyDamageFlash();
|
||||
}
|
||||
} else if (engine.player.bonusFlash > 0.0) {
|
||||
if (_usesTerminalLayout) {
|
||||
_applyBonusFlashToScene();
|
||||
} else {
|
||||
_applyBonusFlash();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_usesTerminalLayout) {
|
||||
@@ -2275,6 +2283,44 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
|
||||
return (0xFF000000) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
||||
void _applyBonusFlash() {
|
||||
for (int y = 0; y < viewHeight; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
final ColoredChar cell = _screen[y][x];
|
||||
_screen[y][x] = ColoredChar(
|
||||
cell.char,
|
||||
_applyBonusFlashToColor(cell.rawColor),
|
||||
cell.rawBackgroundColor == null
|
||||
? null
|
||||
: _applyBonusFlashToColor(cell.rawBackgroundColor!),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _applyBonusFlashToScene() {
|
||||
for (int y = 0; y < _terminalPixelHeight; y++) {
|
||||
for (int x = projectionOffsetX; x < _viewportRightX; x++) {
|
||||
_scenePixels[y][x] = _applyBonusFlashToColor(_scenePixels[y][x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int _applyBonusFlashToColor(int color) {
|
||||
final double intensity = engine.player.bonusFlash;
|
||||
final double whiteMix = 0.65 * intensity;
|
||||
|
||||
int r = color & 0xFF;
|
||||
int g = (color >> 8) & 0xFF;
|
||||
int b = (color >> 16) & 0xFF;
|
||||
|
||||
r = (r + ((255 - r) * whiteMix)).round().clamp(0, 255);
|
||||
g = (g + ((255 - g) * whiteMix)).round().clamp(0, 255);
|
||||
b = (b + ((255 - b) * whiteMix)).round().clamp(0, 255);
|
||||
|
||||
return (0xFF000000) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
||||
int _scaleColor(int color, double brightness) {
|
||||
int r = ((color & 0xFF) * brightness).toInt().clamp(0, 255);
|
||||
int g = (((color >> 8) & 0xFF) * brightness).toInt().clamp(0, 255);
|
||||
|
||||
@@ -248,7 +248,7 @@ abstract class RendererBackend<T>
|
||||
_drawHudKeySlot(
|
||||
engine,
|
||||
vgaImages,
|
||||
startX: 30,
|
||||
startX: 240,
|
||||
startY: 164,
|
||||
hasKey: engine.player.hasGoldKey,
|
||||
presentKey: HudKey.goldKeyIcon,
|
||||
@@ -256,7 +256,7 @@ abstract class RendererBackend<T>
|
||||
_drawHudKeySlot(
|
||||
engine,
|
||||
vgaImages,
|
||||
startX: 30,
|
||||
startX: 240,
|
||||
startY: 180,
|
||||
hasKey: engine.player.hasSilverKey,
|
||||
presentKey: HudKey.silverKeyIcon,
|
||||
|
||||
@@ -407,16 +407,16 @@ class SixelRenderer extends CliRendererBackend<String> {
|
||||
final int color = isPushwall
|
||||
? pushwallColor
|
||||
: objTile == MapObject.normalExitTrigger
|
||||
? normalExitColor
|
||||
: objTile == MapObject.secretExitTrigger
|
||||
? secretExitColor
|
||||
: objTile == MapObject.goldKey
|
||||
? goldKeyColor
|
||||
: objTile == MapObject.silverKey
|
||||
? silverKeyColor
|
||||
: (wallTile == 0
|
||||
? floorColor
|
||||
: (wallTile >= 90 ? doorColor : wallColor));
|
||||
? normalExitColor
|
||||
: objTile == MapObject.secretExitTrigger
|
||||
? secretExitColor
|
||||
: objTile == MapObject.goldKey
|
||||
? goldKeyColor
|
||||
: objTile == MapObject.silverKey
|
||||
? silverKeyColor
|
||||
: (wallTile == 0
|
||||
? floorColor
|
||||
: (wallTile >= 90 ? doorColor : wallColor));
|
||||
_fillMapRect(
|
||||
mapStartX + (x * tileSize),
|
||||
mapStartY + (y * tileSize),
|
||||
@@ -1336,11 +1336,16 @@ class SixelRenderer extends CliRendererBackend<String> {
|
||||
sb.write('\x1bPq');
|
||||
sb.write('"1;1;$_outputWidth;$_outputHeight');
|
||||
|
||||
double damageIntensity = engine.difficulty == null
|
||||
? 0.0
|
||||
: engine.player.damageFlash;
|
||||
int redBoost = (150 * damageIntensity).toInt();
|
||||
double colorDrop = 1.0 - (0.5 * damageIntensity);
|
||||
final bool gameplayActive = engine.difficulty != null;
|
||||
final double damageIntensity = gameplayActive
|
||||
? engine.player.damageFlash
|
||||
: 0.0;
|
||||
final double bonusIntensity = gameplayActive && damageIntensity <= 0.0
|
||||
? engine.player.bonusFlash
|
||||
: 0.0;
|
||||
final int redBoost = (150 * damageIntensity).toInt();
|
||||
final double colorDrop = 1.0 - (0.5 * damageIntensity);
|
||||
final double whiteMix = 0.65 * bonusIntensity;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
int color = ColorPalette.vga32Bit[i];
|
||||
@@ -1352,6 +1357,10 @@ class SixelRenderer extends CliRendererBackend<String> {
|
||||
r = (r + redBoost).clamp(0, 255);
|
||||
g = (g * colorDrop).toInt().clamp(0, 255);
|
||||
b = (b * colorDrop).toInt().clamp(0, 255);
|
||||
} else if (bonusIntensity > 0) {
|
||||
r = (r + ((255 - r) * whiteMix)).round().clamp(0, 255);
|
||||
g = (g + ((255 - g) * whiteMix)).round().clamp(0, 255);
|
||||
b = (b + ((255 - b) * whiteMix)).round().clamp(0, 255);
|
||||
}
|
||||
|
||||
int sixelR = (r * 100) ~/ 255;
|
||||
|
||||
@@ -1397,9 +1397,12 @@ class SoftwareRenderer extends RendererBackend<FrameBuffer> {
|
||||
|
||||
@override
|
||||
FrameBuffer finalizeFrame() {
|
||||
// If the player took damage, overlay a red tint across the 3D view
|
||||
if (engine.difficulty != null && engine.player.damageFlash > 0) {
|
||||
_applyDamageFlash();
|
||||
if (engine.difficulty != null) {
|
||||
if (engine.player.damageFlash > 0) {
|
||||
_applyDamageFlash();
|
||||
} else if (engine.player.bonusFlash > 0) {
|
||||
_applyBonusFlash();
|
||||
}
|
||||
}
|
||||
return _buffer; // Return the fully painted pixel array
|
||||
}
|
||||
@@ -1467,4 +1470,26 @@ class SoftwareRenderer extends RendererBackend<FrameBuffer> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _applyBonusFlash() {
|
||||
final double intensity = engine.player.bonusFlash;
|
||||
final double whiteMix = 0.65 * intensity;
|
||||
|
||||
for (int y = 0; y < viewHeight; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
final int index = y * width + x;
|
||||
final int color = _buffer.pixels[index];
|
||||
|
||||
int r = color & 0xFF;
|
||||
int g = (color >> 8) & 0xFF;
|
||||
int b = (color >> 16) & 0xFF;
|
||||
|
||||
r = (r + ((255 - r) * whiteMix)).round().clamp(0, 255);
|
||||
g = (g + ((255 - g) * whiteMix)).round().clamp(0, 255);
|
||||
b = (b + ((255 - b) * whiteMix)).round().clamp(0, 255);
|
||||
|
||||
_buffer.pixels[index] = (0xFF000000) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user