-
Notifications
You must be signed in to change notification settings - Fork 79
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
Add all classic S2 cheats and a few more #1679
Open
kubaau
wants to merge
14
commits into
Return-To-The-Roots:master
Choose a base branch
from
kubaau:cheats2
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
5351b3e
Move existing cheat logic to new class "Cheats"
kubaau a7a9cf2
Move tracking key events and chat commands from Cheats to separate cl…
kubaau 94c3f1d
Make "winter" cheat string tracking more similar to what it was in S2
kubaau 8f28056
Disable cheats in multiplayer
kubaau 81a72a2
Do not enable armageddon if cheat mode is not on
kubaau 0d719f0
Do not enable toggleHumanAIPlayer simply by running debug build
kubaau 0e751dd
Add classic all-visible cheat (F7)
kubaau 9d87799
Add classic build headquarters cheat
kubaau c202a44
Add classic show enemy productivity overlay cheat
kubaau 4a55f94
Add classic enable all buildings cheat
kubaau 3207f97
Add cheat to reveal resources
kubaau a22129d
Add cheats to destroy buildings
kubaau 3d0ac3f
Add classic cheat to set game speed by using ALT+1 through ALT+6
kubaau 7ceb1d7
Add javadocs to cheat-related functions
kubaau File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) | ||
// | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#include "CheatCommandTracker.h" | ||
#include "Cheats.h" | ||
#include "driver/KeyEvent.h" | ||
|
||
namespace { | ||
auto makeCircularBuffer(const std::string& str) | ||
{ | ||
return boost::circular_buffer<char>{cbegin(str), cend(str)}; | ||
} | ||
const auto cheatStr = makeCircularBuffer("winter"); | ||
} // namespace | ||
|
||
CheatCommandTracker::CheatCommandTracker(Cheats& cheats) : cheats_(cheats), lastChars_(cheatStr.size()) {} | ||
|
||
void CheatCommandTracker::trackKeyEvent(const KeyEvent& ke) | ||
{ | ||
if(trackSpecialKeyEvent(ke) || trackSpeedKeyEvent(ke)) | ||
{ | ||
lastChars_.clear(); | ||
return; | ||
} | ||
|
||
trackCharKeyEvent(ke); | ||
} | ||
|
||
void CheatCommandTracker::trackChatCommand(const std::string& cmd) | ||
{ | ||
if(cmd == "apocalypsis") | ||
cheats_.armageddon(); | ||
} | ||
|
||
bool CheatCommandTracker::trackSpecialKeyEvent(const KeyEvent& ke) | ||
{ | ||
if(ke.kt == KeyType::Char) | ||
return false; | ||
|
||
if(ke.ctrl && ke.shift) | ||
{ | ||
if(ke.kt >= KeyType::F1 && ke.kt <= KeyType::F8) | ||
cheats_.destroyBuildings({static_cast<unsigned>(ke.kt) - static_cast<unsigned>(KeyType::F1)}); | ||
else if(ke.kt == KeyType::F9) | ||
cheats_.destroyAllAIBuildings(); | ||
|
||
return true; | ||
} | ||
|
||
switch(ke.kt) | ||
{ | ||
case KeyType::F7: | ||
{ | ||
if(ke.alt) | ||
cheats_.toggleResourceRevealMode(); | ||
else | ||
cheats_.toggleAllVisible(); | ||
} | ||
break; | ||
case KeyType::F10: cheats_.toggleHumanAIPlayer(); break; | ||
default: break; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
bool CheatCommandTracker::trackSpeedKeyEvent(const KeyEvent& ke) | ||
{ | ||
const char c = ke.c; | ||
if(ke.alt && c >= '1' && c <= '6') | ||
{ | ||
cheats_.setGameSpeed(c - '1'); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
bool CheatCommandTracker::trackCharKeyEvent(const KeyEvent& ke) | ||
{ | ||
lastChars_.push_back(ke.c); | ||
|
||
if(lastChars_ == cheatStr) | ||
cheats_.toggleCheatMode(); | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) | ||
// | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#pragma once | ||
|
||
#include <boost/circular_buffer.hpp> | ||
#include <string> | ||
|
||
class Cheats; | ||
struct KeyEvent; | ||
|
||
class CheatCommandTracker | ||
{ | ||
public: | ||
CheatCommandTracker(Cheats& cheats); | ||
|
||
/** Tracks keyboard events related to cheats and triggers the actual cheats. | ||
* Calls related private methods of this class in order but returns at the first success (return true). | ||
* | ||
* @param ke - The keyboard event encountered. | ||
*/ | ||
void trackKeyEvent(const KeyEvent& ke); | ||
|
||
/** Tracks chat commands related to cheats and triggers the actual cheats. | ||
* | ||
* @param cmd - The chat command to track. | ||
*/ | ||
void trackChatCommand(const std::string& cmd); | ||
|
||
private: | ||
/** Tracks keyboard events related to cheats and triggers the actual cheats, but only tracks events of type | ||
* different than KeyType::Char (e.g. F-keys). | ||
* | ||
* @param ke - The keyboard event encountered. | ||
* @return true if keyboard event was NOT of type KeyType::Char, false otherwise | ||
*/ | ||
bool trackSpecialKeyEvent(const KeyEvent& ke); | ||
|
||
/** Tracks keyboard events related to game speed cheats (ALT+1..ALT+6) and triggers the actual cheats. | ||
* | ||
* @param ke - The keyboard event encountered. | ||
* @return true if keyboard event was related to game speed cheats, false otherwise | ||
*/ | ||
bool trackSpeedKeyEvent(const KeyEvent& ke); | ||
|
||
/** Tracks keyboard events related to cheats and triggers the actual cheats, but only tracks events of type | ||
* KeyType::Char (e.g. enabling cheat mode by typing "winter"). | ||
* | ||
* @param ke - The keyboard event encountered. | ||
* @return always true | ||
*/ | ||
bool trackCharKeyEvent(const KeyEvent& ke); | ||
|
||
Cheats& cheats_; | ||
boost::circular_buffer<char> lastChars_; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) | ||
// | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#include "Cheats.h" | ||
#include "CheatCommandTracker.h" | ||
#include "GameInterface.h" | ||
#include "GamePlayer.h" | ||
#include "RttrForeachPt.h" | ||
#include "factories/BuildingFactory.h" | ||
#include "network/GameClient.h" | ||
#include "world/GameWorldBase.h" | ||
|
||
Cheats::Cheats(GameWorldBase& world) : cheatCmdTracker_(std::make_unique<CheatCommandTracker>(*this)), world_(world) {} | ||
|
||
Cheats::~Cheats() = default; | ||
|
||
void Cheats::trackKeyEvent(const KeyEvent& ke) | ||
{ | ||
if(!canCheatModeBeOn()) | ||
return; | ||
|
||
cheatCmdTracker_->trackKeyEvent(ke); | ||
} | ||
|
||
void Cheats::trackChatCommand(const std::string& cmd) | ||
{ | ||
if(!canCheatModeBeOn()) | ||
return; | ||
|
||
cheatCmdTracker_->trackChatCommand(cmd); | ||
} | ||
|
||
void Cheats::toggleCheatMode() | ||
{ | ||
if(!canCheatModeBeOn()) | ||
return; | ||
|
||
isCheatModeOn_ = !isCheatModeOn_; | ||
} | ||
|
||
void Cheats::toggleAllVisible() | ||
{ | ||
// This is actually the behavior of the original game. | ||
// If you enabled cheats, revealed the map and disabled cheats you would be unable to unreveal the map. | ||
if(!isCheatModeOn()) | ||
return; | ||
|
||
isAllVisible_ = !isAllVisible_; | ||
|
||
// The minimap in the original game is not updated immediately, but here this would cause complications. | ||
if(GameInterface* gi = world_.GetGameInterface()) | ||
gi->GI_UpdateMapVisibility(); | ||
} | ||
|
||
bool Cheats::canPlaceCheatBuilding(const MapPoint& mp) const | ||
{ | ||
if(!isCheatModeOn()) | ||
return false; | ||
|
||
// It seems that in the original game you can only build headquarters in unoccupied territory at least 2 nodes | ||
// away from any border markers and that it doesn't need more bq than a hut. | ||
const MapNode& node = world_.GetNode(mp); | ||
return !node.owner && !world_.IsAnyNeighborOwned(mp) && node.bq >= BuildingQuality::Hut; | ||
} | ||
|
||
void Cheats::placeCheatBuilding(const MapPoint& mp, const GamePlayer& player) | ||
{ | ||
if(!canPlaceCheatBuilding(mp)) | ||
return; | ||
|
||
// The new HQ will have default resources. | ||
// In the original game, new HQs created in the Roman campaign had no resources. | ||
constexpr auto checkExists = false; | ||
world_.DestroyNO(mp, checkExists); // if CanPlaceCheatBuilding is true then this must be safe to destroy | ||
BuildingFactory::CreateBuilding(world_, BuildingType::Headquarters, mp, player.GetPlayerId(), player.nation, | ||
player.IsHQTent()); | ||
} | ||
|
||
void Cheats::setGameSpeed(uint8_t speedIndex) | ||
{ | ||
if(!isCheatModeOn()) | ||
return; | ||
|
||
constexpr auto gfLengthInMs = 50; | ||
GAMECLIENT.SetGFLengthReq(FramesInfo::milliseconds32_t{gfLengthInMs >> speedIndex}); | ||
// 50 -> 25 -> 12 -> 6 -> 3 -> 1 | ||
} | ||
|
||
void Cheats::toggleHumanAIPlayer() | ||
{ | ||
if(!isCheatModeOn()) | ||
return; | ||
|
||
if(GAMECLIENT.IsReplayModeOn()) | ||
return; | ||
|
||
GAMECLIENT.ToggleHumanAIPlayer(AI::Info{AI::Type::Default, AI::Level::Easy}); | ||
} | ||
|
||
void Cheats::armageddon() | ||
{ | ||
if(!isCheatModeOn()) | ||
return; | ||
|
||
GAMECLIENT.CheatArmageddon(); | ||
} | ||
|
||
Cheats::ResourceRevealMode Cheats::getResourceRevealMode() const | ||
{ | ||
return isCheatModeOn() ? resourceRevealMode_ : ResourceRevealMode::Nothing; | ||
} | ||
|
||
void Cheats::toggleResourceRevealMode() | ||
{ | ||
switch(resourceRevealMode_) | ||
{ | ||
case ResourceRevealMode::Nothing: resourceRevealMode_ = ResourceRevealMode::Ores; break; | ||
case ResourceRevealMode::Ores: resourceRevealMode_ = ResourceRevealMode::Fish; break; | ||
case ResourceRevealMode::Fish: resourceRevealMode_ = ResourceRevealMode::Water; break; | ||
default: resourceRevealMode_ = ResourceRevealMode::Nothing; break; | ||
} | ||
} | ||
|
||
void Cheats::destroyBuildings(const PlayerIDSet& playerIds) | ||
{ | ||
if(!isCheatModeOn()) | ||
return; | ||
|
||
RTTR_FOREACH_PT(MapPoint, world_.GetSize()) | ||
if(world_.GetNO(pt)->GetType() == NodalObjectType::Building && playerIds.count(world_.GetNode(pt).owner - 1)) | ||
world_.DestroyNO(pt); | ||
} | ||
|
||
void Cheats::destroyAllAIBuildings() | ||
{ | ||
if(!isCheatModeOn()) | ||
return; | ||
|
||
PlayerIDSet ais; | ||
for(auto i = 0u; i < world_.GetNumPlayers(); ++i) | ||
if(!world_.GetPlayer(i).isHuman()) | ||
ais.insert(i); | ||
destroyBuildings(ais); | ||
} | ||
|
||
bool Cheats::canCheatModeBeOn() const | ||
{ | ||
return world_.IsSinglePlayer(); | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can extend this to be a setting inside the create game screen, to allow cheats in multiplayer too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could certainly create an "enable cheats in multiplayer" addon or something similar, but it would be useful to ask which of these cheats make sense in multiplayer. I don't really know a reason to enable most of them since they are so game-breaking.
On the other hand, I guess they could help in debugging, giving someone a handicap (experienced player sees FOW, newbie sees everything; experienced needs geologists, newbie sees resources, etc.) or eliminating the need to send geologists anywhere.