mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	- removed creature-related code from ModHandler
- new towns can be loaded as mods - removed separate DefInfos for towns\capitals - a bit simpler handling of adventure map def's
This commit is contained in:
		| @@ -146,13 +146,14 @@ SDL_Surface * BitmapHandler::loadBitmapFromDir(std::string path, std::string fna | ||||
| 				//set correct value for alpha\unused channel | ||||
| 				for (int i=0; i< ret->format->palette->ncolors; i++) | ||||
| 					ret->format->palette->colors[i].unused = 255; | ||||
| 			}			 | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			tlog1<<"Failed to open "<<fname<<" via SDL_Image\n";		 | ||||
| 			tlog1<<"Failed to open "<<fname<<" via SDL_Image\n"; | ||||
| 		} | ||||
| 	} | ||||
| 	SDL_SetColorKey(ret, SDL_SRCCOLORKEY, SDL_MapRGB(ret->format, 0, 255, 255)); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1152,7 +1152,10 @@ void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key ) | ||||
| 			builds = new CCastleBuildings(town); | ||||
|  | ||||
| 			BOOST_FOREACH(const CStructure * str, town->town->clientInfo.structures) | ||||
| 				tlog1 << int(str->building->bid) << " -> " << int(str->pos.z) << "\n"; | ||||
| 			{ | ||||
| 				if (str->building) | ||||
| 					tlog1 << int(str->building->bid) << " -> " << int(str->pos.z) << "\n"; | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
| 	case SDLK_KP_MINUS: | ||||
| @@ -1165,7 +1168,10 @@ void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key ) | ||||
| 			builds = new CCastleBuildings(town); | ||||
|  | ||||
| 			BOOST_FOREACH(const CStructure * str, town->town->clientInfo.structures) | ||||
| 				tlog1 << int(str->building->bid) << " -> " << int(str->pos.z) << "\n"; | ||||
| 			{ | ||||
| 				if (str->building) | ||||
| 					tlog1 << int(str->building->bid) << " -> " << int(str->pos.z) << "\n"; | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 		break; | ||||
|   | ||||
| @@ -778,7 +778,7 @@ static void listenForEvents() | ||||
| 				delete CGI->dobjinfo.get(); | ||||
| 				const_cast<CGameInfo*>(CGI)->dobjinfo = new CDefObjInfoHandler;  | ||||
| 				const_cast<CGameInfo*>(CGI)->dobjinfo->load(); | ||||
| 				const_cast<CGameInfo*>(CGI)->modh->recreateAdvMapDefs(); //add info about new creatures to dobjinfo | ||||
| 				const_cast<CGameInfo*>(CGI)->modh->reload(); //add info about new creatures to dobjinfo | ||||
| 			}; | ||||
|  | ||||
| 			switch(ev.user.code) | ||||
|   | ||||
| @@ -346,7 +346,9 @@ SDL_Surface * Graphics::getPic(int ID, bool fort, bool builded) | ||||
| 	{ | ||||
| 		assert(vstd::contains(CGI->townh->towns, ID)); | ||||
| 		int pom = CGI->townh->towns[ID].clientInfo.icons[fort][builded]; | ||||
| 		return smallIcons->ourImages[pom + 2].bitmap; | ||||
| 		if (smallIcons->ourImages.size() > pom + 2) | ||||
| 			return smallIcons->ourImages[pom + 2].bitmap; | ||||
| 		return nullptr; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -478,12 +480,12 @@ void Graphics::loadFonts() | ||||
|  | ||||
| CDefEssential * Graphics::getDef( const CGObjectInstance * obj ) | ||||
| { | ||||
| 	return advmapobjGraphics[obj->defInfo->id][obj->defInfo->subid][obj->defInfo->name]; | ||||
| 	return advmapobjGraphics[obj->defInfo->name]; | ||||
| } | ||||
|  | ||||
| CDefEssential * Graphics::getDef( const CGDefInfo * info ) | ||||
| { | ||||
| 	return advmapobjGraphics[info->id][info->subid][info->name]; | ||||
| 	return advmapobjGraphics[info->name]; | ||||
| } | ||||
|  | ||||
| void Graphics::loadErmuToPicture() | ||||
|   | ||||
| @@ -54,11 +54,10 @@ public: | ||||
| 	CDefEssential * heroMoveArrows; | ||||
| 	std::vector<CDefEssential *> heroAnims; // [class id: 0 - 17]  //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing | ||||
| 	std::vector<CDefEssential *> boatAnims; // [boat type: 0 - 3]  //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing | ||||
| 	std::map<std::string, CDefEssential*> mapObjectDefs; //pointers to loaded defs (key is filename, uppercase) | ||||
| 	CDefHandler * FoWfullHide; //for Fog of War | ||||
| 	CDefHandler * FoWpartialHide; //for For of War | ||||
|  | ||||
| 	std::map<int, std::map<int, std::map<std::string, CDefEssential *> > > advmapobjGraphics; | ||||
| 	std::map<std::string, CDefEssential *> advmapobjGraphics; | ||||
| 	CDefEssential * getDef(const CGObjectInstance * obj); | ||||
| 	CDefEssential * getDef(const CGDefInfo * info); | ||||
| 	//creatures | ||||
|   | ||||
| @@ -403,11 +403,11 @@ void NewStructures::applyCl( CClient *cl ) | ||||
| 	{ | ||||
| 		if(id== EBuilding::CAPITOL) //fort or capitol | ||||
| 		{ | ||||
| 			town->defInfo = GS(cl)->capitols[town->subID]; | ||||
| 			town->defInfo = const_cast<CGDefInfo*>(CGI->dobjinfo->capitols[town->subID].get()); | ||||
| 		} | ||||
| 		if(id == EBuilding::FORT) | ||||
| 		{ | ||||
| 			town->defInfo = GS(cl)->forts[town->subID]; | ||||
| 			town->defInfo = const_cast<CGDefInfo*>(CGI->dobjinfo->gobjs[Obj::TOWN][town->subID].get()); | ||||
| 		} | ||||
| 		if(vstd::contains(cl->playerint,town->tempOwner)) | ||||
| 			cl->playerint[town->tempOwner]->buildChanged(town,id,1); | ||||
| @@ -420,7 +420,7 @@ void RazeStructures::applyCl (CClient *cl) | ||||
| 	{ | ||||
| 		if (id == 13) //fort or capitol | ||||
| 		{ | ||||
| 			town->defInfo = GS(cl)->forts[town->subID]; | ||||
| 			town->defInfo = const_cast<CGDefInfo*>(CGI->dobjinfo->gobjs[Obj::TOWN][town->subID].get()); | ||||
| 		} | ||||
| 		if(vstd::contains (cl->playerint,town->tempOwner)) | ||||
| 			cl->playerint[town->tempOwner]->buildChanged (town,id,2); | ||||
|   | ||||
| @@ -74,7 +74,8 @@ void blitAt(SDL_Surface * src, int x, int y, SDL_Surface * dst) | ||||
|  | ||||
| void blitAt(SDL_Surface * src, const SDL_Rect & pos, SDL_Surface * dst) | ||||
| { | ||||
| 	blitAt(src,pos.x,pos.y,dst); | ||||
| 	if (src) | ||||
| 		blitAt(src,pos.x,pos.y,dst); | ||||
| } | ||||
|  | ||||
| SDL_Color genRGB(int r, int g, int b, int a=0) | ||||
|   | ||||
| @@ -240,6 +240,36 @@ void CMapHandler::borderAndTerrainBitmapInit() | ||||
| 	} | ||||
| 	delete bord; | ||||
| } | ||||
|  | ||||
| static void processDef (const CGDefInfo* def) | ||||
| { | ||||
| 	if(def->id == Obj::EVENT) | ||||
| 	{ | ||||
| 		graphics->advmapobjGraphics[def->name] = NULL; | ||||
| 		return; | ||||
| 	} | ||||
| 	CDefEssential * ourDef = graphics->getDef(def); | ||||
| 	if(!ourDef) //if object has already set handler (eg. heroes) it should not be overwritten | ||||
| 	{ | ||||
| 		if(def->name.size()) | ||||
| 		{ | ||||
| 			graphics->advmapobjGraphics[def->name] = CDefHandler::giveDefEss(def->name); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			tlog2 << "No def name for " << def->id << "  " << def->subid << std::endl; | ||||
| 			return; | ||||
| 		} | ||||
| 		ourDef = graphics->getDef(def); | ||||
|  | ||||
| 	} | ||||
| 	//alpha transformation | ||||
| 	for(size_t yy=0; yy < ourDef->ourImages.size(); ++yy) | ||||
| 	{ | ||||
| 		CSDL_Ext::alphaTransform(ourDef->ourImages[yy].bitmap); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CMapHandler::initObjectRects() | ||||
| { | ||||
| 	//initializing objects / rects | ||||
| @@ -249,11 +279,15 @@ void CMapHandler::initObjectRects() | ||||
| 		if(	!obj | ||||
| 			|| (obj->ID==Obj::HERO && static_cast<const CGHeroInstance*>(obj)->inTownGarrison) //garrisoned hero | ||||
| 			|| (obj->ID==Obj::BOAT && static_cast<const CGBoat*>(obj)->hero) //boat with hero (hero graphics is used) | ||||
| 			|| !obj->defInfo | ||||
| 			|| !graphics->getDef(obj)) //no graphic... | ||||
| 			|| !obj->defInfo ) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!graphics->getDef(obj)) //try to load it | ||||
| 			processDef(obj->defInfo); | ||||
| 		if (!graphics->getDef(obj)) // stil no graphics? exit | ||||
| 			continue; | ||||
|  | ||||
| 		const SDL_Surface *bitmap = graphics->getDef(obj)->ourImages[0].bitmap; | ||||
| 		for(int fx=0; fx<bitmap->w>>5; ++fx) //bitmap->w/32 | ||||
| 		{ | ||||
| @@ -294,53 +328,20 @@ void CMapHandler::initObjectRects() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| static void processDef (const CGDefInfo* def) | ||||
| { | ||||
| 	if(def->id == Obj::EVENT) | ||||
| 	{ | ||||
|         graphics->advmapobjGraphics[def->id][def->subid][def->name] = NULL; | ||||
| 		return; | ||||
| 	} | ||||
|     CDefEssential * ourDef = graphics->getDef(def); | ||||
| 	if(!ourDef) //if object has already set handler (eg. heroes) it should not be overwritten  | ||||
| 	{ | ||||
| 		if(def->name.size()) | ||||
| 		{ | ||||
| 			if(vstd::contains(graphics->mapObjectDefs, def->name)) | ||||
| 			{ | ||||
|                 graphics->advmapobjGraphics[def->id][def->subid][def->name] = graphics->mapObjectDefs[def->name]; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
|                 graphics->mapObjectDefs[def->name] = graphics->advmapobjGraphics[def->id][def->subid][def->name] = CDefHandler::giveDefEss(def->name); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			tlog2 << "No def name for " << def->id << "  " << def->subid << std::endl; | ||||
| 			return; | ||||
| 		} | ||||
|         ourDef = graphics->getDef(def); | ||||
|          | ||||
| 	} | ||||
| 	//alpha transformation | ||||
| 	for(size_t yy=0; yy < ourDef->ourImages.size(); ++yy) | ||||
| 	{ | ||||
| 		CSDL_Ext::alphaTransform(ourDef->ourImages[yy].bitmap); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CMapHandler::initHeroDef(const CGHeroInstance * h) | ||||
| { | ||||
|     graphics->advmapobjGraphics[h->defInfo->id][h->defInfo->subid][h->defInfo->name] = graphics->flags1[0]; | ||||
| 	graphics->advmapobjGraphics[h->defInfo->name] = graphics->flags1[0]; | ||||
| } | ||||
|  | ||||
| void CMapHandler::init() | ||||
| { | ||||
| 	CStopWatch th; | ||||
| 	th.getDiff(); | ||||
|  | ||||
|     graphics->advmapobjGraphics[8][0]["AB01_.DEF"] = graphics->boatAnims[0]; | ||||
|     graphics->advmapobjGraphics[8][1]["AB02_.DEF"] = graphics->boatAnims[1]; | ||||
|     graphics->advmapobjGraphics[8][2]["AB03_.DEF"] = graphics->boatAnims[2]; | ||||
| 	graphics->advmapobjGraphics["AB01_.DEF"] = graphics->boatAnims[0]; | ||||
| 	graphics->advmapobjGraphics["AB02_.DEF"] = graphics->boatAnims[1]; | ||||
| 	graphics->advmapobjGraphics["AB03_.DEF"] = graphics->boatAnims[2]; | ||||
| 	// Size of visible terrain. | ||||
| 	int mapW = conf.go()->ac.advmapW; | ||||
| 	int mapH = conf.go()->ac.advmapH; | ||||
| @@ -381,18 +382,6 @@ void CMapHandler::init() | ||||
|     std::for_each(map->customDefs.begin(),map->customDefs.end(),processDef); //load h3m defs | ||||
| 	tlog0<<"\tUnpacking and handling defs: "<<th.getDiff()<<std::endl; | ||||
|  | ||||
| 	//it seems to be completely unnecessary and useless | ||||
| // 	for(int i=0;i<PLAYER_LIMIT;i++) | ||||
| // 	{ | ||||
| // 		for(size_t j=0; j < map->players[i].heroesNames.size(); ++j) | ||||
| // 		{ | ||||
| // 			usedHeroes.insert(map->players[i].heroesNames[j].heroID); | ||||
| // 		} | ||||
| // 	} | ||||
| // 	tlog0<<"\tChecking used heroes: "<<th.getDif()<<std::endl; | ||||
|  | ||||
|  | ||||
|  | ||||
| 	prepareFOWDefs(); | ||||
| 	roadsRiverTerrainInit();	//road's and river's DefHandlers; and simple values initialization | ||||
| 	borderAndTerrainBitmapInit(); | ||||
| @@ -414,7 +403,7 @@ void CMapHandler::terrainRect( int3 top_tile, ui8 anim, const std::vector< std:: | ||||
|  | ||||
| 	// Basic rectangle for a tile. Should be a const but conflicts with SDL headers | ||||
| 	SDL_Rect rtile = { 0, 0, 32, 32 }; | ||||
| 									 | ||||
|  | ||||
| 	// Absolute coords of the first pixel in the top left corner | ||||
| 	int srx_init = offsetX + extRect->x; | ||||
| 	int sry_init = offsetY + extRect->y; | ||||
|   | ||||
| @@ -30,8 +30,16 @@ public: | ||||
|  | ||||
| 	template<typename T> void print(const T &data, int lvl) | ||||
| 	{ | ||||
| #ifndef _WIN32 | ||||
| 		// with love from ffmpeg - library is trying to print some warnings from separate thread | ||||
| 		// this results in broken console on Linux. Lock stdout to print all our data at once | ||||
| 		flockfile(stdout); | ||||
| #endif | ||||
| 		setColor(lvl); | ||||
| 		std::cout << data << std::flush; | ||||
| 		setColor(-1); | ||||
| #ifndef _WIN32 | ||||
| 		funlockfile(stdout); | ||||
| #endif | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -611,6 +611,162 @@ void CCreatureHandler::loadSoundsInfo() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::load(const JsonNode & node) | ||||
| { | ||||
| 	BOOST_FOREACH(auto & entry, node.Struct()) | ||||
| 	{ | ||||
| 		if (!entry.second.isNull()) // may happens if mod removed creature by setting json entry to null | ||||
| 		{ | ||||
| 			CCreature * creature = loadCreature(entry.second); | ||||
| 			creature->nameRef = entry.first; | ||||
| 			creature->idNumber = creatures.size(); | ||||
| 			nameToID[entry.first] = creatures.size(); | ||||
|  | ||||
| 			creatures.push_back(creature); | ||||
| 			tlog3 << "Added creature: " << entry.first << "\n"; | ||||
| 			//TODO: notify modHandler that this refName can be resolved to ID | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CCreature * CCreatureHandler::loadCreature(const JsonNode & node) | ||||
| { | ||||
| 	CCreature * cre = new CCreature(); | ||||
|  | ||||
| 	const JsonNode & name = node["name"]; | ||||
| 	cre->nameSing = name["singular"].String(); | ||||
| 	cre->namePl = name["plural"].String(); | ||||
|  | ||||
| 	cre->cost = Res::ResourceSet(node["cost"]); | ||||
|  | ||||
| 	cre->level = node["level"].Float(); | ||||
| 	cre->faction = node["faction"].Float(); //TODO: replaced by string -> id conversion | ||||
| 	cre->fightValue = node["fightValue"].Float(); | ||||
| 	cre->AIValue = node["aiValue"].Float(); | ||||
| 	cre->growth = node["growth"].Float(); | ||||
| 	cre->hordeGrowth = node["horde"].Float(); // Needed at least until configurable buildings | ||||
|  | ||||
| 	cre->addBonus(node["hitPoints"].Float(), Bonus::STACK_HEALTH); | ||||
| 	cre->addBonus(node["speed"].Float(), Bonus::STACKS_SPEED); | ||||
| 	cre->addBonus(node["attack"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK); | ||||
| 	cre->addBonus(node["defense"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE); | ||||
| 	const JsonNode &  vec = node["damage"]; | ||||
| 	cre->addBonus(vec["min"].Float(), Bonus::CREATURE_DAMAGE, 1); | ||||
| 	cre->addBonus(vec["max"].Float(), Bonus::CREATURE_DAMAGE, 2); | ||||
|  | ||||
| 	auto & amounts = node ["advMapAmount"]; | ||||
| 	cre->ammMin = amounts["min"].Float(); | ||||
| 	cre->ammMax = amounts["max"].Float(); | ||||
|  | ||||
| 	//optional | ||||
| 	BOOST_FOREACH (auto & str, node["upgrades"].Vector()) | ||||
| 	{ | ||||
| 		cre->upgradeNames.insert (str.String()); | ||||
| 	} | ||||
|  | ||||
| 	if (!node["shots"].isNull()) | ||||
| 		cre->addBonus(node["shots"].Float(), Bonus::SHOTS); | ||||
|  | ||||
| 	if (node["spellPoints"].isNull()) | ||||
| 		cre->addBonus(node["spellPoints"].Float(), Bonus::CASTS); | ||||
|  | ||||
| 	cre->doubleWide = node["doubleWide"].Bool(); | ||||
|  | ||||
| 	BOOST_FOREACH (const JsonNode &bonus, node["abilities"].Vector()) | ||||
| 	{ | ||||
| 		auto b = ParseBonus(bonus); | ||||
| 		b->source = Bonus::CREATURE_ABILITY; | ||||
| 		b->duration = Bonus::PERMANENT; | ||||
| 		cre->addNewBonus(b); | ||||
| 	} | ||||
|  | ||||
| 	BOOST_FOREACH (const JsonNode &exp, node["stackExperience"].Vector()) | ||||
| 	{ | ||||
| 		auto bonus = ParseBonus (exp["bonus"]); | ||||
| 		bonus->source = Bonus::STACK_EXPERIENCE; | ||||
| 		bonus->duration = Bonus::PERMANENT; | ||||
| 		const JsonVector &values = exp["values"].Vector(); | ||||
| 		int lowerLimit = 1;//, upperLimit = 255; | ||||
| 		if (values[0].getType() == JsonNode::JsonType::DATA_BOOL) | ||||
| 		{ | ||||
| 			BOOST_FOREACH (const JsonNode &val, values) | ||||
| 			{ | ||||
| 				if (val.Bool() == true) | ||||
| 				{ | ||||
| 					bonus->limiter = make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit)); | ||||
| 					cre->addNewBonus (new Bonus(*bonus)); //bonuses must be unique objects | ||||
| 					break; //TODO: allow bonuses to turn off? | ||||
| 				} | ||||
| 				++lowerLimit; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			int lastVal = 0; | ||||
| 			BOOST_FOREACH (const JsonNode &val, values) | ||||
| 			{ | ||||
| 				if (val.Float() != lastVal) | ||||
| 				{ | ||||
| 					bonus->val = val.Float() - lastVal; | ||||
| 					bonus->limiter.reset (new RankRangeLimiter(lowerLimit)); | ||||
| 					cre->addNewBonus (new Bonus(*bonus)); | ||||
| 				} | ||||
| 				lastVal = val.Float(); | ||||
| 				++lowerLimit; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	//graphics | ||||
|  | ||||
| 	const JsonNode & graphics = node["graphics"]; | ||||
| 	cre->animDefName = graphics["animation"].String(); | ||||
| 	cre->timeBetweenFidgets = graphics["timeBetweenFidgets"].Float(); | ||||
| 	cre->troopCountLocationOffset = graphics["troopCountLocationOffset"].Float(); | ||||
| 	cre->attackClimaxFrame = graphics["attackClimaxFrame"].Float(); | ||||
|  | ||||
| 	const JsonNode & animationTime = graphics["animationTime"]; | ||||
| 	cre->walkAnimationTime = animationTime["walk"].Float(); | ||||
| 	cre->attackAnimationTime = animationTime["attack"].Float(); | ||||
| 	cre->flightAnimationDistance = animationTime["flight"].Float(); //? | ||||
| 	//TODO: background? | ||||
| 	const JsonNode & missile = graphics["missile"]; | ||||
| 	//TODO: parse | ||||
| 	cre->projectile = missile["projectile"].String(); | ||||
| 	cre->projectileSpin = missile["spinning"].Bool(); | ||||
|  | ||||
| 	const JsonNode & offsets = missile["offset"]; | ||||
| 	cre->upperRightMissleOffsetX = offsets["upperX"].Float(); | ||||
| 	cre->upperRightMissleOffsetY = offsets["upperY"].Float(); | ||||
| 	cre->rightMissleOffsetX = offsets["middleX"].Float(); | ||||
| 	cre->rightMissleOffsetY = offsets["middleY"].Float(); | ||||
| 	cre->lowerRightMissleOffsetX = offsets["lowerX"].Float(); | ||||
| 	cre->lowerRightMissleOffsetY = offsets["lowerY"].Float(); | ||||
| 	int i = 0; | ||||
| 	BOOST_FOREACH (auto & angle, missile["frameAngles"].Vector()) | ||||
| 	{ | ||||
| 		cre->missleFrameAngles[i++] = angle.Float(); | ||||
| 	} | ||||
| 	cre->advMapDef = graphics["map"].String(); | ||||
| 	cre->iconIndex = graphics["iconIndex"].Float(); | ||||
|  | ||||
| 	const JsonNode & sounds = node["sound"]; | ||||
|  | ||||
| #define GET_SOUND_VALUE(value_name) do { cre->sounds.value_name = sounds[#value_name].String(); } while(0) | ||||
| 	GET_SOUND_VALUE(attack); | ||||
| 	GET_SOUND_VALUE(defend); | ||||
| 	GET_SOUND_VALUE(killed); | ||||
| 	GET_SOUND_VALUE(move); | ||||
| 	GET_SOUND_VALUE(shoot); | ||||
| 	GET_SOUND_VALUE(wince); | ||||
| 	GET_SOUND_VALUE(ext1); | ||||
| 	GET_SOUND_VALUE(ext2); | ||||
| 	GET_SOUND_VALUE(startMoving); | ||||
| 	GET_SOUND_VALUE(endMoving); | ||||
| #undef GET_SOUND_VALUE | ||||
|  | ||||
| 	return cre; | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser & parser) //help function for parsing CREXPBON.txt | ||||
| { | ||||
| 	bool enable = false; //some bonuses are activated with values 2 or 1 | ||||
| @@ -914,7 +1070,7 @@ static int retreiveRandNum(const boost::function<int()> &randGen) | ||||
|  | ||||
| template <typename T> const T & pickRandomElementOf(const std::vector<T> &v, const boost::function<int()> &randGen) | ||||
| { | ||||
| 	return v[retreiveRandNum(randGen) % v.size()]; | ||||
| 	return v.at(retreiveRandNum(randGen) % v.size()); | ||||
| } | ||||
|  | ||||
| int CCreatureHandler::pickRandomMonster(const boost::function<int()> &randGen, int tier) const | ||||
| @@ -936,7 +1092,6 @@ int CCreatureHandler::pickRandomMonster(const boost::function<int()> &randGen, i | ||||
| 			assert(b->getNodeType() == CBonusSystemNode::CREATURE); | ||||
| 			int creid = static_cast<const CCreature*>(b)->idNumber; | ||||
| 			if(!vstd::contains(notUsedMonsters, creid)) | ||||
|  | ||||
| 				allowed.push_back(creid); | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -140,27 +140,40 @@ public: | ||||
| 	si8 expAfterUpgrade;//multiplier in % | ||||
|  | ||||
| 	//Commanders | ||||
| 	std::map <ui8, ui32> factionCommanders; | ||||
| 	std::map <TFaction, TCreature> factionCommanders; | ||||
| 	BonusList commanderLevelPremy; //bonus values added with each level-up | ||||
| 	std::vector< std::vector <ui8> > skillLevels; //how much of a bonus will be given to commander with every level. SPELL_POWER also gives CASTS and RESISTANCE | ||||
| 	std::vector <std::pair <Bonus, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it | ||||
|  | ||||
| 	void deserializationFix(); | ||||
| 	void loadCreatures(); | ||||
| 	void buildBonusTreeForTiers(); | ||||
| 	void loadAnimationInfo(); | ||||
| 	void loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser &parser); | ||||
| 	void loadSoundsInfo(); | ||||
| 	void loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser &parser); | ||||
| 	int stringToNumber(std::string & s);//help function for parsing CREXPBON.txt | ||||
| 	/// loading functions | ||||
|  | ||||
| 	int pickRandomMonster(const boost::function<int()> &randGen = 0, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any | ||||
| 	void addBonusForTier(int tier, Bonus *b); //tier must be <1-7> | ||||
| 	void addBonusForAllCreatures(Bonus *b); | ||||
| 	/// load all creatures from H3 files | ||||
| 	void loadCreatures(); | ||||
| 	/// load all creatures from json structure | ||||
| 	void load(const JsonNode & node); | ||||
| 	/// load one creature from json config | ||||
| 	CCreature * loadCreature(const JsonNode & node); | ||||
| 	/// generates tier-specific bonus tree entries | ||||
| 	void buildBonusTreeForTiers(); | ||||
| 	/// read cranim.txt file from H3 | ||||
| 	void loadAnimationInfo(); | ||||
| 	/// read one line from cranim.txt | ||||
| 	void loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser &parser); | ||||
| 	/// load cr_sounds.json config | ||||
| 	void loadSoundsInfo(); | ||||
| 	/// parse crexpbon.txt file from H3 | ||||
| 	void loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser &parser); | ||||
| 	/// help function for parsing CREXPBON.txt | ||||
| 	int stringToNumber(std::string & s); | ||||
|  | ||||
| 	CCreatureHandler(); | ||||
| 	~CCreatureHandler(); | ||||
|  | ||||
| 	void deserializationFix(); | ||||
| 	int pickRandomMonster(const boost::function<int()> &randGen = 0, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any | ||||
| 	void addBonusForTier(int tier, Bonus *b); //tier must be <1-7> | ||||
| 	void addBonusForAllCreatures(Bonus *b); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		//TODO: should be optimized, not all these informations needs to be serialized (same for ccreature) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| #pragma once | ||||
|  | ||||
|  | ||||
| #include "GameConstants.h" | ||||
| #include "../lib/ConstTransitivePtr.h" | ||||
|  | ||||
| /* | ||||
| @@ -50,11 +50,14 @@ class DLL_LINKAGE CDefObjInfoHandler | ||||
| public: | ||||
| 	bmap<int, bmap<int, ConstTransitivePtr<CGDefInfo> > > gobjs; | ||||
|  | ||||
| 	bmap<TFaction, ConstTransitivePtr<CGDefInfo> > capitols; | ||||
| 	bmap<TFaction, ConstTransitivePtr<CGDefInfo> > villages; | ||||
|  | ||||
| 	void load(); | ||||
| 	~CDefObjInfoHandler(); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & gobjs; | ||||
| 		h & gobjs & capitols & villages; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -660,11 +660,11 @@ void CGameState::randomizeObject(CGObjectInstance *cur) | ||||
| 			CGTownInstance *t = dynamic_cast<CGTownInstance*>(cur); | ||||
| 			t->town = &VLC->townh->towns[t->subID]; | ||||
| 			if(t->hasCapitol()) | ||||
| 				t->defInfo = capitols[t->subID]; | ||||
| 				t->defInfo = VLC->dobjinfo->capitols[t->subID]; | ||||
| 			else if(t->hasFort()) | ||||
| 				t->defInfo = forts[t->subID]; | ||||
| 				t->defInfo = VLC->dobjinfo->gobjs[Obj::TOWN][t->subID]; | ||||
| 			else | ||||
| 				t->defInfo = villages[t->subID]; | ||||
| 				t->defInfo = VLC->dobjinfo->villages[t->subID]; | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| @@ -685,13 +685,14 @@ void CGameState::randomizeObject(CGObjectInstance *cur) | ||||
| 		if(!t) {tlog2<<"Wrong random town at "<<cur->pos<<std::endl; return;} | ||||
| 		cur->ID = ran.first; | ||||
| 		cur->subID = ran.second; | ||||
| 		t->town = &VLC->townh->towns[ran.second]; | ||||
| 		//FIXME: copy-pasted from above | ||||
| 		t->town = &VLC->townh->towns[t->subID]; | ||||
| 		if(t->hasCapitol()) | ||||
| 			t->defInfo = capitols[t->subID]; | ||||
| 			t->defInfo = VLC->dobjinfo->capitols[t->subID]; | ||||
| 		else if(t->hasFort()) | ||||
| 			t->defInfo = forts[t->subID]; | ||||
| 			t->defInfo = VLC->dobjinfo->gobjs[Obj::TOWN][t->subID]; | ||||
| 		else | ||||
| 			t->defInfo = villages[t->subID]; | ||||
| 			t->defInfo = VLC->dobjinfo->villages[t->subID]; | ||||
| 		t->randomizeArmy(t->subID); | ||||
| 		map->towns.push_back(t); | ||||
| 		return; | ||||
| @@ -700,7 +701,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur) | ||||
| 	cur->ID = ran.first; | ||||
| 	cur->subID = ran.second; | ||||
| 	map->removeBlockVisTiles(cur); //recalculate blockvis tiles - picked object might have different than random placeholder | ||||
|     map->customDefs.push_back(cur->defInfo = VLC->dobjinfo->gobjs[ran.first][ran.second]); | ||||
| 	map->customDefs.push_back(cur->defInfo = VLC->dobjinfo->gobjs[ran.first][ran.second]); | ||||
| 	if(!cur->defInfo) | ||||
| 	{ | ||||
| 		tlog1<<"*BIG* WARNING: Missing def declaration for "<<cur->ID<<" "<<cur->subID<<std::endl; | ||||
| @@ -761,10 +762,6 @@ CGameState::~CGameState() | ||||
| 	//delete initialOpts; | ||||
| 	delete applierGs; | ||||
| 	delete objCaller; | ||||
|  | ||||
| 	//TODO: delete properly that definfos | ||||
| 	villages.clear(); | ||||
| 	capitols.clear(); | ||||
| } | ||||
|  | ||||
| BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town) | ||||
| @@ -866,18 +863,18 @@ void CGameState::init(StartInfo * si) | ||||
| 	switch(scenarioOps->mode) | ||||
| 	{ | ||||
| 	case StartInfo::NEW_GAME: | ||||
|         tlog0 << "Open map file: " << scenarioOps->mapname << std::endl; | ||||
|         map = CMapService::loadMap(scenarioOps->mapname).release(); | ||||
| 		tlog0 << "Open map file: " << scenarioOps->mapname << std::endl; | ||||
| 		map = CMapService::loadMap(scenarioOps->mapname).release(); | ||||
| 		break; | ||||
| 	case StartInfo::CAMPAIGN: | ||||
| 		{ | ||||
|             tlog0 << "Open campaign map file: " << scenarioOps->campState->currentMap << std::endl; | ||||
| 			tlog0 << "Open campaign map file: " << scenarioOps->campState->currentMap << std::endl; | ||||
| 			auto campaign = scenarioOps->campState; | ||||
| 			assert(vstd::contains(campaign->camp->mapPieces, scenarioOps->campState->currentMap)); | ||||
|  | ||||
|             std::string & mapContent = campaign->camp->mapPieces[scenarioOps->campState->currentMap]; | ||||
|             auto buffer = reinterpret_cast<const ui8 *>(mapContent.data()); | ||||
|             map = CMapService::loadMap(buffer, mapContent.size()).release(); | ||||
| 			std::string & mapContent = campaign->camp->mapPieces[scenarioOps->campState->currentMap]; | ||||
| 			auto buffer = reinterpret_cast<const ui8 *>(mapContent.data()); | ||||
| 			map = CMapService::loadMap(buffer, mapContent.size()).release(); | ||||
| 		} | ||||
| 		break; | ||||
| 	case StartInfo::DUEL: | ||||
| @@ -906,7 +903,6 @@ void CGameState::init(StartInfo * si) | ||||
| 		scenarioOps->mapfileChecksum = map->checksum; | ||||
|  | ||||
| 	day = 0; | ||||
| 	loadTownDInfos(); | ||||
|  | ||||
| 	tlog4 << "Initialization:"; | ||||
| 	tlog4 << "\tPicking grail position"; | ||||
| @@ -920,14 +916,14 @@ void CGameState::init(StartInfo * si) | ||||
|  		std::vector<int3> allowedPos; | ||||
|  | ||||
| 		// add all not blocked tiles in range | ||||
|  		for (int i = 0; i < map->width ; i++) | ||||
|  		{ | ||||
|  			for (int j = 0; j < map->height ; j++) | ||||
|  			{ | ||||
|  				for (int k = 0; k <= map->twoLevel ; k++) | ||||
|  				{ | ||||
|  					const TerrainTile &t = map->terrain[i][j][k]; | ||||
|  					if(!t.blocked | ||||
| 		for (int i = 0; i < map->width ; i++) | ||||
| 		{ | ||||
| 			for (int j = 0; j < map->height ; j++) | ||||
| 			{ | ||||
| 				for (int k = 0; k <= map->twoLevel ; k++) | ||||
| 				{ | ||||
| 					const TerrainTile &t = map->terrain[i][j][k]; | ||||
| 					if(!t.blocked | ||||
| 						&& !t.visitable | ||||
|                         && t.terType != ETerrainType::WATER | ||||
|                         && t.terType != ETerrainType::ROCK | ||||
| @@ -946,7 +942,7 @@ void CGameState::init(StartInfo * si) | ||||
| 			map->grailPos = allowedPos[ran() % allowedPos.size()]; | ||||
| 		else | ||||
| 			tlog2 << "Warning: Grail cannot be placed, no appropriate tile found!\n"; | ||||
|  	} | ||||
| 	} | ||||
|  | ||||
| 	//picking random factions for players | ||||
| 	tlog4 << "\tPicking random factions for players"; | ||||
| @@ -1771,38 +1767,6 @@ int CGameState::getPlayerRelations( ui8 color1, ui8 color2 ) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void CGameState::loadTownDInfos() | ||||
| { | ||||
| 	assert(!VLC->dobjinfo->gobjs[Obj::TOWN].empty()); //make sure that at least some def info was found | ||||
|  | ||||
| 	const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::TOWN].begin()->second; | ||||
| 	auto & townInfos = VLC->dobjinfo->gobjs[Obj::TOWN]; | ||||
|  | ||||
|  | ||||
| 	BOOST_FOREACH(auto & town, VLC->townh->towns) | ||||
| 	{ | ||||
| 		if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::TOWN], town.first)) // no obj info for this town type | ||||
| 		{ | ||||
| 			CGDefInfo * info = new CGDefInfo(*baseInfo); | ||||
| 			info->subid = town.first; | ||||
|  | ||||
| 			townInfos[town.first] = info; | ||||
| 		} | ||||
| 		forts[town.first] = townInfos[town.first]; | ||||
| 		townInfos[town.first]->name = town.second.clientInfo.advMapCastle; | ||||
|  | ||||
| 		villages[town.first] = new CGDefInfo(*townInfos[town.first]); | ||||
| 		villages[town.first]->name = town.second.clientInfo.advMapVillage; | ||||
|  | ||||
| 		capitols[town.first] = new CGDefInfo(*townInfos[town.first]); | ||||
| 		capitols[town.first]->name = town.second.clientInfo.advMapCapitol; | ||||
|  | ||||
|         map->customDefs.push_back(villages[town.first]); | ||||
|         map->customDefs.push_back(forts[town.first]); | ||||
|         map->customDefs.push_back(capitols[town.first]); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGameState::getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing) | ||||
| { | ||||
| 	static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0), | ||||
|   | ||||
| @@ -40,7 +40,6 @@ class CGHeroInstance; | ||||
| class CGTownInstance; | ||||
| class CArmedInstance; | ||||
| class CGDwelling; | ||||
| class CGDefInfo; | ||||
| class CObjectScript; | ||||
| class CGObjectInstance; | ||||
| class CCreature; | ||||
| @@ -389,7 +388,6 @@ public: | ||||
| 	ConstTransitivePtr<CMap> map; | ||||
| 	bmap<TPlayerColor, PlayerState> players; | ||||
| 	bmap<TPlayerColor, TeamState> teams; | ||||
| 	bmap<TPlayerColor, ConstTransitivePtr<CGDefInfo> > villages, forts, capitols; //def-info for town graphics | ||||
| 	CBonusSystemNode globalEffects; | ||||
| 	bmap<const CGHeroInstance*, const CGObjectInstance*> ongoingVisits; | ||||
|  | ||||
| @@ -411,7 +409,6 @@ public: | ||||
| 	void init(StartInfo * si); | ||||
|  | ||||
| 	void initDuel(); | ||||
| 	void loadTownDInfos(); | ||||
| 	void randomizeObject(CGObjectInstance *cur); | ||||
| 	std::pair<int,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype> | ||||
| 	int pickHero(int owner); | ||||
| @@ -450,11 +447,6 @@ public: | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects; | ||||
| 		h & villages & forts & capitols; | ||||
| 		if(!h.saving) | ||||
| 		{ | ||||
| 			loadTownDInfos(); | ||||
| 		} | ||||
| 		BONUS_TREE_DESERIALIZATION_FIX | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -30,26 +30,14 @@ CModHandler::CModHandler() | ||||
| 	VLC->modh = this; | ||||
|  | ||||
| 	loadConfigFromFile ("defaultMods"); | ||||
| 	findAvailableMods(); | ||||
| 	//CResourceHandler::loadModsFilesystems(); //scan for all mods | ||||
| 	//TODO: mod filesystem is already initialized at LibClasses launch | ||||
| 	//TODO: load default (last?) config | ||||
| } | ||||
| artID CModHandler::addNewArtifact (CArtifact * art) | ||||
| { | ||||
| 	int id = artifacts.size(); | ||||
| 	artifacts.push_back (art); | ||||
| 	return id; | ||||
| } | ||||
| creID CModHandler::addNewCreature (CCreature * cre) | ||||
| { | ||||
| 	int id = creatures.size(); | ||||
| 	creatures.push_back (cre); | ||||
| 	return id; | ||||
| } | ||||
|  | ||||
| void CModHandler::loadConfigFromFile (std::string name) | ||||
| { | ||||
|  | ||||
| 	const JsonNode config(ResourceID("config/" + name + ".json")); | ||||
| 	const JsonNode & hardcodedFeatures = config["hardcodedFeatures"]; | ||||
|  | ||||
| @@ -67,28 +55,6 @@ void CModHandler::loadConfigFromFile (std::string name) | ||||
| 	modules.MITHRIL = gameModules["MITHRIL"].Bool(); | ||||
|  | ||||
| 	//TODO: load only mods from the list | ||||
|  | ||||
| 	//TODO: read mods from Mods/ folder | ||||
|  | ||||
| 	auto & configList = CResourceHandler::get()->getResourcesWithName (ResourceID("CONFIG/mod.json")); | ||||
|  | ||||
| 	BOOST_FOREACH(auto & entry, configList) | ||||
| 	{ | ||||
| 		auto stream = entry.getLoader()->load (entry.getResourceName()); | ||||
| 		std::unique_ptr<ui8[]> textData (new ui8[stream->getSize()]); | ||||
| 		stream->read (textData.get(), stream->getSize()); | ||||
|  | ||||
| 		tlog3 << "\t\tFound mod file: " << entry.getResourceName() << "\n"; | ||||
| 		const JsonNode config ((char*)textData.get(), stream->getSize()); | ||||
|  | ||||
| 		VLC->townh->loadFactions(config["factions"]); | ||||
|  | ||||
| 		const JsonNode *value = &config["creatures"]; | ||||
| 		BOOST_FOREACH (auto creature, value->Vector()) | ||||
| 		{ | ||||
| 			loadCreature (creature);//create and push back creature | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CModHandler::saveConfigToFile (std::string name) | ||||
| @@ -105,229 +71,80 @@ void CModHandler::saveConfigToFile (std::string name) | ||||
| 	//file << savedConf; | ||||
| } | ||||
|  | ||||
| CCreature * CModHandler::loadCreature (const JsonNode &node) | ||||
|  | ||||
| void CModHandler::findAvailableMods() | ||||
| { | ||||
| 	CCreature * cre = new CCreature(); | ||||
| 	const JsonNode *value; //optional value | ||||
| 	//TODO: read mods from Mods/ folder | ||||
|  | ||||
| 	//TODO: ref name? | ||||
| 	const JsonNode & name = node["name"]; | ||||
| 	cre->nameSing = name["singular"].String(); | ||||
| 	cre->namePl = name["plural"].String(); | ||||
| 	value = &name["reference"]; | ||||
| 	if (!value->isNull()) | ||||
| 		cre->nameRef = value->String(); | ||||
| 	else | ||||
| 		cre->nameRef = cre->nameSing; | ||||
| 	auto & configList = CResourceHandler::get()->getResourcesWithName (ResourceID("CONFIG/mod.json")); | ||||
|  | ||||
| 	cre->cost = Res::ResourceSet(node["cost"]); | ||||
|  | ||||
| 	cre->level = node["level"].Float(); | ||||
| 	cre->faction = 9; //neutral faction is 9 for now. Will be replaced by string -> id conversion | ||||
| 	//TODO: node["faction"].String() to id | ||||
| 	cre->fightValue = node["fightValue"].Float(); | ||||
| 	cre->AIValue = node["aiValue"].Float(); | ||||
| 	cre->growth = node["growth"].Float(); | ||||
| 	cre->hordeGrowth = node["horde"].Float(); // Needed at least until configurable buildings | ||||
|  | ||||
| 	cre->addBonus(node["hitPoints"].Float(), Bonus::STACK_HEALTH); | ||||
| 	cre->addBonus(node["speed"].Float(), Bonus::STACKS_SPEED); | ||||
| 	cre->addBonus(node["attack"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK); | ||||
| 	cre->addBonus(node["defense"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE); | ||||
| 	const JsonNode &  vec = node["damage"]; | ||||
| 	cre->addBonus(vec["min"].Float(), Bonus::CREATURE_DAMAGE, 1); | ||||
| 	cre->addBonus(vec["max"].Float(), Bonus::CREATURE_DAMAGE, 2); | ||||
|  | ||||
| 	auto & amounts = node ["advMapAmount"]; | ||||
| 	cre->ammMin = amounts["min"].Float(); | ||||
| 	cre->ammMax = amounts["max"].Float(); | ||||
|  | ||||
| 	//optional | ||||
| 	BOOST_FOREACH (auto & str, node["upgrades"].Vector()) | ||||
| 	BOOST_FOREACH(auto & entry, configList) | ||||
| 	{ | ||||
| 		cre->upgradeNames.insert (str.String()); | ||||
| 	} | ||||
| 		auto stream = entry.getLoader()->load (entry.getResourceName()); | ||||
| 		std::unique_ptr<ui8[]> textData (new ui8[stream->getSize()]); | ||||
| 		stream->read (textData.get(), stream->getSize()); | ||||
|  | ||||
| 	value = &node["shots"]; | ||||
| 	if (!value->isNull()) | ||||
| 		cre->addBonus(value->Float(), Bonus::SHOTS); | ||||
|  | ||||
| 	value = &node["spellPoints"]; | ||||
| 	if (!value->isNull()) | ||||
| 		cre->addBonus(value->Float(), Bonus::CASTS); | ||||
|  | ||||
| 	cre->doubleWide = node["doubleWide"].Bool(); | ||||
|  | ||||
| 	BOOST_FOREACH (const JsonNode &bonus, node["abilities"].Vector()) | ||||
| 	{ | ||||
| 		auto b = ParseBonus(bonus); | ||||
| 		b->source = Bonus::CREATURE_ABILITY; | ||||
| 		b->duration = Bonus::PERMANENT; | ||||
| 		cre->addNewBonus(b); | ||||
| 	} | ||||
| 	BOOST_FOREACH (const JsonNode &exp, node["stackExperience"].Vector()) | ||||
| 	{ | ||||
| 		auto bonus = ParseBonus (exp["bonus"]); | ||||
| 		bonus->source = Bonus::STACK_EXPERIENCE; | ||||
| 		bonus->duration = Bonus::PERMANENT; | ||||
| 		const JsonVector &values = exp["values"].Vector(); | ||||
| 		int lowerLimit = 1;//, upperLimit = 255; | ||||
| 		if (values[0].getType() == JsonNode::JsonType::DATA_BOOL) | ||||
| 		{ | ||||
| 			BOOST_FOREACH (const JsonNode &val, values) | ||||
| 			{ | ||||
| 				if (val.Bool() == true) | ||||
| 				{ | ||||
| 					bonus->limiter = make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit)); | ||||
| 					cre->addNewBonus (new Bonus(*bonus)); //bonuses must be unique objects | ||||
| 					break; //TODO: allow bonuses to turn off? | ||||
| 				} | ||||
| 				++lowerLimit; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			int lastVal = 0; | ||||
| 			BOOST_FOREACH (const JsonNode &val, values) | ||||
| 			{ | ||||
| 				if (val.Float() != lastVal) | ||||
| 				{ | ||||
| 					bonus->val = val.Float() - lastVal; | ||||
| 					bonus->limiter.reset (new RankRangeLimiter(lowerLimit)); | ||||
| 					cre->addNewBonus (new Bonus(*bonus)); | ||||
| 				} | ||||
| 				lastVal = val.Float(); | ||||
| 				++lowerLimit; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	//graphics | ||||
|  | ||||
| 	const JsonNode & graphics = node["graphics"]; | ||||
| 	cre->animDefName = graphics["animation"].String(); | ||||
| 	cre->timeBetweenFidgets = graphics["timeBetweenFidgets"].Float(); | ||||
| 	cre->troopCountLocationOffset = graphics["troopCountLocationOffset"].Float(); | ||||
| 	cre->attackClimaxFrame = graphics["attackClimaxFrame"].Float(); | ||||
|  | ||||
| 	const JsonNode & animationTime = graphics["animationTime"]; | ||||
| 	cre->walkAnimationTime = animationTime["walk"].Float(); | ||||
| 	cre->attackAnimationTime = animationTime["attack"].Float(); | ||||
| 	cre->flightAnimationDistance = animationTime["flight"].Float(); //? | ||||
| 	//TODO: background? | ||||
| 	const JsonNode & missile = graphics["missile"]; | ||||
| 	//TODO: parse | ||||
| 	value = &missile["projectile"]; | ||||
| 	if (value->isNull()) | ||||
| 		cre->projectile = "PLCBOWX.DEF"; | ||||
| 	else | ||||
| 		cre->projectile = value->String(); | ||||
|  | ||||
| 	value = &missile["spinning"]; | ||||
| 	if (value->isNull()) | ||||
| 		cre->projectileSpin = false; //no animation by default to avoid crash | ||||
| 	else | ||||
| 		cre->projectileSpin = value->Bool(); | ||||
|  | ||||
| 	const JsonNode & offsets = missile["offset"]; | ||||
| 	cre->upperRightMissleOffsetX = offsets["upperX"].Float(); | ||||
| 	cre->upperRightMissleOffsetY = offsets["upperY"].Float(); | ||||
| 	cre->rightMissleOffsetX = offsets["middleX"].Float(); | ||||
| 	cre->rightMissleOffsetY = offsets["middleY"].Float(); | ||||
| 	cre->lowerRightMissleOffsetX = offsets["lowerX"].Float(); | ||||
| 	cre->lowerRightMissleOffsetY = offsets["lowerY"].Float(); | ||||
| 	int i = 0; | ||||
| 	BOOST_FOREACH (auto & angle, missile["frameAngles"].Vector()) | ||||
| 	{ | ||||
| 		cre->missleFrameAngles[i++] = angle.Float(); | ||||
| 	} | ||||
| 	cre->advMapDef = graphics["map"].String(); | ||||
| 	cre->iconIndex = graphics["iconIndex"].Float(); | ||||
|  | ||||
| 	const JsonNode & sounds = node["sound"]; | ||||
|  | ||||
| #define GET_SOUND_VALUE(value_name) do { cre->sounds.value_name = sounds[#value_name].String(); } while(0) | ||||
| 	GET_SOUND_VALUE(attack); | ||||
| 	GET_SOUND_VALUE(defend); | ||||
| 	GET_SOUND_VALUE(killed); | ||||
| 	GET_SOUND_VALUE(move); | ||||
| 	GET_SOUND_VALUE(shoot); | ||||
| 	GET_SOUND_VALUE(wince); | ||||
| 	GET_SOUND_VALUE(ext1); | ||||
| 	GET_SOUND_VALUE(ext2); | ||||
| 	GET_SOUND_VALUE(startMoving); | ||||
| 	GET_SOUND_VALUE(endMoving); | ||||
| #undef GET_SOUND_VALUE | ||||
|  | ||||
| 	creatures.push_back(cre); | ||||
|  | ||||
| 	tlog3 << "Added new creature " << cre->nameRef << "\n"; | ||||
|  | ||||
| 	return cre; | ||||
| } | ||||
| void CModHandler::recreateAdvMapDefs() | ||||
| { | ||||
| 	BOOST_FOREACH (auto creature, creatures) | ||||
| 	{ | ||||
| 		//generate adventure map object info & graphics | ||||
| 		CGDefInfo* nobj = new CGDefInfo (*VLC->dobjinfo->gobjs[Obj::MONSTER][0]);//copy all typical properties | ||||
| 		nobj->name = creature->advMapDef; //change only def name (?) | ||||
| 		VLC->dobjinfo->gobjs[Obj::MONSTER][creature->idNumber] = nobj; | ||||
| 		tlog3 << "\t\tFound mod file: " << entry.getResourceName() << "\n"; | ||||
| 		allMods[allMods.size()].config.reset(new JsonNode((char*)textData.get(), stream->getSize())); | ||||
| 	} | ||||
| } | ||||
| void CModHandler::recreateHandlers() | ||||
|  | ||||
| void CModHandler::loadActiveMods() | ||||
| { | ||||
| 	//TODO: consider some template magic to unify all handlers? | ||||
|  | ||||
| 	//VLC->arth->artifacts.clear(); | ||||
| 	//VLC->creh->creatures.clear(); //TODO: what about items from original game? | ||||
|  | ||||
| 	BOOST_FOREACH (auto creature, creatures) | ||||
| 	BOOST_FOREACH(auto & mod, allMods) | ||||
| 	{ | ||||
| 		creature->idNumber = VLC->creh->creatures.size(); //calculate next index for every used creature | ||||
| 		BOOST_FOREACH (auto bonus, creature->getBonusList()) | ||||
| 		{ | ||||
| 			bonus->sid = creature->idNumber; | ||||
| 		} | ||||
| 		VLC->creh->creatures.push_back (creature); | ||||
| 		//TODO: use refName? | ||||
| 		//if (creature->nameRef.size()) | ||||
| 		//	VLC->creh->nameToID[creature->nameRef] = creature->idNumber; | ||||
| 		VLC->creh->nameToID[creature->nameSing] = creature->idNumber; | ||||
| 		const JsonNode & config = *mod.second.config; | ||||
|  | ||||
| 		VLC->townh->load(config["factions"]); | ||||
| 		VLC->creh->load(config["creatures"]); | ||||
| 	} | ||||
| 	recreateAdvMapDefs(); | ||||
| 	BOOST_FOREACH (auto creature, VLC->creh->creatures) //populate upgrades described with string | ||||
| 	{ | ||||
| 		BOOST_FOREACH (auto upgradeName, creature->upgradeNames) | ||||
| 		{ | ||||
| 			auto it = VLC->creh->nameToID.find(upgradeName); | ||||
| 			if (it != VLC->creh->nameToID.end()) | ||||
| 			{ | ||||
| 				creature->upgrades.insert (it->second); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded | ||||
| } | ||||
|  | ||||
| 	BOOST_FOREACH (auto mod, activeMods) //inactive part | ||||
| void CModHandler::reload() | ||||
| { | ||||
| 	{ | ||||
| 		BOOST_FOREACH (auto art, allMods[mod].artifacts) | ||||
| 		{ | ||||
| 			VLC->arth->artifacts.push_back (artifacts[art]); | ||||
| 		assert(!VLC->dobjinfo->gobjs[Obj::MONSTER].empty()); //make sure that at least some def info was found | ||||
|  | ||||
| 			//TODO: recreate types / limiters based on string id | ||||
| 		const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::MONSTER].begin()->second; | ||||
|  | ||||
| 		BOOST_FOREACH(auto & crea, VLC->creh->creatures) | ||||
| 		{ | ||||
| 			if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::MONSTER], crea->idNumber)) // no obj info for this type | ||||
| 			{ | ||||
| 				CGDefInfo * info = new CGDefInfo(*baseInfo); | ||||
| 				info->subid = crea->idNumber; | ||||
| 				info->name = crea->advMapDef; | ||||
|  | ||||
| 				VLC->dobjinfo->gobjs[Obj::MONSTER][crea->idNumber] = info; | ||||
| 			} | ||||
| 		} | ||||
| 		BOOST_FOREACH (auto creature, allMods[mod].creatures) | ||||
| 		{ | ||||
| 			VLC->creh->creatures.push_back (creatures[creature]); | ||||
| 			//TODO VLC->creh->notUsedMonster.push_back (creatures[creature]); | ||||
| 	} | ||||
|  | ||||
| 			//TODO: recreate upgrades and other properties based on string id | ||||
| 	{ | ||||
| 		assert(!VLC->dobjinfo->gobjs[Obj::TOWN].empty()); //make sure that at least some def info was found | ||||
|  | ||||
| 		const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::TOWN].begin()->second; | ||||
| 		auto & townInfos = VLC->dobjinfo->gobjs[Obj::TOWN]; | ||||
|  | ||||
| 		BOOST_FOREACH(auto & town, VLC->townh->towns) | ||||
| 		{ | ||||
| 			auto & cientInfo = town.second.clientInfo; | ||||
|  | ||||
| 			if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::TOWN], town.first)) // no obj info for this type | ||||
| 			{ | ||||
| 				CGDefInfo * info = new CGDefInfo(*baseInfo); | ||||
| 				info->subid = town.first; | ||||
|  | ||||
| 				townInfos[town.first] = info; | ||||
| 			} | ||||
| 			townInfos[town.first]->name = cientInfo.advMapCastle; | ||||
|  | ||||
| 			VLC->dobjinfo->villages[town.first] = new CGDefInfo(*townInfos[town.first]); | ||||
| 			VLC->dobjinfo->villages[town.first]->name = cientInfo.advMapVillage; | ||||
|  | ||||
| 			VLC->dobjinfo->capitols[town.first] = new CGDefInfo(*townInfos[town.first]); | ||||
| 			VLC->dobjinfo->capitols[town.first]->name = cientInfo.advMapCapitol; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CModHandler::~CModHandler() | ||||
| { | ||||
| } | ||||
|   | ||||
| @@ -20,65 +20,46 @@ | ||||
| class CModHandler; | ||||
| class CModIndentifier; | ||||
| class CModInfo; | ||||
| class JsonNode; | ||||
|  | ||||
| typedef si32 artID; | ||||
| typedef si32 creID; | ||||
|  | ||||
| class DLL_LINKAGE CModIdentifier | ||||
| { | ||||
| 	//TODO? are simple integer identifiers enough? | ||||
| 	int id; | ||||
| public: | ||||
| 	// int operator ()() {return 0;}; | ||||
| 	bool operator < (CModIdentifier rhs) const {return true;}; //for map | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & id; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| typedef si32 TModID; | ||||
|  | ||||
| class DLL_LINKAGE CModInfo | ||||
| { | ||||
| public: | ||||
| 	std::vector <CModIdentifier> requirements; | ||||
| 	std::vector <ResourceID> usedFiles; | ||||
| 	//TODO: config options? | ||||
| 	/// TODO: list of mods that should be loaded before this one | ||||
| 	std::vector <TModID> requirements; | ||||
|  | ||||
| 	//items added by this mod | ||||
| 	std::vector <artID> artifacts; | ||||
| 	std::vector <creID> creatures; | ||||
|  | ||||
| 	//TODO: some additional scripts? | ||||
| 	/// mod configuration (mod.json). | ||||
| 	std::unique_ptr<JsonNode> config; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & requirements & artifacts & creatures; | ||||
| 		//h & usedFiles; //TODO: make seralizable? | ||||
| 		h & requirements & config; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CModHandler | ||||
| { | ||||
| public: | ||||
| 	std::string currentConfig; //save settings in this file | ||||
| 	//list of all possible objects in game, including inactive mods or not allowed | ||||
| 	std::vector <ConstTransitivePtr<CCreature> > creatures; | ||||
| 	std::vector <ConstTransitivePtr<CArtifact> > artifacts; | ||||
| 	//std::string currentConfig; //save settings in this file | ||||
|  | ||||
| 	std::map <CModIdentifier, CModInfo> allMods; | ||||
| 	std::set <CModIdentifier> activeMods; | ||||
| 	std::map <TModID, CModInfo> allMods; | ||||
| 	std::set <TModID> activeMods;//TODO: use me | ||||
|  | ||||
| 	//create unique object indentifier | ||||
| 	artID addNewArtifact (CArtifact * art); | ||||
| 	creID addNewCreature (CCreature * cre); | ||||
|  | ||||
| 	void loadConfigFromFile (std::string name); | ||||
| 	/// management of game settings config | ||||
| 	void loadConfigFromFile (std::string name);	 | ||||
| 	void saveConfigToFile (std::string name); | ||||
| 	CCreature * loadCreature (const JsonNode &node); | ||||
| 	void recreateAdvMapDefs(); | ||||
| 	void recreateHandlers(); | ||||
|  | ||||
| 	/// find all available mods and load them into FS | ||||
| 	void findAvailableMods(); | ||||
|  | ||||
| 	/// load content from all available mods | ||||
| 	void loadActiveMods(); | ||||
|  | ||||
| 	/// actions that should be triggered on map restart | ||||
| 	/// TODO: merge into appropriate handlers? | ||||
| 	void reload(); | ||||
|  | ||||
| 	struct DLL_LINKAGE hardcodedFeatures | ||||
| 	{ | ||||
| @@ -110,12 +91,9 @@ public: | ||||
| 	} modules; | ||||
|  | ||||
| 	CModHandler(); | ||||
| 	~CModHandler(); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & currentConfig; | ||||
| 		h & creatures & artifacts; | ||||
| 		h & allMods & activeMods & settings & modules; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -442,7 +442,7 @@ void CTownHandler::loadPuzzle(CFaction &faction, const JsonNode &source) | ||||
| 	assert(faction.puzzleMap.size() == GameConstants::PUZZLE_MAP_PIECES); | ||||
| } | ||||
|  | ||||
| void CTownHandler::loadFactions(const JsonNode &source) | ||||
| void CTownHandler::load(const JsonNode &source) | ||||
| { | ||||
| 	BOOST_FOREACH(auto & node, source.Struct()) | ||||
| 	{ | ||||
| @@ -469,6 +469,8 @@ void CTownHandler::loadFactions(const JsonNode &source) | ||||
| 		} | ||||
| 		if (!node.second["puzzleMap"].isNull()) | ||||
| 			loadPuzzle(faction, node.second["puzzleMap"]); | ||||
|  | ||||
| 		tlog3 << "Added faction: " << node.first << "\n"; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -518,5 +520,5 @@ void CTownHandler::load() | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	loadFactions(buildingsConf); | ||||
| 	load(buildingsConf); | ||||
| } | ||||
|   | ||||
| @@ -209,12 +209,11 @@ public: | ||||
|  | ||||
| 	/// main loading function for mods, accepts merged JSON source and add all entries from it into game | ||||
| 	/// all entries in JSON should be checked for validness before using this function | ||||
| 	void loadFactions(const JsonNode & source); | ||||
| 	void load(const JsonNode & source); | ||||
|  | ||||
| 	/// "entry point" for loading of OH3 town. | ||||
| 	/// reads legacy txt's from H3 + vcmi json, merges them | ||||
| 	/// and loads resulting structure to game using loadTowns method | ||||
| 	/// in future may require loaded Creature Handler | ||||
| 	void load(); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
|   | ||||
| @@ -4,6 +4,8 @@ class JsonNode; | ||||
| typedef std::map <std::string, JsonNode> JsonMap; | ||||
| typedef std::vector <JsonNode> JsonVector; | ||||
|  | ||||
| DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const JsonNode &node); | ||||
|  | ||||
| struct Bonus; | ||||
| class ResourceID; | ||||
|  | ||||
| @@ -96,6 +98,23 @@ public: | ||||
| 	static void merge(JsonNode & dest, JsonNode & source); | ||||
| 	/// this function will preserve data stored in source by creating copy | ||||
| 	static void mergeCopy(JsonNode & dest, JsonNode source); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		if (h.saving) | ||||
| 		{ | ||||
| 			std::ostringstream stream; | ||||
| 			stream << *this; | ||||
| 			std::string str = stream.str(); | ||||
| 			h & str; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			std::string str; | ||||
| 			h & str; | ||||
| 			JsonNode(str.c_str(), str.size()).swap(*this); | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| template<> | ||||
| @@ -136,8 +155,6 @@ public: | ||||
| 	JsonWriter(std::ostream &output, const JsonNode &node); | ||||
| }; | ||||
|  | ||||
| DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const JsonNode &node); | ||||
|  | ||||
| //Tiny string class that uses const char* as data for speed, members are private | ||||
| //for ease of debugging and some compatibility with std::string | ||||
| class constString | ||||
|   | ||||
| @@ -86,7 +86,6 @@ void registerTypes1(Serializer &s) | ||||
| 	s.template registerType<StackOwnerLimiter>(); | ||||
|  | ||||
| 	s.template registerType<CModInfo>(); | ||||
| 	s.template registerType<CModIdentifier>(); | ||||
|  | ||||
| 	s.template registerType<CBonusSystemNode>(); | ||||
| 	s.template registerType<CArtifact>(); | ||||
|   | ||||
| @@ -101,7 +101,8 @@ void LibClasses::init() | ||||
| 	spellh->loadSpells(); | ||||
| 	tlog0<<"\tSpell handler: "<<pomtime.getDiff()<<std::endl; | ||||
|  | ||||
| 	modh->recreateHandlers(); //load all new creatures parsed in the meantime. | ||||
| 	modh->loadActiveMods(); | ||||
| 	modh->reload(); | ||||
| 	//FIXME: make sure that everything is ok after game restart | ||||
| 	//TODO: This should be done every time mod config changes | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user