mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Banks now use new scheme as well
- Implemented Bank Constructor object. - Merged Pyramid object into common Bank class. Banks can now grant spells as part of their reward. - Move bank config code to config/objects/creatureBanks.json. Note: WoG banks are not updated yet, should be moved to WoG mod. - Updated AI code so it can correctly evaluate bank danger (should be generic enough for use with other objects) - New files JsonRandom.* that contain routines for loading random objects from Json (still WiP but should be stable)
This commit is contained in:
		| @@ -5,6 +5,7 @@ | ||||
| #include "../../lib/UnlockGuard.h" | ||||
| #include "../../lib/CConfigHandler.h" | ||||
| #include "../../lib/CHeroHandler.h" | ||||
| #include "../../lib/mapObjects/CBank.h" | ||||
|  | ||||
| /* | ||||
|  * AIUtility.cpp, part of VCMI engine | ||||
| @@ -302,11 +303,11 @@ ui64 evaluateDanger(const CGObjectInstance *obj) | ||||
| 	case Obj::SHIPWRECK: //shipwreck | ||||
| 	case Obj::DERELICT_SHIP: //derelict ship | ||||
| //	case Obj::PYRAMID: | ||||
| 		return fh->estimateBankDanger (VLC->objh->bankObjToIndex(obj)); | ||||
| 		return fh->estimateBankDanger (dynamic_cast<const CBank *>(obj)); | ||||
| 	case Obj::PYRAMID: | ||||
| 		{ | ||||
| 		    if(obj->subID == 0) | ||||
| 				return fh->estimateBankDanger (VLC->objh->bankObjToIndex(obj)); | ||||
| 				return fh->estimateBankDanger (dynamic_cast<const CBank *>(obj)); | ||||
| 			else | ||||
| 				return 0; | ||||
| 		} | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include <limits> | ||||
|  | ||||
| #include "../../lib/mapObjects/MapObjects.h" | ||||
| #include "../../lib/mapObjects/CommonConstructors.h" | ||||
| #include "../../lib/CCreatureHandler.h" | ||||
| #include "../../lib/VCMI_Lib.h" | ||||
| #include "../../CCallback.h" | ||||
| @@ -41,16 +42,6 @@ struct armyStructure | ||||
| 	ui32 maxSpeed; | ||||
| }; | ||||
|  | ||||
| ui64 evaluateBankConfig (BankConfig * bc) | ||||
| { | ||||
| 	ui64 danger = 0; | ||||
| 	for (auto opt : bc->guards) | ||||
| 	{ | ||||
| 		danger += VLC->creh->creatures[opt.first]->fightValue * opt.second; | ||||
| 	} | ||||
| 	return danger; | ||||
| } | ||||
|  | ||||
| armyStructure evaluateArmyStructure (const CArmedInstance * army) | ||||
| { | ||||
| 	ui64 totalStrenght = army->getArmyStrength(); | ||||
| @@ -208,42 +199,26 @@ void FuzzyHelper::initTacticalAdvantage() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ui64 FuzzyHelper::estimateBankDanger (int ID) | ||||
| ui64 FuzzyHelper::estimateBankDanger (const CBank * bank) | ||||
| { | ||||
| 	std::vector <ConstTransitivePtr<BankConfig>> & configs = VLC->objh->banksInfo[ID]; | ||||
| 	auto info = VLC->objtypeh->getHandlerFor(bank->ID, bank->subID)->getObjectInfo(bank->appearance); | ||||
|  | ||||
| 	ui64 val = std::numeric_limits<ui64>::max(); | ||||
| 	try | ||||
| 	{ | ||||
| 		switch (configs.size()) | ||||
| 		{ | ||||
| 			case 4: | ||||
| 				try | ||||
| 				{ | ||||
| 					for (int i = 0; i < 4; ++i) | ||||
| 					{ | ||||
| 						int 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); | ||||
| 					} | ||||
| 					//comparison purposes | ||||
| 					//int averageValue = (evaluateBankConfig (VLC->objh->banksInfo[ID][0]) + evaluateBankConfig (VLC->objh->banksInfo[ID][3])) * 0.5; | ||||
| 					//dynamic_cast<fl::SingletonTerm*>(bankInput->term("SET"))->setValue(0.5); | ||||
| 					bankInput->setInput (0.5); | ||||
| 					engine.process (BANK_DANGER); | ||||
| 					//engine.process(); | ||||
| 					val = bankDanger->output().defuzzify(); //some expected value of this bank | ||||
| 				} | ||||
| 				catch (fl::FuzzyException & fe) | ||||
| 				{ | ||||
|                     logAi->errorStream() << fe.name() << ": " << fe.message(); | ||||
| 				} | ||||
| 				break; | ||||
| 			case 1: //rare case - Pyramid | ||||
| 				val = evaluateBankConfig (VLC->objh->banksInfo[ID][0]); | ||||
| 				break; | ||||
| 			default: | ||||
|                 logAi->warnStream() << ("Uhnandled bank config!"); | ||||
| 		} | ||||
| 		bankDanger->term("Bank0")->setMinimum(info->minGuards().totalStrength * 0.5f); | ||||
| 		bankDanger->term("Bank0")->setMaximum(info->minGuards().totalStrength * 1.5f); | ||||
|  | ||||
| 		bankDanger->term("Bank1")->setMinimum(info->maxGuards().totalStrength * 0.5f); | ||||
| 		bankDanger->term("Bank1")->setMaximum(info->maxGuards().totalStrength * 1.5f); | ||||
|  | ||||
| 		//comparison purposes | ||||
| 		//int averageValue = (evaluateBankConfig (VLC->objh->banksInfo[ID][0]) + evaluateBankConfig (VLC->objh->banksInfo[ID][3])) * 0.5; | ||||
| 		//dynamic_cast<fl::SingletonTerm*>(bankInput->term("SET"))->setValue(0.5); | ||||
| 		bankInput->setInput (0.5); | ||||
| 		engine.process (BANK_DANGER); | ||||
| 		//engine.process(); | ||||
| 		val = bankDanger->output().defuzzify(); //some expected value of this bank | ||||
| 	} | ||||
| 	catch (fl::FuzzyException & fe) | ||||
| 	{ | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
|  | ||||
| class VCAI; | ||||
| class CArmedInstance; | ||||
| class CBank; | ||||
|  | ||||
| class FuzzyHelper | ||||
| { | ||||
| @@ -72,7 +73,7 @@ public: | ||||
| 	float evaluate (Goals::AbstractGoal & g); | ||||
| 	void setPriority (Goals::TSubgoal & g); | ||||
|  | ||||
| 	ui64 estimateBankDanger (int ID); | ||||
| 	ui64 estimateBankDanger (const CBank * bank); | ||||
| 	float getTacticalAdvantage (const CArmedInstance *we, const CArmedInstance *enemy); //returns factor how many times enemy is stronger than us | ||||
|  | ||||
| 	Goals::TSubgoal chooseSolution (Goals::TGoalVec vec); | ||||
|   | ||||
| @@ -1,675 +1,9 @@ | ||||
| //Resources:  Wood, Mercury, Ore, Sulfur, Crystal, Gems, Gold | ||||
| //Artifacts:  Treasure, Minor, Major, Relic | ||||
| //NOTE: all H3M banks were moved to objects/creatureBanks.json | ||||
| //Remaining part should be moved to WoG mod | ||||
| { | ||||
| 	"banks": [ | ||||
| 		{ | ||||
| 			"name" : "Cyclops Stockpile", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 20, "id": 94 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 506, | ||||
| 					"reward_resources":  | ||||
| 					{ | ||||
| 						"wood" : 4, | ||||
| 						"mercury" : 4, | ||||
| 						"ore" : 4, | ||||
| 						"sulfur" : 4, | ||||
| 						"crystal" : 4, | ||||
| 						"gems" : 4, | ||||
| 						"gold" : 0 | ||||
| 					}, | ||||
| 					"value": 10000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
|  | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 30, "id": 94 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 760, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"wood" : 6, | ||||
| 						"mercury" : 6, | ||||
| 						"ore" : 6, | ||||
| 						"sulfur" : 6, | ||||
| 						"crystal" : 6, | ||||
| 						"gems" : 6 | ||||
| 					}, | ||||
| 					"value": 15000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 150 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 40, "id": 94 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 1013, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"wood" : 8, | ||||
| 						"mercury" : 8, | ||||
| 						"ore" : 8, | ||||
| 						"sulfur" : 8, | ||||
| 						"crystal" : 8, | ||||
| 						"gems" : 8 | ||||
| 					}, | ||||
| 					"value": 20000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 200 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 50, "id": 94 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 1266, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"wood" : 10, | ||||
| 						"mercury" : 10, | ||||
| 						"ore" : 10, | ||||
| 						"sulfur" : 10, | ||||
| 						"crystal" : 10, | ||||
| 						"gems" : 10 | ||||
| 					}, | ||||
| 					"value": 25000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 250 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Dwarven Treasury", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 50, "id": 16 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 194, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"crystal" : 2, | ||||
| 						"gold" : 2500 | ||||
| 					}, | ||||
| 					"value": 3500, | ||||
| 					"profitability": 18, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 75, "id": 16 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 291, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"crystal" : 3, | ||||
| 						"gold" : 4000 | ||||
| 					}, | ||||
| 					"value": 5500, | ||||
| 					"profitability": 19, | ||||
| 					"easiest": 150 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 100, "id": 16 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 388, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"crystal" : 5, | ||||
| 						"gold" : 5000 | ||||
| 					}, | ||||
| 					"value": 7500, | ||||
| 					"profitability": 19, | ||||
| 					"easiest": 200 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 150, "id": 16 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 582, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"crystal" : 10, | ||||
| 						"gold" : 7500 | ||||
| 					}, | ||||
| 					"value": 12500, | ||||
| 					"profitability": 21, | ||||
| 					"easiest": 300 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Griffin Conservatory", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 50, "id": 4 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 351, | ||||
| 					"reward_creatures": [ { "number": 1, "id": 12 } ], | ||||
| 					"value": 3000, | ||||
| 					"profitability": 9, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 100, "id": 4 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 702, | ||||
| 					"reward_creatures": [ { "number": 2, "id": 12 } ], | ||||
| 					"value": 6000, | ||||
| 					"profitability": 9, | ||||
| 					"easiest": 200 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 150, "id": 4 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 1053, | ||||
| 					"reward_creatures": [ { "number": 3, "id": 12 } ], | ||||
| 					"value": 9000, | ||||
| 					"profitability": 9, | ||||
| 					"easiest": 300 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 200, "id": 4 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 1404, | ||||
| 					"reward_creatures": [ { "number": 4, "id": 12 } ], | ||||
| 					"value": 12000, | ||||
| 					"profitability": 9, | ||||
| 					"easiest": 400 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Imp Cache", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 100, "id": 42 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 100, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"wood" : 0, | ||||
| 						"mercury" : 2, | ||||
| 						"ore" : 0, | ||||
| 						"sulfur" : 0, | ||||
| 						"crystal" : 0, | ||||
| 						"gems" : 0, | ||||
| 						"gold" : 1000 | ||||
| 					}, | ||||
| 					"value": 2000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 150, "id": 42 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 150, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"mercury" : 3, | ||||
| 						"gold" : 1500 | ||||
| 					}, | ||||
| 					"value": 3000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 150 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 200, "id": 42 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 200, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"mercury" : 4, | ||||
| 						"gold" : 2000 | ||||
| 					}, | ||||
| 					"value": 4000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 200 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 300, "id": 42 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 300, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"mercury" : 6, | ||||
| 						"gold" : 3000 | ||||
| 					}, | ||||
| 					"value": 6000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 300 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Medusa Stores", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 20, "id": 76 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 207, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"sulfur" : 5, | ||||
| 						"gold" : 2000 | ||||
| 					}, | ||||
| 					"value": 4500, | ||||
| 					"profitability": 22, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 30, "id": 76 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 310, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"sulfur" : 6, | ||||
| 						"gold" : 3000 | ||||
| 					}, | ||||
| 					"value": 6000, | ||||
| 					"profitability": 19, | ||||
| 					"easiest": 150 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 40, "id": 76 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 414, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"sulfur" : 8, | ||||
| 						"gold" : 4000 | ||||
| 					}, | ||||
| 					"value": 8000, | ||||
| 					"profitability": 19, | ||||
| 					"easiest": 200 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 50, "id": 76 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 517, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"sulfur" : 10, | ||||
| 						"gold" : 5000 | ||||
| 					}, | ||||
| 					"value": 10000, | ||||
| 					"profitability": 19, | ||||
| 					"easiest": 250 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Naga Bank", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 10, "id": 38 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 403, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gems" : 8, | ||||
| 						"gold" : 4000 | ||||
| 					}, | ||||
| 					"value": 8000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 15, "id": 38 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 605, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gems" : 12, | ||||
| 						"gold" : 6000 | ||||
| 					}, | ||||
| 					"value": 12000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 150 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 20, "id": 38 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 806, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gems" : 16, | ||||
| 						"gold" : 8000 | ||||
| 					}, | ||||
| 					"value": 16000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 200 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 30, "id": 38 } ], | ||||
| 					"upgrade_chance": 50, | ||||
| 					"combat_value": 1210, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gems" : 24, | ||||
| 						"gold" : 12000 | ||||
| 					}, | ||||
| 					"value": 24000, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 300 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Dragon Fly Hive", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 30, "id": 105} ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 154, | ||||
| 					"reward_creatures": [ { "number": 4, "id": 108 } ], | ||||
| 					"value": 3200, | ||||
| 					"profitability": 21, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 45, "id": 105 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 230, | ||||
| 					"reward_creatures": [ { "number": 6, "id": 108 } ], | ||||
| 					"value": 4800, | ||||
| 					"profitability": 21, | ||||
| 					"easiest": 150 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 60, "id": 105 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 307, | ||||
| 					"reward_creatures": [ { "number": 8, "id": 108 } ], | ||||
| 					"value": 6400, | ||||
| 					"profitability": 21, | ||||
| 					"easiest": 200 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 90, "id": 105 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 461, | ||||
| 					"reward_creatures": [ { "number": 12, "id": 108 } ], | ||||
| 					"value": 9600, | ||||
| 					"profitability": 21, | ||||
| 					"easiest": 300 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Shipwreck", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 10, "id": 60 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 31, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 2000 | ||||
| 					}, | ||||
| 					"value": 2000, | ||||
| 					"profitability": 65, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 15, "id": 60 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 46, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 3000 | ||||
| 					}, | ||||
| 					"value": 3000, | ||||
| 					"profitability": 65, | ||||
| 					"easiest": 150 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 25, "id": 60 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 77, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 4000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 1, 0, 0, 0 ], | ||||
| 					"value": 5000, | ||||
| 					"profitability": 65, | ||||
| 					"easiest": 250 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 50, "id": 60 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 154, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 5000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 0, 1, 0, 0 ], | ||||
| 					"value": 7000, | ||||
| 					"profitability": 45, | ||||
| 					"easiest": 500 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Derelict Ship", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 20, "id": 115 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 138, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 3000 | ||||
| 					}, | ||||
| 					"value": 3000, | ||||
| 					"profitability": 22, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 30, "id": 115 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 207, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 3000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 1, 0, 0, 0 ], | ||||
| 					"value": 4000, | ||||
| 					"profitability": 19, | ||||
| 					"easiest": 150 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 40, "id": 115 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 276, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 4000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 1, 0, 0, 0 ], | ||||
| 					"value": 5000, | ||||
| 					"profitability": 18, | ||||
| 					"easiest": 200 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 60, "id": 115 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 414, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 6000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 0, 1, 0, 0 ], | ||||
| 					"value": 8000, | ||||
| 					"profitability": 19, | ||||
| 					"easiest": 300 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Crypt", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 30, "id": 56 }, { "number": 20, "id": 58 }, { "number": 0, "id": 60 } , { "number": 0, "id": 62 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 75, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 1500 | ||||
| 					}, | ||||
| 					"value": 1500, | ||||
| 					"profitability": 20, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 25, "id": 56 }, { "number": 20, "id": 58 }, { "number": 5, "id": 60 }, { "number": 0, "id": 62 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 94, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 2000 | ||||
| 					}, | ||||
| 					"value": 2000, | ||||
| 					"profitability": 21, | ||||
| 					"easiest": 126 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 20, "id": 56 }, { "number": 20, "id": 58 }, { "number": 10, "id": 60 }, { "number": 5, "id": 62 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 169, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 2500 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 1, 0, 0, 0 ], | ||||
| 					"value": 3500, | ||||
| 					"profitability": 21, | ||||
| 					"easiest": 225 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 20, "id": 56 }, { "number": 20, "id": 58 }, { "number": 10, "id": 60 }, { "number": 10, "id": 62 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 225, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 5000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 1, 0, 0, 0 ], | ||||
| 					"value": 6000, | ||||
| 					"profitability": 27, | ||||
| 					"easiest": 299 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Dragon Utopia", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 8, "id": 26 }, { "number": 5, "id": 82 }, { "number": 2, "id": 27 }, { "number": 1, "id": 83 }	], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 769, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 20000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 1, 1, 1, 1 ], | ||||
| 					"value": 38000, | ||||
| 					"profitability": 21, | ||||
| 					"easiest": 100 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 8, "id": 26 }, { "number": 6, "id": 82 }, { "number": 3, "id": 27 }, { "number": 2, "id": 83 }	], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 209, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 30000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 0, 1, 1, 2 ], | ||||
| 					"value": 57000, | ||||
| 					"profitability": 26, | ||||
| 					"easiest": 125 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 30, | ||||
| 					"guards": [ { "number": 8, "id": 26 }, { "number": 6, "id": 82 }, { "number": 4, "id": 27 }, { "number": 3, "id": 83 }	], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 556, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 40000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 0, 0, 1, 3 ], | ||||
| 					"value": 75000, | ||||
| 					"profitability": 29, | ||||
| 					"easiest": 145 | ||||
| 				}, | ||||
| 				{ | ||||
| 					"chance": 10, | ||||
| 					"guards": [ { "number": 8, "id": 26 }, { "number": 7, "id": 82 }, { "number": 6, "id": 27 }, { "number": 5, "id": 83 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 343, | ||||
| 					"reward_resources": | ||||
| 					{ | ||||
| 						"gold" : 50000 | ||||
| 					}, | ||||
| 					"reward_artifacts": [ 0, 0, 0, 4 ], | ||||
| 					"value": 90000, | ||||
| 					"profitability": 27, | ||||
| 					"easiest": 189 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Hunting Lodge", | ||||
| 			"levels": [ | ||||
| @@ -1252,21 +586,6 @@ | ||||
| 					"easiest": 250 | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|  | ||||
| 		{ | ||||
| 			"name" : "Pyramid", | ||||
| 			"levels": [ | ||||
| 				{ | ||||
| 					"chance": 100, | ||||
| 					"guards": [	{ "number": 20, "id": 116 }, { "number": 10, "id": 117 }, { "number": 20, "id": 116 }, { "number": 10, "id": 117 } ], | ||||
| 					"upgrade_chance": 0, | ||||
| 					"combat_value": 786, | ||||
| 					"value": 15000, | ||||
| 					"profitability": 19, | ||||
| 					"easiest": 100 | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
|   | ||||
| @@ -49,6 +49,7 @@ | ||||
| 	[ | ||||
| 		"config/objects/generic.json", | ||||
| 		"config/objects/moddables.json", | ||||
| 		"config/objects/creatureBanks.json", | ||||
| 		"config/objects/dwellings.json", | ||||
| 		"config/objects/rewardable.json" | ||||
| 	], | ||||
|   | ||||
							
								
								
									
										975
									
								
								config/objects/creatureBanks.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										975
									
								
								config/objects/creatureBanks.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,975 @@ | ||||
| { | ||||
| 	"creatureBank" : { | ||||
| 		"index" :16, | ||||
| 		"handler": "bank", | ||||
| 		"types" : { | ||||
| 			"cyclopsStockpile" : | ||||
| 			{ | ||||
| 				"index" : 0, | ||||
| 				"name" : "Cyclops Stockpile", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 4, "type": "cyclop" }, | ||||
| 							{ "amount": 4, "type": "cyclop" }, | ||||
| 							{ "amount": 4, "type": "cyclop", "upgradeChance": 50 }, | ||||
| 							{ "amount": 4, "type": "cyclop" }, | ||||
| 							{ "amount": 4, "type": "cyclop" } | ||||
| 						], | ||||
| 						 | ||||
| 						"combat_value": 506, | ||||
| 						"reward" : { | ||||
| 							"value": 10000, | ||||
| 							"resources":  | ||||
| 							{ | ||||
| 								"wood" : 4, | ||||
| 								"mercury" : 4, | ||||
| 								"ore" : 4, | ||||
| 								"sulfur" : 4, | ||||
| 								"crystal" : 4, | ||||
| 								"gems" : 4, | ||||
| 								"gold" : 0 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
|  | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 6, "type": "cyclop" }, | ||||
| 							{ "amount": 6, "type": "cyclop" }, | ||||
| 							{ "amount": 6, "type": "cyclop", "upgradeChance": 50 }, | ||||
| 							{ "amount": 6, "type": "cyclop" }, | ||||
| 							{ "amount": 6, "type": "cyclop" } | ||||
| 						], | ||||
| 						"combat_value": 760, | ||||
| 						"reward" : { | ||||
| 							"value": 15000, | ||||
| 							"resources":  | ||||
| 							{ | ||||
| 								"wood" : 6, | ||||
| 								"mercury" : 6, | ||||
| 								"ore" : 6, | ||||
| 								"sulfur" : 6, | ||||
| 								"crystal" : 6, | ||||
| 								"gems" : 6 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 8, "type": "cyclop" }, | ||||
| 							{ "amount": 8, "type": "cyclop" }, | ||||
| 							{ "amount": 8, "type": "cyclop", "upgradeChance": 50 }, | ||||
| 							{ "amount": 8, "type": "cyclop" }, | ||||
| 							{ "amount": 8, "type": "cyclop" } | ||||
| 						], | ||||
| 						"combat_value": 1013, | ||||
| 						"reward" : { | ||||
| 							"value": 20000 | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"wood" : 8, | ||||
| 								"mercury" : 8, | ||||
| 								"ore" : 8, | ||||
| 								"sulfur" : 8, | ||||
| 								"crystal" : 8, | ||||
| 								"gems" : 8 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 10, "type": "cyclop" }, | ||||
| 							{ "amount": 10, "type": "cyclop" }, | ||||
| 							{ "amount": 10, "type": "cyclop", "upgradeChance": 50 }, | ||||
| 							{ "amount": 10, "type": "cyclop" }, | ||||
| 							{ "amount": 10, "type": "cyclop" } | ||||
| 						], | ||||
| 						"combat_value": 1266, | ||||
| 						"reward" : { | ||||
| 							"value": 25000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"wood" : 10, | ||||
| 								"mercury" : 10, | ||||
| 								"ore" : 10, | ||||
| 								"sulfur" : 10, | ||||
| 								"crystal" : 10, | ||||
| 								"gems" : 10 | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			}, | ||||
| 			"dwarvenTreasury" : { | ||||
| 				"index" : 1, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Dwarven Treasury", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 10, "type": "dwarf" }, | ||||
| 							{ "amount": 10, "type": "dwarf" }, | ||||
| 							{ "amount": 10, "type": "dwarf", "upgradeChance": 50 }, | ||||
| 							{ "amount": 10, "type": "dwarf" }, | ||||
| 							{ "amount": 10, "type": "dwarf" } | ||||
| 						], | ||||
| 						"combat_value": 194, | ||||
| 						"reward" : { | ||||
| 						"value": 3500, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"crystal" : 2, | ||||
| 								"gold" : 2500 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 15, "type": "dwarf" }, | ||||
| 							{ "amount": 15, "type": "dwarf" }, | ||||
| 							{ "amount": 15, "type": "dwarf", "upgradeChance": 50 }, | ||||
| 							{ "amount": 15, "type": "dwarf" }, | ||||
| 							{ "amount": 15, "type": "dwarf" } | ||||
| 						], | ||||
| 						"combat_value": 291, | ||||
| 						"reward" : { | ||||
| 							"value": 5500, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"crystal" : 3, | ||||
| 								"gold" : 4000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 20, "type": "dwarf" }, | ||||
| 							{ "amount": 20, "type": "dwarf" }, | ||||
| 							{ "amount": 20, "type": "dwarf", "upgradeChance": 50 }, | ||||
| 							{ "amount": 20, "type": "dwarf" }, | ||||
| 							{ "amount": 20, "type": "dwarf" } | ||||
| 						], | ||||
| 						"combat_value": 388, | ||||
| 						"reward" : { | ||||
| 							"value": 7500, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"crystal" : 5, | ||||
| 								"gold" : 5000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 30, "type": "dwarf" }, | ||||
| 							{ "amount": 30, "type": "dwarf" }, | ||||
| 							{ "amount": 30, "type": "dwarf", "upgradeChance": 50 }, | ||||
| 							{ "amount": 30, "type": "dwarf" }, | ||||
| 							{ "amount": 30, "type": "dwarf" } | ||||
| 						], | ||||
| 						"combat_value": 582, | ||||
| 						"reward" : { | ||||
| 							"value": 12500, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"crystal" : 10, | ||||
| 								"gold" : 7500 | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			}, | ||||
| 			"griffinConservatory" : { | ||||
| 				"index" : 2, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Griffin Conservatory", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 10, "type": "griffin" }, | ||||
| 							{ "amount": 10, "type": "griffin" }, | ||||
| 							{ "amount": 10, "type": "griffin", "upgradeChance": 50 }, | ||||
| 							{ "amount": 10, "type": "griffin" }, | ||||
| 							{ "amount": 10, "type": "griffin" } | ||||
| 						], | ||||
| 						"combat_value": 351, | ||||
| 						"reward" : { | ||||
| 							"value": 3000, | ||||
| 							"creatures": [ { "amount": 1, "type": "angel" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 20, "type": "griffin" }, | ||||
| 							{ "amount": 20, "type": "griffin" }, | ||||
| 							{ "amount": 20, "type": "griffin", "upgradeChance": 50 }, | ||||
| 							{ "amount": 20, "type": "griffin" }, | ||||
| 							{ "amount": 20, "type": "griffin" } | ||||
| 						], | ||||
| 						"combat_value": 702, | ||||
| 						"reward" : { | ||||
| 							"value": 6000, | ||||
| 							"creatures": [ { "amount": 2, "type": "angel" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 30, "type": "griffin" }, | ||||
| 							{ "amount": 30, "type": "griffin" }, | ||||
| 							{ "amount": 30, "type": "griffin", "upgradeChance": 50 }, | ||||
| 							{ "amount": 30, "type": "griffin" }, | ||||
| 							{ "amount": 30, "type": "griffin" } | ||||
| 						], | ||||
| 						"combat_value": 1053, | ||||
| 						"reward" : { | ||||
| 							"value": 9000, | ||||
| 							"creatures": [ { "amount": 3, "type": "angel" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 40, "type": "griffin" }, | ||||
| 							{ "amount": 40, "type": "griffin" }, | ||||
| 							{ "amount": 40, "type": "griffin", "upgradeChance": 50 }, | ||||
| 							{ "amount": 40, "type": "griffin" }, | ||||
| 							{ "amount": 40, "type": "griffin" } | ||||
| 						], | ||||
| 						"combat_value": 1404, | ||||
| 						"reward" : { | ||||
| 							"value": 12000, | ||||
| 							"creatures": [ { "amount": 4, "type": "angel" } ] | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			}, | ||||
| 			"inpCache" :  { | ||||
| 				"index" : 3, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Imp Cache", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 20, "type": "imp" }, | ||||
| 							{ "amount": 20, "type": "imp" }, | ||||
| 							{ "amount": 20, "type": "imp", "upgradeChance": 50 }, | ||||
| 							{ "amount": 20, "type": "imp" }, | ||||
| 							{ "amount": 20, "type": "imp" } | ||||
| 						], | ||||
| 						"combat_value": 100, | ||||
| 						"reward" : { | ||||
| 							"value": 2000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"wood" : 0, | ||||
| 								"mercury" : 2, | ||||
| 								"ore" : 0, | ||||
| 								"sulfur" : 0, | ||||
| 								"crystal" : 0, | ||||
| 								"gems" : 0, | ||||
| 								"gold" : 1000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 30, "type": "imp" }, | ||||
| 							{ "amount": 30, "type": "imp" }, | ||||
| 							{ "amount": 30, "type": "imp", "upgradeChance": 50 }, | ||||
| 							{ "amount": 30, "type": "imp" }, | ||||
| 							{ "amount": 30, "type": "imp" } | ||||
| 						], | ||||
| 						"combat_value": 150, | ||||
| 						"reward" : { | ||||
| 							"value": 3000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"mercury" : 3, | ||||
| 								"gold" : 1500 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 40, "type": "imp" }, | ||||
| 							{ "amount": 40, "type": "imp" }, | ||||
| 							{ "amount": 40, "type": "imp", "upgradeChance": 50 }, | ||||
| 							{ "amount": 40, "type": "imp" }, | ||||
| 							{ "amount": 40, "type": "imp" } | ||||
| 						], | ||||
| 						"combat_value": 200, | ||||
| 						"reward" : { | ||||
| 							"value": 4000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"mercury" : 4, | ||||
| 								"gold" : 2000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 60, "type": "imp" }, | ||||
| 							{ "amount": 60, "type": "imp" }, | ||||
| 							{ "amount": 60, "type": "imp", "upgradeChance": 50 }, | ||||
| 							{ "amount": 60, "type": "imp" }, | ||||
| 							{ "amount": 60, "type": "imp" } | ||||
| 						], | ||||
| 						"combat_value": 300, | ||||
| 						"reward" : { | ||||
| 							"value": 6000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"mercury" : 6, | ||||
| 								"gold" : 3000 | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			}, | ||||
| 			"medusaStore" : { | ||||
| 				"index" : 4, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Medusa Stores", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 4, "type": "medusa" }, | ||||
| 							{ "amount": 4, "type": "medusa" }, | ||||
| 							{ "amount": 4, "type": "medusa", "upgradeChance": 50 }, | ||||
| 							{ "amount": 4, "type": "medusa" }, | ||||
| 							{ "amount": 4, "type": "medusa" } | ||||
| 						], | ||||
| 						"combat_value": 207, | ||||
| 						"reward" : { | ||||
| 							"value": 4500, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"sulfur" : 5, | ||||
| 								"gold" : 2000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 6, "type": "medusa" }, | ||||
| 							{ "amount": 6, "type": "medusa" }, | ||||
| 							{ "amount": 6, "type": "medusa", "upgradeChance": 50 }, | ||||
| 							{ "amount": 6, "type": "medusa" }, | ||||
| 							{ "amount": 6, "type": "medusa" } | ||||
| 						], | ||||
| 						"combat_value": 310, | ||||
| 						"reward" : { | ||||
| 							"value": 6000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"sulfur" : 6, | ||||
| 								"gold" : 3000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 8, "type": "medusa" }, | ||||
| 							{ "amount": 8, "type": "medusa" }, | ||||
| 							{ "amount": 8, "type": "medusa", "upgradeChance": 50 }, | ||||
| 							{ "amount": 8, "type": "medusa" }, | ||||
| 							{ "amount": 8, "type": "medusa" } | ||||
| 						], | ||||
| 						"combat_value": 414, | ||||
| 						"reward" : { | ||||
| 							"value": 8000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"sulfur" : 8, | ||||
| 								"gold" : 4000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 10, "type": "medusa" }, | ||||
| 							{ "amount": 10, "type": "medusa" }, | ||||
| 							{ "amount": 10, "type": "medusa", "upgradeChance": 50 }, | ||||
| 							{ "amount": 10, "type": "medusa" }, | ||||
| 							{ "amount": 10, "type": "medusa" } | ||||
| 						], | ||||
| 						"combat_value": 517, | ||||
| 						"reward" : { | ||||
| 							"value": 10000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"sulfur" : 10, | ||||
| 								"gold" : 5000 | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			}, | ||||
| 			"nagaBank" : { | ||||
| 				"index" : 5, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Naga Bank", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 2, "type": "naga" }, | ||||
| 							{ "amount": 2, "type": "naga" }, | ||||
| 							{ "amount": 2, "type": "naga", "upgradeChance": 50 }, | ||||
| 							{ "amount": 2, "type": "naga" }, | ||||
| 							{ "amount": 2, "type": "naga" } | ||||
| 						], | ||||
| 						"combat_value": 403, | ||||
| 						"reward" : { | ||||
| 							"value": 8000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gems" : 8, | ||||
| 								"gold" : 4000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 3, "type": "naga" }, | ||||
| 							{ "amount": 3, "type": "naga" }, | ||||
| 							{ "amount": 3, "type": "naga", "upgradeChance": 50 }, | ||||
| 							{ "amount": 3, "type": "naga" }, | ||||
| 							{ "amount": 3, "type": "naga" } | ||||
| 						], | ||||
| 						"combat_value": 605, | ||||
| 						"reward" : { | ||||
| 							"value": 12000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gems" : 12, | ||||
| 								"gold" : 6000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 4, "type": "naga" }, | ||||
| 							{ "amount": 4, "type": "naga" }, | ||||
| 							{ "amount": 4, "type": "naga", "upgradeChance": 50 }, | ||||
| 							{ "amount": 4, "type": "naga" }, | ||||
| 							{ "amount": 4, "type": "naga" } | ||||
| 						], | ||||
| 						"combat_value": 806, | ||||
| 						"reward" : { | ||||
| 							"value": 16000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gems" : 16, | ||||
| 								"gold" : 8000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 6, "type": "naga" }, | ||||
| 							{ "amount": 6, "type": "naga" }, | ||||
| 							{ "amount": 6, "type": "naga", "upgradeChance": 50 }, | ||||
| 							{ "amount": 6, "type": "naga" }, | ||||
| 							{ "amount": 6, "type": "naga" } | ||||
| 						], | ||||
| 						"combat_value": 1210, | ||||
| 						"reward" : { | ||||
| 							"value": 24000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gems" : 24, | ||||
| 								"gold" : 12000 | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			}, | ||||
| 			"dragonflyHive" : { | ||||
| 				"index" : 6, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Dragon Fly Hive", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 6, "type": "dragonFly" }, | ||||
| 							{ "amount": 6, "type": "dragonFly" }, | ||||
| 							{ "amount": 6, "type": "dragonFly" }, | ||||
| 							{ "amount": 6, "type": "dragonFly" }, | ||||
| 							{ "amount": 6, "type": "dragonFly" } | ||||
| 						], | ||||
| 						"combat_value": 154, | ||||
| 						"reward" : { | ||||
| 							"value": 3200, | ||||
| 							"creatures": [ { "amount": 4, "type": "vyvern" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 9, "type": "dragonFly" }, | ||||
| 							{ "amount": 9, "type": "dragonFly" }, | ||||
| 							{ "amount": 9, "type": "dragonFly" }, | ||||
| 							{ "amount": 9, "type": "dragonFly" }, | ||||
| 							{ "amount": 9, "type": "dragonFly" } | ||||
| 						], | ||||
| 						"combat_value": 230, | ||||
| 						"reward" : { | ||||
| 							"value": 4800, | ||||
| 							"creatures": [ { "amount": 6, "type": "vyvern" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 12, "type": "dragonFly" }, | ||||
| 							{ "amount": 12, "type": "dragonFly" }, | ||||
| 							{ "amount": 12, "type": "dragonFly" }, | ||||
| 							{ "amount": 12, "type": "dragonFly" }, | ||||
| 							{ "amount": 12, "type": "dragonFly" } | ||||
| 						], | ||||
| 						"combat_value": 307, | ||||
| 						"reward" : { | ||||
| 							"value": 6400, | ||||
| 							"creatures": [ { "amount": 8, "type": "vyvern" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 18, "type": "dragonFly" }, | ||||
| 							{ "amount": 18, "type": "dragonFly" }, | ||||
| 							{ "amount": 18, "type": "dragonFly" }, | ||||
| 							{ "amount": 18, "type": "dragonFly" }, | ||||
| 							{ "amount": 18, "type": "dragonFly" } | ||||
| 						], | ||||
| 						"combat_value": 461, | ||||
| 						"reward" : { | ||||
| 							"value": 9600, | ||||
| 							"creatures": [ { "amount": 12, "type": "vyvern" } ] | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| 	"shipwreck" : { | ||||
| 		"index" :85, | ||||
| 		"handler": "bank", | ||||
| 		"types" : { | ||||
| 			"shipwreck" : { | ||||
| 				"index" : 0, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Shipwreck", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 2, "type": "wight" }, | ||||
| 							{ "amount": 2, "type": "wight" }, | ||||
| 							{ "amount": 2, "type": "wight" }, | ||||
| 							{ "amount": 2, "type": "wight" }, | ||||
| 							{ "amount": 2, "type": "wight" } | ||||
| 						], | ||||
| 						"combat_value": 31, | ||||
| 						"reward" : { | ||||
| 							"value": 2000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 2000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 3, "type": "wight" }, | ||||
| 							{ "amount": 3, "type": "wight" }, | ||||
| 							{ "amount": 3, "type": "wight" }, | ||||
| 							{ "amount": 3, "type": "wight" }, | ||||
| 							{ "amount": 3, "type": "wight" } | ||||
| 						], | ||||
| 						"combat_value": 46, | ||||
| 						"reward" : { | ||||
| 							"value": 3000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 3000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 5, "type": "wight" }, | ||||
| 							{ "amount": 5, "type": "wight" }, | ||||
| 							{ "amount": 5, "type": "wight" }, | ||||
| 							{ "amount": 5, "type": "wight" }, | ||||
| 							{ "amount": 5, "type": "wight" } | ||||
| 						], | ||||
| 						"combat_value": 77, | ||||
| 						"reward" : { | ||||
| 							"value": 5000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 4000 | ||||
| 							}, | ||||
| 							"artifacts": [ { "class" : "TREASURE" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 10, "type": "wight" }, | ||||
| 							{ "amount": 10, "type": "wight" }, | ||||
| 							{ "amount": 10, "type": "wight" }, | ||||
| 							{ "amount": 10, "type": "wight" }, | ||||
| 							{ "amount": 10, "type": "wight" } | ||||
| 						], | ||||
| 						"combat_value": 154, | ||||
| 						"reward" : { | ||||
| 							"value": 7000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 5000 | ||||
| 							}, | ||||
| 							"artifacts": [ { "class" : "MINOR" } ] | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	"derelictShip" : { | ||||
| 		"index" :24, | ||||
| 		"handler": "bank", | ||||
| 		"types" : { | ||||
| 			"derelictShip" : { | ||||
| 				"index" : 0, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Derelict Ship", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 4, "type": "waterElemental" }, | ||||
| 							{ "amount": 4, "type": "waterElemental" }, | ||||
| 							{ "amount": 4, "type": "waterElemental" }, | ||||
| 							{ "amount": 4, "type": "waterElemental" }, | ||||
| 							{ "amount": 4, "type": "waterElemental" } | ||||
| 						], | ||||
| 						"combat_value": 138, | ||||
| 						"reward" : { | ||||
| 							"value": 3000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 3000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 6, "type": "waterElemental" }, | ||||
| 							{ "amount": 6, "type": "waterElemental" }, | ||||
| 							{ "amount": 6, "type": "waterElemental" }, | ||||
| 							{ "amount": 6, "type": "waterElemental" }, | ||||
| 							{ "amount": 6, "type": "waterElemental" } | ||||
| 						], | ||||
| 						"combat_value": 207, | ||||
| 						"reward" : { | ||||
| 							"value": 4000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 3000 | ||||
| 							}, | ||||
| 							"artifacts": [ { "class" : "TREASURE" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 8, "type": "waterElemental" }, | ||||
| 							{ "amount": 8, "type": "waterElemental" }, | ||||
| 							{ "amount": 8, "type": "waterElemental" }, | ||||
| 							{ "amount": 8, "type": "waterElemental" }, | ||||
| 							{ "amount": 8, "type": "waterElemental" } | ||||
| 						], | ||||
| 						"combat_value": 276, | ||||
| 						"reward" : { | ||||
| 							"value": 5000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 4000 | ||||
| 							}, | ||||
| 							"artifacts": [ { "class" : "TREASURE" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 12, "type": "waterElemental" }, | ||||
| 							{ "amount": 12, "type": "waterElemental" }, | ||||
| 							{ "amount": 12, "type": "waterElemental" }, | ||||
| 							{ "amount": 12, "type": "waterElemental" }, | ||||
| 							{ "amount": 12, "type": "waterElemental" } | ||||
| 						], | ||||
| 						"combat_value": 414, | ||||
| 						"reward" : { | ||||
| 							"value": 8000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 6000 | ||||
| 							}, | ||||
| 							"artifacts": [ { "class" : "MINOR" } ] | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| 	"crypt" : { | ||||
| 		"index" :84, | ||||
| 		"handler": "bank", | ||||
| 		"types" : { | ||||
| 			"crypt" : { | ||||
| 				"index" : 0, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Crypt", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 10, "type": "skeleton" }, | ||||
| 							{ "amount": 10, "type": "walkingDead" }, | ||||
| 							{ "amount": 10, "type": "walkingDead" }, | ||||
| 							{ "amount": 10, "type": "skeleton" }, | ||||
| 							{ "amount": 10, "type": "skeleton" } | ||||
| 						], | ||||
| 						"combat_value": 75, | ||||
| 						"reward" : { | ||||
| 							"value": 1500, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 1500 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 13, "type": "skeleton" }, | ||||
| 							{ "amount": 10, "type": "walkingDead" }, | ||||
| 							{ "amount": 5, "type": "wight" }, | ||||
| 							{ "amount": 10, "type": "walkingDead" }, | ||||
| 							{ "amount": 12, "type": "skeleton" } | ||||
| 						], | ||||
| 						"combat_value": 94, | ||||
| 						"reward" : { | ||||
| 							"value": 2000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 2000 | ||||
| 							} | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 20, "type": "skeleton" }, | ||||
| 							{ "amount": 20, "type": "walkingDead" }, | ||||
| 							{ "amount": 10, "type": "wight" }, | ||||
| 							{ "amount": 5, "type": "vampire" } | ||||
| 						], | ||||
| 						"combat_value": 169, | ||||
| 						"reward" : { | ||||
| 							"value": 3500, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 2500 | ||||
| 							}, | ||||
| 							"artifacts": [ { "class" : "TREASURE" } ] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 20, "type": "skeleton" }, | ||||
| 							{ "amount": 20, "type": "walkingDead" }, | ||||
| 							{ "amount": 10, "type": "wight" }, | ||||
| 							{ "amount": 10, "type": "vampire" } | ||||
| 						], | ||||
| 						"combat_value": 225, | ||||
| 						"reward" : { | ||||
| 							"value": 6000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 5000 | ||||
| 							}, | ||||
| 							"artifacts": [ { "class" : "TREASURE" } ] | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| 	"dragonUtopia" : { | ||||
| 		"index" :25, | ||||
| 		"handler": "bank", | ||||
| 		"types" : { | ||||
| 			"dragonUtopia" : { | ||||
| 				"index" : 0, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Dragon Utopia", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 8, "type": "greenDragon" }, | ||||
| 							{ "amount": 5, "type": "redDragon" }, | ||||
| 							{ "amount": 2, "type": "goldDragon" }, | ||||
| 							{ "amount": 1, "type": "blackDragon" } | ||||
| 						], | ||||
| 						"combat_value": 769, | ||||
| 						"reward" : { | ||||
| 							"value": 38000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 20000 | ||||
| 							}, | ||||
| 							"artifacts": [ | ||||
| 								{ "class" : "TREASURE" } | ||||
| 								{ "class" : "MINOR" } | ||||
| 								{ "class" : "MAJOR" } | ||||
| 								{ "class" : "RELIC" } | ||||
| 							] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 8, "type": "greenDragon" }, | ||||
| 							{ "amount": 6, "type": "redDragon" }, | ||||
| 							{ "amount": 3, "type": "goldDragon" }, | ||||
| 							{ "amount": 2, "type": "blackDragon" } | ||||
| 						], | ||||
| 						"combat_value": 209, | ||||
| 						"reward" : { | ||||
| 							"value": 57000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 30000 | ||||
| 							}, | ||||
| 							"artifacts": [ | ||||
| 								{ "class" : "MINOR" } | ||||
| 								{ "class" : "MAJOR" } | ||||
| 								{ "class" : "RELIC" } | ||||
| 								{ "class" : "RELIC" } | ||||
| 							] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 30, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 8, "type": "greenDragon" }, | ||||
| 							{ "amount": 6, "type": "redDragon" }, | ||||
| 							{ "amount": 4, "type": "goldDragon" }, | ||||
| 							{ "amount": 3, "type": "blackDragon" } | ||||
| 						], | ||||
| 						"combat_value": 556, | ||||
| 						"reward" : { | ||||
| 							"value": 75000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 40000 | ||||
| 							}, | ||||
| 							"artifacts": [ 0, 0, 1, 3 ] | ||||
| 							"artifacts": [ | ||||
| 								{ "class" : "MAJOR" } | ||||
| 								{ "class" : "RELIC" } | ||||
| 								{ "class" : "RELIC" } | ||||
| 								{ "class" : "RELIC" } | ||||
| 							] | ||||
| 						} | ||||
| 					}, | ||||
| 					{ | ||||
| 						"chance": 10, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 8, "type": "greenDragon" }, | ||||
| 							{ "amount": 7, "type": "redDragon" }, | ||||
| 							{ "amount": 6, "type": "goldDragon" }, | ||||
| 							{ "amount": 5, "type": "blackDragon" } | ||||
| 						], | ||||
| 						"combat_value": 343, | ||||
| 						"reward" : { | ||||
| 							"value": 90000, | ||||
| 							"resources": | ||||
| 							{ | ||||
| 								"gold" : 50000 | ||||
| 							}, | ||||
| 							"artifacts": [ 0, 0, 0, 4 ] | ||||
| 							"artifacts": [ | ||||
| 								{ "class" : "RELIC" } | ||||
| 								{ "class" : "RELIC" } | ||||
| 								{ "class" : "RELIC" } | ||||
| 								{ "class" : "RELIC" } | ||||
| 							] | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| 	"pyramid" : { | ||||
| 		"index" :63, | ||||
| 		"handler": "bank", | ||||
| 		"types" : { | ||||
| 			"pyramid" : { | ||||
| 				"index" : 0, | ||||
| 				"resetDuraition" : 28, | ||||
| 				"name" : "Pyramid", | ||||
| 				"levels": [ | ||||
| 					{ | ||||
| 						"chance": 100, | ||||
| 						"guards": [ | ||||
| 							{ "amount": 20, "type": "goldGolem" }, | ||||
| 							{ "amount": 10, "type": "diamondGolem" }, | ||||
| 							{ "amount": 20, "type": "goldGolem" }, | ||||
| 							{ "amount": 10, "type": "diamondGolem" } | ||||
| 						], | ||||
| 						"combat_value": 786, | ||||
| 						"reward" : { | ||||
| 							"value": 15000, | ||||
| 							"spells" : [ { "level" : 5 } ] | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -104,9 +104,9 @@ | ||||
| 					[ "fireElemental" ], | ||||
| 					[ "earthElemental" ] | ||||
| 				], | ||||
| 				"guards" : { | ||||
| 					"earthElemental" : 12 | ||||
| 				} | ||||
| 				"guards" : [ | ||||
| 					{ "amount" : 12, "type" : "earthElemental" } | ||||
| 				] | ||||
| 			}, | ||||
| 			"golemFactory" : { | ||||
| 				"index" : 1, | ||||
| @@ -116,10 +116,10 @@ | ||||
| 					[ "goldGolem" ], | ||||
| 					[ "diamondGolem" ] | ||||
| 				], | ||||
| 				"guards" : { | ||||
| 					"goldGolem" : 9, | ||||
| 					"diamondGolem" : 6 | ||||
| 				} | ||||
| 				"guards" : [ | ||||
| 					{ "amount" : 9, "type" : "goldGolem" }, | ||||
| 					{ "amount" : 6, "type" : "diamondGolem" } | ||||
| 				] | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
|   | ||||
| @@ -16,11 +16,6 @@ | ||||
|  | ||||
| 	"blackMarket"					: { "index" :7,  "handler": "blackMarket" }, | ||||
|  | ||||
| 	"crypt"							: { "index" :84, "handler": "bank" }, | ||||
| 	"shipwreck"						: { "index" :85, "handler": "bank" }, | ||||
| 	"derelictShip"					: { "index" :24, "handler": "bank" }, | ||||
| 	"dragonUtopia"					: { "index" :25, "handler": "bank" }, | ||||
|  | ||||
| 	"pandoraBox"					: { "index" :6,  "handler": "pandora" }, | ||||
| 	"event"							: { "index" :26, "handler": "event" }, | ||||
|  | ||||
| @@ -45,7 +40,6 @@ | ||||
| 	"magicWell"						: { "index" :49, "handler": "magicWell" }, | ||||
| 	"obelisk"						: { "index" :57, "handler": "obelisk" }, | ||||
| 	"oceanBottle"					: { "index" :59, "handler": "sign" }, | ||||
| 	"pyramid"						: { "index" :63, "handler": "pyramid" }, | ||||
| 	"scholar"						: { "index" :81, "handler": "scholar" }, | ||||
| 	"shipyard"						: { "index" :87, "handler": "shipyard" }, | ||||
| 	"sign"							: { "index" :91, "handler": "sign" }, | ||||
|   | ||||
| @@ -184,9 +184,6 @@ | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	// subtype: different content | ||||
| 	"creatureBank" : { "index" :16, "handler": "bank" }, | ||||
|  | ||||
| 	// subtype: 0 = normal, 1 = anti-magic | ||||
| 	"garrisonHorizontal"			: { "index" :33, "handler": "garrison" }, | ||||
| 	"garrisonVertical"				: { "index" :219, "handler": "garrison" }, | ||||
|   | ||||
| @@ -262,12 +262,21 @@ CArtifact * CArtHandler::loadFromJson(const JsonNode & node) | ||||
| 	return art; | ||||
| } | ||||
|  | ||||
| void CArtHandler::addSlot(CArtifact * art, const std::string & slotID) | ||||
| ArtifactPosition CArtHandler::stringToSlot(std::string slotName) | ||||
| { | ||||
| #define ART_POS(x) ( #x, ArtifactPosition::x ) | ||||
| 	static const std::map<std::string, ArtifactPosition> artifactPositionMap = boost::assign::map_list_of ART_POS_LIST; | ||||
| #undef ART_POS | ||||
| 	auto it = artifactPositionMap.find (slotName); | ||||
| 	if (it != artifactPositionMap.end()) | ||||
| 		return it->second; | ||||
|  | ||||
| 	logGlobal->warnStream() << "Warning! Artifact slot " << slotName << " not recognized!"; | ||||
| 	return ArtifactPosition::PRE_FIRST; | ||||
| } | ||||
|  | ||||
| void CArtHandler::addSlot(CArtifact * art, const std::string & slotID) | ||||
| { | ||||
| 	if (slotID == "MISC") | ||||
| 	{ | ||||
| 		art->possibleSlots[ArtBearer::HERO] += ArtifactPosition::MISC1, ArtifactPosition::MISC2, ArtifactPosition::MISC3, ArtifactPosition::MISC4, ArtifactPosition::MISC5; | ||||
| @@ -278,14 +287,9 @@ void CArtHandler::addSlot(CArtifact * art, const std::string & slotID) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		auto it = artifactPositionMap.find (slotID); | ||||
| 		if (it != artifactPositionMap.end()) | ||||
| 		{ | ||||
| 			auto slot = it->second; | ||||
| 		auto slot = stringToSlot(slotID); | ||||
| 		if (slot != ArtifactPosition::PRE_FIRST) | ||||
| 			art->possibleSlots[ArtBearer::HERO].push_back (slot); | ||||
| 		} | ||||
| 		else | ||||
|             logGlobal->warnStream() << "Warning! Artifact slot " << slotID << " not recognized!"; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -303,7 +307,7 @@ void CArtHandler::loadSlots(CArtifact * art, const JsonNode & node) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CArtHandler::loadClass(CArtifact * art, const JsonNode & node) | ||||
| CArtifact::EartClass CArtHandler::stringToClass(std::string className) | ||||
| { | ||||
| 	static const std::map<std::string, CArtifact::EartClass> artifactClassMap = boost::assign::map_list_of | ||||
| 		("TREASURE", CArtifact::ART_TREASURE) | ||||
| @@ -312,16 +316,17 @@ void CArtHandler::loadClass(CArtifact * art, const JsonNode & node) | ||||
| 		("RELIC", CArtifact::ART_RELIC) | ||||
| 		("SPECIAL", CArtifact::ART_SPECIAL); | ||||
|  | ||||
| 	auto it = artifactClassMap.find (node["class"].String()); | ||||
| 	auto it = artifactClassMap.find (className); | ||||
| 	if (it != artifactClassMap.end()) | ||||
| 	{ | ||||
| 		art->aClass = it->second; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
|         logGlobal->warnStream() << "Warning! Artifact rarity " << node["class"].String() << " not recognized!"; | ||||
| 		art->aClass = CArtifact::ART_SPECIAL; | ||||
| 	} | ||||
| 		return it->second; | ||||
|  | ||||
| 	logGlobal->warnStream() << "Warning! Artifact rarity " << className << " not recognized!"; | ||||
| 	return CArtifact::ART_SPECIAL; | ||||
| } | ||||
|  | ||||
| void CArtHandler::loadClass(CArtifact * art, const JsonNode & node) | ||||
| { | ||||
| 	art->aClass = stringToClass(node["class"].String()); | ||||
| } | ||||
|  | ||||
| void CArtHandler::loadType(CArtifact * art, const JsonNode & node) | ||||
| @@ -424,7 +429,7 @@ CreatureID CArtHandler::machineIDToCreature(ArtifactID id) | ||||
| 	return CreatureID::NONE; //this artifact is not a creature | ||||
| } | ||||
|  | ||||
| ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags) | ||||
| ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags, std::function<bool(ArtifactID)> accepts) | ||||
| { | ||||
| 	auto getAllowedArts = [&](std::vector<ConstTransitivePtr<CArtifact> > &out, std::vector<CArtifact*> *arts, CArtifact::EartClass flag) | ||||
| 	{ | ||||
| @@ -433,8 +438,11 @@ ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags) | ||||
|  | ||||
| 		for (auto & arts_i : *arts) | ||||
| 		{ | ||||
| 			CArtifact *art = arts_i; | ||||
| 			out.push_back(art); | ||||
| 			if (accepts(arts_i->id)) | ||||
| 			{ | ||||
| 				CArtifact *art = arts_i; | ||||
| 				out.push_back(art); | ||||
| 			} | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| @@ -469,6 +477,16 @@ ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags) | ||||
| 	return artID; | ||||
| } | ||||
|  | ||||
| ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, std::function<bool(ArtifactID)> accepts) | ||||
| { | ||||
| 	return pickRandomArtifact(rand, 0xff, accepts); | ||||
| } | ||||
|  | ||||
| ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags) | ||||
| { | ||||
| 	return pickRandomArtifact(rand, flags, [](ArtifactID){ return true;}); | ||||
| } | ||||
|  | ||||
| Bonus *createBonus(Bonus::BonusType type, int val, int subtype, Bonus::ValueType valType, shared_ptr<ILimiter> limiter = shared_ptr<ILimiter>(), int additionalInfo = 0) | ||||
| { | ||||
| 	auto added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,-1,subtype); | ||||
|   | ||||
| @@ -203,11 +203,17 @@ public: | ||||
|  | ||||
| 	boost::optional<std::vector<CArtifact*>&> listFromClass(CArtifact::EartClass artifactClass); | ||||
|  | ||||
| 	ArtifactPosition stringToSlot(std::string slotName); | ||||
| 	CArtifact::EartClass stringToClass(std::string className); | ||||
|  | ||||
| 	/// Gets a artifact ID randomly and removes the selected artifact from this handler. | ||||
| 	ArtifactID pickRandomArtifact(CRandomGenerator & rand, int flags); | ||||
| 	ArtifactID pickRandomArtifact(CRandomGenerator & rand, std::function<bool(ArtifactID)> accepts); | ||||
| 	ArtifactID pickRandomArtifact(CRandomGenerator & rand, int flags, std::function<bool(ArtifactID)> accepts); | ||||
|  | ||||
| 	bool legalArtifact(ArtifactID id); | ||||
| 	void getAllowedArts(std::vector<ConstTransitivePtr<CArtifact> > &out, std::vector<CArtifact*> *arts, int flag); | ||||
| 	void getAllowed(std::vector<ConstTransitivePtr<CArtifact> > &out, int flags); | ||||
| 	//void getAllowedArts(std::vector<ConstTransitivePtr<CArtifact> > &out, std::vector<CArtifact*> *arts, int flag); | ||||
| 	//void getAllowed(std::vector<ConstTransitivePtr<CArtifact> > &out, int flags); | ||||
| 	bool isBigArtifact (ArtifactID artID) const {return bigArtifacts.find(artID) != bigArtifacts.end();} | ||||
| 	void initAllowedArtifactsList(const std::vector<bool> &allowed); //allowed[art_id] -> 0 if not allowed, 1 if allowed | ||||
| 	static ArtifactID creatureToMachineID(CreatureID id); | ||||
|   | ||||
| @@ -31,6 +31,7 @@ set(lib_SRCS | ||||
| 		mapObjects/CQuest.cpp | ||||
| 		mapObjects/CRewardableConstructor.cpp | ||||
| 		mapObjects/CRewardableObject.cpp | ||||
| 		mapObjects/JsonRandom.cpp | ||||
| 		mapObjects/MiscObjects.cpp | ||||
| 		mapObjects/ObjectTemplate.cpp | ||||
|  | ||||
|   | ||||
| @@ -1021,8 +1021,7 @@ namespace ObjProperty | ||||
| 		BONUS_VALUE_FIRST, BONUS_VALUE_SECOND, //used in Rampart for special building that generates resources (storing resource type and quantity) | ||||
|  | ||||
| 		//creature-bank specific | ||||
| 		BANK_DAYCOUNTER, BANK_CLEAR_ARTIFACTS, BANK_ADD_ARTIFACT, BANK_MULTIPLIER, BANK_CONFIG_PRESET,  | ||||
| 		BANK_CLEAR_CONFIG, BANK_INIT_ARMY, BANK_RESET, | ||||
| 		BANK_DAYCOUNTER, BANK_RESET, BANK_CLEAR, | ||||
|  | ||||
| 		//object with reward | ||||
| 		REWARD_RESET, REWARD_SELECT | ||||
|   | ||||
| @@ -45,11 +45,11 @@ DLL_LINKAGE void preinitDLL(CConsoleHandler *Console) | ||||
|  | ||||
| DLL_LINKAGE void loadDLLClasses() | ||||
| { | ||||
| 	try | ||||
| 	//try | ||||
| 	{ | ||||
| 		VLC->init(); | ||||
| 	} | ||||
| 	HANDLE_EXCEPTION; | ||||
| 	//HANDLE_EXCEPTION; | ||||
| } | ||||
|  | ||||
| const IBonusTypeHandler * LibClasses::getBth() const | ||||
|   | ||||
| @@ -14,6 +14,8 @@ | ||||
| #include "../NetPacks.h" | ||||
| #include "../CGeneralTextHandler.h" | ||||
| #include "../CSoundBase.h" | ||||
| #include "CommonConstructors.h" | ||||
| #include "../CSpellHandler.h" | ||||
|  | ||||
| using namespace boost::assign; | ||||
|  | ||||
| @@ -24,134 +26,51 @@ static std::string & visitedTxt(const bool visited) | ||||
| 	return VLC->generaltexth->allTexts[id]; | ||||
| } | ||||
|  | ||||
| CBank::CBank() | ||||
| { | ||||
| } | ||||
|  | ||||
| CBank::~CBank() | ||||
| { | ||||
| } | ||||
|  | ||||
| void CBank::initObj() | ||||
| { | ||||
| 	index = VLC->objh->bankObjToIndex(this); | ||||
| 	bc = nullptr; | ||||
| 	daycounter = 0; | ||||
| 	multiplier = 1; | ||||
| 	resetDuration = 0; | ||||
| 	VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, cb->gameState()->getRandomGenerator()); | ||||
| } | ||||
|  | ||||
| const std::string & CBank::getHoverText() const | ||||
| { | ||||
| 	bool visited = (bc == nullptr); | ||||
| 	hoverName = VLC->objh->creBanksNames[index] + " " + visitedTxt(visited); | ||||
| 	hoverName = visitedTxt(visited); // FIXME: USE BANK_SPECIFIC NAMES | ||||
| 	return hoverName; | ||||
| } | ||||
| void CBank::reset(ui16 var1) //prevents desync | ||||
|  | ||||
| void CBank::setConfig(const BankConfig & config) | ||||
| { | ||||
| 	ui8 chance = 0; | ||||
| 	for (auto & elem : VLC->objh->banksInfo[index]) | ||||
| 	{ | ||||
| 		if (var1 < (chance += elem->chance)) | ||||
| 		{ | ||||
|  			bc = elem; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	artifacts.clear(); | ||||
| 	bc.reset(new BankConfig(config)); | ||||
| 	clear(); // remove all stacks, if any | ||||
|  | ||||
| 	for (auto & stack : config.guards) | ||||
| 		setCreature (SlotID(stacksCount()), stack.type->idNumber, stack.count); | ||||
| } | ||||
|  | ||||
| void CBank::initialize() const | ||||
| { | ||||
| 	cb->setObjProperty(id, ObjProperty::BANK_RESET, cb->gameState()->getRandomGenerator().nextInt()); //synchronous reset | ||||
|  | ||||
| 	for (ui8 i = 0; i <= 3; i++) | ||||
| 	{ | ||||
| 		for (ui8 n = 0; n < bc->artifacts[i]; n++) | ||||
| 		{ | ||||
| 			CArtifact::EartClass artClass; | ||||
| 			switch(i) | ||||
| 			{ | ||||
| 			case 0: artClass = CArtifact::ART_TREASURE; break; | ||||
| 			case 1: artClass = CArtifact::ART_MINOR; break; | ||||
| 			case 2: artClass = CArtifact::ART_MAJOR; break; | ||||
| 			case 3: artClass = CArtifact::ART_RELIC; break; | ||||
| 			default: assert(0); continue; | ||||
| 			} | ||||
|  | ||||
| 			int artID = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), artClass); | ||||
| 			cb->setObjProperty(id, ObjProperty::BANK_ADD_ARTIFACT, artID); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	cb->setObjProperty(id, ObjProperty::BANK_INIT_ARMY, cb->gameState()->getRandomGenerator().nextInt()); //get army | ||||
| } | ||||
| void CBank::setPropertyDer (ui8 what, ui32 val) | ||||
| /// random values are passed as arguments and processed identically on all clients | ||||
| { | ||||
| 	switch (what) | ||||
| 	{ | ||||
| 		case ObjProperty::BANK_DAYCOUNTER: //daycounter | ||||
| 			if (val == 0) | ||||
| 				daycounter = 1; //yes, 1 | ||||
| 			else | ||||
| 				daycounter++; | ||||
| 			break; | ||||
| 		case ObjProperty::BANK_MULTIPLIER: //multiplier, in percent | ||||
| 			multiplier = val / 100.0; | ||||
| 			break; | ||||
| 		case 13: //bank preset | ||||
| 			bc = VLC->objh->banksInfo[index][val]; | ||||
| 				daycounter+=val; | ||||
| 			break; | ||||
| 		case ObjProperty::BANK_RESET: | ||||
| 			reset (val%100); | ||||
| 			initObj(); | ||||
| 			daycounter = 1; //yes, 1 since "today" daycounter won't be incremented | ||||
| 			break; | ||||
| 		case ObjProperty::BANK_CLEAR_CONFIG: | ||||
| 			bc = nullptr; | ||||
| 		case ObjProperty::BANK_CLEAR: | ||||
| 			bc.reset(); | ||||
| 			break; | ||||
| 		case ObjProperty::BANK_CLEAR_ARTIFACTS: //remove rewards from Derelict Ship | ||||
| 			artifacts.clear(); | ||||
| 			break; | ||||
| 		case ObjProperty::BANK_INIT_ARMY: //set ArmedInstance army | ||||
| 			{ | ||||
| 				int upgraded = 0; | ||||
| 				if (val%100 < bc->upgradeChance) //once again anti-desync | ||||
| 					upgraded = 1; | ||||
| 				switch (bc->guards.size()) | ||||
| 				{ | ||||
| 					case 1: | ||||
| 						for	(int i = 0; i < 4; ++i) | ||||
| 							setCreature (SlotID(i), bc->guards[0].first, bc->guards[0].second  / 5 ); | ||||
| 						setCreature (SlotID(4), CreatureID(bc->guards[0].first + upgraded), bc->guards[0].second  / 5 ); | ||||
| 						break; | ||||
| 					case 4: | ||||
| 					{ | ||||
| 						if (bc->guards.back().second) //all stacks are present | ||||
| 						{ | ||||
| 							for (auto & elem : bc->guards) | ||||
| 							{ | ||||
| 								setCreature (SlotID(stacksCount()), elem.first, elem.second); | ||||
| 							} | ||||
| 						} | ||||
| 						else if (bc->guards[2].second)//Wraiths are present, split two stacks in Crypt | ||||
| 						{ | ||||
| 							setCreature (SlotID(0), bc->guards[0].first, bc->guards[0].second  / 2 ); | ||||
| 							setCreature (SlotID(1), bc->guards[1].first, bc->guards[1].second / 2); | ||||
| 							setCreature (SlotID(2), CreatureID(bc->guards[2].first + upgraded), bc->guards[2].second); | ||||
| 							setCreature (SlotID(3), bc->guards[1].first, bc->guards[1].second / 2 ); | ||||
| 							setCreature (SlotID(4), bc->guards[0].first, bc->guards[0].second - (bc->guards[0].second  / 2) ); | ||||
|  | ||||
| 						} | ||||
| 						else //split both stacks | ||||
| 						{ | ||||
| 							for	(int i = 0; i < 3; ++i) //skellies | ||||
| 								setCreature (SlotID(2*i), bc->guards[0].first, bc->guards[0].second  / 3); | ||||
| 							for	(int i = 0; i < 2; ++i) //zombies | ||||
| 								setCreature (SlotID(2*i+1), bc->guards[1].first, bc->guards[1].second  / 2); | ||||
| 						} | ||||
| 					} | ||||
| 						break; | ||||
| 					default: | ||||
|                         logGlobal->warnStream() << "Error: Unexpected army data: " << bc->guards.size() <<" items found"; | ||||
| 						return; | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 		case ObjProperty::BANK_ADD_ARTIFACT: //add Artifact | ||||
| 		{ | ||||
| 			artifacts.push_back (val); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -159,25 +78,19 @@ void CBank::newTurn() const | ||||
| { | ||||
| 	if (bc == nullptr) | ||||
| 	{ | ||||
| 		if (cb->getDate() == 1) | ||||
| 			initialize(); //initialize on first day | ||||
| 		else if (daycounter >= 28 && (subID < 13 || subID > 16)) //no reset for Emissaries | ||||
| 		if (resetDuration != 0) | ||||
| 		{ | ||||
| 			initialize(); | ||||
| 			cb->setObjProperty (id, ObjProperty::BANK_DAYCOUNTER, 0); //daycounter 0 | ||||
| 			if (ID == Obj::DERELICT_SHIP && cb->getDate() > 1) | ||||
| 			{ | ||||
| 				cb->setObjProperty (id, ObjProperty::BANK_MULTIPLIER, 0);//ugly hack to make derelict ships usable only once | ||||
| 				cb->setObjProperty (id, ObjProperty::BANK_CLEAR_ARTIFACTS, 0); | ||||
| 			} | ||||
| 			if (daycounter >= resetDuration) | ||||
| 				cb->setObjProperty (id, ObjProperty::BANK_RESET, 0); //daycounter 0 | ||||
| 			else | ||||
| 				cb->setObjProperty (id, ObjProperty::BANK_DAYCOUNTER, 1); //daycounter++ | ||||
| 		} | ||||
| 		else | ||||
| 			cb->setObjProperty (id, ObjProperty::BANK_DAYCOUNTER, 1); //daycounter++ | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CBank::wasVisited (PlayerColor player) const | ||||
| { | ||||
| 	return !bc; | ||||
| 	return !bc; //FIXME: player A should not know about visit done by player B | ||||
| } | ||||
|  | ||||
| void CBank::onHeroVisit (const CGHeroInstance * h) const | ||||
| @@ -185,6 +98,7 @@ void CBank::onHeroVisit (const CGHeroInstance * h) const | ||||
| 	if (bc) | ||||
| 	{ | ||||
| 		int banktext = 0; | ||||
| 		ui16 soundID = soundBase::ROGUE; | ||||
| 		switch (ID) | ||||
| 		{ | ||||
| 		case Obj::CREATURE_BANK: | ||||
| @@ -202,13 +116,17 @@ void CBank::onHeroVisit (const CGHeroInstance * h) const | ||||
| 		case Obj::SHIPWRECK: | ||||
| 			banktext = 122; | ||||
| 			break; | ||||
| 		case Obj::PYRAMID: | ||||
| 			soundID = soundBase::MYSTERY; | ||||
| 			banktext = 105; | ||||
| 			break; | ||||
| 		} | ||||
| 		BlockingDialog bd (true, false); | ||||
| 		bd.player = h->getOwner(); | ||||
| 		bd.soundID = soundBase::ROGUE; | ||||
| 		bd.text.addTxt(MetaString::ADVOB_TXT,banktext); | ||||
| 		if (ID == Obj::CREATURE_BANK) | ||||
| 			bd.text.addReplacement(VLC->objh->creBanksNames[index]); | ||||
| 		bd.soundID = soundID; | ||||
| 		bd.text.addTxt(MetaString::ADVOB_TXT, banktext); | ||||
| 		//if (ID == Obj::CREATURE_BANK) | ||||
| 		//	bd.text.addReplacement(VLC->objh->creBanksNames[index]); // FIXME: USE BANK SPECIFIC NAMES | ||||
| 		cb->showBlockingDialog (&bd); | ||||
| 	} | ||||
| 	else | ||||
| @@ -216,105 +134,100 @@ void CBank::onHeroVisit (const CGHeroInstance * h) const | ||||
| 		InfoWindow iw; | ||||
| 		iw.soundID = soundBase::GRAVEYARD; | ||||
| 		iw.player = h->getOwner(); | ||||
| 		if (ID == Obj::CRYPT) //morale penalty for empty Crypt | ||||
| 		if (ID == Obj::PYRAMID) // You come upon the pyramid ... pyramid is completely empty. | ||||
| 		{ | ||||
| 			GiveBonus gbonus; | ||||
| 			gbonus.id = h->id.getNum(); | ||||
| 			gbonus.bonus.duration = Bonus::ONE_BATTLE; | ||||
| 			gbonus.bonus.source = Bonus::OBJECT; | ||||
| 			gbonus.bonus.sid = ID; | ||||
| 			gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[98]; | ||||
| 			gbonus.bonus.type = Bonus::MORALE; | ||||
| 			gbonus.bonus.val = -1; | ||||
| 			cb->giveHeroBonus(&gbonus); | ||||
| 			iw.text << VLC->generaltexth->advobtxt[120]; | ||||
| 			iw.components.push_back (Component (Component::MORALE, 0 , -1, 0)); | ||||
| 			iw.text << VLC->generaltexth->advobtxt[107]; | ||||
| 			iw.components.push_back (Component (Component::LUCK, 0 , -2, 0)); | ||||
| 			GiveBonus gb; | ||||
| 			gb.bonus = Bonus(Bonus::ONE_BATTLE,Bonus::LUCK,Bonus::OBJECT,-2,id.getNum(),VLC->generaltexth->arraytxt[70]); | ||||
| 			gb.id = h->id.getNum(); | ||||
| 			cb->giveHeroBonus(&gb); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			iw.text << VLC->generaltexth->advobtxt[33]; | ||||
| 			iw.text.addReplacement(VLC->objh->creBanksNames[index]); | ||||
| 			iw.text << VLC->generaltexth->advobtxt[33];// This was X, now is completely empty | ||||
| 			//iw.text.addReplacement(VLC->objh->creBanksNames[index]); // FIXME: USE BANK SPECIFIC NAMES | ||||
| 		} | ||||
| 		cb->showInfoDialog(&iw); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBank::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const | ||||
| void CBank::doVisit(const CGHeroInstance * hero) const | ||||
| { | ||||
| 	if (result.winner == 0) | ||||
| 	int textID = -1; | ||||
| 	InfoWindow iw; | ||||
| 	iw.player = hero->getOwner(); | ||||
| 	MetaString loot; | ||||
|  | ||||
| 	switch (ID) | ||||
| 	{ | ||||
| 		int textID = -1; | ||||
| 		InfoWindow iw; | ||||
| 		iw.player = hero->getOwner(); | ||||
| 		MetaString loot; | ||||
|  | ||||
| 		switch (ID) | ||||
| 	case Obj::CREATURE_BANK: | ||||
| 	case Obj::DRAGON_UTOPIA: | ||||
| 		textID = 34; | ||||
| 		break; | ||||
| 	case Obj::DERELICT_SHIP: | ||||
| 		if (!bc) | ||||
| 			textID = 43; | ||||
| 		else | ||||
| 		{ | ||||
| 		case Obj::CREATURE_BANK: case Obj::DRAGON_UTOPIA: | ||||
| 			textID = 34; | ||||
| 			break; | ||||
| 		case Obj::DERELICT_SHIP: | ||||
| 			if (multiplier) | ||||
| 				textID = 43; | ||||
| 			else | ||||
| 			{ | ||||
| 				GiveBonus gbonus; | ||||
| 				gbonus.id = hero->id.getNum(); | ||||
| 				gbonus.bonus.duration = Bonus::ONE_BATTLE; | ||||
| 				gbonus.bonus.source = Bonus::OBJECT; | ||||
| 				gbonus.bonus.sid = ID; | ||||
| 				gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[101]; | ||||
| 				gbonus.bonus.type = Bonus::MORALE; | ||||
| 				gbonus.bonus.val = -1; | ||||
| 				cb->giveHeroBonus(&gbonus); | ||||
| 				textID = 42; | ||||
| 				iw.components.push_back (Component (Component::MORALE, 0 , -1, 0)); | ||||
| 			} | ||||
| 			break; | ||||
| 		case Obj::CRYPT: | ||||
| 			if (bc->resources.size() != 0) | ||||
| 				textID = 121; | ||||
| 			else | ||||
| 			{ | ||||
| 				iw.components.push_back (Component (Component::MORALE, 0 , -1, 0)); | ||||
| 				GiveBonus gbonus; | ||||
| 				gbonus.id = hero->id.getNum(); | ||||
| 				gbonus.bonus.duration = Bonus::ONE_BATTLE; | ||||
| 				gbonus.bonus.source = Bonus::OBJECT; | ||||
| 				gbonus.bonus.sid = ID; | ||||
| 				gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[ID]; | ||||
| 				gbonus.bonus.type = Bonus::MORALE; | ||||
| 				gbonus.bonus.val = -1; | ||||
| 				cb->giveHeroBonus(&gbonus); | ||||
| 				textID = 120; | ||||
| 				iw.components.push_back (Component (Component::MORALE, 0 , -1, 0)); | ||||
| 			} | ||||
| 			break; | ||||
| 		case Obj::SHIPWRECK: | ||||
| 			if (bc->resources.size()) | ||||
| 				textID = 124; | ||||
| 			else | ||||
| 				textID = 123; | ||||
| 			break; | ||||
| 			GiveBonus gbonus; | ||||
| 			gbonus.id = hero->id.getNum(); | ||||
| 			gbonus.bonus.duration = Bonus::ONE_BATTLE; | ||||
| 			gbonus.bonus.source = Bonus::OBJECT; | ||||
| 			gbonus.bonus.sid = ID; | ||||
| 			gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[101]; | ||||
| 			gbonus.bonus.type = Bonus::MORALE; | ||||
| 			gbonus.bonus.val = -1; | ||||
| 			cb->giveHeroBonus(&gbonus); | ||||
| 			textID = 42; | ||||
| 			iw.components.push_back (Component (Component::MORALE, 0 , -1, 0)); | ||||
| 		} | ||||
|  | ||||
| 		//grant resources | ||||
| 		if (textID != 42) //empty derelict ship gives no cash | ||||
| 		break; | ||||
| 	case Obj::CRYPT: | ||||
| 		if (bc) | ||||
| 			textID = 121; | ||||
| 		else | ||||
| 		{ | ||||
| 			for (int it = 0; it < bc->resources.size(); it++) | ||||
| 			iw.components.push_back (Component (Component::MORALE, 0 , -1, 0)); | ||||
| 			GiveBonus gbonus; | ||||
| 			gbonus.id = hero->id.getNum(); | ||||
| 			gbonus.bonus.duration = Bonus::ONE_BATTLE; | ||||
| 			gbonus.bonus.source = Bonus::OBJECT; | ||||
| 			gbonus.bonus.sid = ID; | ||||
| 			gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[ID]; | ||||
| 			gbonus.bonus.type = Bonus::MORALE; | ||||
| 			gbonus.bonus.val = -1; | ||||
| 			cb->giveHeroBonus(&gbonus); | ||||
| 			textID = 120; | ||||
| 			iw.components.push_back (Component (Component::MORALE, 0 , -1, 0)); | ||||
| 		} | ||||
| 		break; | ||||
| 	case Obj::SHIPWRECK: | ||||
| 		if (bc) | ||||
| 			textID = 124; | ||||
| 		else | ||||
| 			textID = 123; | ||||
| 		break; | ||||
| 	case Obj::PYRAMID: | ||||
| 		textID = 106; | ||||
| 	} | ||||
|  | ||||
| 	//grant resources | ||||
| 	if (bc) | ||||
| 	{ | ||||
| 		for (int it = 0; it < bc->resources.size(); it++) | ||||
| 		{ | ||||
| 			if (bc->resources[it] != 0) | ||||
| 			{ | ||||
| 				if (bc->resources[it] != 0) | ||||
| 				{ | ||||
| 					iw.components.push_back (Component (Component::RESOURCE, it, bc->resources[it], 0)); | ||||
| 					loot << "%d %s"; | ||||
| 					loot.addReplacement(iw.components.back().val); | ||||
| 					loot.addReplacement(MetaString::RES_NAMES, iw.components.back().subtype); | ||||
| 					cb->giveResource (hero->getOwner(), static_cast<Res::ERes>(it), bc->resources[it]); | ||||
| 				} | ||||
| 				iw.components.push_back (Component (Component::RESOURCE, it, bc->resources[it], 0)); | ||||
| 				loot << "%d %s"; | ||||
| 				loot.addReplacement(iw.components.back().val); | ||||
| 				loot.addReplacement(MetaString::RES_NAMES, iw.components.back().subtype); | ||||
| 				cb->giveResource (hero->getOwner(), static_cast<Res::ERes>(it), bc->resources[it]); | ||||
| 			} | ||||
| 		} | ||||
| 		//grant artifacts | ||||
| 		for (auto & elem : artifacts) | ||||
| 		for (auto & elem : bc->artifacts) | ||||
| 		{ | ||||
| 			iw.components.push_back (Component (Component::ARTIFACT, elem, 0, 0)); | ||||
| 			loot << "%s"; | ||||
| @@ -327,22 +240,52 @@ void CBank::battleFinished(const CGHeroInstance *hero, const BattleResult &resul | ||||
| 			iw.text.addTxt (MetaString::ADVOB_TXT, textID); | ||||
| 			if (textID == 34) | ||||
| 			{ | ||||
| 				iw.text.addReplacement(MetaString::CRE_PL_NAMES, result.casualties[1].begin()->first); | ||||
| 				const CCreature * strongest = boost::range::max_element(bc->guards, [](const CStackBasicDescriptor & a, const CStackBasicDescriptor & b) | ||||
| 				{ | ||||
| 					return a.type->fightValue < b.type->fightValue; | ||||
| 				})->type; | ||||
|  | ||||
| 				iw.text.addReplacement(MetaString::CRE_PL_NAMES, strongest->idNumber); | ||||
| 				iw.text.addReplacement(loot.buildList()); | ||||
| 			} | ||||
| 			cb->showInfoDialog(&iw); | ||||
| 		} | ||||
|  | ||||
| 		if (!bc->spells.empty()) | ||||
| 		{ | ||||
| 			std::set<SpellID> spells; | ||||
|  | ||||
| 			bool noWisdom = false; | ||||
| 			for (SpellID spell : bc->spells) | ||||
| 			{ | ||||
| 				iw.text.addTxt (MetaString::SPELL_NAME, spell); | ||||
| 				if (VLC->spellh->objects[spell]->level <= hero->getSecSkillLevel(SecondarySkill::WISDOM) + 2) | ||||
| 				{ | ||||
| 					spells.insert(spell); | ||||
| 					iw.components.push_back(Component (Component::SPELL, spell, 0, 0)); | ||||
| 				} | ||||
| 				else | ||||
| 					noWisdom = true; | ||||
| 			} | ||||
|  | ||||
| 			if (!hero->getArt(ArtifactPosition::SPELLBOOK)) | ||||
| 				iw.text.addTxt (MetaString::ADVOB_TXT, 109); //no spellbook | ||||
| 			else if (noWisdom) | ||||
| 				iw.text.addTxt (MetaString::ADVOB_TXT, 108); //no expert Wisdom | ||||
| 			if (spells.empty()) | ||||
| 				cb->changeSpells (hero, true, spells); | ||||
| 		} | ||||
| 		loot.clear(); | ||||
| 		iw.components.clear(); | ||||
| 		iw.text.clear(); | ||||
|  | ||||
| 		//grant creatures | ||||
| 		CCreatureSet ourArmy; | ||||
| 		for (auto it = bc->creatures.cbegin(); it != bc->creatures.cend(); it++) | ||||
| 		for (auto slot : bc->creatures) | ||||
| 		{ | ||||
| 			SlotID slot = ourArmy.getSlotFor(it->first); | ||||
| 			ourArmy.addToSlot(slot, it->first, it->second); | ||||
| 			ourArmy.addToSlot(ourArmy.getSlotFor(slot.type->idNumber), slot.type->idNumber, slot.count); | ||||
| 		} | ||||
|  | ||||
| 		for (auto & elem : ourArmy.Slots()) | ||||
| 		{ | ||||
| 			iw.components.push_back(Component(*elem.second)); | ||||
| @@ -362,7 +305,15 @@ void CBank::battleFinished(const CGHeroInstance *hero, const BattleResult &resul | ||||
| 			cb->showInfoDialog(&iw); | ||||
| 			cb->giveCreatures(this, hero, ourArmy, false); | ||||
| 		} | ||||
| 		cb->setObjProperty (id, ObjProperty::BANK_CLEAR_CONFIG, 0); //bc = nullptr | ||||
| 	cb->setObjProperty (id, ObjProperty::BANK_CLEAR, 0); //bc = nullptr | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBank::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const | ||||
| { | ||||
| 	if (result.winner == 0) | ||||
| 	{ | ||||
| 		doVisit(hero); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -370,74 +321,9 @@ void CBank::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) cons | ||||
| { | ||||
| 	if (answer) | ||||
| 	{ | ||||
| 		cb->startBattleI(hero, this, true); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGPyramid::initObj() | ||||
| { | ||||
| 	std::vector<SpellID> available; | ||||
| 	cb->getAllowedSpells (available, 5); | ||||
| 	if (available.size()) | ||||
| 	{ | ||||
| 		bc = VLC->objh->banksInfo[21].front(); //TODO: remove hardcoded value? | ||||
| 		spell = *RandomGeneratorUtil::nextItem(available, cb->gameState()->getRandomGenerator()); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
|         logGlobal->errorStream() <<"No spells available for Pyramid! Object set to empty."; | ||||
| 	} | ||||
| 	setPropertyDer(ObjProperty::BANK_INIT_ARMY, cb->gameState()->getRandomGenerator().nextInt()); //set guards at game start | ||||
| } | ||||
| const std::string & CGPyramid::getHoverText() const | ||||
| { | ||||
| 	hoverName = VLC->objh->creBanksNames[21]+ " " + visitedTxt((bc==nullptr)); | ||||
| 	return hoverName; | ||||
| } | ||||
| void CGPyramid::onHeroVisit (const CGHeroInstance * h) const | ||||
| { | ||||
| 	if (bc) | ||||
| 	{ | ||||
| 		BlockingDialog bd (true, false); | ||||
| 		bd.player = h->getOwner(); | ||||
| 		bd.soundID = soundBase::MYSTERY; | ||||
| 		bd.text << VLC->generaltexth->advobtxt[105]; | ||||
| 		cb->showBlockingDialog(&bd); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		InfoWindow iw; | ||||
| 		iw.player = h->getOwner(); | ||||
| 		iw.text << VLC->generaltexth->advobtxt[107]; | ||||
| 		iw.components.push_back (Component (Component::LUCK, 0 , -2, 0)); | ||||
| 		GiveBonus gb; | ||||
| 		gb.bonus = Bonus(Bonus::ONE_BATTLE,Bonus::LUCK,Bonus::OBJECT,-2,id.getNum(),VLC->generaltexth->arraytxt[70]); | ||||
| 		gb.id = h->id.getNum(); | ||||
| 		cb->giveHeroBonus(&gb); | ||||
| 		cb->showInfoDialog(&iw); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGPyramid::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const | ||||
| { | ||||
| 	if (result.winner == 0) | ||||
| 	{ | ||||
| 		InfoWindow iw; | ||||
| 		iw.player = hero->getOwner(); | ||||
| 		iw.text.addTxt (MetaString::ADVOB_TXT, 106); | ||||
| 		iw.text.addTxt (MetaString::SPELL_NAME, spell); | ||||
| 		if (!hero->getArt(ArtifactPosition::SPELLBOOK)) | ||||
| 			iw.text.addTxt (MetaString::ADVOB_TXT, 109); //no spellbook | ||||
| 		else if (hero->getSecSkillLevel(SecondarySkill::WISDOM) < 3) | ||||
| 			iw.text.addTxt (MetaString::ADVOB_TXT, 108); //no expert Wisdom | ||||
| 		if (bc) // not looted bank | ||||
| 			cb->startBattleI(hero, this, true); | ||||
| 		else | ||||
| 		{ | ||||
| 			std::set<SpellID> spells; | ||||
| 			spells.insert (SpellID(spell)); | ||||
| 			cb->changeSpells (hero, true, spells); | ||||
| 			iw.components.push_back(Component (Component::SPELL, spell, 0, 0)); | ||||
| 		} | ||||
| 		cb->showInfoDialog(&iw); | ||||
| 		cb->setObjProperty (id, ObjProperty::BANK_CLEAR_CONFIG, 0); | ||||
| 			doVisit(hero); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -13,19 +13,26 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| class BankConfig; | ||||
| class CBankInstanceConstructor; | ||||
|  | ||||
| class DLL_LINKAGE CBank : public CArmedInstance | ||||
| { | ||||
| 	public: | ||||
| 	int index; //banks have unusal numbering - see ZCRBANK.txt and initObj() | ||||
| 	BankConfig *bc; | ||||
| 	double multiplier; //for improved banks script | ||||
| 	std::vector<ui32> artifacts; //fixed and deterministic | ||||
| 	std::unique_ptr<BankConfig> bc; | ||||
| 	ui32 daycounter; | ||||
| 	ui32 resetDuration; | ||||
|  | ||||
| 	void setPropertyDer(ui8 what, ui32 val) override; | ||||
| 	void doVisit(const CGHeroInstance * hero) const; | ||||
|  | ||||
| public: | ||||
| 	CBank(); | ||||
| 	~CBank(); | ||||
|  | ||||
| 	void setConfig(const BankConfig & bc); | ||||
|  | ||||
| 	void initObj() override; | ||||
| 	const std::string & getHoverText() const override; | ||||
| 	void initialize() const; | ||||
| 	void reset(ui16 var1); | ||||
| 	void newTurn() const override; | ||||
| 	bool wasVisited (PlayerColor player) const override; | ||||
| 	void onHeroVisit(const CGHeroInstance * h) const override; | ||||
| @@ -35,25 +42,8 @@ class DLL_LINKAGE CBank : public CArmedInstance | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<CArmedInstance&>(*this); | ||||
| 		h & index & multiplier & artifacts & daycounter & bc; | ||||
| 		h & daycounter & bc & resetDuration; | ||||
| 	} | ||||
| protected: | ||||
| 	void setPropertyDer(ui8 what, ui32 val) override; | ||||
| }; | ||||
| class DLL_LINKAGE CGPyramid : public CBank | ||||
| { | ||||
| public: | ||||
| 	ui16 spell; | ||||
|  | ||||
| 	void initObj() override; | ||||
| 	const std::string & getHoverText() const override; | ||||
| 	void newTurn() const override {}; //empty, no reset | ||||
| 	void onHeroVisit(const CGHeroInstance * h) const override; | ||||
| 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<CBank&>(*this); | ||||
| 		h & spell; | ||||
| 	} | ||||
| 	friend class CBankInstanceConstructor; | ||||
| }; | ||||
|   | ||||
| @@ -35,13 +35,13 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| 	SET_HANDLER_CLASS("dwelling", CDwellingInstanceConstructor); | ||||
| 	SET_HANDLER_CLASS("hero", CHeroInstanceConstructor); | ||||
| 	SET_HANDLER_CLASS("town", CTownInstanceConstructor); | ||||
| 	SET_HANDLER_CLASS("bank", CBankInstanceConstructor); | ||||
|  | ||||
| 	SET_HANDLER_CLASS("static", CObstacleConstructor); | ||||
| 	SET_HANDLER_CLASS("", CObstacleConstructor); | ||||
|  | ||||
| 	SET_HANDLER("generic", CGObjectInstance); | ||||
| 	SET_HANDLER("market", CGMarket); | ||||
| 	SET_HANDLER("bank", CBank); | ||||
| 	SET_HANDLER("cartographer", CCartographer); | ||||
| 	SET_HANDLER("artifact", CGArtifact); | ||||
| 	SET_HANDLER("blackMarket", CGBlackMarket); | ||||
| @@ -67,7 +67,6 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| 	SET_HANDLER("pandora", CGPandoraBox); | ||||
| 	SET_HANDLER("pickable", CGPickable); | ||||
| 	SET_HANDLER("prison", CGHeroInstance); | ||||
| 	SET_HANDLER("pyramid", CGPyramid); | ||||
| 	SET_HANDLER("questGuard", CGQuestGuard); | ||||
| 	SET_HANDLER("resource", CGResource); | ||||
| 	SET_HANDLER("scholar", CGScholar); | ||||
| @@ -130,6 +129,11 @@ si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID) | ||||
|  | ||||
| void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContainter * obj) | ||||
| { | ||||
| 	if (!handlerConstructors.count(obj->handlerName)) | ||||
| 	{ | ||||
| 		logGlobal->errorStream() << "Handler with name " << obj->handlerName << " was not found!"; | ||||
| 		return; | ||||
| 	} | ||||
| 	auto handler = handlerConstructors.at(obj->handlerName)(); | ||||
| 	handler->init(entry); | ||||
|  | ||||
|   | ||||
| @@ -50,20 +50,45 @@ struct RandomMapInfo | ||||
| class IObjectInfo | ||||
| { | ||||
| public: | ||||
| 	virtual bool givesResources() const = 0; | ||||
| 	struct CArmyStructure | ||||
| 	{ | ||||
| 		ui32 totalStrength; | ||||
| 		ui32 shootersStrength; | ||||
| 		ui32 flyersStrength; | ||||
| 		ui32 walkersStrength; | ||||
|  | ||||
| 	virtual bool givesExperience() const = 0; | ||||
| 	virtual bool givesMana() const = 0; | ||||
| 	virtual bool givesMovement() const = 0; | ||||
| 		CArmyStructure() : | ||||
| 			totalStrength(0), | ||||
| 			shootersStrength(0), | ||||
| 			flyersStrength(0), | ||||
| 			walkersStrength(0) | ||||
| 		{} | ||||
|  | ||||
| 	virtual bool givesPrimarySkills() const = 0; | ||||
| 	virtual bool givesSecondarySkills() const = 0; | ||||
| 		bool operator <(const CArmyStructure & other) | ||||
| 		{ | ||||
| 			return this->totalStrength < other.totalStrength; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	virtual bool givesArtifacts() const = 0; | ||||
| 	virtual bool givesCreatures() const = 0; | ||||
| 	virtual bool givesSpells() const = 0; | ||||
| 	/// Returns possible composition of guards. Actual guards would be | ||||
| 	/// somewhere between these two values | ||||
| 	virtual CArmyStructure minGuards() const { return CArmyStructure(); } | ||||
| 	virtual CArmyStructure maxGuards() const { return CArmyStructure(); } | ||||
|  | ||||
| 	virtual bool givesBonuses() const = 0; | ||||
| 	virtual bool givesResources() const { return false; } | ||||
|  | ||||
| 	virtual bool givesExperience() const { return false; } | ||||
| 	virtual bool givesMana() const { return false; } | ||||
| 	virtual bool givesMovement() const { return false; } | ||||
|  | ||||
| 	virtual bool givesPrimarySkills() const { return false; } | ||||
| 	virtual bool givesSecondarySkills() const { return false; } | ||||
|  | ||||
| 	virtual bool givesArtifacts() const { return false; } | ||||
| 	virtual bool givesCreatures() const { return false; } | ||||
| 	virtual bool givesSpells() const { return false; } | ||||
|  | ||||
| 	virtual bool givesBonuses() const { return false; } | ||||
| }; | ||||
|  | ||||
| class CGObjectInstance; | ||||
| @@ -118,7 +143,7 @@ public: | ||||
| 	virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0; | ||||
|  | ||||
| 	/// Returns object configuration, if available. Othervice returns NULL | ||||
| 	virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const = 0; | ||||
| 	virtual std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const = 0; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -108,53 +108,6 @@ void IObjectInterface::garrisonDialogClosed(const CGHeroInstance *hero) const | ||||
| void IObjectInterface::heroLevelUpDone(const CGHeroInstance *hero) const | ||||
| {} | ||||
|  | ||||
| // Bank helper. Find the creature ID and their number, and store the | ||||
| // result in storage (either guards or reward creatures). | ||||
| static void readCreatures(const JsonNode &creature, std::vector< std::pair <CreatureID, ui32> > &storage) | ||||
| { | ||||
| 	std::pair<CreatureID, si32> creInfo = std::make_pair(CreatureID::NONE, 0); | ||||
|  | ||||
| 	//TODO: replace numeric id's with mod-friendly string id's | ||||
| 	creInfo.second = creature["number"].Float(); | ||||
| 	creInfo.first = CreatureID((si32)creature["id"].Float()); | ||||
| 	storage.push_back(creInfo); | ||||
| } | ||||
|  | ||||
| // Bank helper. Process a bank level. | ||||
| static void readBankLevel(const JsonNode &level, BankConfig &bc) | ||||
| { | ||||
| 	int idx; | ||||
|  | ||||
| 	bc.chance = level["chance"].Float(); | ||||
|  | ||||
| 	for(const JsonNode &creature : level["guards"].Vector()) | ||||
| 	{ | ||||
| 		readCreatures(creature, bc.guards); | ||||
| 	} | ||||
|  | ||||
| 	bc.upgradeChance = level["upgrade_chance"].Float(); | ||||
| 	bc.combatValue = level["combat_value"].Float(); | ||||
|  | ||||
| 	bc.resources = Res::ResourceSet(level["reward_resources"]); | ||||
|  | ||||
| 	for(const JsonNode &creature : level["reward_creatures"].Vector()) | ||||
| 	{ | ||||
| 		readCreatures(creature, bc.creatures); | ||||
| 	} | ||||
|  | ||||
| 	bc.artifacts.resize(4); | ||||
| 	idx = 0; | ||||
| 	for(const JsonNode &artifact : level["reward_artifacts"].Vector()) | ||||
| 	{ | ||||
| 		bc.artifacts[idx] = artifact.Float(); | ||||
| 		idx ++; | ||||
| 	} | ||||
|  | ||||
| 	bc.value = level["value"].Float(); | ||||
| 	bc.rewardDifficulty = level["profitability"].Float(); | ||||
| 	bc.easiest = level["easiest"].Float(); | ||||
| } | ||||
|  | ||||
| CObjectHandler::CObjectHandler() | ||||
| { | ||||
|     logGlobal->traceStream() << "\t\tReading resources prices "; | ||||
| @@ -164,62 +117,8 @@ CObjectHandler::CObjectHandler() | ||||
| 		resVals.push_back(price.Float()); | ||||
| 	} | ||||
|     logGlobal->traceStream() << "\t\tDone loading resource prices!"; | ||||
|  | ||||
|     logGlobal->traceStream() << "\t\tReading banks configs"; | ||||
| 	const JsonNode config3(ResourceID("config/bankconfig.json")); | ||||
| 	int bank_num = 0; | ||||
| 	for(const JsonNode &bank : config3["banks"].Vector()) | ||||
| 	{ | ||||
| 		creBanksNames[bank_num] = bank["name"].String(); | ||||
|  | ||||
| 		int level_num = 0; | ||||
| 		for(const JsonNode &level : bank["levels"].Vector()) | ||||
| 		{ | ||||
| 			banksInfo[bank_num].push_back(new BankConfig); | ||||
| 			BankConfig &bc = *banksInfo[bank_num].back(); | ||||
| 			bc.level = level_num; | ||||
|  | ||||
| 			readBankLevel(level, bc); | ||||
| 			level_num ++; | ||||
| 		} | ||||
|  | ||||
| 		bank_num ++; | ||||
| 	} | ||||
|     logGlobal->traceStream() << "\t\tDone loading banks configs"; | ||||
| } | ||||
|  | ||||
| CObjectHandler::~CObjectHandler() | ||||
| { | ||||
| 	for(auto & mapEntry : banksInfo) | ||||
| 	{ | ||||
| 		for(auto & vecEntry : mapEntry.second) | ||||
| 		{ | ||||
| 			vecEntry.dellNull(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int CObjectHandler::bankObjToIndex (const CGObjectInstance * obj) | ||||
| { | ||||
| 	switch (obj->ID) //find appriopriate key | ||||
| 	{ | ||||
| 	case Obj::CREATURE_BANK: | ||||
| 		return obj->subID; | ||||
| 	case Obj::DERELICT_SHIP: | ||||
| 		return 8; | ||||
| 	case Obj::DRAGON_UTOPIA: | ||||
| 		return 10; | ||||
| 	case Obj::CRYPT: | ||||
| 		return 9; | ||||
| 	case Obj::SHIPWRECK: | ||||
| 		return 7; | ||||
| 	case Obj::PYRAMID: | ||||
| 		return 21; | ||||
| 	default: | ||||
|         logGlobal->warnStream() << "Unrecognized Bank indetifier!"; | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| PlayerColor CGObjectInstance::getOwner() const | ||||
| { | ||||
| 	//if (state) | ||||
|   | ||||
| @@ -163,41 +163,15 @@ private: | ||||
| 	CGObjectInstance * obj; | ||||
| }; | ||||
|  | ||||
| struct BankConfig | ||||
| { | ||||
| 	BankConfig() {level = chance = upgradeChance = combatValue = value = rewardDifficulty = easiest = 0; }; | ||||
| 	ui8 level; //1 - 4, how hard the battle will be | ||||
| 	ui8 chance; //chance for this level being chosen | ||||
| 	ui8 upgradeChance; //chance for creatures to be in upgraded versions | ||||
| 	std::vector< std::pair <CreatureID, ui32> > guards; //creature ID, amount | ||||
| 	ui32 combatValue; //how hard are guards of this level | ||||
| 	Res::ResourceSet resources; //resources given in case of victory | ||||
| 	std::vector< std::pair <CreatureID, ui32> > creatures; //creatures granted in case of victory (creature ID, amount) | ||||
| 	std::vector<ui16> artifacts; //number of artifacts given in case of victory [0] -> treasure, [1] -> minor [2] -> major [3] -> relic | ||||
| 	ui32 value; //overall value of given things | ||||
| 	ui32 rewardDifficulty; //proportion of reward value to difficulty of guards; how profitable is this creature Bank config | ||||
| 	ui16 easiest; //?!? | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & level & chance & upgradeChance & guards & combatValue & resources & creatures & artifacts & value & rewardDifficulty & easiest; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CObjectHandler | ||||
| { | ||||
| public: | ||||
| 	std::map <ui32, std::vector < ConstTransitivePtr<BankConfig> > > banksInfo; //[index][preset] | ||||
| 	std::map <ui32, std::string> creBanksNames; //[crebank index] -> name of this creature bank | ||||
| 	std::vector<ui32> resVals; //default values of resources in gold | ||||
|  | ||||
| 	CObjectHandler(); | ||||
| 	~CObjectHandler(); | ||||
|  | ||||
| 	int bankObjToIndex (const CGObjectInstance * obj); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & banksInfo & creBanksNames & resVals; | ||||
| 		h & resVals; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #include "../CRandomGenerator.h" | ||||
| #include "../StringConstants.h" | ||||
| #include "../CCreatureHandler.h" | ||||
| #include "JsonRandom.h" | ||||
|  | ||||
| /* | ||||
|  * CRewardableConstructor.cpp, part of VCMI engine | ||||
| @@ -16,100 +17,6 @@ | ||||
|  */ | ||||
|  | ||||
| namespace { | ||||
| 	si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue = 0) | ||||
| 	{ | ||||
| 		if (value.isNull()) | ||||
| 			return defaultValue; | ||||
| 		if (value.getType() == JsonNode::DATA_FLOAT) | ||||
| 			return value.Float(); | ||||
| 		si32 min = value["min"].Float(); | ||||
| 		si32 max = value["max"].Float(); | ||||
| 		return rng.getIntRange(min, max)(); | ||||
| 	} | ||||
|  | ||||
| 	TResources loadResources(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		TResources ret; | ||||
| 		for (size_t i=0; i<GameConstants::RESOURCE_QUANTITY; i++) | ||||
| 		{ | ||||
| 			ret[i] = loadValue(value[GameConstants::RESOURCE_NAMES[i]], rng); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::vector<si32> ret; | ||||
| 		for (auto & name : PrimarySkill::names) | ||||
| 		{ | ||||
| 			ret.push_back(loadValue(value[name], rng)); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::map<SecondarySkill, si32> loadSecondary(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::map<SecondarySkill, si32> ret; | ||||
| 		for (auto & pair : value.Struct()) | ||||
| 		{ | ||||
| 			SecondarySkill id(VLC->modh->identifiers.getIdentifier(pair.second.meta, "skill", pair.first).get()); | ||||
| 			ret[id] = loadValue(pair.second, rng); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::vector<ArtifactID> ret; | ||||
| 		for (const JsonNode & entry : value.Vector()) | ||||
| 		{ | ||||
| 			ArtifactID art(VLC->modh->identifiers.getIdentifier("artifact", entry).get()); | ||||
| 			ret.push_back(art); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::vector<SpellID> ret; | ||||
| 		for (const JsonNode & entry : value.Vector()) | ||||
| 		{ | ||||
| 			SpellID spell(VLC->modh->identifiers.getIdentifier("spell", entry).get()); | ||||
| 			ret.push_back(spell); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::vector<CStackBasicDescriptor> ret; | ||||
| 		for (auto & pair : value.Struct()) | ||||
| 		{ | ||||
| 			CStackBasicDescriptor stack; | ||||
| 			stack.type = VLC->creh->creatures[VLC->modh->identifiers.getIdentifier(pair.second.meta, "creature", pair.first).get()]; | ||||
| 			stack.count = loadValue(pair.second, rng); | ||||
| 			ret.push_back(stack); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<Bonus> loadBonuses(const JsonNode & value) | ||||
| 	{ | ||||
| 		std::vector<Bonus> ret; | ||||
| 		for (const JsonNode & entry : value.Vector()) | ||||
| 		{ | ||||
| 			Bonus * bonus = JsonUtils::parseBonus(entry); | ||||
| 			ret.push_back(*bonus); | ||||
| 			delete bonus; | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<Component> loadComponents(const JsonNode & value) | ||||
| 	{ | ||||
| 		//TODO | ||||
| 	} | ||||
|  | ||||
| 	MetaString loadMessage(const JsonNode & value) | ||||
| 	{ | ||||
| 		MetaString ret; | ||||
| @@ -167,38 +74,42 @@ void CRandomRewardObjectInfo::configureObject(CRewardableObject * object, CRando | ||||
| 		const JsonNode & limiter = reward["limiter"]; | ||||
| 		CVisitInfo info; | ||||
| 		// load limiter | ||||
| 		info.limiter.numOfGrants = loadValue(limiter["numOfGrants"], rng); | ||||
| 		info.limiter.dayOfWeek = loadValue(limiter["dayOfWeek"], rng); | ||||
| 		info.limiter.minLevel = loadValue(limiter["minLevel"], rng); | ||||
| 		info.limiter.resources = loadResources(limiter["resources"], rng); | ||||
| 		info.limiter.numOfGrants = JsonRandom::loadValue(limiter["numOfGrants"], rng); | ||||
| 		info.limiter.dayOfWeek = JsonRandom::loadValue(limiter["dayOfWeek"], rng); | ||||
| 		info.limiter.minLevel = JsonRandom::loadValue(limiter["minLevel"], rng); | ||||
| 		info.limiter.resources = JsonRandom::loadResources(limiter["resources"], rng); | ||||
|  | ||||
| 		info.limiter.primary = loadPrimary(limiter["primary"], rng); | ||||
| 		info.limiter.secondary = loadSecondary(limiter["secondary"], rng); | ||||
| 		info.limiter.artifacts = loadArtifacts(limiter["artifacts"], rng); | ||||
| 		info.limiter.creatures = loadCreatures(limiter["creatures"], rng); | ||||
| 		info.limiter.primary = JsonRandom::loadPrimary(limiter["primary"], rng); | ||||
| 		info.limiter.secondary = JsonRandom::loadSecondary(limiter["secondary"], rng); | ||||
| 		info.limiter.artifacts = JsonRandom::loadArtifacts(limiter["artifacts"], rng); | ||||
| 		info.limiter.creatures = JsonRandom::loadCreatures(limiter["creatures"], rng); | ||||
|  | ||||
| 		info.reward.resources = loadResources(reward["resources"], rng); | ||||
| 		info.reward.resources = JsonRandom::loadResources(reward["resources"], rng); | ||||
|  | ||||
| 		info.reward.gainedExp = loadValue(reward["gainedExp"], rng); | ||||
| 		info.reward.gainedLevels = loadValue(reward["gainedLevels"], rng); | ||||
| 		info.reward.gainedExp = JsonRandom::loadValue(reward["gainedExp"], rng); | ||||
| 		info.reward.gainedLevels = JsonRandom::loadValue(reward["gainedLevels"], rng); | ||||
|  | ||||
| 		info.reward.manaDiff = loadValue(reward["manaPoints"], rng); | ||||
| 		info.reward.manaPercentage = loadValue(reward["manaPercentage"], rng, -1); | ||||
| 		info.reward.manaDiff = JsonRandom::loadValue(reward["manaPoints"], rng); | ||||
| 		info.reward.manaPercentage = JsonRandom::loadValue(reward["manaPercentage"], rng, -1); | ||||
|  | ||||
| 		info.reward.movePoints = loadValue(reward["movePoints"], rng); | ||||
| 		info.reward.movePercentage = loadValue(reward["movePercentage"], rng, -1); | ||||
| 		info.reward.movePoints = JsonRandom::loadValue(reward["movePoints"], rng); | ||||
| 		info.reward.movePercentage = JsonRandom::loadValue(reward["movePercentage"], rng, -1); | ||||
|  | ||||
| 		info.reward.bonuses = loadBonuses(reward["bonuses"]); | ||||
| 		info.reward.bonuses = JsonRandom::loadBonuses(reward["bonuses"]); | ||||
|  | ||||
| 		info.reward.primary = loadPrimary(reward["primary"], rng); | ||||
| 		info.reward.secondary = loadSecondary(reward["secondary"], rng); | ||||
| 		info.reward.primary = JsonRandom::loadPrimary(reward["primary"], rng); | ||||
| 		info.reward.secondary = JsonRandom::loadSecondary(reward["secondary"], rng); | ||||
|  | ||||
| 		info.reward.artifacts = loadArtifacts(reward["artifacts"], rng); | ||||
| 		info.reward.spells = loadSpells(reward["spells"], rng); | ||||
| 		info.reward.creatures = loadCreatures(reward["creatures"], rng); | ||||
| 		std::vector<SpellID> spells; | ||||
| 		for (size_t i=0; i<6; i++) | ||||
| 			IObjectInterface::cb->getAllowedSpells(spells, i); | ||||
|  | ||||
| 		info.reward.artifacts = JsonRandom::loadArtifacts(reward["artifacts"], rng); | ||||
| 		info.reward.spells = JsonRandom::loadSpells(reward["spells"], rng, spells); | ||||
| 		info.reward.creatures = JsonRandom::loadCreatures(reward["creatures"], rng); | ||||
|  | ||||
| 		info.message = loadMessage(reward["message"]); | ||||
| 		info.selectChance = loadValue(reward["selectChance"], rng); | ||||
| 		info.selectChance = JsonRandom::loadValue(reward["selectChance"], rng); | ||||
| 	} | ||||
|  | ||||
| 	object->onSelect  = loadMessage(parameters["onSelectMessage"]); | ||||
| @@ -284,7 +195,7 @@ void CRewardableConstructor::configureObject(CGObjectInstance * object, CRandomG | ||||
| 	objectInfo.configureObject(dynamic_cast<CRewardableObject*>(object), rng); | ||||
| } | ||||
|  | ||||
| const IObjectInfo * CRewardableConstructor::getObjectInfo(ObjectTemplate tmpl) const | ||||
| std::unique_ptr<IObjectInfo> CRewardableConstructor::getObjectInfo(ObjectTemplate tmpl) const | ||||
| { | ||||
| 	return &objectInfo; | ||||
| 	return std::unique_ptr<IObjectInfo>(new CRandomRewardObjectInfo(objectInfo)); | ||||
| } | ||||
|   | ||||
| @@ -54,5 +54,5 @@ public: | ||||
|  | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; | ||||
|  | ||||
| 	const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const override; | ||||
| 	std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const override; | ||||
| }; | ||||
|   | ||||
| @@ -3,9 +3,11 @@ | ||||
|  | ||||
| #include "CGTownInstance.h" | ||||
| #include "CGHeroInstance.h" | ||||
| #include "CBank.h" | ||||
| #include "../mapping/CMap.h" | ||||
| #include "../CHeroHandler.h" | ||||
| #include "../CCreatureHandler.h" | ||||
| #include "JsonRandom.h" | ||||
|  | ||||
| /* | ||||
|  * CommonConstructors.cpp, part of VCMI engine | ||||
| @@ -176,33 +178,6 @@ CGObjectInstance * CDwellingInstanceConstructor::create(ObjectTemplate tmpl) con | ||||
| 	return obj; | ||||
| } | ||||
|  | ||||
| namespace | ||||
| { | ||||
| 	si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue = 0) | ||||
| 	{ | ||||
| 		if (value.isNull()) | ||||
| 			return defaultValue; | ||||
| 		if (value.getType() == JsonNode::DATA_FLOAT) | ||||
| 			return value.Float(); | ||||
| 		si32 min = value["min"].Float(); | ||||
| 		si32 max = value["max"].Float(); | ||||
| 		return rng.getIntRange(min, max)(); | ||||
| 	} | ||||
|  | ||||
| 	std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::vector<CStackBasicDescriptor> ret; | ||||
| 		for (auto & pair : value.Struct()) | ||||
| 		{ | ||||
| 			CStackBasicDescriptor stack; | ||||
| 			stack.type = VLC->creh->creatures[VLC->modh->identifiers.getIdentifier(pair.second.meta, "creature", pair.first).get()]; | ||||
| 			stack.count = loadValue(pair.second, rng); | ||||
| 			ret.push_back(stack); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CDwellingInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator &rng) const | ||||
| { | ||||
| 	CGDwelling * dwelling = dynamic_cast<CGDwelling*>(object); | ||||
| @@ -221,7 +196,7 @@ void CDwellingInstanceConstructor::configureObject(CGObjectInstance * object, CR | ||||
| 		const CCreature * crea = availableCreatures.at(0).at(0); | ||||
| 		dwelling->putStack(SlotID(0), new CStackInstance(crea->idNumber, crea->growth * 3 )); | ||||
| 	} | ||||
| 	else for (auto & stack : loadCreatures(guards, rng)) | ||||
| 	else for (auto & stack : JsonRandom::loadCreatures(guards, rng)) | ||||
| 	{ | ||||
| 		dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(stack.type->idNumber, stack.count)); | ||||
| 	} | ||||
| @@ -237,3 +212,175 @@ bool CDwellingInstanceConstructor::producesCreature(const CCreature * crea) cons | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| CBankInstanceConstructor::CBankInstanceConstructor() | ||||
| { | ||||
| } | ||||
|  | ||||
| void CBankInstanceConstructor::initTypeData(const JsonNode & input) | ||||
| { | ||||
| 	//TODO: name = input["name"].String(); | ||||
| 	levels = input["levels"].Vector(); | ||||
| 	bankResetDuration = input["resetDuration"].Float(); | ||||
| } | ||||
|  | ||||
| CGObjectInstance *CBankInstanceConstructor::create(ObjectTemplate tmpl) const | ||||
| { | ||||
| 	return createTyped(tmpl); | ||||
| } | ||||
|  | ||||
| BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRandomGenerator & rng) const | ||||
| { | ||||
| 	BankConfig bc; | ||||
|  | ||||
| 	bc.chance = level["chance"].Float(); | ||||
|  | ||||
| 	bc.guards = JsonRandom::loadCreatures(level["guards"], rng); | ||||
| 	bc.upgradeChance = level["upgrade_chance"].Float(); | ||||
| 	bc.combatValue = level["combat_value"].Float(); | ||||
|  | ||||
| 	std::vector<SpellID> spells; | ||||
| 	for (size_t i=0; i<6; i++) | ||||
| 		IObjectInterface::cb->getAllowedSpells(spells, i); | ||||
|  | ||||
| 	bc.resources = Res::ResourceSet(level["reward"]["resources"]); | ||||
| 	bc.creatures = JsonRandom::loadCreatures(level["reward"]["creatures"], rng); | ||||
| 	bc.artifacts = JsonRandom::loadArtifacts(level["reward"]["artifacts"], rng); | ||||
| 	bc.spells    = JsonRandom::loadSpells(level["reward"]["spells"], rng, spells); | ||||
|  | ||||
| 	bc.value = level["value"].Float(); | ||||
|  | ||||
| 	return bc; | ||||
| } | ||||
|  | ||||
| void CBankInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const | ||||
| { | ||||
| 	auto bank = dynamic_cast<CBank*>(object); | ||||
|  | ||||
| 	bank->resetDuration = bankResetDuration; | ||||
|  | ||||
| 	si32 totalChance = 0; | ||||
| 	for (auto & node : levels) | ||||
| 		totalChance += node["chance"].Float(); | ||||
|  | ||||
| 	assert(totalChance != 0); | ||||
|  | ||||
| 	si32 selectedChance = rng.nextInt(totalChance - 1); | ||||
|  | ||||
| 	for (auto & node : levels) | ||||
| 	{ | ||||
| 		if (selectedChance < node["chance"].Float()) | ||||
| 		{ | ||||
| 			 bank->setConfig(generateConfig(node, rng)); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			selectedChance -= node["chance"].Float(); | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CBankInfo::CBankInfo(JsonVector config): | ||||
| 	config(config) | ||||
| { | ||||
| } | ||||
|  | ||||
| static void addStackToArmy(IObjectInfo::CArmyStructure & army, const CCreature * crea, si32 amount) | ||||
| { | ||||
| 	army.totalStrength += crea->fightValue * amount; | ||||
|  | ||||
| 	bool walker = true; | ||||
| 	if (crea->hasBonusOfType(Bonus::SHOOTER)) | ||||
| 	{ | ||||
| 		army.shootersStrength += crea->fightValue * amount; | ||||
| 		walker = false; | ||||
| 	} | ||||
| 	if (crea->hasBonusOfType(Bonus::FLYING)) | ||||
| 	{ | ||||
| 		army.flyersStrength += crea->fightValue * amount; | ||||
| 		walker = false; | ||||
| 	} | ||||
| 	if (walker) | ||||
| 		army.walkersStrength += crea->fightValue * amount; | ||||
| } | ||||
|  | ||||
| IObjectInfo::CArmyStructure CBankInfo::minGuards() const | ||||
| { | ||||
| 	std::vector<IObjectInfo::CArmyStructure> armies; | ||||
| 	for (auto configEntry : config) | ||||
| 	{ | ||||
| 		auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]); | ||||
| 		IObjectInfo::CArmyStructure army; | ||||
| 		for (auto & stack : stacks) | ||||
| 		{ | ||||
| 			assert(!stack.allowedCreatures.empty()); | ||||
| 			auto weakest = boost::range::min_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b) | ||||
| 			{ | ||||
| 				return a->fightValue < b->fightValue; | ||||
| 			}); | ||||
| 			addStackToArmy(army, *weakest, stack.minAmount); | ||||
| 		} | ||||
| 		armies.push_back(army); | ||||
| 	} | ||||
| 	return *boost::range::min_element(armies); | ||||
| } | ||||
|  | ||||
| IObjectInfo::CArmyStructure CBankInfo::maxGuards() const | ||||
| { | ||||
| 	std::vector<IObjectInfo::CArmyStructure> armies; | ||||
| 	for (auto configEntry : config) | ||||
| 	{ | ||||
| 		auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]); | ||||
| 		IObjectInfo::CArmyStructure army; | ||||
| 		for (auto & stack : stacks) | ||||
| 		{ | ||||
| 			assert(!stack.allowedCreatures.empty()); | ||||
| 			auto strongest = boost::range::max_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b) | ||||
| 			{ | ||||
| 				return a->fightValue < b->fightValue; | ||||
| 			}); | ||||
| 			addStackToArmy(army, *strongest, stack.maxAmount); | ||||
| 		} | ||||
| 		armies.push_back(army); | ||||
| 	} | ||||
| 	return *boost::range::max_element(armies); | ||||
| } | ||||
|  | ||||
| bool CBankInfo::givesResources() const | ||||
| { | ||||
| 	for (const JsonNode & node : config) | ||||
| 		if (!node["reward"]["resources"].isNull()) | ||||
| 			return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| bool CBankInfo::givesArtifacts() const | ||||
| { | ||||
| 	for (const JsonNode & node : config) | ||||
| 		if (!node["reward"]["artifacts"].isNull()) | ||||
| 			return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| bool CBankInfo::givesCreatures() const | ||||
| { | ||||
| 	for (const JsonNode & node : config) | ||||
| 		if (!node["reward"]["creatures"].isNull()) | ||||
| 			return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| bool CBankInfo::givesSpells() const | ||||
| { | ||||
| 	for (const JsonNode & node : config) | ||||
| 		if (!node["reward"]["spells"].isNull()) | ||||
| 			return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
|  | ||||
| std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(ObjectTemplate tmpl) const | ||||
| { | ||||
| 	return std::unique_ptr<IObjectInfo>(new CBankInfo(levels)); | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,8 @@ class CGDwelling; | ||||
| //class CGArtifact; | ||||
| //class CGCreature; | ||||
| class CHeroClass; | ||||
| class CBank; | ||||
| class CStackBasicDescriptor; | ||||
|  | ||||
| /// Class that is used for objects that do not have dedicated handler | ||||
| template<class ObjectType> | ||||
| @@ -45,7 +47,7 @@ public: | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const | ||||
| 	virtual std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
| @@ -63,6 +65,7 @@ class CTownInstanceConstructor : public CDefaultObjectTypeHandler<CGTownInstance | ||||
| 	JsonNode filtersJson; | ||||
| protected: | ||||
| 	bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; | ||||
| 	void initTypeData(const JsonNode & input); | ||||
|  | ||||
| public: | ||||
| 	CFaction * faction; | ||||
| @@ -70,7 +73,6 @@ public: | ||||
|  | ||||
| 	CTownInstanceConstructor(); | ||||
| 	CGObjectInstance * create(ObjectTemplate tmpl) const; | ||||
| 	void initTypeData(const JsonNode & input); | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const; | ||||
| 	void afterLoadFinalization(); | ||||
|  | ||||
| @@ -86,6 +88,7 @@ class CHeroInstanceConstructor : public CDefaultObjectTypeHandler<CGHeroInstance | ||||
| 	JsonNode filtersJson; | ||||
| protected: | ||||
| 	bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; | ||||
| 	void initTypeData(const JsonNode & input); | ||||
|  | ||||
| public: | ||||
| 	CHeroClass * heroClass; | ||||
| @@ -93,7 +96,6 @@ public: | ||||
|  | ||||
| 	CHeroInstanceConstructor(); | ||||
| 	CGObjectInstance * create(ObjectTemplate tmpl) const; | ||||
| 	void initTypeData(const JsonNode & input); | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const; | ||||
| 	void afterLoadFinalization(); | ||||
|  | ||||
| @@ -112,12 +114,12 @@ class CDwellingInstanceConstructor : public CDefaultObjectTypeHandler<CGDwelling | ||||
|  | ||||
| protected: | ||||
| 	bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; | ||||
| 	void initTypeData(const JsonNode & input); | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	CDwellingInstanceConstructor(); | ||||
| 	CGObjectInstance * create(ObjectTemplate tmpl) const; | ||||
| 	void initTypeData(const JsonNode & input); | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const; | ||||
|  | ||||
| 	bool producesCreature(const CCreature * crea) const; | ||||
| @@ -128,3 +130,56 @@ public: | ||||
| 		h & static_cast<CDefaultObjectTypeHandler<CGDwelling>&>(*this); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct BankConfig | ||||
| { | ||||
| 	BankConfig() { chance = upgradeChance = combatValue = value = 0; }; | ||||
| 	ui32 value; //overall value of given things | ||||
| 	ui32 chance; //chance for this level being chosen | ||||
| 	ui32 upgradeChance; //chance for creatures to be in upgraded versions | ||||
| 	ui32 combatValue; //how hard are guards of this level | ||||
| 	std::vector<CStackBasicDescriptor> guards; //creature ID, amount | ||||
| 	Res::ResourceSet resources; //resources given in case of victory | ||||
| 	std::vector<CStackBasicDescriptor> creatures; //creatures granted in case of victory (creature ID, amount) | ||||
| 	std::vector<ArtifactID> artifacts; //artifacts given in case of victory | ||||
| 	std::vector<SpellID> spells; // granted spell(s), for Pyramid | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & chance & upgradeChance & guards & combatValue & resources & creatures & artifacts & value & spells; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class CBankInfo : public IObjectInfo | ||||
| { | ||||
| 	JsonVector config; | ||||
| public: | ||||
| 	CBankInfo(JsonVector config); | ||||
|  | ||||
| 	CArmyStructure minGuards() const; | ||||
| 	CArmyStructure maxGuards() const; | ||||
| 	bool givesResources() const; | ||||
| 	bool givesArtifacts() const; | ||||
| 	bool givesCreatures() const; | ||||
| 	bool givesSpells() const; | ||||
| }; | ||||
|  | ||||
| class CBankInstanceConstructor : public CDefaultObjectTypeHandler<CBank> | ||||
| { | ||||
| 	BankConfig generateConfig(const JsonNode & conf, CRandomGenerator & rng) const; | ||||
|  | ||||
| 	JsonVector levels; | ||||
| protected: | ||||
| 	void initTypeData(const JsonNode & input); | ||||
|  | ||||
| public: | ||||
| 	// all banks of this type will be reset N days after clearing, | ||||
| 	si32 bankResetDuration; | ||||
|  | ||||
| 	CBankInstanceConstructor(); | ||||
|  | ||||
| 	CGObjectInstance *create(ObjectTemplate tmpl) const; | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const; | ||||
|  | ||||
| 	std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const; | ||||
| }; | ||||
|   | ||||
							
								
								
									
										225
									
								
								lib/mapObjects/JsonRandom.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								lib/mapObjects/JsonRandom.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,225 @@ | ||||
| /* | ||||
|  * | ||||
|  * CRewardableObject.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "StdInc.h" | ||||
| #include "JsonRandom.h" | ||||
|  | ||||
| #include "../JsonNode.h" | ||||
| #include "../CRandomGenerator.h" | ||||
| #include "../StringConstants.h" | ||||
| #include "../VCMI_Lib.h" | ||||
| #include "../CModHandler.h" | ||||
| #include "../CArtHandler.h" | ||||
| #include "../CCreatureHandler.h" | ||||
| #include "../CCreatureSet.h" | ||||
| #include "../CSpellHandler.h" | ||||
|  | ||||
| namespace JsonRandom | ||||
| { | ||||
| 	si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue) | ||||
| 	{ | ||||
| 		if (value.isNull()) | ||||
| 			return defaultValue; | ||||
| 		if (value.getType() == JsonNode::DATA_FLOAT) | ||||
| 			return value.Float(); | ||||
| 		if (!value["amount"].isNull()) | ||||
| 			return value["amount"].Float(); | ||||
| 		si32 min = value["min"].Float(); | ||||
| 		si32 max = value["max"].Float(); | ||||
| 		return rng.getIntRange(min, max)(); | ||||
| 	} | ||||
|  | ||||
| 	TResources loadResources(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		TResources ret; | ||||
| 		for (size_t i=0; i<GameConstants::RESOURCE_QUANTITY; i++) | ||||
| 		{ | ||||
| 			ret[i] = loadValue(value[GameConstants::RESOURCE_NAMES[i]], rng); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::vector<si32> ret; | ||||
| 		for (auto & name : PrimarySkill::names) | ||||
| 		{ | ||||
| 			ret.push_back(loadValue(value[name], rng)); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::map<SecondarySkill, si32> loadSecondary(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::map<SecondarySkill, si32> ret; | ||||
| 		for (auto & pair : value.Struct()) | ||||
| 		{ | ||||
| 			SecondarySkill id(VLC->modh->identifiers.getIdentifier(pair.second.meta, "skill", pair.first).get()); | ||||
| 			ret[id] = loadValue(pair.second, rng); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		if (value.getType() == JsonNode::DATA_STRING) | ||||
| 			return ArtifactID(VLC->modh->identifiers.getIdentifier("artifact", value).get()); | ||||
|  | ||||
| 		std::set<CArtifact::EartClass> allowedClasses; | ||||
| 		std::set<ArtifactPosition> allowedPositions; | ||||
| 		ui32 minValue = 0; | ||||
| 		ui32 maxValue = std::numeric_limits<ui32>::max(); | ||||
|  | ||||
| 		if (value["class"].getType() == JsonNode::DATA_STRING) | ||||
| 			allowedClasses.insert(VLC->arth->stringToClass(value["class"].String())); | ||||
| 		else | ||||
| 			for (auto & entry : value["class"].Vector()) | ||||
| 				allowedClasses.insert(VLC->arth->stringToClass(entry.String())); | ||||
|  | ||||
| 		if (value["slot"].getType() == JsonNode::DATA_STRING) | ||||
| 			allowedPositions.insert(VLC->arth->stringToSlot(value["class"].String())); | ||||
| 		else | ||||
| 			for (auto & entry : value["slot"].Vector()) | ||||
| 				allowedPositions.insert(VLC->arth->stringToSlot(entry.String())); | ||||
|  | ||||
| 		if (value["minValue"].isNull()) minValue = value["minValue"].Float(); | ||||
| 		if (value["maxValue"].isNull()) maxValue = value["maxValue"].Float(); | ||||
|  | ||||
| 		return VLC->arth->pickRandomArtifact(rng, [=](ArtifactID artID) -> bool | ||||
| 		{ | ||||
| 			CArtifact * art = VLC->arth->artifacts[artID]; | ||||
|  | ||||
| 			if (!vstd::iswithin(art->price, minValue, maxValue)) | ||||
| 				return false; | ||||
|  | ||||
| 			if (!allowedClasses.empty() && !allowedClasses.count(art->aClass)) | ||||
| 				return false; | ||||
|  | ||||
| 			if (!allowedPositions.empty()) | ||||
| 			{ | ||||
| 				for (auto pos : art->possibleSlots[ArtBearer::HERO]) | ||||
| 				{ | ||||
| 					if (allowedPositions.count(pos)) | ||||
| 						return true; | ||||
| 				} | ||||
| 				return false; | ||||
| 			} | ||||
| 			return true; | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::vector<ArtifactID> ret; | ||||
| 		for (const JsonNode & entry : value.Vector()) | ||||
| 		{ | ||||
| 			ret.push_back(loadArtifact(entry, rng)); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells) | ||||
| 	{ | ||||
| 		if (value.getType() == JsonNode::DATA_STRING) | ||||
| 			return SpellID(VLC->modh->identifiers.getIdentifier("spell", value).get()); | ||||
| 		if (value["type"].getType() == JsonNode::DATA_STRING) | ||||
| 			return SpellID(VLC->modh->identifiers.getIdentifier("spell", value["type"]).get()); | ||||
|  | ||||
| 		spells.erase(std::remove_if(spells.begin(), spells.end(), [=](SpellID spell) | ||||
| 		{ | ||||
| 			return VLC->spellh->objects[spell]->level != si32(value["level"].Float()); | ||||
| 		}), spells.end()); | ||||
|  | ||||
| 		return SpellID(*RandomGeneratorUtil::nextItem(spells, rng)); | ||||
| 	} | ||||
|  | ||||
| 	std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells) | ||||
| 	{ | ||||
| 		// possible extensions: (taken from spell json config) | ||||
| 		// "type": "adventure",//"adventure", "combat", "ability" | ||||
| 		// "school": {"air":true, "earth":true, "fire":true, "water":true}, | ||||
| 		// "level": 1, | ||||
|  | ||||
| 		std::vector<SpellID> ret; | ||||
| 		for (const JsonNode & entry : value.Vector()) | ||||
| 		{ | ||||
| 			ret.push_back(loadSpell(entry, rng, spells)); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		CStackBasicDescriptor stack; | ||||
| 		stack.type = VLC->creh->creatures[VLC->modh->identifiers.getIdentifier("creature", value["type"]).get()]; | ||||
| 		stack.count = loadValue(value, rng); | ||||
| 		if (!value["upgradeChance"].isNull() && !stack.type->upgrades.empty()) | ||||
| 		{ | ||||
| 			if (int(value["upgradeChance"].Float()) > rng.nextInt(99)) // select random upgrade | ||||
| 			{ | ||||
| 				stack.type = VLC->creh->creatures[*RandomGeneratorUtil::nextItem(stack.type->upgrades, rng)]; | ||||
| 			} | ||||
| 		} | ||||
| 		return stack; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng) | ||||
| 	{ | ||||
| 		std::vector<CStackBasicDescriptor> ret; | ||||
| 		for (const JsonNode & node : value.Vector()) | ||||
| 		{ | ||||
| 			ret.push_back(loadCreature(node, rng)); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value) | ||||
| 	{ | ||||
| 		std::vector<RandomStackInfo> ret; | ||||
| 		for (const JsonNode & node : value.Vector()) | ||||
| 		{ | ||||
| 			RandomStackInfo info; | ||||
|  | ||||
| 			if (!node["amount"].isNull()) | ||||
| 				info.minAmount = info.maxAmount = node["amount"].Float(); | ||||
| 			else | ||||
| 			{ | ||||
| 				info.minAmount = node["min"].Float(); | ||||
| 				info.maxAmount = node["max"].Float(); | ||||
| 			} | ||||
| 			const CCreature * crea = VLC->creh->creatures[VLC->modh->identifiers.getIdentifier("creature", node["type"]).get()]; | ||||
| 			info.allowedCreatures.push_back(crea); | ||||
| 			if (!node["upgradeChance"].Float() > 0) | ||||
| 			{ | ||||
| 				for (auto creaID : crea->upgrades) | ||||
| 					info.allowedCreatures.push_back(VLC->creh->creatures[creaID]); | ||||
| 			} | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<Bonus> loadBonuses(const JsonNode & value) | ||||
| 	{ | ||||
| 		std::vector<Bonus> ret; | ||||
| 		for (const JsonNode & entry : value.Vector()) | ||||
| 		{ | ||||
| 			Bonus * bonus = JsonUtils::parseBonus(entry); | ||||
| 			ret.push_back(*bonus); | ||||
| 			delete bonus; | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<Component> loadComponents(const JsonNode & value) | ||||
| 	{ | ||||
| 		//TODO | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										50
									
								
								lib/mapObjects/JsonRandom.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								lib/mapObjects/JsonRandom.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../GameConstants.h" | ||||
| #include "../ResourceSet.h" | ||||
|  | ||||
| /* | ||||
|  * JsonRandom.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 JsonNode; | ||||
| typedef std::vector<JsonNode> JsonVector; | ||||
| class CRandomGenerator; | ||||
|  | ||||
| class Bonus; | ||||
| class Component; | ||||
| class CStackBasicDescriptor; | ||||
|  | ||||
| namespace JsonRandom | ||||
| { | ||||
| 	struct RandomStackInfo | ||||
| 	{ | ||||
| 		std::vector<const CCreature *> allowedCreatures; | ||||
| 		si32 minAmount; | ||||
| 		si32 maxAmount; | ||||
| 	}; | ||||
|  | ||||
| 	si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue = 0); | ||||
| 	TResources loadResources(const JsonNode & value, CRandomGenerator & rng); | ||||
| 	std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng); | ||||
| 	std::map<SecondarySkill, si32> loadSecondary(const JsonNode & value, CRandomGenerator & rng); | ||||
|  | ||||
| 	ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng); | ||||
| 	std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng); | ||||
|  | ||||
| 	SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells); | ||||
| 	std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells); | ||||
|  | ||||
| 	CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng); | ||||
| 	std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng); | ||||
| 	std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value); | ||||
|  | ||||
| 	std::vector<Bonus> loadBonuses(const JsonNode & value); | ||||
| 	std::vector<Component> loadComponents(const JsonNode & value); | ||||
| } | ||||
| @@ -1569,7 +1569,7 @@ void CMapLoaderH3M::readObjects() | ||||
| 			{ | ||||
| 				if(objTempl.subid == 0) | ||||
| 				{ | ||||
| 					nobj = new CGPyramid(); | ||||
| 					nobj = new CBank(); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
|   | ||||
| @@ -69,7 +69,6 @@ void registerTypesMapObjects1(Serializer &s) | ||||
| 	s.template registerType<CArmedInstance, CGResource>(); | ||||
| 	s.template registerType<CArmedInstance, CGMine>(); | ||||
| 	s.template registerType<CArmedInstance, CBank>(); | ||||
| 		s.template registerType<CBank, CGPyramid>(); | ||||
| 	s.template registerType<CArmedInstance, CGSeerHut>(); s.template registerType<IQuestObject, CGSeerHut>(); | ||||
| 	s.template registerType<CGSeerHut, CGQuestGuard>(); | ||||
| } | ||||
| @@ -81,13 +80,13 @@ void registerTypesMapObjectTypes(Serializer &s) | ||||
| 	s.template registerType<AObjectTypeHandler, CHeroInstanceConstructor>(); | ||||
| 	s.template registerType<AObjectTypeHandler, CTownInstanceConstructor>(); | ||||
| 	s.template registerType<AObjectTypeHandler, CDwellingInstanceConstructor>(); | ||||
| 	s.template registerType<AObjectTypeHandler, CBankInstanceConstructor>(); | ||||
| 	s.template registerType<AObjectTypeHandler, CObstacleConstructor>(); | ||||
|  | ||||
| #define REGISTER_GENERIC_HANDLER(TYPENAME) s.template registerType<AObjectTypeHandler, CDefaultObjectTypeHandler<TYPENAME> >() | ||||
|  | ||||
| 	REGISTER_GENERIC_HANDLER(CGObjectInstance); | ||||
| 	REGISTER_GENERIC_HANDLER(CGMarket); | ||||
| 	REGISTER_GENERIC_HANDLER(CBank); | ||||
| 	REGISTER_GENERIC_HANDLER(CCartographer); | ||||
| 	REGISTER_GENERIC_HANDLER(CGArtifact); | ||||
| 	REGISTER_GENERIC_HANDLER(CGBlackMarket); | ||||
| @@ -113,7 +112,6 @@ void registerTypesMapObjectTypes(Serializer &s) | ||||
| 	REGISTER_GENERIC_HANDLER(CGOnceVisitable); | ||||
| 	REGISTER_GENERIC_HANDLER(CGPandoraBox); | ||||
| 	REGISTER_GENERIC_HANDLER(CGPickable); | ||||
| 	REGISTER_GENERIC_HANDLER(CGPyramid); | ||||
| 	REGISTER_GENERIC_HANDLER(CGQuestGuard); | ||||
| 	REGISTER_GENERIC_HANDLER(CGResource); | ||||
| 	REGISTER_GENERIC_HANDLER(CGScholar); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user