< Summary

Information
Class: RaidLoop.Client.Components.RaidHUD
Assembly: RaidLoop.Client
File(s): /home/runner/work/RaidLoop/RaidLoop/src/RaidLoop.Client/Components/RaidHUD.razor
Line coverage
0%
Covered lines: 0
Uncovered lines: 160
Coverable lines: 160
Total lines: 370
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 86
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
BuildRenderTree(...)0%2756520%
get_Raid()100%210%
get_MaxHealth()100%210%
get_AmmoHudText()100%210%
get_Medkits()100%210%
get_LootSlots()100%210%
get_RaidEncumbranceText()100%210%
get_Challenge()100%210%
get_DistanceFromExtract()100%210%
get_EncounterType()100%210%
get_EncounterTitle()100%210%
get_EncounterDescription()100%210%
get_ContactState()100%210%
get_SurpriseSide()100%210%
get_InitiativeWinner()100%210%
get_OpeningActionsRemaining()100%210%
get_SurprisePersistenceEligible()100%210%
get_EnemyName()100%210%
get_EnemyHealth()100%210%
get_LootContainer()100%210%
get_DiscoveredLoot()100%210%
get_CarriedLoot()100%210%
get_EquippedItems()100%210%
get_LogEntries()100%210%
get_AwaitingDecision()100%210%
get_CanAttack()100%210%
get_CanAttackEnabled()100%210%
get_CanBurstFire()100%210%
get_CanBurstFireEnabled()100%210%
get_CanFullAuto()100%210%
get_CanFullAutoEnabled()100%210%
get_CanReload()100%210%
get_CanUseMedkit()100%210%
get_CanLootItem()100%210%
get_CanEquipItem()100%210%
get_ExtractHoldActive()100%210%
get_HoldAtExtractUntil()100%210%
get_OnAttack()100%210%
get_OnBurstFire()100%210%
get_OnFullAuto()100%210%
get_OnReload()100%210%
get_OnFlee()100%210%
get_OnUseMedkit()100%210%
get_OnTakeLoot()100%210%
get_OnDropCarried()100%210%
get_OnDropEquipped()100%210%
get_OnEquipFromDiscovered()100%210%
get_OnEquipFromCarried()100%210%
get_OnAttemptExtract()100%210%
get_OnGoDeeper()100%210%
get_OnStartExtractHold()100%210%
get_OnCancelExtractHold()100%210%
get_OnMoveTowardExtract()100%210%
IsExtractHoldEffectivelyActive()0%4260%
GetOpeningPhaseSummary()0%156120%
Matches(...)100%210%
IsEquipable(...)0%620%
GetExtractHoldCountdownText()0%2040%
IsTooHeavyToCarry(...)100%210%
IsBlockedByLootSlots(...)100%210%
RaidEncumbrance()100%210%
GetDisplayedEncumbranceTier()0%4260%
ShouldShowEncumbranceTier()100%210%
GetEncumbranceTierLabel()100%210%
GetEncumbranceSeverityCssClass()0%2040%

File(s)

/home/runner/work/RaidLoop/RaidLoop/src/RaidLoop.Client/Components/RaidHUD.razor

#LineLine coverage
 1<section class="panel">
 2    <h2>In Raid</h2>
 3
 4    <div class="hud">
 05        <span>Health: @Raid.Health / @MaxHealth</span>
 06        <span>@AmmoHudText</span>
 07        <span>Medkits: @Medkits</span>
 08        <span>Loot Slots: @LootSlots / @Raid.BackpackCapacity</span>
 9        <span class="encumbrance-readout">
 10            <span class="encumbrance-label">Encumbrance:</span>
 011            <span class="encumbrance-value @GetEncumbranceSeverityCssClass()">@RaidEncumbranceText</span>
 012            @if (ShouldShowEncumbranceTier())
 13            {
 014                <span class="encumbrance-tier @GetEncumbranceSeverityCssClass()">@GetEncumbranceTierLabel()</span>
 15            }
 16        </span>
 017        <span>Challenge: @Challenge</span>
 018        <span>Distance from Extract: @DistanceFromExtract</span>
 19    </div>
 20
 21    <div class="encounter">
 022        <h3>@EncounterTitle</h3>
 023        <p>@EncounterDescription</p>
 024        @if (IsExtractHoldEffectivelyActive())
 25        {
 026            <p class="extract-hold-status">Hold active for @GetExtractHoldCountdownText()</p>
 27        }
 28
 029        @if (EncounterType == EncounterType.Combat)
 30        {
 031            var openingPhaseSummary = GetOpeningPhaseSummary();
 032            if (!string.IsNullOrWhiteSpace(openingPhaseSummary))
 33            {
 34                <div class="opening-phase">
 035                    <p>@openingPhaseSummary</p>
 36                </div>
 37            }
 038            <p>Enemy: @EnemyName (HP: @EnemyHealth)</p>
 39            <div class="actions">
 040                @if (CanAttack)
 41                {
 042                    <button class="action" disabled="@(!CanAttackEnabled)" @onclick="() => OnAttack.InvokeAsync()">Attac
 43                }
 044                @if (CanBurstFire)
 45                {
 046                    <button class="action" disabled="@(!CanBurstFireEnabled)" @onclick="() => OnBurstFire.InvokeAsync()"
 47                }
 048                @if (CanFullAuto)
 49                {
 050                    <button class="action" disabled="@(!CanFullAutoEnabled)" @onclick="() => OnFullAuto.InvokeAsync()">U
 51                }
 052                @if (CanReload)
 53                {
 054                    <button class="action" @onclick="() => OnReload.InvokeAsync()">Reload</button>
 55                }
 056                <button class="action" @onclick="() => OnFlee.InvokeAsync()">Flee</button>
 57            </div>
 58        }
 059        else if (EncounterType == EncounterType.Loot)
 60        {
 061            <p>Container discovered: @LootContainer</p>
 62            <div class="grid-two">
 63                <div>
 064                    @if (DiscoveredLoot.Count == 0)
 65                    {
 66                        <p>Nothing useful left.</p>
 67                    }
 68                    else
 69                    {
 70                        <h4>Discovered Loot</h4>
 71                        <ul>
 072                            @foreach (var lootItem in DiscoveredLoot)
 73                            {
 74                                <li>
 75                                    <div class="row-item row-item-inline">
 76                                        <ItemTypeIcon Type="lootItem.Type" />
 077                                        <span class="item-name rarity-@lootItem.DisplayRarity.ToString().ToLower()">@Ite
 78                                        <div class="row-actions">
 079                                            @if (IsEquipable(lootItem))
 80                                            {
 081                                                <button class="action" disabled="@(!CanEquipItem(lootItem))" @onclick="(
 82                                            }
 083                                            <button class="action" disabled="@(!CanLootItem(lootItem))" @onclick="() => 
 84                                        </div>
 85                                    </div>
 86                                </li>
 87                            }
 88                        </ul>
 89                    }
 090                    @if (DiscoveredLoot.Any(item => IsTooHeavyToCarry(item)))
 91                    {
 92                        <p>Too heavy to carry.</p>
 93                    }
 094                    @if (DiscoveredLoot.Any(IsBlockedByLootSlots))
 95                    {
 96                        <p>Backpack full for some items.</p>
 97                    }
 98                </div>
 99                <div>
 100                    <h4>Character Inventory</h4>
 101                    <h4>Equipped</h4>
 0102                    @foreach (var equipped in EquippedItems)
 103                    {
 104                        <div class="row-item">
 105                            <ItemTypeIcon Type="equipped.Type" />
 0106                            <span class="item-name rarity-@equipped.DisplayRarity.ToString().ToLower()">@ItemPresentatio
 107                            <div class="row-actions">
 0108                                <button class="action" @onclick="() => OnDropEquipped.InvokeAsync(equipped.Type)">Drop</
 109                            </div>
 110                        </div>
 111                    }
 112
 113                    <h4>Carried</h4>
 0114                    @if (CarriedLoot.Count == 0)
 115                    {
 116                        <p>No carried loot.</p>
 117                    }
 118                    else
 119                    {
 0120                        @foreach (var carried in CarriedLoot)
 121                        {
 122                            <div class="row-item">
 123                                <ItemTypeIcon Type="carried.Type" />
 0124                                <span class="item-name rarity-@carried.DisplayRarity.ToString().ToLower()">@ItemPresenta
 125                                <div class="row-actions">
 0126                                    <button class="action" @onclick="() => OnDropCarried.InvokeAsync(carried)">Drop</but
 0127                                    @if (IsEquipable(carried))
 128                                    {
 0129                                        <button class="action" disabled="@(!CanEquipItem(carried))" @onclick="() => OnEq
 130                                    }
 131                                </div>
 132                            </div>
 133                        }
 0134                        @if (CarriedLoot.Any(item => IsEquipable(item) && !CanEquipItem(item)))
 135                        {
 136                            <p>Too heavy to equip.</p>
 137                        }
 138                    }
 139                </div>
 140            </div>
 141        }
 0142        else if (EncounterType == EncounterType.Extraction)
 143        {
 144            <div class="actions">
 0145                <button class="action" disabled="@IsExtractHoldEffectivelyActive()" @onclick="() => OnAttemptExtract.Inv
 0146                <button class="action" disabled="@IsExtractHoldEffectivelyActive()" @onclick="() => OnStartExtractHold.I
 0147                @if (ExtractHoldActive)
 148                {
 0149                    <button class="action" @onclick="() => OnCancelExtractHold.InvokeAsync()">Cancel Hold</button>
 150                }
 151            </div>
 152        }
 0153        else if (EncounterType == EncounterType.Neutral)
 154        {
 155            <div class="actions">
 0156                <button class="action" disabled="@IsExtractHoldEffectivelyActive()" @onclick="() => OnGoDeeper.InvokeAsy
 0157                <button class="action" disabled="@IsExtractHoldEffectivelyActive()" @onclick="() => OnMoveTowardExtract.
 158            </div>
 159        }
 160
 0161        @if (AwaitingDecision || EncounterType == EncounterType.Loot)
 162        {
 163            <div class="actions top-gap">
 0164                <button class="action" disabled="@IsExtractHoldEffectivelyActive()" @onclick="() => OnGoDeeper.InvokeAsy
 0165                <button class="action" disabled="@IsExtractHoldEffectivelyActive()" @onclick="() => OnMoveTowardExtract.
 166            </div>
 167        }
 168
 169        <div class="actions top-gap">
 0170            @if (CanReload)
 171            {
 0172                <button class="action" @onclick="() => OnReload.InvokeAsync()">Reload</button>
 173            }
 0174            <button class="action" disabled="@(!CanUseMedkit)" @onclick="() => OnUseMedkit.InvokeAsync()">Use Medkit</bu
 175        </div>
 176    </div>
 177
 178    <h3>Raid Log</h3>
 179    <ul>
 0180        @foreach (var entry in LogEntries)
 181        {
 0182            <li>@entry</li>
 183        }
 184    </ul>
 185</section>
 186
 187@code {
 0188    [Parameter, EditorRequired] public RaidState Raid { get; set; } = default!;
 0189    [Parameter, EditorRequired] public int MaxHealth { get; set; }
 0190    [Parameter, EditorRequired] public string AmmoHudText { get; set; } = string.Empty;
 0191    [Parameter, EditorRequired] public int Medkits { get; set; }
 0192    [Parameter, EditorRequired] public int LootSlots { get; set; }
 0193    [Parameter, EditorRequired] public string RaidEncumbranceText { get; set; } = string.Empty;
 0194    [Parameter, EditorRequired] public int Challenge { get; set; }
 0195    [Parameter, EditorRequired] public int DistanceFromExtract { get; set; }
 0196    [Parameter, EditorRequired] public EncounterType EncounterType { get; set; }
 0197    [Parameter, EditorRequired] public string EncounterTitle { get; set; } = string.Empty;
 0198    [Parameter, EditorRequired] public string EncounterDescription { get; set; } = string.Empty;
 0199    [Parameter] public string ContactState { get; set; } = string.Empty;
 0200    [Parameter] public string SurpriseSide { get; set; } = string.Empty;
 0201    [Parameter] public string InitiativeWinner { get; set; } = string.Empty;
 0202    [Parameter, EditorRequired] public int OpeningActionsRemaining { get; set; }
 0203    [Parameter, EditorRequired] public bool SurprisePersistenceEligible { get; set; }
 0204    [Parameter] public string EnemyName { get; set; } = string.Empty;
 0205    [Parameter, EditorRequired] public int EnemyHealth { get; set; }
 0206    [Parameter] public string LootContainer { get; set; } = string.Empty;
 0207    [Parameter, EditorRequired] public IReadOnlyList<Item> DiscoveredLoot { get; set; } = [];
 0208    [Parameter, EditorRequired] public IReadOnlyList<Item> CarriedLoot { get; set; } = [];
 0209    [Parameter, EditorRequired] public IReadOnlyList<Item> EquippedItems { get; set; } = [];
 0210    [Parameter, EditorRequired] public IReadOnlyList<string> LogEntries { get; set; } = [];
 0211    [Parameter, EditorRequired] public bool AwaitingDecision { get; set; }
 0212    [Parameter, EditorRequired] public bool CanAttack { get; set; }
 0213    [Parameter, EditorRequired] public bool CanAttackEnabled { get; set; }
 0214    [Parameter, EditorRequired] public bool CanBurstFire { get; set; }
 0215    [Parameter, EditorRequired] public bool CanBurstFireEnabled { get; set; }
 0216    [Parameter, EditorRequired] public bool CanFullAuto { get; set; }
 0217    [Parameter, EditorRequired] public bool CanFullAutoEnabled { get; set; }
 0218    [Parameter, EditorRequired] public bool CanReload { get; set; }
 0219    [Parameter, EditorRequired] public bool CanUseMedkit { get; set; }
 0220    [Parameter, EditorRequired] public Func<Item, bool> CanLootItem { get; set; } = _ => false;
 0221    [Parameter, EditorRequired] public Func<Item, bool> CanEquipItem { get; set; } = _ => false;
 0222    [Parameter, EditorRequired] public bool ExtractHoldActive { get; set; }
 0223    [Parameter] public DateTimeOffset? HoldAtExtractUntil { get; set; }
 0224    [Parameter, EditorRequired] public EventCallback OnAttack { get; set; }
 0225    [Parameter, EditorRequired] public EventCallback OnBurstFire { get; set; }
 0226    [Parameter, EditorRequired] public EventCallback OnFullAuto { get; set; }
 0227    [Parameter, EditorRequired] public EventCallback OnReload { get; set; }
 0228    [Parameter, EditorRequired] public EventCallback OnFlee { get; set; }
 0229    [Parameter, EditorRequired] public EventCallback OnUseMedkit { get; set; }
 0230    [Parameter, EditorRequired] public EventCallback<Item> OnTakeLoot { get; set; }
 0231    [Parameter, EditorRequired] public EventCallback<Item> OnDropCarried { get; set; }
 0232    [Parameter, EditorRequired] public EventCallback<ItemType> OnDropEquipped { get; set; }
 0233    [Parameter, EditorRequired] public EventCallback<Item> OnEquipFromDiscovered { get; set; }
 0234    [Parameter, EditorRequired] public EventCallback<Item> OnEquipFromCarried { get; set; }
 0235    [Parameter, EditorRequired] public EventCallback OnAttemptExtract { get; set; }
 0236    [Parameter, EditorRequired] public EventCallback OnGoDeeper { get; set; }
 0237    [Parameter, EditorRequired] public EventCallback OnStartExtractHold { get; set; }
 0238    [Parameter, EditorRequired] public EventCallback OnCancelExtractHold { get; set; }
 0239    [Parameter, EditorRequired] public EventCallback OnMoveTowardExtract { get; set; }
 240
 241    private bool IsExtractHoldEffectivelyActive()
 242    {
 0243        if (!ExtractHoldActive)
 244        {
 0245            return false;
 246        }
 247
 0248        return HoldAtExtractUntil is null || HoldAtExtractUntil > DateTimeOffset.UtcNow;
 249    }
 250
 251    private string GetOpeningPhaseSummary()
 252    {
 0253        if (Matches(SurpriseSide, "Player"))
 254        {
 0255            return "You spotted them first.";
 256        }
 257
 0258        if (Matches(SurpriseSide, "Enemy"))
 259        {
 0260            return "They ambushed you.";
 261        }
 262
 0263        if (Matches(InitiativeWinner, "Player"))
 264        {
 0265            return "You won initiative.";
 266        }
 267
 0268        if (Matches(InitiativeWinner, "Enemy"))
 269        {
 0270            return "Enemy won initiative.";
 271        }
 272
 0273        if (Matches(ContactState, "PlayerAmbush"))
 274        {
 0275            return "You spotted them first.";
 276        }
 277
 0278        if (Matches(ContactState, "EnemyAmbush"))
 279        {
 0280            return "They ambushed you.";
 281        }
 282
 0283        return string.Empty;
 284    }
 285
 286    private static bool Matches(string value, string expected)
 287    {
 0288        return string.Equals(value, expected, StringComparison.OrdinalIgnoreCase);
 289    }
 290
 291    private static bool IsEquipable(Item item)
 292    {
 0293        return item.Type is ItemType.Weapon or ItemType.Armor or ItemType.Backpack;
 294    }
 295
 296    private string GetExtractHoldCountdownText()
 297    {
 0298        if (HoldAtExtractUntil is null)
 299        {
 0300            return string.Empty;
 301        }
 302
 0303        var left = HoldAtExtractUntil.Value - DateTimeOffset.UtcNow;
 0304        if (left < TimeSpan.Zero)
 305        {
 0306            left = TimeSpan.Zero;
 307        }
 308
 0309        return $"{left.Minutes:D2}:{left.Seconds:D2}";
 310    }
 311
 312    private bool IsTooHeavyToCarry(Item item)
 313    {
 0314        return RaidEncumbrance() + Math.Max(0, item.Weight) > Raid.MaxEncumbrance;
 315    }
 316
 317    private bool IsBlockedByLootSlots(Item item)
 318    {
 0319        return LootSlots + item.Slots > Raid.BackpackCapacity;
 320    }
 321
 322    private int RaidEncumbrance()
 323    {
 0324        return CombatBalance.GetTotalEncumbrance(Raid.Inventory.GetExtractableItems());
 325    }
 326
 327    private EncumbranceTier GetDisplayedEncumbranceTier()
 328    {
 0329        if (Raid.MaxEncumbrance <= 0)
 330        {
 0331            return EncumbranceTier.Light;
 332        }
 333
 0334        var carriedWeight = RaidEncumbrance();
 0335        var lightThreshold = Raid.MaxEncumbrance / 3;
 0336        var mediumThreshold = (Raid.MaxEncumbrance * 2) / 3;
 337
 0338        if (carriedWeight <= lightThreshold)
 339        {
 0340            return EncumbranceTier.Light;
 341        }
 342
 0343        if (carriedWeight <= mediumThreshold)
 344        {
 0345            return EncumbranceTier.Medium;
 346        }
 347
 0348        return EncumbranceTier.Heavy;
 349    }
 350
 351    private bool ShouldShowEncumbranceTier()
 352    {
 0353        return GetDisplayedEncumbranceTier() is not EncumbranceTier.Light;
 354    }
 355
 356    private string GetEncumbranceTierLabel()
 357    {
 0358        return GetDisplayedEncumbranceTier().ToString();
 359    }
 360
 361    private string GetEncumbranceSeverityCssClass()
 362    {
 0363        return GetDisplayedEncumbranceTier() switch
 0364        {
 0365            EncumbranceTier.Medium => "encumbrance-medium",
 0366            EncumbranceTier.Heavy => "encumbrance-heavy",
 0367            _ => string.Empty
 0368        };
 369    }
 370}

Methods/Properties

BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder)
get_Raid()
get_MaxHealth()
get_AmmoHudText()
get_Medkits()
get_LootSlots()
get_RaidEncumbranceText()
get_Challenge()
get_DistanceFromExtract()
get_EncounterType()
get_EncounterTitle()
get_EncounterDescription()
get_ContactState()
get_SurpriseSide()
get_InitiativeWinner()
get_OpeningActionsRemaining()
get_SurprisePersistenceEligible()
get_EnemyName()
get_EnemyHealth()
get_LootContainer()
get_DiscoveredLoot()
get_CarriedLoot()
get_EquippedItems()
get_LogEntries()
get_AwaitingDecision()
get_CanAttack()
get_CanAttackEnabled()
get_CanBurstFire()
get_CanBurstFireEnabled()
get_CanFullAuto()
get_CanFullAutoEnabled()
get_CanReload()
get_CanUseMedkit()
get_CanLootItem()
get_CanEquipItem()
get_ExtractHoldActive()
get_HoldAtExtractUntil()
get_OnAttack()
get_OnBurstFire()
get_OnFullAuto()
get_OnReload()
get_OnFlee()
get_OnUseMedkit()
get_OnTakeLoot()
get_OnDropCarried()
get_OnDropEquipped()
get_OnEquipFromDiscovered()
get_OnEquipFromCarried()
get_OnAttemptExtract()
get_OnGoDeeper()
get_OnStartExtractHold()
get_OnCancelExtractHold()
get_OnMoveTowardExtract()
IsExtractHoldEffectivelyActive()
GetOpeningPhaseSummary()
Matches(System.String,System.String)
IsEquipable(RaidLoop.Core.Item)
GetExtractHoldCountdownText()
IsTooHeavyToCarry(RaidLoop.Core.Item)
IsBlockedByLootSlots(RaidLoop.Core.Item)
RaidEncumbrance()
GetDisplayedEncumbranceTier()
ShouldShowEncumbranceTier()
GetEncumbranceTierLabel()
GetEncumbranceSeverityCssClass()