소스 검색

Fixed Duel mode. Integrated some changes from programmingChallenge branch - it's possible to define duel parameters using JSON.

Michał W. Urbańczyk 13 년 전
부모
커밋
5981ad15d4
5개의 변경된 파일227개의 추가작업 그리고 58개의 파일을 삭제
  1. 5 1
      client/BattleInterface/CBattleInterfaceClasses.cpp
  2. 2 0
      client/Client.cpp
  3. 186 50
      lib/CGameState.cpp
  4. 32 7
      lib/CGameState.h
  5. 2 0
      lib/IGameCallback.cpp

+ 5 - 1
client/BattleInterface/CBattleInterfaceClasses.cpp

@@ -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;

+ 2 - 0
client/Client.cpp

@@ -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);

+ 186 - 50
lib/CGameState.cpp

@@ -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);

+ 32 - 7
lib/CGameState.h

@@ -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>

+ 2 - 0
lib/IGameCallback.cpp

@@ -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;