Show damage flash in spectator#255
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a configurable “damage screen flash” effect while spectating another player, including persistence via Alpine settings and a new console toggle.
Changes:
- Track spectated player health/armor deltas and trigger a red screen flash on decreases.
- Add
cl_damageflash_spectatorconsole command and persist the setting inalpine_settings.ini. - Document the feature in the changelog.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
game_patch/misc/player.cpp |
Implements spectator damage flash detection in players_do_frame and adds a toggle command. |
game_patch/misc/alpine_settings.h |
Adds spectate_damage_screen_flash setting to AlpineGameSettings. |
game_patch/misc/alpine_settings.cpp |
Loads/saves SpectateDamageScreenFlash from/to the settings file. |
docs/CHANGELOG.md |
Adds an entry describing the spectator damage flash and its console toggle. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
game_patch/misc/player.cpp
Outdated
| else if (target_entity && g_spectate_last_health >= 0.0f) { | ||
| if (target_entity->life < g_spectate_last_health | ||
| || target_entity->armor < g_spectate_last_armor) { | ||
| rf::local_screen_flash(rf::local_player, 255, 0, 0, 128); | ||
| } |
There was a problem hiding this comment.
g_spectate_last_health uses -1.0f as a sentinel and the update path is gated by g_spectate_last_health >= 0.0f. Entity::life can legitimately be <= 0 (and even negative) for dead players, so after the target dies this condition will prevent the baseline from ever updating again (and the flash may stop working until changing targets). Also, if target_entity is null when the target is first set, the baseline is left at -1.0f and will never initialize later. Use a dedicated “initialized” flag/std::optional (or similar) and always refresh the baseline whenever target_entity becomes available; only trigger the flash when you have a valid previous sample.
game_patch/misc/player.cpp
Outdated
| // Spectator damage flash: detect health or armor decreases on the spectated player | ||
| if (target && g_alpine_game_config.spectate_damage_screen_flash) { | ||
| rf::Entity* target_entity = rf::entity_from_handle(target->entity_handle); | ||
| if (target != g_spectate_last_target) { | ||
| g_spectate_last_target = target; | ||
| g_spectate_last_health = target_entity ? target_entity->life : -1.0f; | ||
| g_spectate_last_armor = target_entity ? target_entity->armor : -1.0f; | ||
| } | ||
| else if (target_entity && g_spectate_last_health >= 0.0f) { | ||
| if (target_entity->life < g_spectate_last_health | ||
| || target_entity->armor < g_spectate_last_armor) { | ||
| rf::local_screen_flash(rf::local_player, 255, 0, 0, 128); | ||
| } |
There was a problem hiding this comment.
Because the baseline (g_spectate_last_health / g_spectate_last_armor) is only updated inside the spectate_damage_screen_flash enabled block, turning the setting off while spectating will freeze the baseline. When the user re-enables it, any damage that happened while it was off can cause an immediate false-positive flash due to stale values. Consider continuing to update the baseline even when the effect is disabled (but skip the flash), or reset/reinitialize the baseline when toggling the setting.
| // Spectator damage flash: detect health or armor decreases on the spectated player | |
| if (target && g_alpine_game_config.spectate_damage_screen_flash) { | |
| rf::Entity* target_entity = rf::entity_from_handle(target->entity_handle); | |
| if (target != g_spectate_last_target) { | |
| g_spectate_last_target = target; | |
| g_spectate_last_health = target_entity ? target_entity->life : -1.0f; | |
| g_spectate_last_armor = target_entity ? target_entity->armor : -1.0f; | |
| } | |
| else if (target_entity && g_spectate_last_health >= 0.0f) { | |
| if (target_entity->life < g_spectate_last_health | |
| || target_entity->armor < g_spectate_last_armor) { | |
| rf::local_screen_flash(rf::local_player, 255, 0, 0, 128); | |
| } | |
| // Spectator damage flash: detect health or armor decreases on the spectated player. | |
| // Baselines are updated even when the flash effect is disabled to avoid stale state. | |
| if (target) { | |
| rf::Entity* target_entity = rf::entity_from_handle(target->entity_handle); | |
| if (target != g_spectate_last_target) { | |
| // New spectate target: initialize baselines. | |
| g_spectate_last_target = target; | |
| g_spectate_last_health = target_entity ? target_entity->life : -1.0f; | |
| g_spectate_last_armor = target_entity ? target_entity->armor : -1.0f; | |
| } | |
| else if (target_entity && g_spectate_last_health >= 0.0f) { | |
| // Existing target: detect damage based on current baselines. | |
| bool took_damage = | |
| (target_entity->life < g_spectate_last_health) || | |
| (target_entity->armor < g_spectate_last_armor); | |
| if (took_damage && g_alpine_game_config.spectate_damage_screen_flash) { | |
| rf::local_screen_flash(rf::local_player, 255, 0, 0, 128); | |
| } | |
| // Always refresh baselines so they stay current even when the flash is disabled. |
|
It seems hacky. Servers already tracks spectators. A |
Having this as a packet doesn't make sense to me - damage flash is strictly a clientside graphical feature, having the client determine when to apply it makes sense. This implementation seems like the most lightweight and reasonable way to do this without introducing unnecessary complexity. I do think it would be a good idea to collapse |
Why not hook |
Either the existing hook or hooking Perhaps doing it in |
Yeah and it avoids |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
No description provided.