Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Show enemy productivity overlay" cheat #1738

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions libs/s25main/CheatCommandTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ void CheatCommandTracker::onChatCommand(const std::string& cmd)
cheats_.armageddon();
else if(cmd == "impulse9")
cheats_.toggleAllBuildingsEnabled();
else if(cmd == "spies")
cheats_.toggleShowEnemyProductivityOverlay();
}

bool CheatCommandTracker::checkSpecialKeyEvent(const KeyEvent& ke)
Expand Down
11 changes: 11 additions & 0 deletions libs/s25main/Cheats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ void Cheats::toggleAllBuildingsEnabled()
areAllBuildingsEnabled_ = !areAllBuildingsEnabled_;
}

void Cheats::toggleShowEnemyProductivityOverlay()
{
// In S2, if you enabled cheats you would automatically see the enemy productivity overlay - most importantly what
// buildings the enemy intends to build.
// In RTTR, the user must explicitly enable this feature after enabling cheats.
if(isCheatModeOn())
shouldShowEnemyProductivityOverlay_ = !shouldShowEnemyProductivityOverlay_;
}

void Cheats::toggleHumanAIPlayer()
{
if(isCheatModeOn() && !GAMECLIENT.IsReplayModeOn())
Expand All @@ -68,6 +77,8 @@ void Cheats::turnAllCheatsOff()
toggleAllVisible();
if(areAllBuildingsEnabled_)
toggleAllBuildingsEnabled();
if(shouldShowEnemyProductivityOverlay_)
toggleShowEnemyProductivityOverlay();
if(isHumanAIPlayer_)
toggleHumanAIPlayer();
}
4 changes: 4 additions & 0 deletions libs/s25main/Cheats.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class Cheats
void toggleAllBuildingsEnabled();
bool areAllBuildingsEnabled() const { return areAllBuildingsEnabled_; }

void toggleShowEnemyProductivityOverlay();
bool shouldShowEnemyProductivityOverlay() const { return shouldShowEnemyProductivityOverlay_; }

// RTTR cheats
void toggleHumanAIPlayer();
void armageddon() const;
Expand All @@ -33,6 +36,7 @@ class Cheats
bool isCheatModeOn_ = false;
bool isAllVisible_ = false;
bool areAllBuildingsEnabled_ = false;
bool shouldShowEnemyProductivityOverlay_ = false;
bool isHumanAIPlayer_ = false;
GameWorldBase& world_;
};
7 changes: 6 additions & 1 deletion libs/s25main/world/GameWorldView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

#include "world/GameWorldView.h"
#include "CatapultStone.h"
#include "Cheats.h"
#include "FOWObjects.h"
#include "GameInterface.h"
#include "GamePlayer.h"
#include "GlobalGameSettings.h"
#include "Loader.h"
Expand Down Expand Up @@ -370,7 +372,10 @@ void GameWorldView::DrawNameProductivityOverlay(const TerrainRenderer& terrainRe
auto* attackAidImage = LOADER.GetImageN("map_new", 20000);
attackAidImage->DrawFull(curPos - DrawPoint(0, attackAidImage->getHeight()));
}
continue;
// Do not draw enemy productivity overlay unless the object is visible AND the related cheat is on
if(!(gwv.GetVisibility(pt) == Visibility::Visible
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather put that at the top of both to make it clearer:

if != Visible -> continue
if addon -> draw military aid
// Skip drawing the name and productivity below if not enabled (or similar comment)
if !prod Overlay enabled -> continue

Although the first check isn't exactly there it is there implicitly as you cannot attack when you don't see the building. So !visible implies numSoldiers=0

This avoids the if(!(conditions)) which is (slightly) more complex.

And while touching this code: Can you move the checks for the addon and cheat, and loading the image out of the loop please? This is a hot loop that is run very often (in times and iterations) so we can move those constants, that might not be obvious constants to the compiler, to a single place as const variables.
Speaking of those: The visibility check has a few constant conditions Maybe we split that into 2 functions IsAllVisible and CalcVisibility (both called from the current function) but move a call to the first out of the loop to a constant and use the 2nd here as if (!isAllVisible && !gwv.CalcVisibility(pt)) Although I don't expect that there are too many enemy buildings in the current view that there is a huge impact. So impact is low.
But moving the 2 "constants" used here out of the loop is trivial enough to be worth it without measuring.

And possibly also the 2 lines at the top for coordinate transform below the no check directly on top of curPos = .

This isn't exactly part of the PR topic but I like to do such small cleanups when touching code ("Boy Scout Rule")

&& GetWorld().GetGameInterface()->GI_GetCheats().shouldShowEnemyProductivityOverlay()))
continue;
}

// Draw object name
Expand Down
21 changes: 19 additions & 2 deletions tests/s25Main/integration/testCheats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,16 @@ BOOST_FIXTURE_TEST_CASE(TurningCheatModeOffDisablesAllCheats, CheatsFixture)
{
cheats.toggleCheatMode();
cheats.toggleAllVisible();
BOOST_TEST_REQUIRE(cheats.isAllVisible() == true);
cheats.toggleAllBuildingsEnabled();
cheats.toggleShowEnemyProductivityOverlay();
BOOST_TEST_REQUIRE(cheats.isAllVisible() == true);
BOOST_TEST_REQUIRE(cheats.areAllBuildingsEnabled() == true);
BOOST_TEST_REQUIRE(cheats.shouldShowEnemyProductivityOverlay() == true);

cheats.toggleCheatMode();
BOOST_TEST_REQUIRE(cheats.isAllVisible() == false);
BOOST_TEST_REQUIRE(cheats.areAllBuildingsEnabled() == false);
BOOST_TEST_REQUIRE(cheats.shouldShowEnemyProductivityOverlay() == false);
// testing toggleHumanAIPlayer would require GameClient::state==Loaded, which is guaranteed in code (because Cheats
// only exist after the game is loaded) but is not the case in tests - skipping
}
Expand Down Expand Up @@ -107,18 +111,31 @@ BOOST_FIXTURE_TEST_CASE(CanToggleAllVisible_IfCheatModeIsOn, CheatsFixture)
BOOST_TEST_REQUIRE((viewer.GetVisibility(farawayPos) == Visibility::Visible) == true);
}

BOOST_FIXTURE_TEST_CASE(CanToggleAllBuildingsEnabled_IfCheatModeIsOn, CheatsFixture)
BOOST_FIXTURE_TEST_CASE(CanToggleAllBuildingsEnabled_AndShowEnemyProductivityOverlay_IfCheatModeIsOn, CheatsFixture)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the increasing length in name and that the first 6 lines seem to test the opposite I'd suggest to name this something like Can change cheats (only) if cheat mode is enabled. Instead of "only if" you can use "iff" which is shorter and more clear even if someone doesn't know the difference between "if" and "iff" (i.e. "if and only if").

{
BOOST_TEST_REQUIRE(cheats.areAllBuildingsEnabled() == false);
BOOST_TEST_REQUIRE(cheats.shouldShowEnemyProductivityOverlay() == false);

cheats.toggleAllBuildingsEnabled();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test should be exactly after the call to make sure that e.g. toggleShowEnemyProductivityOverlay doesn't change buildingsEnabled. Or at least for the enabling and subsequent disabling below. At least in one place. I.e.:

  • Cheat mode off. Toggle all. Check all disabled
  • Cheat mode on. Toggle all. Check all enabled
  • Toggle each individually of, check only that changed until all are off
  • Optional: Do the same with enabling all one-by-one or use that instead of the 2nd point which is likely better/shorter

cheats.toggleShowEnemyProductivityOverlay();
BOOST_TEST_REQUIRE(cheats.areAllBuildingsEnabled() == false);
BOOST_TEST_REQUIRE(cheats.shouldShowEnemyProductivityOverlay() == false);

cheats.toggleCheatMode();
cheats.toggleAllBuildingsEnabled();
cheats.toggleShowEnemyProductivityOverlay();
BOOST_TEST_REQUIRE(cheats.areAllBuildingsEnabled() == true);
BOOST_TEST_REQUIRE(cheats.shouldShowEnemyProductivityOverlay() == true);

cheats.toggleAllBuildingsEnabled();
cheats.toggleShowEnemyProductivityOverlay();
BOOST_TEST_REQUIRE(cheats.areAllBuildingsEnabled() == false);
BOOST_TEST_REQUIRE(cheats.shouldShowEnemyProductivityOverlay() == false);

cheats.toggleAllBuildingsEnabled();
cheats.toggleShowEnemyProductivityOverlay();
BOOST_TEST_REQUIRE(cheats.areAllBuildingsEnabled() == true);
BOOST_TEST_REQUIRE(cheats.shouldShowEnemyProductivityOverlay() == true);
}

BOOST_AUTO_TEST_SUITE_END()
Loading