浏览代码

+ Handled banning spells and artifacts
+ Rename allowedSpell => allowedSpells

Tomasz Zieliński 2 年之前
父节点
当前提交
025b0814c8

+ 4 - 0
config/artifacts.json

@@ -1085,6 +1085,7 @@
 	},
 	"necklaceOfOceanGuidance":
 	{
+		"onlyOnWaterMap" : true,
 		"bonuses" : [
 			{
 				"type" : "MOVEMENT",
@@ -1325,6 +1326,7 @@
 	},
 	"bootsOfLevitation":
 	{
+		"onlyOnWaterMap" : true,
 		"bonuses" : [
 			{
 				"type" : "WATER_WALKING",
@@ -1796,6 +1798,7 @@
 	},
 	"seaCaptainsHat":
 	{
+		"onlyOnWaterMap" : true,
 		"bonuses" : [
 			{
 				"type" : "WHIRLPOOL_PROTECTION",
@@ -2159,6 +2162,7 @@
 	},
 	"admiralsHat":
 	{
+		"onlyOnWaterMap" : true,
 		"bonuses" : [
 			{
 				"type" : "FREE_SHIP_BOARDING",

+ 6 - 3
config/spells/adventure.json

@@ -13,7 +13,8 @@
 		},
 		"flags" : {
 			"indifferent": true
-		}
+		},
+		"onlyOnWaterMap" : true
 	},
 	"scuttleBoat" : {
 		"index" : 1,
@@ -29,7 +30,8 @@
 		},
 		"flags" : {
 			"indifferent": true
-		}
+		},
+		"onlyOnWaterMap" : true
 	},
 	"visions" : {
 		"index" : 2,
@@ -237,7 +239,8 @@
 		},
 		"flags" : {
 			"indifferent": true
-		}
+		},
+		"onlyOnWaterMap" : true
 	},
 	"dimensionDoor" : {
 		"index" : 8,

+ 1 - 0
lib/CArtHandler.cpp

@@ -434,6 +434,7 @@ CArtifact * CArtHandler::loadFromJson(const std::string & scope, const JsonNode
 	art->advMapDef = graphics["map"].String();
 
 	art->price = static_cast<ui32>(node["value"].Float());
+	art->onlyOnWaterMap = node["onlyOnWaterMap"].Bool();
 
 	loadSlots(art, node);
 	loadClass(art, node);

+ 2 - 0
lib/CArtHandler.h

@@ -111,6 +111,7 @@ public:
 	enum EartClass {ART_SPECIAL=1, ART_TREASURE=2, ART_MINOR=4, ART_MAJOR=8, ART_RELIC=16}; //artifact classes
 
 	EartClass aClass = ART_SPECIAL;
+	bool onlyOnWaterMap;
 
 	int32_t getIndex() const override;
 	int32_t getIconIndex() const override;
@@ -159,6 +160,7 @@ public:
 		h & modScope;
 		h & identifier;
 		h & warMachine;
+		h & onlyOnWaterMap;
 	}
 
 	CArtifact();

+ 1 - 1
lib/CGameInfoCallback.cpp

@@ -57,7 +57,7 @@ bool CGameInfoCallback::isAllowed(int32_t type, int32_t id) const
 	switch(type)
 	{
 	case 0:
-		return gs->map->allowedSpell[id];
+		return gs->map->allowedSpells[id];
 	case 1:
 		return gs->map->allowedArtifact[id];
 	case 2:

+ 1 - 1
lib/IGameCallback.cpp

@@ -174,7 +174,7 @@ void CPrivilegedInfoCallback::pickAllowedArtsSet(std::vector<const CArtifact *>
 
 void CPrivilegedInfoCallback::getAllowedSpells(std::vector<SpellID> & out, std::optional<ui16> level)
 {
-	for (ui32 i = 0; i < gs->map->allowedSpell.size(); i++) //spellh size appears to be greater (?)
+	for (ui32 i = 0; i < gs->map->allowedSpells.size(); i++) //spellh size appears to be greater (?)
 	{
 		const spells::Spell * spell = SpellID(i).toSpell();
 

+ 58 - 1
lib/mapping/CMap.cpp

@@ -137,7 +137,7 @@ CMap::CMap()
 	allHeroes.resize(allowedHeroes.size());
 	allowedAbilities = VLC->skillh->getDefaultAllowed();
 	allowedArtifact = VLC->arth->getDefaultAllowed();
-	allowedSpell = VLC->spellh->getDefaultAllowed();
+	allowedSpells = VLC->spellh->getDefaultAllowed();
 }
 
 CMap::~CMap()
@@ -580,6 +580,63 @@ bool CMap::calculateWaterContent()
 	return waterMap;
 }
 
+void CMap::banWaterContent()
+{
+	banWaterHeroes();
+	banWaterArtifacts();
+	banWaterSpells();
+}
+
+void CMap::banWaterSpells()
+{
+	for (int j = 0; j < allowedSpells.size(); j++)
+	{
+		if (allowedSpells[j])
+		{
+			auto* spell = dynamic_cast<const CSpell*>(VLC->spells()->getByIndex(j));
+			if (spell->onlyOnWaterMap && !isWaterMap())
+			{
+				allowedSpells[j] = false;
+			}
+		}
+	}
+}
+
+void CMap::banWaterArtifacts()
+{
+	for (int j = 0; j < allowedArtifact.size(); j++)
+	{
+		if (allowedArtifact[j])
+		{
+			auto* art = dynamic_cast<const CArtifact*>(VLC->artifacts()->getByIndex(j));
+			if (art->onlyOnWaterMap && !isWaterMap())
+			{
+				allowedArtifact[j] = false;
+			}
+		}
+	}
+}
+
+void CMap::banWaterHeroes()
+{
+	for (int j = 0; j < allowedHeroes.size(); j++)
+	{
+		if (allowedHeroes[j])
+		{
+			auto* h = dynamic_cast<const CHero*>(VLC->heroTypes()->getByIndex(j));
+			if ((h->onlyOnWaterMap && !isWaterMap()) || (h->onlyOnMapWithoutWater && isWaterMap()))
+			{
+				banHero(HeroTypeID(j));
+			}
+		}
+	}
+}
+
+void CMap::banHero(const HeroTypeID & id)
+{
+	allowedHeroes.at(id) = false;
+}
+
 void CMap::initTerrain()
 {
 	terrain.resize(boost::extents[levels()][width][height]);

+ 7 - 2
lib/mapping/CMap.h

@@ -108,6 +108,11 @@ public:
 
 	bool isWaterMap() const;
 	bool calculateWaterContent();
+	void banWaterArtifacts();
+	void banWaterHeroes();
+	void banHero(const HeroTypeID& id);
+	void banWaterSpells();
+	void banWaterContent();
 
 	/// Gets object of specified type on requested position
 	const CGObjectInstance * getObjectiveObjectFrom(const int3 & pos, Obj::EObj type);
@@ -122,7 +127,7 @@ public:
 	std::vector<Rumor> rumors;
 	std::vector<DisposedHero> disposedHeroes;
 	std::vector<ConstTransitivePtr<CGHeroInstance> > predefinedHeroes;
-	std::vector<bool> allowedSpell;
+	std::vector<bool> allowedSpells;
 	std::vector<bool> allowedArtifact;
 	std::vector<bool> allowedAbilities;
 	std::list<CMapEvent> events;
@@ -163,7 +168,7 @@ public:
 		h & static_cast<CMapHeader&>(*this);
 		h & triggeredEvents; //from CMapHeader
 		h & rumors;
-		h & allowedSpell;
+		h & allowedSpells;
 		h & allowedAbilities;
 		h & allowedArtifact;
 		h & events;

+ 3 - 2
lib/mapping/MapFormatH3M.cpp

@@ -119,6 +119,7 @@ void CMapLoaderH3M::init()
 
 	map->calculateGuardingGreaturePositions();
 	afterRead();
+	//map->banWaterContent(); //Not sure if force this for custom scenarios
 }
 
 void CMapLoaderH3M::readHeader()
@@ -774,12 +775,12 @@ void CMapLoaderH3M::readAllowedArtifacts()
 
 void CMapLoaderH3M::readAllowedSpellsAbilities()
 {
-	map->allowedSpell = VLC->spellh->getDefaultAllowed();
+	map->allowedSpells = VLC->spellh->getDefaultAllowed();
 	map->allowedAbilities = VLC->skillh->getDefaultAllowed();
 
 	if(features.levelSOD)
 	{
-		reader->readBitmaskSpells(map->allowedSpell, true);
+		reader->readBitmaskSpells(map->allowedSpells, true);
 		reader->readBitmaskSkills(map->allowedAbilities, true);
 	}
 }

+ 1 - 1
lib/mapping/MapFormatJson.cpp

@@ -834,7 +834,7 @@ void CMapFormatJson::serializeOptions(JsonSerializeFormat & handler)
 
 	handler.serializeLIC("allowedArtifacts",  &ArtifactID::decode, &ArtifactID::encode, VLC->arth->getDefaultAllowed(), map->allowedArtifact);
 
-	handler.serializeLIC("allowedSpells", &SpellID::decode, &SpellID::encode, VLC->spellh->getDefaultAllowed(), map->allowedSpell);
+	handler.serializeLIC("allowedSpells", &SpellID::decode, &SpellID::encode, VLC->spellh->getDefaultAllowed(), map->allowedSpells);
 
 	//todo:events
 }

+ 2 - 20
lib/rmg/CMapGenerator.cpp

@@ -413,7 +413,7 @@ void CMapGenerator::addHeaderInfo()
 	m.difficulty = 1;
 	addPlayerInfo();
 	m.waterMap = (mapGenOptions.getWaterContent() != EWaterContent::EWaterContent::NONE);
-	banWaterHeroes();
+	m.banWaterContent();
 }
 
 int CMapGenerator::getNextMonlithIndex()
@@ -453,24 +453,6 @@ const std::vector<ArtifactID> & CMapGenerator::getAllPossibleQuestArtifacts() co
 	return questArtifacts;
 }
 
-void CMapGenerator::banWaterHeroes()
-{
-	//This also bans only-land heroes on wazter maps
-	auto isWaterMap = map->getMap(this).isWaterMap();
-
-	for (int j = 0; j < map->getMap(this).allowedHeroes.size(); j++)
-	{
-		if (map->getMap(this).allowedHeroes[j])
-		{
-			auto* h = dynamic_cast<const CHero*>(VLC->heroTypes()->getByIndex(j));
-			if ((h->onlyOnWaterMap && !isWaterMap) || (h->onlyOnMapWithoutWater && isWaterMap)) //TODO: Refactor? Move to hero?
-			{
-				banHero(HeroTypeID(j));
-			}
-		}
-	}
-}
-
 const std::vector<HeroTypeID> CMapGenerator::getAllPossibleHeroes() const
 {
 	auto isWaterMap = map->getMap(this).isWaterMap();
@@ -503,7 +485,7 @@ void CMapGenerator::banQuestArt(const ArtifactID & id)
 void CMapGenerator::banHero(const HeroTypeID & id)
 {
 	//TODO: Protect with mutex
-	map->getMap(this).allowedHeroes[id] = false;
+	map->getMap(this).banHero(id);
 }
 
 Zone * CMapGenerator::getZoneWater() const

+ 0 - 1
lib/rmg/CMapGenerator.h

@@ -63,7 +63,6 @@ public:
 	int getPrisonsRemaning() const;
 	std::shared_ptr<CZonePlacer> getZonePlacer() const;
 	const std::vector<ArtifactID> & getAllPossibleQuestArtifacts() const;
-	void banWaterHeroes();
 	const std::vector<HeroTypeID> getAllPossibleHeroes() const;
 	void banQuestArt(const ArtifactID & id);
 	void banHero(const HeroTypeID& id);

+ 2 - 2
lib/rmg/RmgMap.cpp

@@ -343,9 +343,9 @@ ui32 RmgMap::getTotalZoneCount() const
 bool RmgMap::isAllowedSpell(const SpellID & sid) const
 {
 	assert(sid >= 0);
-	if (sid < mapInstance->allowedSpell.size())
+	if (sid < mapInstance->allowedSpells.size())
 	{
-		return mapInstance->allowedSpell[sid];
+		return mapInstance->allowedSpells[sid];
 	}
 	else
 		return false;

+ 2 - 0
lib/spells/CSpellHandler.cpp

@@ -784,6 +784,8 @@ CSpell * CSpellHandler::loadFromJson(const std::string & scope, const JsonNode &
 
 	spell->special = flags["special"].Bool();
 
+	spell->onlyOnWaterMap = json["onlyOnWaterMap"].Bool();
+
 	auto findBonus = [&](const std::string & name, std::vector<BonusType> & vec)
 	{
 		auto it = bonusNameMap.find(name);

+ 2 - 1
lib/spells/CSpellHandler.h

@@ -199,7 +199,7 @@ public:
 	bool combat; //is this spell combat (true) or adventure (false)
 	bool creatureAbility; //if true, only creatures can use this spell
 	si8 positiveness; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative
-
+	bool onlyOnWaterMap; //Spell will be banned on maps without water
 	std::vector<SpellID> counteredSpells; //spells that are removed when effect of this spell is placed on creature (for bless-curse, haste-slow, and similar pairs)
 
 	JsonNode targetCondition; //custom condition on what spell can affect
@@ -305,6 +305,7 @@ public:
 		h & school;
 		h & animationInfo;
 		h & nonMagical;
+		h& onlyOnWaterMap;
 	}
 	friend class CSpellHandler;
 	friend class Graphics;

+ 2 - 2
mapeditor/inspector/rewardswidget.cpp

@@ -88,9 +88,9 @@ QList<QString> RewardsWidget::getListForType(RewardType typeId)
 			break;
 			
 		case RewardType::SPELL:
-			for(int i = 0; i < map.allowedSpell.size(); ++i)
+			for(int i = 0; i < map.allowedSpells.size(); ++i)
 			{
-				if(map.allowedSpell[i])
+				if(map.allowedSpells[i])
 					result.append(QString::fromStdString(VLC->spells()->getByIndex(i)->getNameTranslated()));
 			}
 			break;

+ 2 - 2
mapeditor/mapcontroller.cpp

@@ -94,9 +94,9 @@ void MapController::repairMap()
 	{
 		map()->allowedArtifact.resize(VLC->arth->getDefaultAllowed().size());
 	}
-	if(VLC->spellh->getDefaultAllowed().size() > map()->allowedSpell.size())
+	if(VLC->spellh->getDefaultAllowed().size() > map()->allowedSpells.size())
 	{
-		map()->allowedSpell.resize(VLC->spellh->getDefaultAllowed().size());
+		map()->allowedSpells.resize(VLC->spellh->getDefaultAllowed().size());
 	}
 	if(VLC->heroh->getDefaultAllowed().size() > map()->allowedHeroes.size())
 	{

+ 4 - 4
mapeditor/mapsettings.cpp

@@ -116,12 +116,12 @@ MapSettings::MapSettings(MapController & ctrl, QWidget *parent) :
 		item->setCheckState(controller.map()->allowedAbilities[i] ? Qt::Checked : Qt::Unchecked);
 		ui->listAbilities->addItem(item);
 	}
-	for(int i = 0; i < controller.map()->allowedSpell.size(); ++i)
+	for(int i = 0; i < controller.map()->allowedSpells.size(); ++i)
 	{
 		auto * item = new QListWidgetItem(QString::fromStdString(VLC->spellh->objects[i]->getNameTranslated()));
 		item->setData(Qt::UserRole, QVariant::fromValue(i));
 		item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
-		item->setCheckState(controller.map()->allowedSpell[i] ? Qt::Checked : Qt::Unchecked);
+		item->setCheckState(controller.map()->allowedSpells[i] ? Qt::Checked : Qt::Unchecked);
 		ui->listSpells->addItem(item);
 	}
 	for(int i = 0; i < controller.map()->allowedArtifact.size(); ++i)
@@ -525,10 +525,10 @@ void MapSettings::on_pushButton_clicked()
 		auto * item = ui->listAbilities->item(i);
 		controller.map()->allowedAbilities[i] = item->checkState() == Qt::Checked;
 	}
-	for(int i = 0; i < controller.map()->allowedSpell.size(); ++i)
+	for(int i = 0; i < controller.map()->allowedSpells.size(); ++i)
 	{
 		auto * item = ui->listSpells->item(i);
-		controller.map()->allowedSpell[i] = item->checkState() == Qt::Checked;
+		controller.map()->allowedSpells[i] = item->checkState() == Qt::Checked;
 	}
 	for(int i = 0; i < controller.map()->allowedArtifact.size(); ++i)
 	{

+ 1 - 1
mapeditor/validator.cpp

@@ -140,7 +140,7 @@ std::list<Validator::Issue> Validator::validate(const CMap * map)
 				{
 					if(ins->storedArtifact)
 					{
-						if(!map->allowedSpell[ins->storedArtifact->getId().getNum()])
+						if(!map->allowedSpells[ins->storedArtifact->getId().getNum()])
 							issues.emplace_back(QString("Spell scroll %1 is prohibited by map settings").arg(ins->getObjectName().c_str()), false);
 					}
 					else