Преглед на файлове

Merge pull request #3266 from Laserlicht/puzzle_cheat

implement missing OH3/HDmod cheats
Ivan Savenko преди 1 година
родител
ревизия
acc09ee51a

+ 15 - 3
docs/players/Cheat_Codes.md

@@ -36,7 +36,7 @@ Gives specific creature in every slot, with optional amount. Examples:
 
 ### Movement points
 
-`nwcnebuchadnezzar` or `vcminahar` or `vcmimove` - give 1000000 movement points and free ship boarding for 1 day  
+`nwcnebuchadnezzar` or `vcminahar` or `vcmimove` - give unlimited (or specified amount of) movement points and free ship boarding
 Alternative usage: `vcmimove <amount>` - gives specified amount of movement points
 
 ### Resources
@@ -57,10 +57,22 @@ Alternative usage: `vcmilevel <amount>` - advances hero by specified number of l
 - `vcmiolorin` or `vcmiexp` - gives selected hero 10000 experience
 Alternative usage: `vcmiexp <amount>` - gives selected hero specified amount of experience
 
+### Luck and morale
+
+`nwcfollowthewhiterabbit` or `vcmiluck` - the currently selected hero permanently gains maximum luck
+`nwcmorpheus` or `vcmimorale` - the currently selected hero permanently gains maximum morale
+
+### Puzzle map
+
+`nwcoracle` or `vcmiobelisk` - reveals the puzzle map
+
 ### Finishing the game
 
-`nwcredpill` or `vcmisilmaril` or `vcmiwin` - player wins  
-`nwcbluepill` or `vcmimelkor` or `vcmilose` - player loses  
+`nwcredpill` or `vcmisilmaril` or `vcmiwin` - player wins
+`nwcbluepill` or `vcmimelkor` or `vcmilose` - player loses
+
+### Misc
+`nwctheone` or `vcmigod` - reveals the whole map, gives 5 archangels in each empty slot, unlimited movement points and permanent flight
 
 ## Using cheat codes on other players
 By default, all cheat codes apply to current player. Alternatively, it is possible to specify player that you want to target:

+ 20 - 6
lib/BasicTypes.cpp

@@ -93,6 +93,16 @@ int AFactionMember::getPrimSkillLevel(PrimarySkill id) const
 
 int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
 {
+	int32_t maxGoodMorale = VLC->settings()->getVector(EGameSettings::COMBAT_GOOD_MORALE_DICE).size();
+	int32_t maxBadMorale = - (int32_t) VLC->settings()->getVector(EGameSettings::COMBAT_BAD_MORALE_DICE).size();
+
+	if(getBonusBearer()->hasBonusOfType(BonusType::MAX_MORALE))
+	{
+		if(bonusList && !bonusList->empty())
+			bonusList = std::make_shared<const BonusList>();
+		return maxGoodMorale;
+	}
+
 	static const auto unaffectedByMoraleSelector = Selector::type()(BonusType::NON_LIVING).Or(Selector::type()(BonusType::UNDEAD))
 													.Or(Selector::type()(BonusType::SIEGE_WEAPON)).Or(Selector::type()(BonusType::NO_MORALE));
 
@@ -109,14 +119,21 @@ int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
 	static const std::string cachingStrMor = "type_MORALE";
 	bonusList = getBonusBearer()->getBonuses(moraleSelector, cachingStrMor);
 
-	int32_t maxGoodMorale = VLC->settings()->getVector(EGameSettings::COMBAT_GOOD_MORALE_DICE).size();
-	int32_t maxBadMorale = - (int32_t) VLC->settings()->getVector(EGameSettings::COMBAT_BAD_MORALE_DICE).size();
-
 	return std::clamp(bonusList->totalValue(), maxBadMorale, maxGoodMorale);
 }
 
 int AFactionMember::luckValAndBonusList(TConstBonusListPtr & bonusList) const
 {
+	int32_t maxGoodLuck = VLC->settings()->getVector(EGameSettings::COMBAT_GOOD_LUCK_DICE).size();
+	int32_t maxBadLuck = - (int32_t) VLC->settings()->getVector(EGameSettings::COMBAT_BAD_LUCK_DICE).size();
+
+	if(getBonusBearer()->hasBonusOfType(BonusType::MAX_LUCK))
+	{
+		if(bonusList && !bonusList->empty())
+			bonusList = std::make_shared<const BonusList>();
+		return maxGoodLuck;
+	}
+
 	if(getBonusBearer()->hasBonusOfType(BonusType::NO_LUCK))
 	{
 		if(bonusList && !bonusList->empty())
@@ -128,9 +145,6 @@ int AFactionMember::luckValAndBonusList(TConstBonusListPtr & bonusList) const
 	static const std::string cachingStrLuck = "type_LUCK";
 	bonusList = getBonusBearer()->getBonuses(luckSelector, cachingStrLuck);
 
-	int32_t maxGoodLuck = VLC->settings()->getVector(EGameSettings::COMBAT_GOOD_LUCK_DICE).size();
-	int32_t maxBadLuck = - (int32_t) VLC->settings()->getVector(EGameSettings::COMBAT_BAD_LUCK_DICE).size();
-
 	return std::clamp(bonusList->totalValue(), maxBadLuck, maxGoodLuck);
 }
 

+ 3 - 0
lib/bonuses/BonusEnum.h

@@ -20,6 +20,8 @@ class JsonNode;
 	BONUS_NAME(MOVEMENT) /*Subtype is 1 - land, 0 - sea*/ \
 	BONUS_NAME(MORALE) \
 	BONUS_NAME(LUCK) \
+	BONUS_NAME(MAX_MORALE) /*cheat bonus*/ \
+	BONUS_NAME(MAX_LUCK) /*cheat bonus*/ \
 	BONUS_NAME(PRIMARY_SKILL) /*uses subtype to pick skill; additional info if set: 1 - only melee, 2 - only distance*/  \
 	BONUS_NAME(SIGHT_RADIUS) \
 	BONUS_NAME(MANA_REGENERATION) /*points per turn*/  \
@@ -28,6 +30,7 @@ class JsonNode;
 	BONUS_NAME(SURRENDER_DISCOUNT) /*%*/  \
 	BONUS_NAME(STACKS_SPEED)  /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - subtracted to this part*/ \
 	BONUS_NAME(FLYING_MOVEMENT) /*value - penalty percentage*/ \
+	BONUS_NAME(UNLIMITED_MOVEMENT) /*cheat bonus*/ \
 	BONUS_NAME(SPELL_DURATION) \
 	BONUS_NAME(WATER_WALKING) /*value - penalty percentage*/ \
 	BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \

+ 4 - 1
lib/mapObjects/CGHeroInstance.cpp

@@ -239,7 +239,10 @@ int CGHeroInstance::movementPointsRemaining() const
 
 void CGHeroInstance::setMovementPoints(int points)
 {
-	movement = std::max(0, points);
+	if(getBonusBearer()->hasBonusOfType(BonusType::UNLIMITED_MOVEMENT))
+		movement = 1000000;
+	else
+		movement = std::max(0, points);
 }
 
 int CGHeroInstance::movementPointsLimit(bool onLand) const

+ 152 - 61
server/processors/PlayerMessageProcessor.cpp

@@ -24,6 +24,7 @@
 #include "../../lib/mapObjects/CGTownInstance.h"
 #include "../../lib/modding/IdentifierStorage.h"
 #include "../../lib/modding/ModScope.h"
+#include "../../lib/mapping/CMap.h"
 #include "../../lib/networkPacks/PacksForClient.h"
 #include "../../lib/networkPacks/StackLocation.h"
 
@@ -289,6 +290,7 @@ void PlayerMessageProcessor::cheatMovement(PlayerColor player, const CGHeroInsta
 
 	SetMovePoints smp;
 	smp.hid = hero->id;
+	bool unlimited = false;
 	try
 	{
 		smp.val = std::stol(words.at(0));;
@@ -296,16 +298,27 @@ void PlayerMessageProcessor::cheatMovement(PlayerColor player, const CGHeroInsta
 	catch(std::logic_error&)
 	{
 		smp.val = 1000000;
+		unlimited = true;
 	}
 
 	gameHandler->sendAndApply(&smp);
 
 	GiveBonus gb(GiveBonus::ETarget::OBJECT);
 	gb.bonus.type = BonusType::FREE_SHIP_BOARDING;
-	gb.bonus.duration = BonusDuration::ONE_DAY;
+	gb.bonus.duration = unlimited ? BonusDuration::PERMANENT : BonusDuration::ONE_DAY;
 	gb.bonus.source = BonusSource::OTHER;
 	gb.id = hero->id;
 	gameHandler->giveHeroBonus(&gb);
+
+	if(unlimited)
+	{
+		GiveBonus gb(GiveBonus::ETarget::OBJECT);
+		gb.bonus.type = BonusType::UNLIMITED_MOVEMENT;
+		gb.bonus.duration = BonusDuration::PERMANENT;
+		gb.bonus.source = BonusSource::OTHER;
+		gb.id = hero->id;
+		gameHandler->giveHeroBonus(&gb);
+	}
 }
 
 void PlayerMessageProcessor::cheatResources(PlayerColor player, std::vector<std::string> words)
@@ -365,6 +378,63 @@ void PlayerMessageProcessor::cheatMapReveal(PlayerColor player, bool reveal)
 	gameHandler->sendAndApply(&fc);
 }
 
+void PlayerMessageProcessor::cheatPuzzleReveal(PlayerColor player)
+{
+	TeamState *t = gameHandler->gameState()->getPlayerTeam(player);
+
+	for(auto & obj : gameHandler->gameState()->map->objects)
+	{
+		if(obj->ID == Obj::OBELISK)
+		{
+			gameHandler->setObjPropertyID(obj->id, ObjProperty::OBELISK_VISITED, t->id);
+			for(const auto & color : t->players)
+			{
+				gameHandler->setObjPropertyID(obj->id, ObjProperty::VISITED, color);
+
+				PlayerCheated pc;
+				pc.player = color;
+				gameHandler->sendAndApply(&pc);
+			}
+		}
+	}
+}
+
+void PlayerMessageProcessor::cheatMaxLuck(PlayerColor player, const CGHeroInstance * hero)
+{
+	if (!hero)
+		return;
+
+	GiveBonus gb;
+	gb.bonus = Bonus(BonusDuration::PERMANENT, BonusType::MAX_LUCK, BonusSource::OTHER, 0, BonusSourceID(Obj(Obj::NO_OBJ)));
+	gb.id = hero->id;
+
+	gameHandler->giveHeroBonus(&gb);
+}
+
+void PlayerMessageProcessor::cheatFly(PlayerColor player, const CGHeroInstance * hero)
+{
+	if (!hero)
+		return;
+		
+	GiveBonus gb;
+	gb.bonus = Bonus(BonusDuration::PERMANENT, BonusType::FLYING_MOVEMENT, BonusSource::OTHER, 0, BonusSourceID(Obj(Obj::NO_OBJ)));
+	gb.id = hero->id;
+
+	gameHandler->giveHeroBonus(&gb);
+}
+
+void PlayerMessageProcessor::cheatMaxMorale(PlayerColor player, const CGHeroInstance * hero)
+{
+	if (!hero)
+		return;
+		
+	GiveBonus gb;
+	gb.bonus = Bonus(BonusDuration::PERMANENT, BonusType::MAX_MORALE, BonusSource::OTHER, 0, BonusSourceID(Obj(Obj::NO_OBJ)));
+	gb.id = hero->id;
+
+	gameHandler->giveHeroBonus(&gb);
+}
+
 bool PlayerMessageProcessor::handleCheatCode(const std::string & cheat, PlayerColor player, ObjectInstanceID currObj)
 {
 	std::vector<std::string> words;
@@ -383,19 +453,23 @@ bool PlayerMessageProcessor::handleCheatCode(const std::string & cheat, PlayerCo
 		"vcmimelkor",    "vcmilose",      "nwcbluepill",
 		"vcmisilmaril",  "vcmiwin",       "nwcredpill",
 		"vcmieagles",    "vcmimap",       "nwcwhatisthematrix",
-		"vcmiungoliant", "vcmihidemap",   "nwcignoranceisbliss"
+		"vcmiungoliant", "vcmihidemap",   "nwcignoranceisbliss",
+		"vcmiobelisk",                    "nwcoracle"
 	};
 	std::vector<std::string> heroTargetedCheats = {
-		"vcmiainur",             "vcmiarchangel",   "nwctrinity",
-		"vcmiangband",           "vcmiblackknight", "nwcagents",
-		"vcmiglaurung",          "vcmicrystal",     "vcmiazure",
-		"vcmifaerie",            "vcmiarmy",        "vcminissi",
-		"vcmiistari",            "vcmispells",      "nwcthereisnospoon",
-		"vcminoldor",            "vcmimachines",     "nwclotsofguns",
-		"vcmiglorfindel",        "vcmilevel",       "nwcneo",
-		"vcminahar",             "vcmimove",        "nwcnebuchadnezzar",
-		"vcmiforgeofnoldorking", "vcmiartifacts",
-		"vcmiolorin",            "vcmiexp",
+		"vcmiainur",               "vcmiarchangel",   "nwctrinity",
+		"vcmiangband",             "vcmiblackknight", "nwcagents",
+		"vcmiglaurung",            "vcmicrystal",     "vcmiazure",
+		"vcmifaerie",              "vcmiarmy",        "vcminissi",
+		"vcmiistari",              "vcmispells",      "nwcthereisnospoon",
+		"vcminoldor",              "vcmimachines",    "nwclotsofguns",
+		"vcmiglorfindel",          "vcmilevel",       "nwcneo",
+		"vcminahar",               "vcmimove",        "nwcnebuchadnezzar",
+		"vcmiforgeofnoldorking",   "vcmiartifacts",
+		"vcmiolorin",              "vcmiexp",
+		"vcmiluck",                                   "nwcfollowthewhiterabbit", 
+		"vcmimorale",                                 "nwcmorpheus",
+		"vcmigod",                                    "nwctheone"
 	};
 
 	if (!vstd::contains(townTargetedCheats, cheatName) && !vstd::contains(playerTargetedCheats, cheatName) && !vstd::contains(heroTargetedCheats, cheatName))
@@ -469,60 +543,77 @@ void PlayerMessageProcessor::executeCheatCode(const std::string & cheatName, Pla
 	const auto & doCheatDefeat = [&]() { cheatDefeat(player); };
 	const auto & doCheatMapReveal = [&]() { cheatMapReveal(player, true); };
 	const auto & doCheatMapHide = [&]() { cheatMapReveal(player, false); };
+	const auto & doCheatRevealPuzzle = [&]() { cheatPuzzleReveal(player); };
+	const auto & doCheatMaxLuck = [&]() { cheatMaxLuck(player, hero); };
+	const auto & doCheatMaxMorale = [&]() { cheatMaxMorale(player, hero); };
+	const auto & doCheatTheOne = [&]()
+	{
+		if(!hero)
+			return;
+		cheatMapReveal(player, true);
+		cheatGiveArmy(player, hero, { "archangel", "5" });
+		cheatMovement(player, hero, { });
+		cheatFly(player, hero);
+	};
 
 	// Unimplemented H3 cheats:
-	// nwcfollowthewhiterabbit - The currently selected hero permanently gains maximum luck.
-	// nwcmorpheus - The currently selected hero permanently gains maximum morale.
-	// nwcoracle - The puzzle map is permanently revealed.
 	// nwcphisherprice - Changes and brightens the game colors.
 
 	std::map<std::string, std::function<void()>> callbacks = {
-		{"vcmiainur",            [&] () {doCheatGiveArmyFixed({ "archangel", "5" });} },
-		{"nwctrinity",           [&] () {doCheatGiveArmyFixed({ "archangel", "5" });} },
-		{"vcmiangband",          [&] () {doCheatGiveArmyFixed({ "blackKnight", "10" });} },
-		{"vcmiglaurung",         [&] () {doCheatGiveArmyFixed({ "crystalDragon", "5000" });} },
-		{"vcmiarchangel",        [&] () {doCheatGiveArmyFixed({ "archangel", "5" });} },
-		{"nwcagents",            [&] () {doCheatGiveArmyFixed({ "blackKnight", "10" });} },
-		{"vcmiblackknight",      [&] () {doCheatGiveArmyFixed({ "blackKnight", "10" });} },
-		{"vcmicrystal",          [&] () {doCheatGiveArmyFixed({ "crystalDragon", "5000" });} },
-		{"vcmiazure",            [&] () {doCheatGiveArmyFixed({ "azureDragon", "5000" });} },
-		{"vcmifaerie",           [&] () {doCheatGiveArmyFixed({ "fairieDragon", "5000" });} },
-		{"vcmiarmy",              doCheatGiveArmyCustom },
-		{"vcminissi",             doCheatGiveArmyCustom },
-		{"vcmiistari",            doCheatGiveSpells     },
-		{"vcmispells",            doCheatGiveSpells     },
-		{"nwcthereisnospoon",     doCheatGiveSpells     },
-		{"vcmiarmenelos",         doCheatBuildTown      },
-		{"vcmibuild",             doCheatBuildTown      },
-		{"nwczion",               doCheatBuildTown      },
-		{"vcminoldor",            doCheatGiveMachines   },
-		{"vcmimachines",          doCheatGiveMachines   },
-		{"nwclotsofguns",         doCheatGiveMachines   },
-		{"vcmiforgeofnoldorking", doCheatGiveArtifacts  },
-		{"vcmiartifacts",         doCheatGiveArtifacts  },
-		{"vcmiglorfindel",        doCheatLevelup        },
-		{"vcmilevel",             doCheatLevelup        },
-		{"nwcneo",                doCheatLevelup        },
-		{"vcmiolorin",            doCheatExperience     },
-		{"vcmiexp",               doCheatExperience     },
-		{"vcminahar",             doCheatMovement       },
-		{"vcmimove",              doCheatMovement       },
-		{"nwcnebuchadnezzar",     doCheatMovement       },
-		{"vcmiformenos",          doCheatResources      },
-		{"vcmiresources",         doCheatResources      },
-		{"nwctheconstruct",       doCheatResources      },
-		{"nwcbluepill",           doCheatDefeat         },
-		{"vcmimelkor",            doCheatDefeat         },
-		{"vcmilose",              doCheatDefeat         },
-		{"nwcredpill",            doCheatVictory        },
-		{"vcmisilmaril",          doCheatVictory        },
-		{"vcmiwin",               doCheatVictory        },
-		{"nwcwhatisthematrix",    doCheatMapReveal      },
-		{"vcmieagles",            doCheatMapReveal      },
-		{"vcmimap",               doCheatMapReveal      },
-		{"vcmiungoliant",         doCheatMapHide        },
-		{"vcmihidemap",           doCheatMapHide        },
-		{"nwcignoranceisbliss",   doCheatMapHide        },
+		{"vcmiainur",              [&] () {doCheatGiveArmyFixed({ "archangel", "5" });} },
+		{"nwctrinity",             [&] () {doCheatGiveArmyFixed({ "archangel", "5" });} },
+		{"vcmiangband",            [&] () {doCheatGiveArmyFixed({ "blackKnight", "10" });} },
+		{"vcmiglaurung",           [&] () {doCheatGiveArmyFixed({ "crystalDragon", "5000" });} },
+		{"vcmiarchangel",          [&] () {doCheatGiveArmyFixed({ "archangel", "5" });} },
+		{"nwcagents",              [&] () {doCheatGiveArmyFixed({ "blackKnight", "10" });} },
+		{"vcmiblackknight",        [&] () {doCheatGiveArmyFixed({ "blackKnight", "10" });} },
+		{"vcmicrystal",            [&] () {doCheatGiveArmyFixed({ "crystalDragon", "5000" });} },
+		{"vcmiazure",              [&] () {doCheatGiveArmyFixed({ "azureDragon", "5000" });} },
+		{"vcmifaerie",             [&] () {doCheatGiveArmyFixed({ "fairieDragon", "5000" });} },
+		{"vcmiarmy",                doCheatGiveArmyCustom },
+		{"vcminissi",               doCheatGiveArmyCustom },
+		{"vcmiistari",              doCheatGiveSpells     },
+		{"vcmispells",              doCheatGiveSpells     },
+		{"nwcthereisnospoon",       doCheatGiveSpells     },
+		{"vcmiarmenelos",           doCheatBuildTown      },
+		{"vcmibuild",               doCheatBuildTown      },
+		{"nwczion",                 doCheatBuildTown      },
+		{"vcminoldor",              doCheatGiveMachines   },
+		{"vcmimachines",            doCheatGiveMachines   },
+		{"nwclotsofguns",           doCheatGiveMachines   },
+		{"vcmiforgeofnoldorking",   doCheatGiveArtifacts  },
+		{"vcmiartifacts",           doCheatGiveArtifacts  },
+		{"vcmiglorfindel",          doCheatLevelup        },
+		{"vcmilevel",               doCheatLevelup        },
+		{"nwcneo",                  doCheatLevelup        },
+		{"vcmiolorin",              doCheatExperience     },
+		{"vcmiexp",                 doCheatExperience     },
+		{"vcminahar",               doCheatMovement       },
+		{"vcmimove",                doCheatMovement       },
+		{"nwcnebuchadnezzar",       doCheatMovement       },
+		{"vcmiformenos",            doCheatResources      },
+		{"vcmiresources",           doCheatResources      },
+		{"nwctheconstruct",         doCheatResources      },
+		{"nwcbluepill",             doCheatDefeat         },
+		{"vcmimelkor",              doCheatDefeat         },
+		{"vcmilose",                doCheatDefeat         },
+		{"nwcredpill",              doCheatVictory        },
+		{"vcmisilmaril",            doCheatVictory        },
+		{"vcmiwin",                 doCheatVictory        },
+		{"nwcwhatisthematrix",      doCheatMapReveal      },
+		{"vcmieagles",              doCheatMapReveal      },
+		{"vcmimap",                 doCheatMapReveal      },
+		{"vcmiungoliant",           doCheatMapHide        },
+		{"vcmihidemap",             doCheatMapHide        },
+		{"nwcignoranceisbliss",     doCheatMapHide        },
+		{"vcmiobelisk",             doCheatRevealPuzzle   },
+		{"nwcoracle",               doCheatRevealPuzzle   },
+		{"vcmiluck",                doCheatMaxLuck        },
+		{"nwcfollowthewhiterabbit", doCheatMaxLuck        },
+		{"vcmimorale",              doCheatMaxMorale      },
+		{"nwcmorpheus",             doCheatMaxMorale      },
+		{"vcmigod",                 doCheatTheOne         },
+		{"nwctheone",               doCheatTheOne         },
 	};
 
 	assert(callbacks.count(cheatName));

+ 4 - 0
server/processors/PlayerMessageProcessor.h

@@ -37,6 +37,10 @@ class PlayerMessageProcessor
 	void cheatVictory(PlayerColor player);
 	void cheatDefeat(PlayerColor player);
 	void cheatMapReveal(PlayerColor player, bool reveal);
+	void cheatPuzzleReveal(PlayerColor player);
+	void cheatMaxLuck(PlayerColor player, const CGHeroInstance * hero);
+	void cheatMaxMorale(PlayerColor player, const CGHeroInstance * hero);
+	void cheatFly(PlayerColor player, const CGHeroInstance * hero);
 
 public:
 	CGameHandler * gameHandler;