Browse Source

* 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 17 years ago
parent
commit
99691b0f11
11 changed files with 245 additions and 42 deletions
  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();
 }
-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);
 	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;
 
 		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;
 		for(int n=0; n<stacksSorted.size(); ++n)
 		{
@@ -1446,6 +1447,11 @@ void CBattleInterface::spellCasted(SpellCasted * sc)
 			displayEffect(19, sc->tile);
 			break;
 		}
+	case 56: //frenzy
+		{
+			displayEffect(17, sc->tile);
+			break;
+		}
 	case 61: //forgetfulness
 		{
 			displayEffect(42, sc->tile);
@@ -1470,14 +1476,39 @@ void CBattleInterface::castThisSpell(int spellID)
 	spellSelMode = 0;
 	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(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); 

+ 1 - 1
CBattleInterface.h

@@ -137,7 +137,7 @@ private:
 	float getAnimSpeedMultiplier() const; //returns multiplier for number of frames in a group
 
 	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
 
 	class CAttHelper

+ 5 - 0
CCallback.cpp

@@ -491,6 +491,11 @@ std::map<int, CStack> CCallback::battleGetStacks()
 	return ret;
 }
 
+std::vector<CStack> CCallback::battleGetStackQueue()
+{
+	return gs->curB->getStackQueue();
+}
+
 CCreature CCallback::battleGetCreature(int number)
 {
 	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 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::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 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
@@ -167,6 +168,7 @@ public:
 	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
 	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
 	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

+ 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 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)->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)->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)->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)->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(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;
 	if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
 	{
 		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
 	{
 		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
 	{
@@ -1698,4 +1687,72 @@ CStack * BattleInfo::getNextStack()
 		return stacks[i];
 	}
 	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;
 	}
 	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 * getStackT(int tileID);
 	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;
 		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
 	bool combatSpell; //is this spell combat (true) or adventure (false)
 	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

+ 10 - 0
server/CGameHandler.cpp

@@ -1400,6 +1400,16 @@ upgend:
 									sendAndApply(&sse);
 									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
 								{
 									SetStackEffect sse;