Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions BazaarAccess/Accessibility/AccessibleMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ public enum AccessibleKey
PrevMessage, // Comma - Previous message
// Additional information
Info, // I - Property/keyword info for the item
Inspect, // X - inspect the current selection when the game supports an inspect-style tooltip
// Upgrade
Upgrade, // Shift+U - Upgrade item at pedestal
// Board and Stash info
Expand Down
4 changes: 4 additions & 0 deletions BazaarAccess/Core/KeyboardNavigator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ private AccessibleKey MapKey(Event e)
case KeyCode.I:
return AccessibleKey.Info;

// Inspect current selection
case KeyCode.X:
return AccessibleKey.Inspect;

// Upgrade item (U or Shift+U)
case KeyCode.U:
return AccessibleKey.Upgrade;
Expand Down
33 changes: 27 additions & 6 deletions BazaarAccess/Gameplay/ActionMenuHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace BazaarAccess.Gameplay;
/// </summary>
public enum ActionOption
{
Details,
Sell,
Upgrade,
Enchant,
Expand All @@ -32,8 +33,9 @@ public enum ActionOption
public class ActionMenuHandler
{
private readonly GameplayNavigator _navigator;
private readonly Action<Card, bool?> _onUpgradeConfirm;
private readonly Action<Card> _onUsePedestalAction;
private readonly Action _onRefreshAndAnnounce;
private readonly Action<Card> _onShowDetails;

// Action mode state
private bool _isInActionMode = false;
Expand All @@ -51,11 +53,16 @@ public class ActionMenuHandler
/// </summary>
public Card ActionCard => _actionCard;

public ActionMenuHandler(GameplayNavigator navigator, Action<Card, bool?> onUpgradeConfirm, Action onRefreshAndAnnounce)
public ActionMenuHandler(
GameplayNavigator navigator,
Action<Card> onUsePedestalAction,
Action onRefreshAndAnnounce,
Action<Card> onShowDetails)
{
_navigator = navigator;
_onUpgradeConfirm = onUpgradeConfirm;
_onUsePedestalAction = onUsePedestalAction;
_onRefreshAndAnnounce = onRefreshAndAnnounce;
_onShowDetails = onShowDetails;
}

/// <summary>
Expand All @@ -78,6 +85,11 @@ public void Enter(Card card)
bool isInStash = _navigator.CurrentSection == NavigationSection.Stash;
bool stashOpen = _navigator.IsStashOpen();

if (card is ItemCard)
{
_actionOptions.Add(ActionOption.Details);
}

// Build available options
// At pedestal, show Upgrade/Enchant first (primary action)
if (currentState == ERunState.Pedestal)
Expand Down Expand Up @@ -331,6 +343,9 @@ private string GetActionOptionText(ActionOption option)
{
switch (option)
{
case ActionOption.Details:
return "Details";

case ActionOption.Sell:
int sellPrice = ItemReader.GetSellPrice(_actionCard);
return $"Sell for {sellPrice} gold (S)";
Expand Down Expand Up @@ -398,6 +413,13 @@ private void ExecuteActionOption(ActionOption option)

switch (option)
{
case ActionOption.Details:
if (itemCard != null)
{
_onShowDetails?.Invoke(itemCard);
}
break;

case ActionOption.Sell:
if (itemCard != null)
{
Expand All @@ -410,17 +432,16 @@ private void ExecuteActionOption(ActionOption option)
break;

case ActionOption.Upgrade:
// Show confirmation dialog with preview instead of executing directly
if (itemCard != null)
{
_onUpgradeConfirm(itemCard, false);
_onUsePedestalAction?.Invoke(itemCard);
}
break;

case ActionOption.Enchant:
if (itemCard != null)
{
_onUpgradeConfirm(itemCard, true);
_onUsePedestalAction?.Invoke(itemCard);
}
break;

Expand Down
47 changes: 47 additions & 0 deletions BazaarAccess/Gameplay/CardReading/DetailLineBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ public static List<string> GetDetailLines(Card card)
if (card.Type == ECardType.PvpEncounter)
return EncounterReader.GetPvpEncounterDetailLines(card);

if (card.Type == ECardType.CombatEncounter)
{
return EncounterReader.GetCombatEncounterDetailLines(card);
}

return BuildDetailLines(card, enemyOrder: false);
}

Expand Down Expand Up @@ -224,6 +229,48 @@ private static List<string> BuildDetailLines(Card card, bool enemyOrder)

lines.Add(CardProperties.GetCardName(card));

if (RecapStatsReader.IsRecapViewActive())
{
if (enemyOrder)
{
lines.AddRange(RecapStatsReader.GetRecapLines(card));
AddDescriptionLines(lines, card);
AddAbilityLines(lines, card);

string recapCooldown = GetCooldownLineText(card);
if (recapCooldown != null) lines.Add(recapCooldown);

AddAllCombatStats(lines, card, EnemyCombatStats);

lines.Add(CardProperties.GetTierName(card));

string recapTags = CardProperties.GetTags(card);
if (!string.IsNullOrEmpty(recapTags)) lines.Add(recapTags);

string recapSizeText = GetSizeText(card);
if (recapSizeText != null) lines.Add(recapSizeText);
}
else
{
// Player board details are passed through DetailReader, which reverses lines before reading.
// Build recap-mode lines in reverse so the spoken order starts with name -> recap -> uses -> tier.
var reversedLines = new List<string>();

AddAbilityLines(reversedLines, card);
AddDescriptionLines(reversedLines, card);
reversedLines.Add(CardProperties.GetTierName(card));

var recapLines = RecapStatsReader.GetRecapLines(card);
recapLines.Reverse();
reversedLines.AddRange(recapLines);

reversedLines.Add(CardProperties.GetCardName(card));
return reversedLines;
}

return lines;
}

if (enemyOrder)
{
AddDescriptionLines(lines, card);
Expand Down
56 changes: 56 additions & 0 deletions BazaarAccess/Gameplay/CardReading/EncounterReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Reflection;
using System.Text;
using BazaarGameClient.Domain.Models.Cards;
using BazaarGameShared.Domain.Cards.Encounter.Combat;
using BazaarGameShared.Domain.Core.Types;
using TheBazaar;

Expand Down Expand Up @@ -39,6 +40,32 @@ public static string GetEncounterInfo(Card card)
return $"{name}, {type}, {tier}";
}

internal static List<string> GetCombatEncounterDetailLines(Card card)
{
var lines = new List<string>();
if (card == null) return lines;

lines.Add(CardProperties.GetCardName(card));
lines.Add(CardProperties.GetTierName(card));

if (TryGetCombatEncounterRewards(card, out uint monsterLevel, out int xpReward, out int goldReward))
{
lines.Add($"Level: {monsterLevel}");
lines.Add($"XP: {xpReward}");
lines.Add($"Gold: {goldReward}");
}

string desc = CardProperties.GetDescription(card);
if (!string.IsNullOrEmpty(desc))
lines.Add(desc);

string flavor = CardProperties.GetFlavorText(card);
if (!string.IsNullOrEmpty(flavor))
lines.Add(flavor);

return lines;
}

public static string GetEncounterDetailedInfo(Card card)
{
if (card == null) return "Empty";
Expand Down Expand Up @@ -78,6 +105,17 @@ public static string GetEncounterDetailedInfo(Card card)
sb.Append(", ");
sb.Append(GetEncounterTypeName(card.Type));

if (TryGetCombatEncounterRewards(card, out uint monsterLevel, out int xpReward, out int goldReward))
{
sb.Append(", Level ");
sb.Append(monsterLevel);
sb.Append(", ");
sb.Append(xpReward);
sb.Append(" XP, ");
sb.Append(goldReward);
sb.Append(" gold");
}

string desc = CardProperties.GetDescription(card);
if (!string.IsNullOrEmpty(desc))
{
Expand Down Expand Up @@ -234,6 +272,24 @@ private static string GetEncounterTypeName(ECardType type)
};
}

private static bool TryGetCombatEncounterRewards(Card card, out uint monsterLevel, out int xpReward, out int goldReward)
{
monsterLevel = 0;
xpReward = 0;
goldReward = 0;

if (card?.Type != ECardType.CombatEncounter)
return false;

if (card.Template is not TCardEncounterCombat combatTemplate)
return false;

monsterLevel = (combatTemplate.CombatantType as TCombatantMonster)?.Level ?? 0;
xpReward = combatTemplate.RewardCombatXp;
goldReward = combatTemplate.RewardCombatGold;
return true;
}

private static T GetPvpProperty<T>(object pvpOpponent, Type type, string propertyName)
{
try
Expand Down
52 changes: 9 additions & 43 deletions BazaarAccess/Gameplay/CardReading/RankReader.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Reflection;
using BazaarGameShared.Domain.Core.Types;
using BazaarGameShared.TempoNet.Enums;
using TheBazaar;

namespace BazaarAccess.Gameplay.CardReading;
Expand All @@ -12,55 +12,20 @@ internal static class RankReader
{
/// <summary>
/// Gets the player's ranked rank (e.g., "Silver 3", "Gold 1", "Legendary").
/// Uses reflection to access Data.Rank.CurrentSeasonRank.
/// Uses the current client rank cache populated by the game.
/// </summary>
public static string GetPlayerRank()
{
try
{
var dataType = typeof(Data);
var rankProp = dataType.GetProperty("Rank", BindingFlags.Public | BindingFlags.Static);
if (rankProp == null) return null;

var rankObj = rankProp.GetValue(null);
if (rankObj == null) return null;

var seasonRankProp = rankObj.GetType().GetProperty("CurrentSeasonRank",
BindingFlags.Public | BindingFlags.Instance);
if (seasonRankProp == null) return null;

var seasonRank = seasonRankProp.GetValue(rankObj);
if (seasonRank == null) return null;

var seasonType = seasonRank.GetType();

// Get ERank (Bronze, Silver, Gold, Diamond, Legendary)
string rankName = null;
var rankEnumProp = seasonType.GetProperty("Rank", BindingFlags.Public | BindingFlags.Instance);
if (rankEnumProp != null)
{
var val = rankEnumProp.GetValue(seasonRank);
if (val != null) rankName = val.ToString();
}
if (!ClientCache.Rank.HasData) return null;

var rank = ClientCache.Rank.Value;
string rankName = rank.Rank.ToString();
if (string.IsNullOrEmpty(rankName)) return null;

// Legendary has no division
if (rankName == "Legendary") return "Legendary";

// Get Division (1-4)
var divProp = seasonType.GetProperty("Division", BindingFlags.Public | BindingFlags.Instance);
if (divProp != null)
{
var divVal = divProp.GetValue(seasonRank);
if (divVal != null)
{
string div = divVal.ToString();
if (!string.IsNullOrEmpty(div) && div != "0")
return $"{rankName} {div}";
}
}

if (rank.Rank == ERank.Legendary) return rankName;
if (rank.Division > 0) return $"{rankName} {rank.Division}";
return rankName;
}
catch (Exception ex)
Expand All @@ -77,7 +42,8 @@ public static bool IsRankedMode()
{
try
{
return Data.RunConfiguration?.RunType == EPlayMode.Ranked;
return ClientCache.RunConfig.HasData &&
ClientCache.RunConfig.Value.RunType == EPlayMode.Ranked;
}
catch
{
Expand Down
Loading