Explorar o código

* fixed compilation error
* added frenzy spell
* repaired order in stack queue in case a unit has waited (it should work correctly now)
* added spell positiveness info, positive spells cannot be cast on hostile stacks and vice versa

mateuszb %!s(int64=17) %!d(string=hai) anos
pai
achega
99691b0f11
Modificáronse 11 ficheiros con 245 adicións e 42 borrados
  1. 1 1
      CAdvmapInterface.cpp
  2. 40 9
      CBattleInterface.cpp
  3. 1 1
      CBattleInterface.h
  4. 5 0
      CCallback.cpp
  5. 2 0
      CCallback.h
  6. 87 30
      CGameState.cpp
  7. 1 0
      CGameState.h
  8. 73 0
      config/spell_info.txt
  9. 24 1
      hch/CSpellHandler.cpp
  10. 1 0
      hch/CSpellHandler.h
  11. 10 0
      server/CGameHandler.cpp

+ 1 - 1
CAdvmapInterface.cpp

@@ -765,7 +765,7 @@ void CResDataBar::deactivate()
 {
 {
 	ClickableR::deactivate();
 	ClickableR::deactivate();
 }
 }
-CResDataBar::CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int datedist)
+CResDataBar::CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist)
 {
 {
 	bg = BitmapHandler::loadBitmap(defname);
 	bg = BitmapHandler::loadBitmap(defname);
 	SDL_SetColorKey(bg,SDL_SRCCOLORKEY,SDL_MapRGB(bg->format,0,255,255));
 	SDL_SetColorKey(bg,SDL_SRCCOLORKEY,SDL_MapRGB(bg->format,0,255,255));

+ 40 - 9
CBattleInterface.cpp

@@ -435,12 +435,13 @@ void CBattleInterface::show(SDL_Surface * to)
 		int yPos = 10;
 		int yPos = 10;
 
 
 		std::vector<CStack> stacksSorted;
 		std::vector<CStack> stacksSorted;
-		for(int v=0; v<stacks.size(); ++v)
-		{
-			if(stacks[v].alive()) //we don't want dead stacks to be there
-				stacksSorted.push_back(stacks[v]);
-		}
-		std::stable_sort(stacksSorted.begin(), stacksSorted.end(), cmpst2);
+		stacksSorted = LOCPLINT->cb->battleGetStackQueue();
+		//for(int v=0; v<stacks.size(); ++v)
+		//{
+		//	if(stacks[v].alive()) //we don't want dead stacks to be there
+		//		stacksSorted.push_back(stacks[v]);
+		//}
+		//std::stable_sort(stacksSorted.begin(), stacksSorted.end(), cmpst2);
 		int startFrom = -1;
 		int startFrom = -1;
 		for(int n=0; n<stacksSorted.size(); ++n)
 		for(int n=0; n<stacksSorted.size(); ++n)
 		{
 		{
@@ -1446,6 +1447,11 @@ void CBattleInterface::spellCasted(SpellCasted * sc)
 			displayEffect(19, sc->tile);
 			displayEffect(19, sc->tile);
 			break;
 			break;
 		}
 		}
+	case 56: //frenzy
+		{
+			displayEffect(17, sc->tile);
+			break;
+		}
 	case 61: //forgetfulness
 	case 61: //forgetfulness
 		{
 		{
 			displayEffect(42, sc->tile);
 			displayEffect(42, sc->tile);
@@ -1470,14 +1476,39 @@ void CBattleInterface::castThisSpell(int spellID)
 	spellSelMode = 0;
 	spellSelMode = 0;
 	if(CGI->spellh->spells[spellID].attributes.find("CREATURE_TARGET") != std::string::npos)
 	if(CGI->spellh->spells[spellID].attributes.find("CREATURE_TARGET") != std::string::npos)
 	{
 	{
-		spellSelMode = 3;
+		switch(CGI->spellh->spells[spellID].positiveness)
+		{
+		case -1 :
+			spellSelMode = 2;
+			break;
+		case 0:
+			spellSelMode = 3;
+			break;
+		case 1:
+			spellSelMode = 1;
+			break;
+		}
 	}
 	}
 	if(CGI->spellh->spells[spellID].attributes.find("CREATURE_TARGET_2") != std::string::npos)
 	if(CGI->spellh->spells[spellID].attributes.find("CREATURE_TARGET_2") != std::string::npos)
 	{
 	{
 		if(castingHero && castingHero->getSpellSecLevel(spellID) < 3)
 		if(castingHero && castingHero->getSpellSecLevel(spellID) < 3)
-			spellSelMode = 3;
-		else //TODO: no destination chould apply in this case
 		{
 		{
+			switch(CGI->spellh->spells[spellID].positiveness)
+			{
+			case -1 :
+				spellSelMode = 2;
+				break;
+			case 0:
+				spellSelMode = 3;
+				break;
+			case 1:
+				spellSelMode = 1;
+				break;
+			}
+		}
+		else
+		{
+			spellSelMode = -1;
 		}
 		}
 	}
 	}
 	CGI->curh->changeGraphic(3, 0); 
 	CGI->curh->changeGraphic(3, 0); 

+ 1 - 1
CBattleInterface.h

@@ -137,7 +137,7 @@ private:
 	float getAnimSpeedMultiplier() const; //returns multiplier for number of frames in a group
 	float getAnimSpeedMultiplier() const; //returns multiplier for number of frames in a group
 
 
 	bool spellDestSelectMode; //if true, player is choosing destination for his spell
 	bool spellDestSelectMode; //if true, player is choosing destination for his spell
-	int spellSelMode; //0 - any location, 1 - any firendly creature, 2 - any hostile creature, 3 - any creature, 4 - obstacle
+	int spellSelMode; //0 - any location, 1 - any firendly creature, 2 - any hostile creature, 3 - any creature, 4 - obstacle, -1 - no location
 	BattleAction * spellToCast; //spell for which player is choosing destination
 	BattleAction * spellToCast; //spell for which player is choosing destination
 
 
 	class CAttHelper
 	class CAttHelper

+ 5 - 0
CCallback.cpp

@@ -491,6 +491,11 @@ std::map<int, CStack> CCallback::battleGetStacks()
 	return ret;
 	return ret;
 }
 }
 
 
+std::vector<CStack> CCallback::battleGetStackQueue()
+{
+	return gs->curB->getStackQueue();
+}
+
 CCreature CCallback::battleGetCreature(int number)
 CCreature CCallback::battleGetCreature(int number)
 {
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);

+ 2 - 0
CCallback.h

@@ -80,6 +80,7 @@ public:
 	virtual int battleGetPos(int stack)=0; //returns position (tile ID) of stack
 	virtual int battleGetPos(int stack)=0; //returns position (tile ID) of stack
 	virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack
 	virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack
 	virtual std::map<int, CStack> battleGetStacks()=0; //returns stacks on battlefield
 	virtual std::map<int, CStack> battleGetStacks()=0; //returns stacks on battlefield
+	virtual std::vector<CStack> battleGetStackQueue()=0; //returns vector of stack in order of their move sequence
 	virtual CCreature battleGetCreature(int number)=0; //returns type of creature by given number of stack
 	virtual CCreature battleGetCreature(int number)=0; //returns type of creature by given number of stack
 	//virtual bool battleMoveCreature(int ID, int dest)=0; //moves creature with id ID to dest if possible
 	//virtual bool battleMoveCreature(int ID, int dest)=0; //moves creature with id ID to dest if possible
 	virtual std::vector<int> battleGetAvailableHexes(int ID)=0; //reutrns numbers of hexes reachable by creature with id ID
 	virtual std::vector<int> battleGetAvailableHexes(int ID)=0; //reutrns numbers of hexes reachable by creature with id ID
@@ -167,6 +168,7 @@ public:
 	int battleGetPos(int stack); //returns position (tile ID) of stack
 	int battleGetPos(int stack); //returns position (tile ID) of stack
 	int battleMakeAction(BattleAction* action);//for casting spells by hero - DO NOT use it for moving active stack
 	int battleMakeAction(BattleAction* action);//for casting spells by hero - DO NOT use it for moving active stack
 	std::map<int, CStack> battleGetStacks(); //returns stacks on battlefield
 	std::map<int, CStack> battleGetStacks(); //returns stacks on battlefield
+	std::vector<CStack> battleGetStackQueue(); //returns vector of stack in order of their move sequence
 	CCreature battleGetCreature(int number); //returns type of creature by given number of stack
 	CCreature battleGetCreature(int number); //returns type of creature by given number of stack
 	std::vector<int> battleGetAvailableHexes(int ID); //reutrns numbers of hexes reachable by creature with id ID
 	std::vector<int> battleGetAvailableHexes(int ID); //reutrns numbers of hexes reachable by creature with id ID
 	bool battleIsStackMine(int ID); //returns true if stack with id ID belongs to caller
 	bool battleIsStackMine(int ID); //returns true if stack with id ID belongs to caller

+ 87 - 30
CGameState.cpp

@@ -1500,58 +1500,47 @@ void CGameState::loadTownDInfos()
 }
 }
 int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting)
 int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting)
 {
 {
-	int attackDefenseBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0) - (defender->creature->defence + (defendingHero ? defendingHero->getPrimSkillLevel(1) : 0));
+	int attackerAttackBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0);
+	if(attacker->getEffect(56)) //frenzy for attacker
+	{
+		attackerAttackBonus += (VLC->spellh->spells[attacker->getEffect(56)->id].powers[attacker->getEffect(56)->level]/100.0) *(attacker->creature->defence + (attackerHero ? attackerHero->getPrimSkillLevel(1) : 0));
+	}
+	int defenderDefenseBonus = defender->creature->defence + (defendingHero ? defendingHero->getPrimSkillLevel(1) : 0);
+	if(defender->getEffect(56)) //frenzy for defender
+	{
+		defenderDefenseBonus = 0;
+	}
+	int attackDefenseBonus = attackerAttackBonus - defenderDefenseBonus;
 	if(defender->getEffect(48)) //defender's prayer handling
 	if(defender->getEffect(48)) //defender's prayer handling
 	{
 	{
-		if(defender->getEffect(48)->level<=1) //none or basic
-			attackDefenseBonus -= 2;
-		else //adv or expert
-			attackDefenseBonus -= 4;
+		attackDefenseBonus -= VLC->spellh->spells[defender->getEffect(48)->id].powers[defender->getEffect(48)->level];
 	}
 	}
 	if(attacker->getEffect(48)) //attacker's prayer handling
 	if(attacker->getEffect(48)) //attacker's prayer handling
 	{
 	{
-		if(attacker->getEffect(48)->level<=1) //none or basic
-			attackDefenseBonus += 2;
-		else //adv or expert
-			attackDefenseBonus += 4;
+		attackDefenseBonus += VLC->spellh->spells[attacker->getEffect(48)->id].powers[attacker->getEffect(48)->level];
 	}
 	}
 	if(defender->getEffect(46)) //stone skin handling
 	if(defender->getEffect(46)) //stone skin handling
 	{
 	{
-		if(defender->getEffect(46)->level<=1) //none or basic
-			attackDefenseBonus -= 3;
-		else //adv or expert
-			attackDefenseBonus -= 6;
+		attackDefenseBonus -= VLC->spellh->spells[defender->getEffect(46)->id].powers[defender->getEffect(46)->level];
 	}
 	}
 	if(attacker->getEffect(45)) //weakness handling
 	if(attacker->getEffect(45)) //weakness handling
 	{
 	{
-		if(attacker->getEffect(45)->level<=1) //none or basic
-			attackDefenseBonus -= 3;
-		else //adv or expert
-			attackDefenseBonus -= 6;
+		attackDefenseBonus -= VLC->spellh->spells[attacker->getEffect(45)->id].powers[attacker->getEffect(45)->level];
 	}
 	}
 	if(!shooting && attacker->getEffect(43)) //bloodlust handling
 	if(!shooting && attacker->getEffect(43)) //bloodlust handling
 	{
 	{
-		if(attacker->getEffect(43)->level<=1) //none or basic
-			attackDefenseBonus += 3;
-		else //adv or expert
-			attackDefenseBonus += 6;
+		attackDefenseBonus += VLC->spellh->spells[attacker->getEffect(43)->id].powers[attacker->getEffect(43)->level];
 	}
 	}
 	int damageBase = 0;
 	int damageBase = 0;
 	if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
 	if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
 	{
 	{
 		damageBase = attacker->creature->damageMin;
 		damageBase = attacker->creature->damageMin;
-		if(attacker->getEffect(42)->level >= 2) //adv or expert
-		{
-			damageBase -= 1;
-		}
+		damageBase -= VLC->spellh->spells[attacker->getEffect(42)->id].powers[attacker->getEffect(42)->level];
 	}
 	}
 	else if(attacker->getEffect(41)) //bless handling
 	else if(attacker->getEffect(41)) //bless handling
 	{
 	{
 		damageBase = attacker->creature->damageMax;
 		damageBase = attacker->creature->damageMax;
-		if(attacker->getEffect(41)->level >= 2) //adv or expert
-		{
-			damageBase += 1;
-		}
+		damageBase += VLC->spellh->spells[attacker->getEffect(41)->id].powers[attacker->getEffect(41)->level];
 	}
 	}
 	else if(attacker->creature->damageMax == attacker->creature->damageMin) //constant damage
 	else if(attacker->creature->damageMax == attacker->creature->damageMin) //constant damage
 	{
 	{
@@ -1698,4 +1687,72 @@ CStack * BattleInfo::getNextStack()
 		return stacks[i];
 		return stacks[i];
 	}
 	}
 	return NULL; //all stacks moved or defending!
 	return NULL; //all stacks moved or defending!
-}
+}
+
+std::vector<CStack> BattleInfo::getStackQueue()
+{
+	std::vector<CStack> ret;
+	std::vector<int> taken; //if non-zero value, corresponding stack has been placed in ret
+	taken.resize(stacks.size());
+	for(int g=0; g<taken.size(); ++g)
+	{
+		taken[g] = 0;
+	}
+
+	for(int moved=0; moved<2; ++moved) //in first cycle we add stacks that can act in current turn, in second one the rest of them
+	{
+		for(int gc=0; gc<stacks.size(); ++gc)
+		{
+			int id = -1, speed = -1;
+			for(int i=0; i<stacks.size(); ++i) //find not waited stacks only
+			{
+				if((moved == 1 ||!vstd::contains(stacks[i]->state,DEFENDING))
+					&& stacks[i]->alive()
+					&& (moved == 1 || !vstd::contains(stacks[i]->state,MOVED))
+					&& !vstd::contains(stacks[i]->state,WAITING)
+					&& taken[i]==0)
+				{
+					if(speed == -1 || stacks[i]->speed() > speed)
+					{
+						id = i;
+						speed = stacks[i]->speed();
+					}
+				}
+			}
+			if(id != -1)
+			{
+				ret.push_back(*stacks[id]);
+				taken[id] = 1;
+			}
+			else //choose something from not moved stacks
+			{
+				int id = -1, speed = 10000; //infinite speed
+				for(int i=0; i<stacks.size(); ++i) //find waited stacks only
+				{
+					if((moved == 1 ||!vstd::contains(stacks[i]->state,DEFENDING))
+						&& stacks[i]->alive()
+						&& (moved == 1 || !vstd::contains(stacks[i]->state,MOVED))
+						&& vstd::contains(stacks[i]->state,WAITING)
+						&& taken[i]==0)
+					{
+						if(stacks[i]->speed() < speed) //slowest one
+						{
+							id = i;
+							speed = stacks[i]->speed();
+						}
+					}
+				}
+				if(id != -1)
+				{
+					ret.push_back(*stacks[id]);
+					taken[id] = 1;
+				}
+				else
+				{
+					break; //no stacks have been found, so none of them will be found in next iterations
+				}
+			}
+		}
+	}
+	return ret;
+}

+ 1 - 0
CGameState.h

@@ -72,6 +72,7 @@ struct DLL_EXPORT BattleInfo
 		h & side1 & side2 & round & activeStack & siege & tile & stacks & army1 & army2 & hero1 & hero2;
 		h & side1 & side2 & round & activeStack & siege & tile & stacks & army1 & army2 & hero1 & hero2;
 	}
 	}
 	CStack * getNextStack(); //which stack will have turn after current one
 	CStack * getNextStack(); //which stack will have turn after current one
+	std::vector<CStack> getStackQueue(); //returns stack in order of their movement action
 	CStack * getStack(int stackID);
 	CStack * getStack(int stackID);
 	CStack * getStackT(int tileID);
 	CStack * getStackT(int tileID);
 	void getAccessibilityMap(bool *accessibility, int stackToOmmit=-1); //send pointer to at least 187 allocated bytes
 	void getAccessibilityMap(bool *accessibility, int stackToOmmit=-1); //send pointer to at least 187 allocated bytes

+ 73 - 0
config/spell_info.txt

@@ -0,0 +1,73 @@
+//additional spell info, not included in original heroes III files
+//[spellID - -1 is the end of data in file] [-1 -> spell is negative for influenced creatures; 0 - spell is indifferent for them; 1 - spell is poitive for them]
+0 0
+1 0
+2 0
+3 0
+4 0
+5 0
+6 0
+7 0
+8 0
+9 0
+10 0
+11 0
+12 0
+13 0
+14 0
+15 -1
+16 -1
+17 -1
+18 -1
+19 -1
+20 -1
+21 -1
+22 -1
+23 -1
+24 -1
+25 -1
+26 -1
+27 1
+28 1
+29 1
+30 1
+31 1
+32 1
+33 1
+34 1
+35 1
+36 1
+37 1
+38 1
+39 1
+40 1
+41 1
+42 -1
+43 1
+44 1
+45 -1
+46 1
+47 -1
+48 1
+49 1
+50 -1
+51 1
+52 -1
+53 1
+54 -1
+55 1
+56 1
+57 -1
+58 1
+59 -1
+60 -1
+61 -1
+62 -1
+63 1
+64 0
+65 1
+66 0 
+67 0
+68 0
+69 0
+-1

+ 24 - 1
hch/CSpellHandler.cpp

@@ -79,4 +79,27 @@ void CSpellHandler::loadSpells()
 		nsp.creatureAbility = creatureAbility;
 		nsp.creatureAbility = creatureAbility;
 		spells.push_back(nsp);
 		spells.push_back(nsp);
 	}
 	}
-}
+	//loading of additional spell traits
+	std::ifstream ast;
+	ast.open("config/spell_info.txt", std::ios::binary);
+	if(!ast.is_open())
+	{
+		tlog1<<"lack of config/spell_info.txt file!"<<std::endl;
+	}
+	else
+	{
+		//reading header
+		std::string dump;
+		for(int i=0; i<42; ++i) ast>>dump;
+		//reading exact info
+		int spellID;
+		ast>>spellID;
+		while(spellID != -1)
+		{
+			int buf;
+			ast>>buf;
+			spells[spellID].positiveness = buf;
+			ast>>spellID;
+		}
+	}
+}

+ 1 - 0
hch/CSpellHandler.h

@@ -24,6 +24,7 @@ public:
 	std::string attributes; //reference only attributes
 	std::string attributes; //reference only attributes
 	bool combatSpell; //is this spell combat (true) or adventure (false)
 	bool combatSpell; //is this spell combat (true) or adventure (false)
 	bool creatureAbility; //if true, only creatures can use this spell
 	bool creatureAbility; //if true, only creatures can use this spell
+	si8 positiveness; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative
 };
 };
 
 
 class DLL_EXPORT CSpellHandler
 class DLL_EXPORT CSpellHandler

+ 10 - 0
server/CGameHandler.cpp

@@ -1400,6 +1400,16 @@ upgend:
 									sendAndApply(&sse);
 									sendAndApply(&sse);
 									break;
 									break;
 								}
 								}
+							case 56: //frenzy
+								{
+									SetStackEffect sse;
+									sse.stack = gs->curB->getStackT(ba.destinationTile)->ID;
+									sse.effect.id = 56;
+									sse.effect.level = getSchoolLevel(h,s);
+									sse.effect.turnsRemain = 1; //! - different duration
+									sendAndApply(&sse);
+									break;
+								}
 							case 61: //forgetfulness
 							case 61: //forgetfulness
 								{
 								{
 									SetStackEffect sse;
 									SetStackEffect sse;