Skip to content

Commit 79fa5fe

Browse files
authored
Merge pull request #1688 from kubaau/cheats_refactoring
Refactoring of existing cheats (see #1679)
2 parents 77372c5 + 9e790e3 commit 79fa5fe

File tree

9 files changed

+342
-42
lines changed

9 files changed

+342
-42
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org)
2+
//
3+
// SPDX-License-Identifier: GPL-2.0-or-later
4+
5+
#include "CheatCommandTracker.h"
6+
#include "Cheats.h"
7+
#include "driver/KeyEvent.h"
8+
9+
namespace {
10+
auto makeCircularBuffer(const std::string& str)
11+
{
12+
return boost::circular_buffer<char>{cbegin(str), cend(str)};
13+
}
14+
const auto enableCheatsStr = makeCircularBuffer("winter");
15+
} // namespace
16+
17+
CheatCommandTracker::CheatCommandTracker(Cheats& cheats) : cheats_(cheats), lastChars_(enableCheatsStr.size()) {}
18+
19+
void CheatCommandTracker::onKeyEvent(const KeyEvent& ke)
20+
{
21+
if(!cheats_.areCheatsAllowed())
22+
return;
23+
24+
if(checkSpecialKeyEvent(ke))
25+
lastChars_.clear();
26+
else
27+
onCharKeyEvent(ke);
28+
}
29+
30+
void CheatCommandTracker::onChatCommand(const std::string& cmd)
31+
{
32+
if(!cheats_.areCheatsAllowed())
33+
return;
34+
35+
if(cmd == "apocalypsis")
36+
cheats_.armageddon();
37+
}
38+
39+
bool CheatCommandTracker::checkSpecialKeyEvent(const KeyEvent& ke)
40+
{
41+
if(ke.kt == KeyType::Char)
42+
return false;
43+
44+
switch(ke.kt)
45+
{
46+
case KeyType::F10: cheats_.toggleHumanAIPlayer(); break;
47+
default: break;
48+
}
49+
50+
return true;
51+
}
52+
53+
void CheatCommandTracker::onCharKeyEvent(const KeyEvent& ke)
54+
{
55+
lastChars_.push_back(ke.c);
56+
57+
if(lastChars_ == enableCheatsStr)
58+
cheats_.toggleCheatMode();
59+
}

libs/s25main/CheatCommandTracker.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org)
2+
//
3+
// SPDX-License-Identifier: GPL-2.0-or-later
4+
5+
#pragma once
6+
7+
#include <boost/circular_buffer.hpp>
8+
#include <string>
9+
10+
class Cheats;
11+
struct KeyEvent;
12+
13+
class CheatCommandTracker
14+
{
15+
public:
16+
CheatCommandTracker(Cheats& cheats);
17+
18+
void onKeyEvent(const KeyEvent& ke);
19+
void onChatCommand(const std::string& cmd);
20+
21+
private:
22+
bool checkSpecialKeyEvent(const KeyEvent& ke);
23+
void onCharKeyEvent(const KeyEvent& ke);
24+
25+
Cheats& cheats_;
26+
boost::circular_buffer<char> lastChars_;
27+
};

libs/s25main/Cheats.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org)
2+
//
3+
// SPDX-License-Identifier: GPL-2.0-or-later
4+
5+
#include "Cheats.h"
6+
#include "network/GameClient.h"
7+
#include "world/GameWorldBase.h"
8+
9+
Cheats::Cheats(GameWorldBase& world) : world_(world) {}
10+
11+
bool Cheats::areCheatsAllowed() const
12+
{
13+
return world_.IsSinglePlayer();
14+
}
15+
16+
void Cheats::toggleCheatMode()
17+
{
18+
isCheatModeOn_ = !isCheatModeOn_;
19+
}
20+
21+
void Cheats::toggleHumanAIPlayer() const
22+
{
23+
if(isCheatModeOn() && !GAMECLIENT.IsReplayModeOn())
24+
GAMECLIENT.ToggleHumanAIPlayer(AI::Info{AI::Type::Default, AI::Level::Easy});
25+
}
26+
27+
void Cheats::armageddon() const
28+
{
29+
if(isCheatModeOn())
30+
GAMECLIENT.CheatArmageddon();
31+
}

libs/s25main/Cheats.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org)
2+
//
3+
// SPDX-License-Identifier: GPL-2.0-or-later
4+
5+
#pragma once
6+
7+
class GameWorldBase;
8+
9+
class Cheats
10+
{
11+
public:
12+
Cheats(GameWorldBase& world);
13+
14+
bool areCheatsAllowed() const;
15+
16+
void toggleCheatMode();
17+
bool isCheatModeOn() const { return isCheatModeOn_; }
18+
19+
void toggleHumanAIPlayer() const;
20+
void armageddon() const;
21+
22+
private:
23+
bool isCheatModeOn_ = false;
24+
GameWorldBase& world_;
25+
};

libs/s25main/GameInterface.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
#include "gameTypes/MapCoordinates.h"
88

9-
class Window;
10-
119
/// Interface, welches vom Spiel angesprocehn werden kann, um beispielsweise GUI wichtige Nachrichten
1210
/// zu übermiteln
1311
class GameInterface

libs/s25main/desktops/dskGameInterface.cpp

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ dskGameInterface::dskGameInterface(std::shared_ptr<Game> game, std::shared_ptr<c
105105
worldViewer(playerIdx, const_cast<Game&>(*game_).world_),
106106
gwv(worldViewer, Position(0, 0), VIDEODRIVER.GetRenderSize()), cbb(*LOADER.GetPaletteN("pal5")),
107107
actionwindow(nullptr), roadwindow(nullptr), minimap(worldViewer), isScrolling(false), zoomLvl(ZOOM_DEFAULT_INDEX),
108-
isCheatModeOn(false)
108+
cheats_(const_cast<Game&>(*game_).world_), cheatCommandTracker_(cheats_)
109109
{
110110
road.mode = RoadBuildMode::Disabled;
111111
road.point = MapPoint(0, 0);
@@ -424,7 +424,7 @@ void dskGameInterface::Msg_PaintAfter()
424424
DrawPoint iconPos(VIDEODRIVER.GetRenderSize().x - 56, 32);
425425

426426
// Draw cheating indicator icon (WINTER)
427-
if(isCheatModeOn)
427+
if(cheats_.isCheatModeOn())
428428
{
429429
glArchivItem_Bitmap* cheatingImg = LOADER.GetImageN("io", 75);
430430
cheatingImg->DrawFull(iconPos);
@@ -738,6 +738,8 @@ bool dskGameInterface::Msg_RightUp(const MouseCoords& /*mc*/) //-V524
738738
*/
739739
bool dskGameInterface::Msg_KeyDown(const KeyEvent& ke)
740740
{
741+
cheatCommandTracker_.onKeyEvent(ke);
742+
741743
switch(ke.kt)
742744
{
743745
default: break;
@@ -779,17 +781,6 @@ bool dskGameInterface::Msg_KeyDown(const KeyEvent& ke)
779781
case KeyType::F9: // Readme
780782
WINDOWMANAGER.ToggleWindow(std::make_unique<iwTextfile>("readme.txt", _("Readme!")));
781783
return true;
782-
case KeyType::F10:
783-
{
784-
#ifdef NDEBUG
785-
const bool allowHumanAI = isCheatModeOn;
786-
#else
787-
const bool allowHumanAI = true;
788-
#endif // !NDEBUG
789-
if(GAMECLIENT.GetState() == ClientState::Game && allowHumanAI && !GAMECLIENT.IsReplayModeOn())
790-
GAMECLIENT.ToggleHumanAIPlayer(AI::Info(AI::Type::Default, AI::Level::Easy));
791-
return true;
792-
}
793784
case KeyType::F11: // Music player (midi files)
794785
WINDOWMANAGER.ToggleWindow(std::make_unique<iwMusicPlayer>());
795786
return true;
@@ -798,28 +789,6 @@ bool dskGameInterface::Msg_KeyDown(const KeyEvent& ke)
798789
return true;
799790
}
800791

801-
static std::string winterCheat = "winter";
802-
switch(ke.c)
803-
{
804-
case 'w':
805-
case 'i':
806-
case 'n':
807-
case 't':
808-
case 'e':
809-
case 'r':
810-
curCheatTxt += char(ke.c);
811-
if(winterCheat.find(curCheatTxt) == 0)
812-
{
813-
if(curCheatTxt == winterCheat)
814-
{
815-
isCheatModeOn = !isCheatModeOn;
816-
curCheatTxt.clear();
817-
}
818-
} else
819-
curCheatTxt.clear();
820-
break;
821-
}
822-
823792
switch(ke.c)
824793
{
825794
case '+':
@@ -1127,9 +1096,9 @@ void dskGameInterface::ShowActionWindow(const iwAction::Tabs& action_tabs, MapPo
11271096

11281097
void dskGameInterface::OnChatCommand(const std::string& cmd)
11291098
{
1130-
if(cmd == "apocalypsis")
1131-
GAMECLIENT.CheatArmageddon();
1132-
else if(cmd == "surrender")
1099+
cheatCommandTracker_.onChatCommand(cmd);
1100+
1101+
if(cmd == "surrender")
11331102
GAMECLIENT.Surrender();
11341103
else if(cmd == "async")
11351104
(void)RANDOM.Rand(RANDOM_CONTEXT2(0), 255);

libs/s25main/desktops/dskGameInterface.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#pragma once
66

7+
#include "CheatCommandTracker.h"
8+
#include "Cheats.h"
79
#include "Desktop.h"
810
#include "GameInterface.h"
911
#include "IngameMinimap.h"
@@ -162,7 +164,8 @@ class dskGameInterface :
162164
bool isScrolling;
163165
Position startScrollPt;
164166
size_t zoomLvl;
165-
bool isCheatModeOn;
166-
std::string curCheatTxt;
167167
Subscription evBld;
168+
169+
Cheats cheats_;
170+
CheatCommandTracker cheatCommandTracker_;
168171
};
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org)
2+
//
3+
// SPDX-License-Identifier: GPL-2.0-or-later
4+
5+
#include "CheatCommandTracker.h"
6+
#include "Cheats.h"
7+
#include "driver/KeyEvent.h"
8+
#include "worldFixtures/CreateEmptyWorld.h"
9+
#include "worldFixtures/WorldFixture.h"
10+
11+
BOOST_AUTO_TEST_SUITE(CheatCommandTrackerTests)
12+
13+
namespace {
14+
template<unsigned T_numPlayers>
15+
struct CheatCommandTrackerFixture : WorldFixture<CreateEmptyWorld, T_numPlayers>
16+
{
17+
Cheats cheats_{this->world};
18+
CheatCommandTracker tracker_{cheats_};
19+
20+
KeyEvent makeKeyEvent(unsigned c) { return {KeyType::Char, c, false, false, false}; }
21+
KeyEvent makeKeyEvent(KeyType kt) { return {kt, 0, false, false, false}; }
22+
23+
void trackString(const std::string& str)
24+
{
25+
for(char c : str)
26+
tracker_.onKeyEvent(makeKeyEvent(c));
27+
}
28+
};
29+
using CheatCommandTrackerFixture1P = CheatCommandTrackerFixture<1>;
30+
using CheatCommandTrackerFixture2P = CheatCommandTrackerFixture<2>;
31+
} // namespace
32+
33+
BOOST_FIXTURE_TEST_CASE(CheatModeIsOffByDefault, CheatCommandTrackerFixture1P)
34+
{
35+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
36+
}
37+
38+
BOOST_FIXTURE_TEST_CASE(CheatModeCanBeTurnedOn, CheatCommandTrackerFixture1P)
39+
{
40+
trackString("winter");
41+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == true);
42+
}
43+
44+
BOOST_FIXTURE_TEST_CASE(CheatModeCannotBeTurnedOn_InMultiplayer, CheatCommandTrackerFixture2P)
45+
{
46+
trackString("winter");
47+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
48+
}
49+
50+
BOOST_FIXTURE_TEST_CASE(CheatModeCanBeTurnedOff, CheatCommandTrackerFixture1P)
51+
{
52+
trackString("winter");
53+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == true);
54+
trackString("winter");
55+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
56+
}
57+
58+
BOOST_FIXTURE_TEST_CASE(CheatModeCanBeTurnedOnAndOffRepeatedly, CheatCommandTrackerFixture1P)
59+
{
60+
trackString("winter");
61+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == true);
62+
trackString("winter");
63+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
64+
trackString("winter");
65+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == true);
66+
trackString("winter");
67+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
68+
}
69+
70+
BOOST_FIXTURE_TEST_CASE(CheatModeIsNotTurnedOn_WhenIncomplete, CheatCommandTrackerFixture1P)
71+
{
72+
trackString("winte");
73+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
74+
}
75+
76+
BOOST_FIXTURE_TEST_CASE(CheatModeIsNotTurnedOn_WhenInterruptedByAnotherKeyType, CheatCommandTrackerFixture1P)
77+
{
78+
trackString("win");
79+
tracker_.onKeyEvent(makeKeyEvent(KeyType::F10));
80+
trackString("ter");
81+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
82+
}
83+
84+
BOOST_FIXTURE_TEST_CASE(CheatModeIsNotTurnedOn_WhenInterruptedByAnotherLetter, CheatCommandTrackerFixture1P)
85+
{
86+
trackString("wainter");
87+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
88+
}
89+
90+
BOOST_FIXTURE_TEST_CASE(CheatModeIsNotTurnedOn_WhenOrderOfCharactersIsWrong, CheatCommandTrackerFixture1P)
91+
{
92+
trackString("winetr");
93+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
94+
}
95+
96+
BOOST_FIXTURE_TEST_CASE(CheatModeIsNotTurnedOn_WhenOrderOfCharactersIsWrong_Wraparound, CheatCommandTrackerFixture1P)
97+
{
98+
trackString("rwinte");
99+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
100+
}
101+
102+
BOOST_FIXTURE_TEST_CASE(CheatModeIsNotTurnedOn_WhenACharacterIsRepeated, CheatCommandTrackerFixture1P)
103+
{
104+
trackString("winnter");
105+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
106+
}
107+
108+
BOOST_FIXTURE_TEST_CASE(CheatModeIsTurnedOn_WhenTheFirstCharacterIsRepeated, CheatCommandTrackerFixture1P)
109+
{
110+
trackString("wwwinter");
111+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == true);
112+
}
113+
114+
BOOST_FIXTURE_TEST_CASE(CheatModeIsTurnedOn_EvenWhenWrongInputsWereProvidedBefore, CheatCommandTrackerFixture1P)
115+
{
116+
trackString("www");
117+
auto ke = makeKeyEvent('1');
118+
ke.alt = true;
119+
tracker_.onKeyEvent(ke);
120+
trackString("interwitter");
121+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == false);
122+
trackString("winter");
123+
BOOST_TEST_REQUIRE(cheats_.isCheatModeOn() == true);
124+
}
125+
126+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)