1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

Merge pull request #5815 from Laserlicht/cheats

add skill cheat / allow more than 8 skills
This commit is contained in:
Ivan Savenko
2025-06-20 17:56:41 +03:00
committed by GitHub
18 changed files with 151 additions and 18 deletions

View File

@@ -20,6 +20,7 @@
#include "../../../lib/CCreatureHandler.h" #include "../../../lib/CCreatureHandler.h"
#include "../../../lib/GameLibrary.h" #include "../../../lib/GameLibrary.h"
#include "../../../lib/StartInfo.h" #include "../../../lib/StartInfo.h"
#include "../../../lib/GameSettings.h"
#include "../../../lib/filesystem/Filesystem.h" #include "../../../lib/filesystem/Filesystem.h"
#include "../Goals/ExecuteHeroChain.h" #include "../Goals/ExecuteHeroChain.h"
#include "../Goals/BuildThis.h" #include "../Goals/BuildThis.h"
@@ -581,7 +582,7 @@ float RewardEvaluator::evaluateWitchHutSkillScore(const CGObjectInstance * hut,
return role == HeroRole::SCOUT ? 2 : 0; return role == HeroRole::SCOUT ? 2 : 0;
if(hero->getSecSkillLevel(skill) != MasteryLevel::NONE if(hero->getSecSkillLevel(skill) != MasteryLevel::NONE
|| hero->secSkills.size() >= GameConstants::SKILL_PER_HERO) || static_cast<int>(hero->secSkills.size()) >= cb->getSettings().getInteger(EGameSettings::HEROES_SKILL_PER_HERO))
return 0; return 0;
auto score = ai->heroManager->evaluateSecSkill(skill, hero); auto score = ai->heroManager->evaluateSecSkill(skill, hero);

View File

@@ -435,6 +435,9 @@
"vcmi.townWindow.upgradeAll.notAllUpgradable" : "Not enough resources to upgrade all creatures. Do you want to upgrade following creatures?", "vcmi.townWindow.upgradeAll.notAllUpgradable" : "Not enough resources to upgrade all creatures. Do you want to upgrade following creatures?",
"vcmi.townWindow.upgradeAll.notUpgradable" : "Not enough resources to upgrade any creature.", "vcmi.townWindow.upgradeAll.notUpgradable" : "Not enough resources to upgrade any creature.",
"vcmi.kingdomOverview.secSkillOverflow.hover" : "More skills",
"vcmi.kingdomOverview.secSkillOverflow.help" : "{More skills}\n\nThis hero has more skills.\nYou can see all of them in the hero overview.",
"vcmi.logicalExpressions.anyOf" : "Any of the following:", "vcmi.logicalExpressions.anyOf" : "Any of the following:",
"vcmi.logicalExpressions.allOf" : "All of the following:", "vcmi.logicalExpressions.allOf" : "All of the following:",
"vcmi.logicalExpressions.noneOf" : "None of the following:", "vcmi.logicalExpressions.noneOf" : "None of the following:",

View File

@@ -425,6 +425,9 @@
"vcmi.townWindow.upgradeAll.notAllUpgradable" : "Nicht genügend Ressourcen um alle Kreaturen aufzurüsten. Folgende Kreaturen aufrüsten?", "vcmi.townWindow.upgradeAll.notAllUpgradable" : "Nicht genügend Ressourcen um alle Kreaturen aufzurüsten. Folgende Kreaturen aufrüsten?",
"vcmi.townWindow.upgradeAll.notUpgradable" : "Nicht genügend Ressourcen um mindestens eine Kreatur aufzurüsten.", "vcmi.townWindow.upgradeAll.notUpgradable" : "Nicht genügend Ressourcen um mindestens eine Kreatur aufzurüsten.",
"vcmi.kingdomOverview.secSkillOverflow.hover" : "Mehr skills",
"vcmi.kingdomOverview.secSkillOverflow.help" : "{Mehr skills}\n\nDieser Held hat mehr Skills.\nIn der Heldenübersicht können alle eingesehen werden.",
"vcmi.logicalExpressions.anyOf" : "Eines der folgenden:", "vcmi.logicalExpressions.anyOf" : "Eines der folgenden:",
"vcmi.logicalExpressions.allOf" : "Alles der folgenden:", "vcmi.logicalExpressions.allOf" : "Alles der folgenden:",
"vcmi.logicalExpressions.noneOf" : "Keines der folgenden:", "vcmi.logicalExpressions.noneOf" : "Keines der folgenden:",

View File

@@ -81,7 +81,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
primSkillValues[leftRight].push_back(std::make_shared<CLabel>(352 + (qeLayout ? 96 : 93) * leftRight, (qeLayout ? 22 : 35) + (qeLayout ? 26 : 36) * m, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE)); primSkillValues[leftRight].push_back(std::make_shared<CLabel>(352 + (qeLayout ? 96 : 93) * leftRight, (qeLayout ? 22 : 35) + (qeLayout ? 26 : 36) * m, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE));
for(int m=0; m < hero->secSkills.size(); ++m) for(int m=0; m < std::min(static_cast<int>(hero->secSkills.size()), 8); ++m)
secSkills[leftRight].push_back(std::make_shared<CSecSkillPlace>(Point(32 + 36 * m + 454 * leftRight, qeLayout ? 83 : 88), CSecSkillPlace::ImageSize::SMALL, secSkills[leftRight].push_back(std::make_shared<CSecSkillPlace>(Point(32 + 36 * m + 454 * leftRight, qeLayout ? 83 : 88), CSecSkillPlace::ImageSize::SMALL,
hero->secSkills[m].first, hero->secSkills[m].second)); hero->secSkills[m].first, hero->secSkills[m].second));
@@ -377,6 +377,10 @@ void CExchangeWindow::questLogShortcut()
void CExchangeWindow::update() void CExchangeWindow::update()
{ {
const bool qeLayout = isQuickExchangeLayoutAvailable();
OBJECT_CONSTRUCTION;
CWindowWithArtifacts::update(); CWindowWithArtifacts::update();
for(size_t leftRight : {0, 1}) for(size_t leftRight : {0, 1})
@@ -389,8 +393,27 @@ void CExchangeWindow::update()
primSkillValues[leftRight][m]->setText(std::to_string(value)); primSkillValues[leftRight][m]->setText(std::to_string(value));
} }
for(int m=0; m < hero->secSkills.size(); ++m) int slots = 8;
bool isMoreSkillsThanSlots = hero->secSkills.size() > slots;
for(int m=0; m < std::min(static_cast<int>(hero->secSkills.size()), 8); ++m)
{ {
if(m == slots - 1)
{
if(isMoreSkillsThanSlots)
{
Rect r(Point(32 + 36 * m + 454 * leftRight, qeLayout ? 83 : 88), Point(34, 28));
secSkillsFull[leftRight] = std::make_shared<CMultiLineLabel>(r, EFonts::FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, "...");
secSkillsFullArea[leftRight] = std::make_shared<LRClickableAreaWText>(r, LIBRARY->generaltexth->translate("vcmi.kingdomOverview.secSkillOverflow.hover"), LIBRARY->generaltexth->translate("vcmi.kingdomOverview.secSkillOverflow.help"));
secSkills[leftRight][m]->setSkill(SecondarySkill::NONE);
continue;
}
else
{
secSkillsFull[leftRight].reset();
secSkillsFullArea[leftRight].reset();
}
}
int id = hero->secSkills[m].first; int id = hero->secSkills[m].first;
int level = hero->secSkills[m].second; int level = hero->secSkills[m].second;

View File

@@ -13,6 +13,8 @@
#include "../widgets/CExchangeController.h" #include "../widgets/CExchangeController.h"
class CGarrisonSlot; class CGarrisonSlot;
class CMultiLineLabel;
class LRClickableAreaWText;
class CExchangeWindow : public CStatusbarWindow, public IGarrisonHolder, public CWindowWithArtifacts class CExchangeWindow : public CStatusbarWindow, public IGarrisonHolder, public CWindowWithArtifacts
{ {
@@ -27,6 +29,8 @@ class CExchangeWindow : public CStatusbarWindow, public IGarrisonHolder, public
std::vector<std::shared_ptr<LRClickableAreaWTextComp>> primSkillAreas; std::vector<std::shared_ptr<LRClickableAreaWTextComp>> primSkillAreas;
std::array<std::vector<std::shared_ptr<CSecSkillPlace>>, 2> secSkills; std::array<std::vector<std::shared_ptr<CSecSkillPlace>>, 2> secSkills;
std::array<std::shared_ptr<CMultiLineLabel>, 2> secSkillsFull;
std::array<std::shared_ptr<LRClickableAreaWText>, 2> secSkillsFullArea;
std::array<std::shared_ptr<CHeroArea>, 2> heroAreas; std::array<std::shared_ptr<CHeroArea>, 2> heroAreas;
std::array<std::shared_ptr<LRClickableAreaWText>, 2> specialtyAreas; std::array<std::shared_ptr<LRClickableAreaWText>, 2> specialtyAreas;

View File

@@ -28,6 +28,7 @@
#include "../widgets/CGarrisonInt.h" #include "../widgets/CGarrisonInt.h"
#include "../widgets/TextControls.h" #include "../widgets/TextControls.h"
#include "../widgets/Buttons.h" #include "../widgets/Buttons.h"
#include "../widgets/Slider.h"
#include "../render/IRenderHandler.h" #include "../render/IRenderHandler.h"
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
@@ -148,16 +149,27 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
expValue = std::make_shared<CLabel>(68, 252); expValue = std::make_shared<CLabel>(68, 252);
manaValue = std::make_shared<CLabel>(211, 252); manaValue = std::make_shared<CLabel>(211, 252);
if(hero->secSkills.size() > 8)
{
auto divisionRoundUp = [](int x, int y){ return (x + (y - 1)) / y; };
int lines = divisionRoundUp(hero->secSkills.size(), 2);
secSkillSlider = std::make_shared<CSlider>(Point(284, 276), 189, [this](int val){ CHeroWindow::update(); }, 4, lines, 0, Orientation::VERTICAL, CSlider::BROWN);
secSkillSlider->setPanningStep(48);
secSkillSlider->setScrollBounds(Rect(-266, 0, secSkillSlider->pos.x - pos.x + secSkillSlider->pos.w, secSkillSlider->pos.h));
}
for(int i = 0; i < std::min<size_t>(hero->secSkills.size(), 8u); ++i) for(int i = 0; i < std::min<size_t>(hero->secSkills.size(), 8u); ++i)
{ {
Rect r = Rect(i%2 == 0 ? 18 : 162, 276 + 48 * (i/2), 136, 42); bool isSmallBox = (secSkillSlider && i%2 == 1);
Rect r = Rect(i%2 == 0 ? 18 : 162, 276 + 48 * (i/2), isSmallBox ? 120 : 136, 42);
secSkills.emplace_back(std::make_shared<CSecSkillPlace>(r.topLeft(), CSecSkillPlace::ImageSize::MEDIUM)); secSkills.emplace_back(std::make_shared<CSecSkillPlace>(r.topLeft(), CSecSkillPlace::ImageSize::MEDIUM));
int x = (i % 2) ? 212 : 68; int x = (i % 2) ? 212 : 68;
int y = 280 + 48 * (i/2); int y = 280 + 48 * (i/2);
int width = isSmallBox ? 71 : 87;
secSkillValues.push_back(std::make_shared<CLabel>(x, y, FONT_SMALL, ETextAlignment::TOPLEFT)); secSkillValues.push_back(std::make_shared<CLabel>(x, y, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, "", width));
secSkillNames.push_back(std::make_shared<CLabel>(x, y+20, FONT_SMALL, ETextAlignment::TOPLEFT)); secSkillNames.push_back(std::make_shared<CLabel>(x, y+20, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, "", width));
} }
// various texts // various texts
@@ -175,6 +187,8 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
void CHeroWindow::update() void CHeroWindow::update()
{ {
OBJECT_CONSTRUCTION;
CWindowWithArtifacts::update(); CWindowWithArtifacts::update();
auto & heroscrn = LIBRARY->generaltexth->heroscrn; auto & heroscrn = LIBRARY->generaltexth->heroscrn;
assert(curHero); assert(curHero);
@@ -195,7 +209,6 @@ void CHeroWindow::update()
portraitImage->setFrame(curHero->getIconIndex()); portraitImage->setFrame(curHero->getIconIndex());
{ {
OBJECT_CONSTRUCTION;
if(!garr) if(!garr)
{ {
bool removableTroops = curHero->getOwner() == GAME->interface()->playerID; bool removableTroops = curHero->getOwner() == GAME->interface()->playerID;
@@ -235,7 +248,15 @@ void CHeroWindow::update()
//secondary skills support //secondary skills support
for(size_t g=0; g < secSkills.size(); ++g) for(size_t g=0; g < secSkills.size(); ++g)
{ {
SecondarySkill skill = curHero->secSkills[g].first; int offset = secSkillSlider ? secSkillSlider->getValue() * 2 : 0;
if(curHero->secSkills.size() < g + offset + 1)
{
secSkillNames[g]->setText("");
secSkillValues[g]->setText("");
secSkills[g]->setSkill(SecondarySkill::NONE);
break;
}
SecondarySkill skill = curHero->secSkills[g + offset].first;
int level = curHero->getSecSkillLevel(skill); int level = curHero->getSecSkillLevel(skill);
std::string skillName = skill.toEntity(LIBRARY)->getNameTranslated(); std::string skillName = skill.toEntity(LIBRARY)->getNameTranslated();
std::string skillValue = LIBRARY->generaltexth->levels[level-1]; std::string skillValue = LIBRARY->generaltexth->levels[level-1];

View File

@@ -33,6 +33,7 @@ class CToggleGroup;
class CGStatusBar; class CGStatusBar;
class CTextBox; class CTextBox;
class CGarrisonInt; class CGarrisonInt;
class CSlider;
/// Button which switches hero selection /// Button which switches hero selection
class CHeroSwitcher : public CIntObject class CHeroSwitcher : public CIntObject
@@ -77,6 +78,7 @@ class CHeroWindow : public CStatusbarWindow, public IGarrisonHolder, public CWin
std::vector< std::shared_ptr<CSecSkillPlace>> secSkills; std::vector< std::shared_ptr<CSecSkillPlace>> secSkills;
std::vector<std::shared_ptr<CLabel>> secSkillNames; std::vector<std::shared_ptr<CLabel>> secSkillNames;
std::vector<std::shared_ptr<CLabel>> secSkillValues; std::vector<std::shared_ptr<CLabel>> secSkillValues;
std::shared_ptr<CSlider> secSkillSlider;
std::shared_ptr<CButton> quitButton; std::shared_ptr<CButton> quitButton;
std::shared_ptr<CTextBox> dismissLabel; std::shared_ptr<CTextBox> dismissLabel;

View File

@@ -41,7 +41,8 @@
#include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/mapObjects/MiscObjects.h" #include "../../lib/mapObjects/MiscObjects.h"
#include "../../lib/texts/CGeneralTextHandler.h" #include "texts/CGeneralTextHandler.h"
#include "../../lib/GameSettings.h"
static const std::string OVERVIEW_BACKGROUND = "OvCast.pcx"; static const std::string OVERVIEW_BACKGROUND = "OvCast.pcx";
static const size_t OVERVIEW_SIZE = 4; static const size_t OVERVIEW_SIZE = 4;
@@ -983,8 +984,17 @@ CHeroItem::CHeroItem(const CGHeroInstance * Hero)
heroInfo.push_back(std::make_shared<InfoBox>(Point(78+(int)i*36, 26), InfoBox::POS_DOWN, InfoBox::SIZE_SMALL, data)); heroInfo.push_back(std::make_shared<InfoBox>(Point(78+(int)i*36, 26), InfoBox::POS_DOWN, InfoBox::SIZE_SMALL, data));
} }
for(size_t i=0; i<GameConstants::SKILL_PER_HERO; i++) int slots = 8;
bool isMoreSkillsThanSlots = hero->secSkills.size() > slots;
for(size_t i=0; i<slots; i++)
{ {
if(isMoreSkillsThanSlots && i == slots - 1)
{
Rect r(Point(410+(int)i*36, 5), Point(34, 28));
heroInfoFull = std::make_shared<CMultiLineLabel>(r, EFonts::FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, "...");
heroInfoFullArea = std::make_shared<LRClickableAreaWText>(r, LIBRARY->generaltexth->translate("vcmi.kingdomOverview.secSkillOverflow.hover"), LIBRARY->generaltexth->translate("vcmi.kingdomOverview.secSkillOverflow.help"));
continue;
}
auto data = std::make_shared<InfoBoxHeroData>(IInfoBoxData::HERO_SECONDARY_SKILL, hero, (int)i); auto data = std::make_shared<InfoBoxHeroData>(IInfoBoxData::HERO_SECONDARY_SKILL, hero, (int)i);
heroInfo.push_back(std::make_shared<InfoBox>(Point(410+(int)i*36, 5), InfoBox::POS_NONE, InfoBox::SIZE_SMALL, data)); heroInfo.push_back(std::make_shared<InfoBox>(Point(410+(int)i*36, 5), InfoBox::POS_NONE, InfoBox::SIZE_SMALL, data));
} }

View File

@@ -32,6 +32,7 @@ class CTabbedInt;
class CGStatusBar; class CGStatusBar;
class CGarrisonInt; class CGarrisonInt;
class CMultiLineLabel; class CMultiLineLabel;
class LRClickableAreaWText;
class CKingdHeroList; class CKingdHeroList;
class CKingdTownList; class CKingdTownList;
@@ -310,6 +311,8 @@ class CHeroItem : public CIntObject, public IGarrisonHolder
std::shared_ptr<CToggleGroup> artButtons; std::shared_ptr<CToggleGroup> artButtons;
std::vector<std::shared_ptr<InfoBox>> heroInfo; std::vector<std::shared_ptr<InfoBox>> heroInfo;
std::shared_ptr<CMultiLineLabel> heroInfoFull;
std::shared_ptr<LRClickableAreaWText> heroInfoFullArea;
std::shared_ptr<MoraleLuckBox> morale; std::shared_ptr<MoraleLuckBox> morale;
std::shared_ptr<MoraleLuckBox> luck; std::shared_ptr<MoraleLuckBox> luck;

View File

@@ -508,6 +508,9 @@
/// movement points hero can get on start of the turn when on sea, depending on speed of slowest creature (0-based list) /// movement points hero can get on start of the turn when on sea, depending on speed of slowest creature (0-based list)
"movementPointsSea" : [ 1500 ], "movementPointsSea" : [ 1500 ],
/// maximal secondary skills per hero
"skillPerHero" : 8,
/// Base scouting range for hero without any range modifiers /// Base scouting range for hero without any range modifiers
"baseScoutingRange" : 5, "baseScoutingRange" : 5,

View File

@@ -48,6 +48,7 @@
"movementCostBase" : { "type" : "number" }, "movementCostBase" : { "type" : "number" },
"movementPointsLand" : { "type" : "array" }, "movementPointsLand" : { "type" : "array" },
"movementPointsSea" : { "type" : "array" }, "movementPointsSea" : { "type" : "array" },
"skillPerHero" : { "type" : "number" },
"specialtyCreatureGrowth" : { "type" : "number" }, "specialtyCreatureGrowth" : { "type" : "number" },
"specialtySecondarySkillGrowth" : { "type" : "number" }, "specialtySecondarySkillGrowth" : { "type" : "number" },
"baseScoutingRange" : { "type" : "number" } "baseScoutingRange" : { "type" : "number" }

View File

@@ -10,6 +10,17 @@ To use cheat code, press `Tab` key or click/tap on status bar to open game chat
`nwcthereisnospoon`, `nwcmidichlorians`, `nwctim`, `vcmiistari` or `vcmispells` - give a spell book, all spells and 999 mana to currently selected hero. Also allows casting spell up to 100 times per combat round `nwcthereisnospoon`, `nwcmidichlorians`, `nwctim`, `vcmiistari` or `vcmispells` - give a spell book, all spells and 999 mana to currently selected hero. Also allows casting spell up to 100 times per combat round
### Secondary Skills
`vcmiskill <skillID> <mastery>` - give a secondary skill to currently selected hero
Examples:
`vcmiskill learning` - give expert level learning skill
`vcmiskill leadership 2` - give advanced level leadership skill
`vcmiskill wisdom 0` - remove wisdom skill
`vcmiskill every` - give all skills on expert level
`vcmiskill every 0` - remove all skills
### Army ### Army
`nwctrinity`, `nwcpadme`, `nwcavertingoureyes`, `vcmiainur` or `vcmiarchangel` - give 5 Archangels in every empty slot (to currently selected hero) `nwctrinity`, `nwcpadme`, `nwcavertingoureyes`, `vcmiainur` or `vcmiarchangel` - give 5 Archangels in every empty slot (to currently selected hero)

View File

@@ -87,6 +87,7 @@ const std::vector<GameSettings::SettingOption> GameSettings::settingProperties =
{EGameSettings::HEROES_MOVEMENT_COST_BASE, "heroes", "movementCostBase" }, {EGameSettings::HEROES_MOVEMENT_COST_BASE, "heroes", "movementCostBase" },
{EGameSettings::HEROES_MOVEMENT_POINTS_LAND, "heroes", "movementPointsLand" }, {EGameSettings::HEROES_MOVEMENT_POINTS_LAND, "heroes", "movementPointsLand" },
{EGameSettings::HEROES_MOVEMENT_POINTS_SEA, "heroes", "movementPointsSea" }, {EGameSettings::HEROES_MOVEMENT_POINTS_SEA, "heroes", "movementPointsSea" },
{EGameSettings::HEROES_SKILL_PER_HERO, "heroes", "skillPerHero" },
{EGameSettings::HEROES_SPECIALTY_CREATURE_GROWTH, "heroes", "specialtyCreatureGrowth" }, {EGameSettings::HEROES_SPECIALTY_CREATURE_GROWTH, "heroes", "specialtyCreatureGrowth" },
{EGameSettings::HEROES_SPECIALTY_SECONDARY_SKILL_GROWTH, "heroes", "specialtySecondarySkillGrowth" }, {EGameSettings::HEROES_SPECIALTY_SECONDARY_SKILL_GROWTH, "heroes", "specialtySecondarySkillGrowth" },
{EGameSettings::MAP_FORMAT_ARMAGEDDONS_BLADE, "mapFormat", "armageddonsBlade" }, {EGameSettings::MAP_FORMAT_ARMAGEDDONS_BLADE, "mapFormat", "armageddonsBlade" },

View File

@@ -60,6 +60,7 @@ enum class EGameSettings
HEROES_MOVEMENT_COST_BASE, HEROES_MOVEMENT_COST_BASE,
HEROES_MOVEMENT_POINTS_LAND, HEROES_MOVEMENT_POINTS_LAND,
HEROES_MOVEMENT_POINTS_SEA, HEROES_MOVEMENT_POINTS_SEA,
HEROES_SKILL_PER_HERO,
HEROES_SPECIALTY_CREATURE_GROWTH, HEROES_SPECIALTY_CREATURE_GROWTH,
HEROES_SPECIALTY_SECONDARY_SKILL_GROWTH, HEROES_SPECIALTY_SECONDARY_SKILL_GROWTH,
INTERFACE_PLAYER_COLORED_BACKGROUND, INTERFACE_PLAYER_COLORED_BACKGROUND,

View File

@@ -33,7 +33,6 @@ namespace GameConstants
constexpr int BATTLE_SHOOTING_PENALTY_DISTANCE = 10; //if the distance is > than this, then shooting stack has distance penalty constexpr int BATTLE_SHOOTING_PENALTY_DISTANCE = 10; //if the distance is > than this, then shooting stack has distance penalty
constexpr int BATTLE_SHOOTING_RANGE_DISTANCE = std::numeric_limits<uint8_t>::max(); // used when shooting stack has no shooting range limit constexpr int BATTLE_SHOOTING_RANGE_DISTANCE = std::numeric_limits<uint8_t>::max(); // used when shooting stack has no shooting range limit
constexpr int ARMY_SIZE = 7; constexpr int ARMY_SIZE = 7;
constexpr int SKILL_PER_HERO = 8;
constexpr ui32 HERO_HIGH_LEVEL = 10; // affects primary skill upgrade order constexpr ui32 HERO_HIGH_LEVEL = 10; // affects primary skill upgrade order
constexpr int SKILL_QUANTITY=28; constexpr int SKILL_QUANTITY=28;

View File

@@ -31,6 +31,7 @@
#include "../CCreatureHandler.h" #include "../CCreatureHandler.h"
#include "../mapping/CMap.h" #include "../mapping/CMap.h"
#include "../StartInfo.h" #include "../StartInfo.h"
#include "../GameSettings.h"
#include "CGTownInstance.h" #include "CGTownInstance.h"
#include "../entities/artifact/ArtifactUtils.h" #include "../entities/artifact/ArtifactUtils.h"
#include "../entities/artifact/CArtifact.h" #include "../entities/artifact/CArtifact.h"
@@ -167,7 +168,7 @@ int3 CGHeroInstance::convertFromVisitablePos(const int3 & position) const
bool CGHeroInstance::canLearnSkill() const bool CGHeroInstance::canLearnSkill() const
{ {
return secSkills.size() < GameConstants::SKILL_PER_HERO; return secSkills.size() < cb->getSettings().getInteger(EGameSettings::HEROES_SKILL_PER_HERO);
} }
bool CGHeroInstance::canLearnSkill(const SecondarySkill & which) const bool CGHeroInstance::canLearnSkill(const SecondarySkill & which) const

View File

@@ -17,7 +17,9 @@
#include "../TurnTimerHandler.h" #include "../TurnTimerHandler.h"
#include "../../lib/CPlayerState.h" #include "../../lib/CPlayerState.h"
#include "../../lib/CSkillHandler.h"
#include "../../lib/StartInfo.h" #include "../../lib/StartInfo.h"
#include "../../lib/constants/Enumerations.h"
#include "../../lib/entities/artifact/CArtHandler.h" #include "../../lib/entities/artifact/CArtHandler.h"
#include "../../lib/entities/building/CBuilding.h" #include "../../lib/entities/building/CBuilding.h"
#include "../../lib/entities/hero/CHeroHandler.h" #include "../../lib/entities/hero/CHeroHandler.h"
@@ -694,6 +696,46 @@ void PlayerMessageProcessor::cheatMaxMorale(PlayerColor player, const CGHeroInst
gameHandler->giveHeroBonus(&gb); gameHandler->giveHeroBonus(&gb);
} }
void PlayerMessageProcessor::cheatSkill(PlayerColor player, const CGHeroInstance * hero, std::vector<std::string> words)
{
if (!hero)
return;
std::string identifier;
try
{
identifier = words.at(0);
}
catch(std::logic_error&)
{
return;
}
MasteryLevel::Type mastery;
try
{
mastery = static_cast<MasteryLevel::Type>(std::stoi(words.at(1)));
}
catch(std::logic_error&)
{
mastery = MasteryLevel::Type::EXPERT;
}
if(identifier == "every")
{
for(const auto & skill : LIBRARY->skillh->objects)
gameHandler->changeSecSkill(hero, SecondarySkill(skill->getId()), mastery, ChangeValueMode::ABSOLUTE);
return;
}
std::optional<int32_t> skillId = LIBRARY->identifiers()->getIdentifier(ModScope::scopeGame(), "skill", identifier, false);
if(!skillId.has_value())
return;
auto skill = SecondarySkill(skillId.value());
gameHandler->changeSecSkill(hero, skill, mastery, ChangeValueMode::ABSOLUTE);
}
bool PlayerMessageProcessor::handleCheatCode(const std::string & cheat, PlayerColor player, ObjectInstanceID currObj) bool PlayerMessageProcessor::handleCheatCode(const std::string & cheat, PlayerColor player, ObjectInstanceID currObj)
{ {
std::vector<std::string> words; std::vector<std::string> words;
@@ -736,7 +778,8 @@ bool PlayerMessageProcessor::handleCheatCode(const std::string & cheat, PlayerCo
"vcmiluck", "nwcfollowthewhiterabbit", "nwccastleanthrax", "vcmiluck", "nwcfollowthewhiterabbit", "nwccastleanthrax",
"vcmimorale", "nwcmorpheus", "nwcmuchrejoicing", "vcmimorale", "nwcmorpheus", "nwcmuchrejoicing",
"vcmigod", "nwctheone", "vcmigod", "nwctheone",
"vcmiscrolls" "vcmiscrolls",
"vcmiskill"
}; };
if(vstd::contains(localCheats, cheatName)) if(vstd::contains(localCheats, cheatName))
@@ -829,7 +872,8 @@ void PlayerMessageProcessor::executeCheatCode(const std::string & cheatName, Pla
cheatMovement(player, hero, { }); cheatMovement(player, hero, { });
cheatFly(player, hero); cheatFly(player, hero);
}; };
const auto & doColorSchemeChange = [&](ColorScheme filter) { cheatColorSchemeChange(player, filter); }; const auto & doCheatColorSchemeChange = [&](ColorScheme filter) { cheatColorSchemeChange(player, filter); };
const auto & doCheatSkill = [&]() { cheatSkill(player, hero, words); };
std::map<std::string, std::function<void()>> callbacks = { std::map<std::string, std::function<void()>> callbacks = {
{"vcmiainur", [&] () {doCheatGiveArmyFixed({ "archangel", "5" });} }, {"vcmiainur", [&] () {doCheatGiveArmyFixed({ "archangel", "5" });} },
@@ -909,9 +953,10 @@ void PlayerMessageProcessor::executeCheatCode(const std::string & cheatName, Pla
{"vcmigod", doCheatTheOne }, {"vcmigod", doCheatTheOne },
{"nwctheone", doCheatTheOne }, {"nwctheone", doCheatTheOne },
{"vcmiscrolls", doCheatGiveScrolls }, {"vcmiscrolls", doCheatGiveScrolls },
{"vcmicolor", [&] () {doColorSchemeChange(ColorScheme::H2_SCHEME);} }, {"vcmicolor", [&] () {doCheatColorSchemeChange(ColorScheme::H2_SCHEME);} },
{"nwcphisherprice", [&] () {doColorSchemeChange(ColorScheme::H2_SCHEME);} }, {"nwcphisherprice", [&] () {doCheatColorSchemeChange(ColorScheme::H2_SCHEME);} },
{"vcmigray", [&] () {doColorSchemeChange(ColorScheme::GRAYSCALE);} }, {"vcmigray", [&] () {doCheatColorSchemeChange(ColorScheme::GRAYSCALE);} },
{"vcmiskill", doCheatSkill },
}; };
assert(callbacks.count(cheatName)); assert(callbacks.count(cheatName));

View File

@@ -59,6 +59,7 @@ class PlayerMessageProcessor
void cheatMaxLuck(PlayerColor player, const CGHeroInstance * hero); void cheatMaxLuck(PlayerColor player, const CGHeroInstance * hero);
void cheatMaxMorale(PlayerColor player, const CGHeroInstance * hero); void cheatMaxMorale(PlayerColor player, const CGHeroInstance * hero);
void cheatFly(PlayerColor player, const CGHeroInstance * hero); void cheatFly(PlayerColor player, const CGHeroInstance * hero);
void cheatSkill(PlayerColor player, const CGHeroInstance * hero, std::vector<std::string> words);
void commandExit(PlayerColor player, const std::vector<std::string> & words); void commandExit(PlayerColor player, const std::vector<std::string> & words);
void commandKick(PlayerColor player, const std::vector<std::string> & words); void commandKick(PlayerColor player, const std::vector<std::string> & words);