Browse Source

Added trivial fuzzy logic to handle creature banks estimation.

Check http://forum.vcmi.eu/viewtopic.php?p=6570#6570 for new library used.
DjWarmonger 13 years ago
parent
commit
998d8bf501
6 changed files with 231 additions and 79 deletions
  1. 110 0
      AI/VCAI/Fuzzy.cpp
  2. 34 0
      AI/VCAI/Fuzzy.h
  3. 64 66
      AI/VCAI/VCAI.cpp
  4. 2 0
      AI/VCAI/VCAI.h
  5. 20 13
      lib/CObjectHandler.cpp
  6. 1 0
      lib/CObjectHandler.h

+ 110 - 0
AI/VCAI/Fuzzy.cpp

@@ -0,0 +1,110 @@
+#include "StdInc.h"
+#include "Fuzzy.h"
+#include "../../lib/CObjectHandler.h"
+#include "AreaCentroidAlgorithm.cpp"
+#include "CompoundTerm.cpp"
+#include "DescriptiveAntecedent.cpp"
+#include "FuzzyEngine.cpp"
+#include "FuzzyAnd.cpp"
+#include "FuzzyOr.cpp"
+#include "InputLVar.cpp"
+#include "OutputLVar.cpp"
+#include "FuzzyAntecedent.cpp"
+#include "FuzzyConsequent.cpp"
+#include "FuzzyDefuzzifier.cpp"
+#include "FuzzyModulation.cpp"
+#include "FuzzyOperator.cpp"
+#include "FuzzyOperation.cpp"
+#include "FuzzyException.cpp"
+#include "FuzzyExceptions.cpp"
+#include "FuzzyRule.cpp"
+#include "HedgeSet.cpp"
+#include "Hedge.cpp"
+#include "SingletonTerm.cpp"
+#include "TrapezoidalTerm.cpp"
+#include "TriangularTerm.cpp"
+#include "LinguisticTerm.cpp"
+#include "LinguisticVariable.cpp"
+#include "RuleBlock.cpp"
+#include "ShoulderTerm.cpp"
+#include "StrOp.cpp"
+#include "MamdaniRule.cpp"
+#include "MamdaniConsequent.cpp"
+
+/*
+ * Fuzzy.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+*/
+
+class BankConfig;
+class FuzzyEngine;
+class InputLVar;
+
+FuzzyHelper fh;
+
+ui64 evaluateBankConfig (BankConfig * bc)
+{
+	ui64 danger = 0;
+	BOOST_FOREACH (auto opt, bc->guards)
+	{
+		danger += VLC->creh->creatures[opt.first]->fightValue * opt.second;
+	}
+	return danger;
+}
+
+FuzzyHelper::FuzzyHelper()
+{
+	bankInput = new fl::InputLVar("BankInput");
+	bankDanger = new fl::OutputLVar("BankDanger");
+	bankInput->addTerm(new fl::SingletonTerm ("SET"));
+
+	engine.addRuleBlock (&ruleBlock); //have to be added before the rules are parsed
+	engine.addInputLVar (bankInput);
+	for (int i = 0; i < 4; ++i)
+	{
+		bankDanger->addTerm(new fl::TriangularTerm ("Bank" + boost::lexical_cast<std::string>(i), 0, 1));
+		ruleBlock.addRule(new fl::MamdaniRule("if BankInput is SET then BankDanger is Bank" + boost::lexical_cast<std::string>(i), engine));
+	}
+	engine.addOutputLVar (bankDanger);
+}
+
+ui64 FuzzyHelper::estimateBankDanger (int ID)
+{
+	std::vector <ConstTransitivePtr<BankConfig>> & configs = VLC->objh->banksInfo[ID];
+	ui64 val = INFINITY;;
+	switch (configs.size())
+	{
+		case 4:
+			try
+			{
+				int bankVal;
+				for (int i = 0; i < 4; ++i)
+				{
+					bankVal = evaluateBankConfig (VLC->objh->banksInfo[ID][i]);
+					bankDanger->term("Bank" + boost::lexical_cast<std::string>(i))->setMinimum(bankVal * 0.5f);
+					bankDanger->term("Bank" + boost::lexical_cast<std::string>(i))->setMaximum(bankVal * 1.5f);
+				}
+				int averageValue = (evaluateBankConfig (VLC->objh->banksInfo[ID][0]) + evaluateBankConfig (VLC->objh->banksInfo[ID][3])) * 0.5;
+				dynamic_cast<fl::SingletonTerm*>(bankInput->term("SET"))->setValue(1);
+				bankInput->setInput (0);
+				engine.process();
+				val = bankDanger->output().defuzzify(); //some expected value of this bank
+			}
+			catch (fl::FuzzyException fe)
+			{
+				tlog1 << fe.name() << ": " << fe.message() << '\n';
+			}
+		case 1: //rare case - Pyramid
+			val = evaluateBankConfig (VLC->objh->banksInfo[ID][0]);
+			break;
+		default:
+			tlog3 << ("Uhnandled bank config!\n");
+	}
+	return val;
+
+}

+ 34 - 0
AI/VCAI/Fuzzy.h

@@ -0,0 +1,34 @@
+#define INFINITY 1000000000 //definition required by FuzzyLite (?)
+#define NAN 1000000001
+#include "FuzzyLite.h"
+
+/*
+ * Fuzzy.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+*/
+
+class VCAI;
+
+template <typename T> bool isinf (T val)
+{
+	return val == INFINITY || val == -INFINITY;
+}
+
+class FuzzyHelper
+{
+	friend class VCAI;
+
+	fl::FuzzyEngine engine;
+	fl::InputLVar* bankInput;
+	fl::OutputLVar* bankDanger;
+	fl::RuleBlock ruleBlock;
+
+public:
+	FuzzyHelper();
+	ui64 estimateBankDanger (int ID);
+};

+ 64 - 66
AI/VCAI/VCAI.cpp

@@ -1,12 +1,14 @@
 #include "StdInc.h"
 #include "VCAI.h"
 #include "../../lib/UnlockGuard.h"
+#include "Fuzzy.h"
+#include "../../lib/CObjectHandler.h"
 
 #define I_AM_ELEMENTAR return CGoal(*this).setisElementar(true)
-
-
 CLogger &aiLogger = tlog6;
 
+extern FuzzyHelper fh;
+
 const int ACTUAL_RESOURCE_COUNT = 7;
 
 const double SAFE_ATTACK_CONSTANT = 2.5;
@@ -15,6 +17,7 @@ using namespace vstd;
 //one thread may be turn of AI and another will be handling a side effect for AI2
 boost::thread_specific_ptr<CCallback> cb;
 boost::thread_specific_ptr<VCAI> ai;
+
 // CCallback *cb;
 // VCAI *ai;
 
@@ -72,6 +75,7 @@ namespace Obj
 		MINE = 53,
 		MONSTER = 54,
 		OBELISK = 57,
+		PYRAMID = 63,
 		CRYPT = 84,
 		SHIPWRECK = 85,
 		TRADING_POST = 99,
@@ -319,22 +323,16 @@ ui64 evaluateDanger(const CGObjectInstance *obj)
 			return cre->getArmyStrength();
 		}
 	case Obj::CRYPT: //crypt
-		{
-			return VLC->creh->creatures[56]->AIValue * 25
-				+ VLC->creh->creatures[58]->AIValue * 20
-				+ VLC->creh->creatures[60]->AIValue * 9
-				+ VLC->creh->creatures[62]->AIValue * 5;
-		}
 	case Obj::CREATURE_BANK: //crebank
 	case Obj::SHIPWRECK: //shipwreck
 	case Obj::DERELICT_SHIP: //derelict ship
-		//TODO estimate danger
-		return 1000000000;
+	case Obj::PYRAMID:
+		return fh.estimateBankDanger (VLC->objh->bankObjToIndex(obj));
 	case Obj::WHIRLPOOL: //whirlpool
 	case Obj::MONOLITH1:
 	case Obj::MONOLITH2:
 	case Obj::MONOLITH3:
-		//TODO mechinism for handling monoliths
+		//TODO mechanism for handling monoliths
 		return 1000000000;
 	default:
 		return 0;
@@ -347,7 +345,7 @@ bool compareDanger(const CGObjectInstance *lhs, const CGObjectInstance *rhs)
 }
 
 VCAI::VCAI(void)
-{
+{
 	LOG_ENTRY;
 	myCb = NULL;
 	battleAIName = "StupidAI";
@@ -356,19 +354,19 @@ VCAI::VCAI(void)
 
 
 VCAI::~VCAI(void)
-{
+{
 	LOG_ENTRY;
 }
 
 void VCAI::availableCreaturesChanged(const CGDwelling *town)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::heroMoved(const TryMoveHero & details)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	if(details.result == TryMoveHero::TELEPORTATION)
 	{
@@ -393,43 +391,43 @@ void VCAI::heroMoved(const TryMoveHero & details)
 
 void VCAI::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::heroInGarrisonChange(const CGTownInstance *town)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::centerView(int3 pos, int focusTime)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::artifactAssembled(const ArtifactLocation &al)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::showTavernWindow(const CGObjectInstance *townOrTavern)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::playerBlocked(int reason)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	if (reason == PlayerBlocked::UPCOMING_BATTLE)
 		status.setBattle(UPCOMING_BATTLE);
@@ -437,19 +435,19 @@ void VCAI::playerBlocked(int reason)
 
 void VCAI::showPuzzleMap()
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::showShipyardDialog(const IShipyard *obj)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::gameOver(ui8 player, bool victory)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	BNLOG("Player %d: I heard that player %d %s.", playerID % (int)player % (victory ? "won" : "lost"));
 	if(player == playerID)
@@ -480,32 +478,32 @@ void VCAI::gameOver(ui8 player, bool victory)
 
 void VCAI::artifactPut(const ArtifactLocation &al)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::artifactRemoved(const ArtifactLocation &al)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::stacksErased(const StackLocation &location)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::artifactDisassembled(const ArtifactLocation &al)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 
 void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	if(start && visitedObj->ID != Obj::MONSTER)
 		alreadyVisited.push_back(visitedObj);
@@ -513,13 +511,13 @@ void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visi
 
 void VCAI::availableArtifactsChanged(const CGBlackMarket *bm /*= NULL*/)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	//buildArmyIn(town);
 	//moveCreaturesToHero(town);
@@ -527,7 +525,7 @@ void VCAI::heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * tow
 
 void VCAI::tileHidden(const boost::unordered_set<int3, ShashInt3> &pos)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 // 	BOOST_FOREACH(int3 tile, pos)
 // 		BOOST_FOREACH(const CGObjectInstance *obj, cb->getVisitableObjs(tile))
@@ -537,7 +535,7 @@ void VCAI::tileHidden(const boost::unordered_set<int3, ShashInt3> &pos)
 
 void VCAI::tileRevealed(const boost::unordered_set<int3, ShashInt3> &pos)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	BOOST_FOREACH(int3 tile, pos)
 		BOOST_FOREACH(const CGObjectInstance *obj, myCb->getVisitableObjs(tile))
@@ -546,43 +544,43 @@ void VCAI::tileRevealed(const boost::unordered_set<int3, ShashInt3> &pos)
 
 void VCAI::heroExchangeStarted(si32 hero1, si32 hero2)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::heroMovePointsChanged(const CGHeroInstance * hero)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::stackChangedType(const StackLocation &location, const CCreature &newType)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::newObject(const CGObjectInstance * obj)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	if(obj->isVisitable())
 		addVisitableObj(obj);
@@ -590,7 +588,7 @@ void VCAI::newObject(const CGObjectInstance * obj)
 
 void VCAI::objectRemoved(const CGObjectInstance *obj)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	if(remove_if_present(visitableObjs, obj))
 		assert(obj->isVisitable());
@@ -598,43 +596,43 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
 
 void VCAI::showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::playerBonusChanged(const Bonus &bonus, bool gain)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::newStackInserted(const StackLocation &location, const CStackInstance &stack)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::heroCreated(const CGHeroInstance*)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::advmapSpellCast(const CGHeroInstance * caster, int spellID)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::requestRealized(PackageApplied *pa)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	if(status.haveTurn())
 	{
@@ -651,37 +649,37 @@ void VCAI::requestRealized(PackageApplied *pa)
 
 void VCAI::receivedResource(int type, int val)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::stacksSwapped(const StackLocation &loc1, const StackLocation &loc2)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::heroManaPointsChanged(const CGHeroInstance * hero)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::battleResultsApplied()
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	assert(status.getBattle() == ENDING_BATTLE);
 	status.setBattle(NO_BATTLE);
@@ -689,7 +687,7 @@ void VCAI::battleResultsApplied()
 
 void VCAI::objectPropertyChanged(const SetObjectProperty * sop)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	if(sop->what == ObjProperty::OWNER)
 	{
@@ -701,19 +699,19 @@ void VCAI::objectPropertyChanged(const SetObjectProperty * sop)
 
 void VCAI::buildChanged(const CGTownInstance *town, int buildingID, int what)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::showMarketWindow(const IMarket *market, const CGHeroInstance *visitor)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
@@ -721,7 +719,7 @@ void VCAI::init(CCallback * CB)
 {
 	myCb = CB;
 	cbc = CB;
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	playerID = myCb->getMyColor();
 	myCb->waitTillRealize = true;
@@ -732,7 +730,7 @@ void VCAI::init(CCallback * CB)
 
 void VCAI::yourTurn()
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	status.startedTurn();
 	makingTurn = new boost::thread(&VCAI::makeTurn, this);
@@ -740,7 +738,7 @@ void VCAI::yourTurn()
 
 void VCAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	status.addQuery();
 	callback(0);
@@ -748,7 +746,7 @@ void VCAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16
 
 void VCAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	int sel = 0;
 	status.addQuery();
@@ -764,7 +762,7 @@ void VCAI::showBlockingDialog(const std::string &text, const std::vector<Compone
 
 void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 	status.addQuery();
 	onEnd();
@@ -772,13 +770,13 @@ void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *do
 
 void VCAI::serialize(COSer<CSaveFile> &h, const int version)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 
 void VCAI::serialize(CISer<CLoadFile> &h, const int version)
 {
-	NET_EVENT_HANDLER;
+	NET_EVENT_HANDLER;
 	LOG_ENTRY;
 }
 

+ 2 - 0
AI/VCAI/VCAI.h

@@ -150,6 +150,8 @@ struct CIssueCommand : CGoal
 class VCAI : public CAdventureAI
 {
 public:
+	friend class FuzzyHelper;
+
 	std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
 	std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
 	std::map<const CGHeroInstance *, std::vector<const CGTownInstance *> > townVisitsThisWeek;

+ 20 - 13
lib/CObjectHandler.cpp

@@ -190,6 +190,25 @@ void CObjectHandler::loadObjects()
 	tlog5 << "\t\tDone loading banks configs \n";
 }
 
+int CObjectHandler::bankObjToIndex (const CGObjectInstance * obj)
+{
+	switch (obj->ID) //find apriopriate key
+	{
+		case 16: //bank
+			return obj->subID;
+		case 24: //derelict ship
+			return 8;
+		case 25: //utopia
+			return 10;
+		case 84: //crypt
+			return 9;
+		case 85: //shipwreck
+			return 7;
+		default:
+			tlog2 << "Unrecognixed Bank indetifier!\n";
+			return 0;
+	}
+}
 int CGObjectInstance::getOwner() const
 {
 	//if (state)
@@ -5688,19 +5707,7 @@ void CGOnceVisitable::searchTomb(const CGHeroInstance *h, ui32 accept) const
 
 void CBank::initObj()
 {
-	switch (ID) //find apriopriate key
-	{
-		case 16: //bank
-			index = subID; break;
-		case 24: //derelict ship
-			index = 8; break;
-		case 25: //utopia
-			index = 10; break;
-		case 84: //crypt
-			index = 9; break;
-		case 85: //shipwreck
-			index = 7; break;
-	}
+	index = VLC->objh->bankObjToIndex(this);
 	bc = NULL;
 	daycounter = 0;
 	multiplier = 1;

+ 1 - 0
lib/CObjectHandler.h

@@ -1309,6 +1309,7 @@ public:
 	std::vector<ui32> resVals; //default values of resources in gold
 
 	void loadObjects();
+	int bankObjToIndex (const CGObjectInstance * obj);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{