mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Fixed Duel mode. Integrated some changes from programmingChallenge branch - it's possible to define duel parameters using JSON.
This commit is contained in:
		| @@ -480,7 +480,11 @@ void CBattleResultWindow::bExitf() | ||||
| { | ||||
| 	if(LOCPLINT->cb->getStartInfo()->mode == StartInfo::DUEL) | ||||
| 	{ | ||||
| 		std::exit(0); | ||||
| 		SDL_Event ev; | ||||
| 		ev.type = SDL_QUIT; | ||||
| 		ev.user.code = 0; | ||||
| 		SDL_PushEvent(&ev); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	CPlayerInterface * intTmp = owner->curInt; | ||||
|   | ||||
| @@ -393,9 +393,11 @@ void CClient::newGame( CConnection *con, StartInfo *si ) | ||||
|  | ||||
| 	if(si->mode == StartInfo::DUEL) | ||||
| 	{ | ||||
| 		boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim); | ||||
| 		CPlayerInterface *p = new CPlayerInterface(-1); | ||||
| 		p->observerInDuelMode = true; | ||||
| 		battleints[254] = playerint[254] = p; | ||||
| 		privilagedBattleEventReceivers.push_back(p); | ||||
| 		GH.curInt = p; | ||||
| 		p->init(new CCallback(gs, -1, this)); | ||||
| 		battleStarted(gs->curB); | ||||
|   | ||||
| @@ -848,56 +848,8 @@ void CGameState::init(StartInfo * si) | ||||
| 		} | ||||
| 		break; | ||||
| 	case StartInfo::DUEL: | ||||
| 		{ | ||||
| 			DuelParameters dp; | ||||
| 			try | ||||
| 			{ | ||||
| 				CLoadFile lf(scenarioOps->mapname); | ||||
| 				lf >> dp; | ||||
| 			} | ||||
| 			catch(...) | ||||
| 			{} | ||||
|  | ||||
|  | ||||
| 			const CArmedInstance *armies[2] = {0}; | ||||
| 			const CGHeroInstance *heroes[2] = {0}; | ||||
| 			CGTownInstance *town = NULL; | ||||
|  | ||||
| 			for(int i = 0; i < 2; i++) | ||||
| 			{ | ||||
| 				CArmedInstance *obj = NULL; | ||||
| 				if(dp.sides[i].heroId >= 0) | ||||
| 				{ | ||||
| 					CGHeroInstance *h = new CGHeroInstance(); | ||||
| 					armies[i] = heroes[i] = h; | ||||
| 					obj = h; | ||||
| 					h->subID = dp.sides[i].heroId; | ||||
| 					h->initHero(h->subID); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					CGCreature *c = new CGCreature(); | ||||
| 					armies[i] = obj = c; | ||||
| 					c->subID = 34; | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 				obj->initObj(); | ||||
| 				obj->setOwner(i); | ||||
|  | ||||
| 				for(int j = 0; j < ARRAY_COUNT(dp.sides[i].stacks); j++) | ||||
| 				{ | ||||
| 					int cre = dp.sides[i].stacks[j].type, count = dp.sides[i].stacks[j].count; | ||||
| 					if(count || obj->hasStackAtSlot(j)) | ||||
| 						obj->setCreature(j, cre, count); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			curB = BattleInfo::setupBattle(int3(), dp.bfieldType, dp.terType, armies, heroes, false, town); | ||||
| 			curB->localInit(); | ||||
| 			return; | ||||
| 		} | ||||
| 		break; | ||||
| 		initDuel(); | ||||
| 		return; | ||||
| 	default: | ||||
| 		tlog1 << "Wrong mode: " << (int)scenarioOps->mode << std::endl; | ||||
| 		return; | ||||
| @@ -1527,6 +1479,108 @@ void CGameState::init(StartInfo * si) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGameState::initDuel() | ||||
| { | ||||
| 	DuelParameters dp; | ||||
| 	try //CLoadFile likes throwing | ||||
| 	{ | ||||
| 		if(boost::algorithm::ends_with(scenarioOps->mapname, ".json")) | ||||
| 		{ | ||||
| 			tlog0 << "Loading duel settings from JSON file: " << scenarioOps->mapname << std::endl; | ||||
| 			dp = DuelParameters::fromJSON(scenarioOps->mapname); | ||||
| 			tlog0 << "JSON file has been successfully read!\n"; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			CLoadFile lf(scenarioOps->mapname); | ||||
| 			lf >> dp; | ||||
| 		} | ||||
| 	} | ||||
| 	catch(...) | ||||
| 	{ | ||||
| 		tlog1 << "Cannot load duel settings from " << scenarioOps->mapname << std::endl; | ||||
| 		throw; | ||||
| 	} | ||||
|  | ||||
| 	const CArmedInstance *armies[2] = {0}; | ||||
| 	const CGHeroInstance *heroes[2] = {0}; | ||||
| 	CGTownInstance *town = NULL; | ||||
|  | ||||
| 	for(int i = 0; i < 2; i++) | ||||
| 	{ | ||||
| 		CArmedInstance *obj = NULL; | ||||
| 		if(dp.sides[i].heroId >= 0) | ||||
| 		{ | ||||
| 			const DuelParameters::SideSettings &ss = dp.sides[i]; | ||||
| 			CGHeroInstance *h = new CGHeroInstance(); | ||||
| 			armies[i] = heroes[i] = h; | ||||
| 			obj = h; | ||||
| 			h->subID = ss.heroId; | ||||
| 			for(int i = 0; i < ss.heroPrimSkills.size(); i++) | ||||
| 				h->pushPrimSkill(i, ss.heroPrimSkills[i]); | ||||
|  | ||||
| 			if(ss.spells.size()) | ||||
| 			{ | ||||
| 				h->putArtifact(ArtifactPosition::SPELLBOOK, CArtifactInstance::createNewArtifactInstance(0)); | ||||
| 				boost::copy(ss.spells, std::inserter(h->spells, h->spells.begin())); | ||||
| 			} | ||||
|  | ||||
| 			BOOST_FOREACH(auto &parka, ss.artifacts) | ||||
| 			{ | ||||
| 				h->putArtifact(parka.first, parka.second); | ||||
| 			} | ||||
|  | ||||
| 			typedef const std::pair<si32, si8> &TSecSKill; | ||||
| 			BOOST_FOREACH(TSecSKill secSkill, ss.heroSecSkills) | ||||
| 				h->setSecSkillLevel((CGHeroInstance::SecondarySkill)secSkill.first, secSkill.second, 1); | ||||
|  | ||||
| 			h->initHero(h->subID); | ||||
| 			obj->initObj(); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			CGCreature *c = new CGCreature(); | ||||
| 			armies[i] = obj = c; | ||||
| 			//c->subID = 34; | ||||
| 		} | ||||
|  | ||||
| 		obj->setOwner(i); | ||||
|  | ||||
| 		for(int j = 0; j < ARRAY_COUNT(dp.sides[i].stacks); j++) | ||||
| 		{ | ||||
| 			TCreature cre = dp.sides[i].stacks[j].type; | ||||
| 			TQuantity count = dp.sides[i].stacks[j].count; | ||||
| 			if(count || obj->hasStackAtSlot(j)) | ||||
| 				obj->setCreature(j, cre, count); | ||||
| 		} | ||||
|  | ||||
| 		BOOST_FOREACH(const DuelParameters::CusomCreature &cc, dp.creatures) | ||||
| 		{ | ||||
| 			CCreature *c = VLC->creh->creatures[cc.id]; | ||||
| 			if(cc.attack >= 0) | ||||
| 				c->getBonus(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK))->val = cc.attack; | ||||
| 			if(cc.defense >= 0) | ||||
| 				c->getBonus(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE))->val = cc.defense; | ||||
| 			if(cc.speed >= 0) | ||||
| 				c->getBonus(Selector::type(Bonus::STACKS_SPEED))->val = cc.speed; | ||||
| 			if(cc.HP >= 0) | ||||
| 				c->getBonus(Selector::type(Bonus::STACK_HEALTH))->val = cc.HP; | ||||
| 			if(cc.dmg >= 0) | ||||
| 			{ | ||||
| 				c->getBonus(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 1))->val = cc.dmg; | ||||
| 				c->getBonus(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 2))->val = cc.dmg; | ||||
| 			} | ||||
| 			if(cc.shoots >= 0) | ||||
| 				c->getBonus(Selector::type(Bonus::SHOTS))->val = cc.shoots; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	curB = BattleInfo::setupBattle(int3(), dp.bfieldType, dp.terType, armies, heroes, false, town); | ||||
| 	curB->obstacles = dp.obstacles; | ||||
| 	curB->localInit(); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| int CGameState::battleGetBattlefieldType(int3 tile) const | ||||
| { | ||||
| 	if(tile==int3() && curB) | ||||
| @@ -2723,6 +2777,88 @@ DuelParameters::DuelParameters() | ||||
| 	bfieldType = 15; | ||||
| } | ||||
|  | ||||
| DuelParameters DuelParameters::fromJSON(const std::string &fname) | ||||
| { | ||||
| 	DuelParameters ret; | ||||
|  | ||||
| 	const JsonNode duelData(fname); | ||||
| 	ret.terType = duelData["terType"].Float(); | ||||
| 	ret.bfieldType = duelData["bfieldType"].Float(); | ||||
| 	BOOST_FOREACH(const JsonNode &n, duelData["sides"].Vector()) | ||||
| 	{ | ||||
| 		SideSettings &ss = ret.sides[(int)n["side"].Float()]; | ||||
| 		int i = 0; | ||||
| 		BOOST_FOREACH(const JsonNode &stackNode, n["army"].Vector()) | ||||
| 		{ | ||||
| 			ss.stacks[i].type = stackNode.Vector()[0].Float(); | ||||
| 			ss.stacks[i].count = stackNode.Vector()[1].Float(); | ||||
| 			i++; | ||||
| 		} | ||||
|  | ||||
| 		if(n["heroid"].getType() == JsonNode::DATA_FLOAT) | ||||
| 			ss.heroId = n["heroid"].Float(); | ||||
| 		else | ||||
| 			ss.heroId = -1; | ||||
|  | ||||
| 		BOOST_FOREACH(const JsonNode &n, n["heroPrimSkills"].Vector()) | ||||
| 			ss.heroPrimSkills.push_back(n.Float()); | ||||
|  | ||||
| 		BOOST_FOREACH(const JsonNode &skillNode, n["heroSecSkills"].Vector()) | ||||
| 		{ | ||||
| 			std::pair<si32, si8> secSkill; | ||||
| 			secSkill.first = skillNode.Vector()[0].Float(); | ||||
| 			secSkill.second = skillNode.Vector()[1].Float(); | ||||
| 			ss.heroSecSkills.push_back(secSkill); | ||||
| 		} | ||||
|  | ||||
| 		assert(ss.heroPrimSkills.empty() || ss.heroPrimSkills.size() == GameConstants::PRIMARY_SKILLS); | ||||
|  | ||||
| 		if(ss.heroId != -1) | ||||
| 			BOOST_FOREACH(const JsonNode &spell, n["spells"].Vector()) | ||||
| 				ss.spells.insert(spell.Float()); | ||||
| 	} | ||||
|  | ||||
| 	BOOST_FOREACH(const JsonNode &n, duelData["obstacles"].Vector()) | ||||
| 	{ | ||||
| 		auto oi = make_shared<CObstacleInstance>(); | ||||
| 		if(n.getType() == JsonNode::DATA_VECTOR) | ||||
| 		{ | ||||
| 			oi->ID = n.Vector()[0].Float(); | ||||
| 			oi->pos = n.Vector()[1].Float(); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			assert(n.getType() == JsonNode::DATA_FLOAT); | ||||
| 			oi->ID = 21; | ||||
| 			oi->pos = n.Float(); | ||||
| 		} | ||||
| 		oi->uniqueID = ret.obstacles.size(); | ||||
| 		ret.obstacles.push_back(oi); | ||||
| 	} | ||||
|  | ||||
| 	BOOST_FOREACH(const JsonNode &n, duelData["creatures"].Vector()) | ||||
| 	{ | ||||
| 		CusomCreature cc; | ||||
| 		cc.id = n["id"].Float(); | ||||
|  | ||||
| #define retreive(name)								\ | ||||
| 	if(n[ #name ].getType() == JsonNode::DATA_FLOAT)\ | ||||
| 	cc.name = n[ #name ].Float();			\ | ||||
| 	else											\ | ||||
| 	cc.name = -1; | ||||
|  | ||||
| 		retreive(attack); | ||||
| 		retreive(defense); | ||||
| 		retreive(HP); | ||||
| 		retreive(dmg); | ||||
| 		retreive(shoots); | ||||
| 		retreive(speed); | ||||
| 		ret.creatures.push_back(cc); | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| TeamState::TeamState() | ||||
| { | ||||
| 	setNodeType(TEAM); | ||||
|   | ||||
| @@ -284,12 +284,12 @@ struct DLL_LINKAGE CPathsInfo | ||||
| 	~CPathsInfo(); | ||||
| }; | ||||
|  | ||||
| struct DLL_LINKAGE DuelParameters | ||||
| struct DLL_EXPORT DuelParameters | ||||
| { | ||||
| 	si32 terType, bfieldType; | ||||
| 	struct SideSettings | ||||
| 	struct DLL_EXPORT SideSettings | ||||
| 	{ | ||||
| 		struct StackSettings | ||||
| 		struct DLL_EXPORT StackSettings | ||||
| 		{ | ||||
| 			si32 type; | ||||
| 			si32 count; | ||||
| @@ -300,23 +300,46 @@ struct DLL_LINKAGE DuelParameters | ||||
|  | ||||
| 			StackSettings(); | ||||
| 			StackSettings(si32 Type, si32 Count); | ||||
| 		}; | ||||
| 		StackSettings stacks[GameConstants::ARMY_SIZE]; | ||||
| 		} stacks[GameConstants::ARMY_SIZE]; | ||||
|  | ||||
| 		si32 heroId; //-1 if none | ||||
| 		std::vector<si32> heroPrimSkills; //may be empty | ||||
| 		std::map<si32, CArtifactInstance*> artifacts; | ||||
| 		std::vector<std::pair<si32, si8> > heroSecSkills; //may be empty; pairs <id, level>, level [0-3] | ||||
| 		std::set<si32> spells; | ||||
|  | ||||
| 		SideSettings(); | ||||
| 		template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 		{ | ||||
| 			h & stacks & heroId & spells; | ||||
| 			h & stacks & heroId & heroPrimSkills & artifacts & heroSecSkills & spells; | ||||
| 		} | ||||
| 	} sides[2]; | ||||
|  | ||||
| 	std::vector<shared_ptr<CObstacleInstance> > obstacles; | ||||
|  | ||||
| 	static DuelParameters fromJSON(const std::string &fname); | ||||
|  | ||||
| 	struct CusomCreature | ||||
| 	{ | ||||
| 		int id; | ||||
| 		int attack, defense, dmg, HP, speed, shoots; | ||||
|  | ||||
| 		CusomCreature()  | ||||
| 		{ | ||||
| 			id = attack = defense = dmg = HP = speed = shoots = -1; | ||||
| 		} | ||||
| 		template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 		{ | ||||
| 			h & id & attack & defense & dmg & HP & speed & shoots; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	std::vector<CusomCreature> creatures; | ||||
|  | ||||
| 	DuelParameters(); | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & terType & bfieldType & sides; | ||||
| 		h & terType & bfieldType & sides & obstacles & creatures; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -387,6 +410,8 @@ public: | ||||
| 	boost::shared_mutex *mx; | ||||
|  | ||||
| 	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> | ||||
|   | ||||
| @@ -56,6 +56,8 @@ si8 CBattleInfoCallback::battleCanTeleportTo(const CStack * stack, BattleHex des | ||||
|  | ||||
| std::vector<int> CBattleInfoCallback::battleGetDistances(const CStack * stack, BattleHex hex /*= BattleHex::INVALID*/, BattleHex * predecessors /*= NULL*/) | ||||
| { | ||||
| 	// FIXME - This method is broken, hex argument is not used. However AI depends on that wrong behaviour. | ||||
|  | ||||
| 	if(!hex.isValid()) | ||||
| 		hex = stack->position; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user