Laserlicht 1 年間 前
コミット
2052a26031

+ 1 - 1
client/NetPacksClient.cpp

@@ -176,7 +176,7 @@ void ApplyClientNetPackVisitor::visitSetMovePoints(SetMovePoints & pack)
 void ApplyClientNetPackVisitor::visitSetTownSpells(SetTownSpells & pack)
 {
 	for(const auto & win : GH.windows().findWindows<CMageGuildScreen>())
-		win->update();
+		win->updateSpells();
 }
 
 void ApplyClientNetPackVisitor::visitFoWChange(FoWChange & pack)

+ 6 - 9
client/windows/CCastleInterface.cpp

@@ -1982,10 +1982,10 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner, const ImagePath & i
 
 	exit = std::make_shared<CButton>(Point(748, 556), AnimationPath::builtin("TPMAGE1.DEF"), CButton::tooltip(CGI->generaltexth->allTexts[593]), [&](){ close(); }, EShortcut::GLOBAL_RETURN);
 
-	update();
+	updateSpells();
 }
 
-void CMageGuildScreen::update()
+void CMageGuildScreen::updateSpells()
 {
 	OBJECT_CONSTRUCTION;
 	static const std::vector<std::vector<Point> > positions =
@@ -2031,7 +2031,7 @@ CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell, ObjectInst
 void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition)
 {
 	const CGTownInstance * town = LOCPLINT->cb->getTown(townId);
-	if(LOCPLINT->cb->getSettings().getBoolean(EGameSettings::TOWNS_SPELL_RESEARCH))
+	if(LOCPLINT->cb->getSettings().getBoolean(EGameSettings::TOWNS_SPELL_RESEARCH) && town->spellResearchAllowed)
 	{
 		int daysSinceLastResearch = LOCPLINT->cb->getDate(Date::DAY) - town->lastSpellResearchDay;
 		if(!daysSinceLastResearch)
@@ -2045,12 +2045,9 @@ void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition)
 			if(vstd::find_pos(town->spells[i], spell->id) != -1)
 				level = i;
 
-		TResources cost;
-		cost[EGameResID::GOLD] = 1000;
-		cost[EGameResID::MERCURY] = (level + 1) * 2;
-		cost[EGameResID::SULFUR] = (level + 1) * 2;
-		cost[EGameResID::CRYSTAL] = (level + 1) * 2;
-		cost[EGameResID::GEMS] = (level + 1) * 2;
+		auto costBase = TResources(LOCPLINT->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_BASE));
+		auto costPerLevel = TResources(LOCPLINT->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_PER_LEVEL));
+		auto cost = costBase + costPerLevel * (level + 1);
 
 		std::vector<std::shared_ptr<CComponent>> resComps;
 		resComps.push_back(std::make_shared<CComponent>(ComponentType::SPELL, town->spells[level].at(town->spellsAtLevel(level, false))));

+ 1 - 1
client/windows/CCastleInterface.h

@@ -398,7 +398,7 @@ class CMageGuildScreen : public CStatusbarWindow
 
 public:
 	CMageGuildScreen(CCastleInterface * owner, const ImagePath & image);
-	void update();
+	void updateSpells();
 };
 
 /// The blacksmith window where you can buy available in town war machine

+ 5 - 1
config/gameConfig.json

@@ -313,7 +313,11 @@
 			// Chances for a town with default buildings to receive corresponding dwelling level built in start
 			"startingDwellingChances": [100, 50],
 			// Enable spell research in mage guild
-			"spellResearch": false
+			"spellResearch": false,
+			// Base cost for an spell research
+			"spellResearchCostBase": { "gold": 1000 },
+			// Costs depends on level for an spell research
+			"spellResearchCostPerLevel": { "wood" : 2, "mercury": 2, "ore": 2, "sulfur": 2, "crystal": 2, "gems": 2 }
 		},
 
 		"combat":

+ 5 - 3
config/schemas/gameSettings.json

@@ -51,9 +51,11 @@
 			"type" : "object",
 			"additionalProperties" : false,
 			"properties" : {
-				"buildingsPerTurnCap"  :    { "type" : "number" },
-				"startingDwellingChances" : { "type" : "array" },
-				"spellResearch" :           { "type" : "boolean" }
+				"buildingsPerTurnCap"  :      { "type" : "number" },
+				"startingDwellingChances" :   { "type" : "array" },
+				"spellResearch" :             { "type" : "boolean" },
+				"spellResearchCostBase" :     { "type" : "object" },
+				"spellResearchCostPerLevel" : { "type" : "object" }
 			}
 		},
 		"combat": {

+ 2 - 0
lib/GameSettings.cpp

@@ -102,6 +102,8 @@ const std::vector<GameSettings::SettingOption> GameSettings::settingProperties =
 		{EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP,           "towns",     "buildingsPerTurnCap"              },
 		{EGameSettings::TOWNS_STARTING_DWELLING_CHANCES,        "towns",     "startingDwellingChances"          },
 		{EGameSettings::TOWNS_SPELL_RESEARCH,                   "towns",     "spellResearch"                    },
+		{EGameSettings::TOWNS_SPELL_RESEARCH_COST_BASE,         "towns",     "spellResearchCostBase"            },
+		{EGameSettings::TOWNS_SPELL_RESEARCH_COST_PER_LEVEL,    "towns",     "spellResearchCostPerLevel"        },
 	};
 
 void GameSettings::loadBase(const JsonNode & input)

+ 2 - 0
lib/IGameSettings.h

@@ -80,6 +80,8 @@ enum class EGameSettings
 	TOWNS_BUILDINGS_PER_TURN_CAP,
 	TOWNS_STARTING_DWELLING_CHANCES,
 	TOWNS_SPELL_RESEARCH,
+	TOWNS_SPELL_RESEARCH_COST_BASE,
+	TOWNS_SPELL_RESEARCH_COST_PER_LEVEL,
 
 	OPTIONS_COUNT,
 	OPTIONS_BEGIN = BONUSES_GLOBAL

+ 2 - 1
lib/mapObjects/CGTownInstance.cpp

@@ -269,7 +269,8 @@ CGTownInstance::CGTownInstance(IGameCallback *cb):
 	destroyed(0),
 	identifier(0),
 	alignmentToPlayer(PlayerColor::NEUTRAL),
-	lastSpellResearchDay(0)
+	lastSpellResearchDay(0),
+	spellResearchAllowed(true)
 {
 	this->setNodeType(CBonusSystemNode::TOWN);
 }

+ 1 - 0
lib/mapObjects/CGTownInstance.h

@@ -74,6 +74,7 @@ public:
 	std::vector<CCastleEvent> events;
 	std::pair<si32, si32> bonusValue;//var to store town bonuses (rampart = resources from mystic pond, factory = save debts);
 	int lastSpellResearchDay;
+	bool spellResearchAllowed;
 
 	//////////////////////////////////////////////////////////////////////////
 	template <typename Handler> void serialize(Handler &h)

+ 1 - 4
lib/mapping/MapFormatH3M.cpp

@@ -2235,10 +2235,7 @@ CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_pt
 	}
 
 	if(features.levelHOTA1)
-	{
-		// TODO: HOTA support
-		[[maybe_unused]] bool spellResearchAvailable = reader->readBool();
-	}
+		object->spellResearchAllowed = reader->readBool();
 
 	// Read castle events
 	uint32_t eventsCount = reader->readUInt32();

+ 6 - 9
server/CGameHandler.cpp

@@ -2244,11 +2244,11 @@ bool CGameHandler::razeStructure (ObjectInstanceID tid, BuildingID bid)
 
 bool CGameHandler::spellResearch(ObjectInstanceID tid, SpellID spellAtSlot)
 {
-	if(!getSettings().getBoolean(EGameSettings::TOWNS_SPELL_RESEARCH) && complain("Spell research not allowed!"))
-		return false;
-
 	CGTownInstance *t = gs->getTown(tid);
 
+	if(!(getSettings().getBoolean(EGameSettings::TOWNS_SPELL_RESEARCH) && t->spellResearchAllowed) && complain("Spell research not allowed!"))
+		return false;
+
 	int level = -1;
 	for(int i = 0; i < t->spells.size(); i++)
 		if(vstd::find_pos(t->spells[i], spellAtSlot) != -1)
@@ -2261,12 +2261,9 @@ bool CGameHandler::spellResearch(ObjectInstanceID tid, SpellID spellAtSlot)
 	if(!daysSinceLastResearch && complain("Already researched today!"))
 		return false;
 
-	TResources cost;
-	cost[EGameResID::GOLD] = 1000;
-	cost[EGameResID::MERCURY] = (level + 1) * 2;
-	cost[EGameResID::SULFUR] = (level + 1) * 2;
-	cost[EGameResID::CRYSTAL] = (level + 1) * 2;
-	cost[EGameResID::GEMS] = (level + 1) * 2;
+	auto costBase = TResources(getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_BASE));
+	auto costPerLevel = TResources(getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_PER_LEVEL));
+	auto cost = costBase + costPerLevel * (level + 1);
 
 	if(!getPlayerState(t->getOwner())->resources.canAfford(cost) && complain("Spell replacement cannot be afforded!"))
 		return false;