Skip to content
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
64a75f9
feat: add location entity model
utilForever Jul 30, 2026
c2e900e
refactor: distinguish field minions from occupants
utilForever Jul 30, 2026
6fb20cd
test: update field minion accessors
utilForever Jul 30, 2026
63adf57
feat: support location play and activation
utilForever Jul 30, 2026
8bdae4c
feat(impl-card): implement card 'Great Hall' (REV_983)
utilForever Jul 30, 2026
5fcdbb0
feat(impl-card): implement card 'Demolition Renovator' (REV_023)
utilForever Jul 30, 2026
4b50ffe
chore: format touched sources
utilForever Jul 30, 2026
4a27557
refactor: model locations as field characters
utilForever Jul 30, 2026
a6275f2
fix: report location activation availability
utilForever Jul 30, 2026
764138a
feat(impl-card): update card 'Murozond the Infinite' (CORE_DRG_090)
utilForever Jul 30, 2026
513c738
feat(impl-card): update card 'Murozond the Infinite' (DRG_090)
utilForever Jul 30, 2026
a09800b
refactor: move operator[] definition to source file
utilForever Jul 30, 2026
bac2326
feat(impl-card): update card 'Tess Greymane' (GIL_598)
utilForever Jul 31, 2026
2f07df4
fix: harden Location aura and targeting interactions
utilForever Jul 31, 2026
1cda4f9
fix: exclude Locations from minion presence checks
utilForever Jul 31, 2026
537ff64
docs: update card implementation progress
utilForever Aug 2, 2026
9226537
fix: harden location interactions
utilForever Aug 2, 2026
046b390
refactor: centralize played-card replay
utilForever Aug 2, 2026
7d242e4
refactor: simplify location-aware field access
utilForever Aug 2, 2026
c1db036
refactor: streamline location play and targeting
utilForever Aug 2, 2026
0fdd498
test: strengthen location integration coverage
utilForever Aug 3, 2026
c0f81d9
test: enable command-line arguments for doctest
utilForever Aug 3, 2026
329c63c
chore: exclude Rider user settings from version control
utilForever Aug 3, 2026
4dcf49b
fix: enforce location play requirements
utilForever Aug 3, 2026
6133f9c
fix: avoid empty replay target ranges
utilForever Aug 3, 2026
e45b4cd
fix: resolve replay choices by entity ID
utilForever Aug 3, 2026
f555b09
test: play locations through the game flow
utilForever Aug 3, 2026
7f1b23b
perf: count field minions without allocation
utilForever Aug 3, 2026
372f8bc
test: distinguish rolling fireball location cases
utilForever Aug 3, 2026
15908cc
refactor: scope played card type check
utilForever Aug 3, 2026
4253d93
refactor: simplify replay card cases
utilForever Aug 3, 2026
632b191
refactor: update card 'Bloodboil Brute' (BT_138)
utilForever Aug 3, 2026
055f45c
refactor: scope graveyard requirement data
utilForever Aug 3, 2026
600db61
refactor: mark adjacent aura updates const
utilForever Aug 3, 2026
e795ebd
refactor: mark field zone reference const
utilForever Aug 3, 2026
8ad97cb
refactor: improve code readability and location test clarity
utilForever Aug 3, 2026
0619df8
refactor: replace static_cast with std::to_underlying
utilForever Aug 3, 2026
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
6 changes: 3 additions & 3 deletions Documents/CardList - Standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ REVENDRETH | REV_019 | Famished Fool | O
REVENDRETH | REV_020 | Dinner Performer |
REVENDRETH | REV_021 | Kael'thas Sinstrider |
REVENDRETH | REV_022 | Murloc Holmes |
REVENDRETH | REV_023 | Demolition Renovator |
REVENDRETH | REV_023 | Demolition Renovator | O
REVENDRETH | REV_238 | Theotar, the Mad Duke |
REVENDRETH | REV_239 | Suffocating Shadows |
REVENDRETH | REV_240 | Tome Tampering |
Expand Down Expand Up @@ -1145,10 +1145,10 @@ REVENDRETH | REV_958 | Buffet Biggun |
REVENDRETH | REV_959 | Ghastly Gravedigger |
REVENDRETH | REV_960 | Ashen Elemental |
REVENDRETH | REV_961 | Elitist Snob |
REVENDRETH | REV_983 | Great Hall |
REVENDRETH | REV_983 | Great Hall | O
REVENDRETH | REV_990 | Sanguine Depths |

- Progress: 10% (17 of 170 Cards)
- Progress: 11% (19 of 170 Cards)

## March of the Lich King

Expand Down
4 changes: 0 additions & 4 deletions Folder.DotSettings.user

This file was deleted.

2 changes: 1 addition & 1 deletion Includes/Rosetta/Common/Utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void EraseIf(ContainerT& items, const PredicateT& predicate)
//! \return A list of N distinct elements.
template <typename T, std::size_t N>
std::vector<std::remove_cv_t<T>> ChooseNElements(std::span<T, N> list,
std::size_t amount)
std::size_t amount)
{
std::vector<std::remove_cv_t<T>> results(list.begin(), list.end());

Expand Down
12 changes: 12 additions & 0 deletions Includes/Rosetta/PlayMode/Actions/PlayCard.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#ifndef ROSETTASTONE_PLAYMODE_PLAY_CARD_HPP
#define ROSETTASTONE_PLAYMODE_PLAY_CARD_HPP

#include <Rosetta/PlayMode/Models/Location.hpp>
#include <Rosetta/PlayMode/Models/Minion.hpp>
#include <Rosetta/PlayMode/Models/Player.hpp>
#include <Rosetta/PlayMode/Models/Spell.hpp>
Expand Down Expand Up @@ -52,6 +53,17 @@ void PlaySpell(Player* player, Spell* spell, Character* target = nullptr,
//! \param weapon A pointer to weapon card to play.
//! \param target A target of the character to receive power.
void PlayWeapon(Player* player, Weapon* weapon, Character* target = nullptr);

//! Plays a location card from player's hand.
//! \param player The player to play location card.
//! \param location A pointer to location card to play.
//! \param fieldPos A value indicating where to place card.
void PlayLocation(Player* player, Location* location, int fieldPos = -1);

//! Replays a card without paying its cost.
//! \param player The player to replay the card.
//! \param card The card to replay.
void ReplayCard(Player* player, Card* card);
} // namespace RosettaStone::PlayMode::Generic

#endif // ROSETTASTONE_PLAYMODE_PLAY_CARD_HPP
53 changes: 53 additions & 0 deletions Includes/Rosetta/PlayMode/Models/Location.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#ifndef ROSETTASTONE_PLAYMODE_LOCATION_HPP
#define ROSETTASTONE_PLAYMODE_LOCATION_HPP

#include <Rosetta/PlayMode/Models/Character.hpp>

namespace RosettaStone::PlayMode
{
//!
//! \brief Location class.
//!
//! Locations are a type of card first introduced in the Murder at Castle
//! Nathria expansion. Locations are played onto the battlefield for an initial
//! cost, and then have an ability that can be activated for free on the
//! player's turns. Each activation costs 1 Health and has a cooldown of 1
//! turn where it cannot be used.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
//!
class Location : public Character
{
public:
//! Constructs location with given \p _player, \p _card, \p tags and \p id.
Location(Player* _player, Card* _card, std::map<GameTag, int> tags,
int id = -1);

//! Default destructor.
~Location() override = default;

//! Returns whether this location is on cooldown.
bool IsOnCooldown() const;

//! Sets whether this location is on cooldown.
void SetOnCooldown(bool onCooldown);

//! Returns false because locations cannot attack.
bool CanAttack() const override;

//! Returns whether this location can be activated by its owner.
bool IsPlayableByPlayer() override;

//! Consumes one Health and starts the cooldown.
void Use();

//! Removes the location from the battlefield.
void Destroy() override;
};
} // namespace RosettaStone::PlayMode

#endif // ROSETTASTONE_PLAYMODE_LOCATION_HPP
1 change: 1 addition & 0 deletions Includes/Rosetta/PlayMode/Tasks/PlayerTasks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
#include <Rosetta/PlayMode/Tasks/PlayerTasks/EndTurnTask.hpp>
#include <Rosetta/PlayMode/Tasks/PlayerTasks/HeroPowerTask.hpp>
#include <Rosetta/PlayMode/Tasks/PlayerTasks/PlayCardTask.hpp>
#include <Rosetta/PlayMode/Tasks/PlayerTasks/PlayLocationTask.hpp>

#endif // ROSETTASTONE_PLAYMODE_PLAYER_TASKS_HPP
5 changes: 5 additions & 0 deletions Includes/Rosetta/PlayMode/Tasks/PlayerTasks/PlayCardTask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ class PlayCardTask : public ITask
static PlayCardTask MinionTarget(Entity* source, Playable* target,
int chooseOne = 0);

//! PlayCardTask wrapper for location.
//! \param source A pointer to source location to play.
//! \return Generated PlayCardTask for intended purpose.
static PlayCardTask Location(Entity* source);

//! PlayCardTask wrapper for spell without target.
//! \param source A pointer to source entity to play card.
//! \param chooseOne The index of chosen card from two cards.
Expand Down
34 changes: 34 additions & 0 deletions Includes/Rosetta/PlayMode/Tasks/PlayerTasks/PlayLocationTask.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2026 Chris Ohk

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#ifndef ROSETTASTONE_PLAYMODE_PLAY_LOCATION_TASK_HPP
#define ROSETTASTONE_PLAYMODE_PLAY_LOCATION_TASK_HPP

#include <Rosetta/PlayMode/Tasks/ITask.hpp>

namespace RosettaStone::PlayMode::PlayerTasks
{
//!
//! \brief PlayLocationTask class.
//!
//! This class activates a location already on the battlefield.
//!
class PlayLocationTask : public ITask
{
public:
//! Constructs task with given \p source and \p target.
explicit PlayLocationTask(Entity* source, Playable* target = nullptr);

private:
//! Processes task logic internally and returns meta data.
TaskStatus Impl(Player* player) override;

//! Internal method of Clone().
std::unique_ptr<ITask> CloneImpl() override;
};
} // namespace RosettaStone::PlayMode::PlayerTasks

#endif // ROSETTASTONE_PLAYMODE_PLAY_LOCATION_TASK_HPP
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ namespace RosettaStone::PlayMode::SimpleTasks
class ConsecutiveDamageTask : public ITask
{
public:
//! Constructs task with given \p entityType, \p damages and \p isSpellDamage.
//! Constructs task with given \p entityType, \p damages and \p
//! isSpellDamage.
//! \param entityType The entity type of target to take damages.
//! \param damages A list of values indicating how much to take.
//! \param isSpellDamage true if it is spell damage, and false otherwise.
Expand Down
3 changes: 2 additions & 1 deletion Includes/Rosetta/PlayMode/Tasks/SimpleTasks/DamageTask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ namespace RosettaStone::PlayMode::SimpleTasks
class DamageTask : public ITask
{
public:
//! Constructs task with given \p entityType, \p damage and \p isSpellDamage.
//! Constructs task with given \p entityType, \p damage and \p
//! isSpellDamage.
//! \param entityType The entity type of target to take damage.
//! \param damage A value indicating how much to take.
//! \param isSpellDamage true if it is spell damage, and false otherwise.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ enum class DiscardType
DEFAULT, //!< Don't care.
LOWEST_COST, //!< Lowest cost card.
HIGHEST_COST, //!< Highest cost card.
ENEMY_MINION, //!< A random enemy minion.
ENEMY_MINION, //!< A random enemy minion.
};

//!
Expand Down
3 changes: 2 additions & 1 deletion Includes/Rosetta/PlayMode/Tasks/SimpleTasks/SummonTask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class SummonTask : public ITask
//! \param amount The number of minions to summon.
explicit SummonTask(SummonSide side = SummonSide::DEFAULT,
std::optional<Card*> card = std::nullopt,
bool removeFromStack = false, bool addToStack = false, int amount = 1);
bool removeFromStack = false, bool addToStack = false,
int amount = 1);

//! Constructs task with given \p cardID, \p side and \p addToStack.
//! \param cardID The card ID to summon.
Expand Down
34 changes: 27 additions & 7 deletions Includes/Rosetta/PlayMode/Zones/FieldZone.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define ROSETTASTONE_PLAYMODE_FIELD_ZONE_HPP

#include <Rosetta/PlayMode/Auras/AdjacentAura.hpp>
#include <Rosetta/PlayMode/Models/Location.hpp>
#include <Rosetta/PlayMode/Models/Minion.hpp>
#include <Rosetta/PlayMode/Zones/Zone.hpp>

Expand All @@ -24,20 +25,33 @@ namespace RosettaStone::PlayMode
//! battlefield selection. Battlefields are chosen at random and are independent
//! of the heroes chosen by players or used by the Innkeeper.
//!
class FieldZone : public PositioningZone<Minion>
class FieldZone : public PositioningZone<Character>
{
public:
//! Constructs field zone with given \p player.
//! \param player The player.
explicit FieldZone(Player* player);

//! Returns the minion at \p zonePos.
//! \param zonePos The zone position of minion.
//! \return The minion at \p zonePos, or nullptr for another field entity.
Minion* operator[](int zonePos);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

//! Returns the number of minions except untouchables.
//! \return The number of minions except untouchables.
int GetCountExceptUntouchables() const;

//! Returns all entities in board zone.
//! \return A list of entity in board zone.
std::vector<Minion*> GetAll() override;
//! Returns the number of minions.
//! \return The number of minions.
int GetMinionCount() const;

//! Returns all minions in board zone.
//! \return A list of minions in board zone.
std::vector<Minion*> GetMinions() const;

//! Returns all locations in board zone.
//! \return A list of locations in board zone.
std::vector<Location*> GetLocations() const;

//! Adds the specified entity into this zone, at the given position.
//! \param entity The entity.
Expand All @@ -57,16 +71,22 @@ class FieldZone : public PositioningZone<Minion>
//! Activates a minion's trigger and aura and
//! applies it's spell power increment.
//! \param entity The entity to activate aura.
static void ActivateAura(Minion* entity);
static void ActivateAura(Playable* entity);

//! Registers an adjacent aura on this field.
//! \param aura The adjacent aura.
void AddAdjacentAura(AdjacentAura* aura);

std::vector<AdjacentAura*> adjacentAuras;
//! Marks every adjacent aura for an update.
void MarkAdjacentAurasDirty() const;

private:
//! Removes a minion's trigger and aura and
//! applies it's spell power increment.
//! \param entity The entity to remove aura.
static void RemoveAura(const Minion* entity);
static void RemoveAura(const Playable* entity);

std::vector<AdjacentAura*> m_adjacentAuras;
int m_untouchableCount = 0;
};
} // namespace RosettaStone::PlayMode
Expand Down
2 changes: 2 additions & 0 deletions Includes/Rosetta/RosettaStone.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
#include <Rosetta/PlayMode/Models/Entity.hpp>
#include <Rosetta/PlayMode/Models/Hero.hpp>
#include <Rosetta/PlayMode/Models/HeroPower.hpp>
#include <Rosetta/PlayMode/Models/Location.hpp>
#include <Rosetta/PlayMode/Models/Minion.hpp>
#include <Rosetta/PlayMode/Models/Playable.hpp>
#include <Rosetta/PlayMode/Models/Player.hpp>
Expand All @@ -176,6 +177,7 @@
#include <Rosetta/PlayMode/Tasks/PlayerTasks/EndTurnTask.hpp>
#include <Rosetta/PlayMode/Tasks/PlayerTasks/HeroPowerTask.hpp>
#include <Rosetta/PlayMode/Tasks/PlayerTasks/PlayCardTask.hpp>
#include <Rosetta/PlayMode/Tasks/PlayerTasks/PlayLocationTask.hpp>
#include <Rosetta/PlayMode/Tasks/PlayerTasks/TradeCardTask.hpp>
#include <Rosetta/PlayMode/Tasks/SimpleTasks.hpp>
#include <Rosetta/PlayMode/Tasks/SimpleTasks/ActivateCapturedDeathrattleTask.hpp>
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ Implementation progress is generated from the `Implemented` column in the card l
| United in Stormwind | 60 | 170 | 35.3% |
| Fractured in Alterac Valley | 61 | 170 | 35.9% |
| Voyage to the Sunken City | 22 | 170 | 12.9% |
| Murder at Castle Nathria | 17 | 170 | 10% |
| Murder at Castle Nathria | 19 | 170 | 11.2% |
| March of the Lich King | 0 | 1 | 0% |
| **Total** | **546** | **1101** | **49.6%** |
| **Total** | **548** | **1101** | **49.8%** |

### [Wild Format](Documents/CardList%20-%20Wild.md)

Expand Down
14 changes: 7 additions & 7 deletions Sources/Rosetta/Battlegrounds/Cards/Card.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,14 @@ int Card::GetTier() const

bool Card::IsPlayableByCardReq([[maybe_unused]] Player& player) const
{
//for (const auto& playReq : playRequirements)
// for (const auto& playReq : playRequirements)
//{
// switch (playReq.first)
// {
// default:
// break;
// }
//}
// switch (playReq.first)
// {
// default:
// break;
// }
// }

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ TaskStatus CountTask::Run(Player& player, Minion& source)
switch (m_numIndex)
{
case 0:
player.taskStack.num = count;
player.taskStack.num = count;
break;
default:
throw std::invalid_argument(
Expand Down
Loading
Loading