소스 검색

* new spell: blind
* a part of hypnotize support
* minor changes and bugfixes

mateuszb 16 년 전
부모
커밋
0787b6a79b
6개의 변경된 파일79개의 추가작업 그리고 18개의 파일을 삭제
  1. 3 1
      client/CBattleInterface.cpp
  2. 5 5
      config/spell_info.txt
  3. 11 1
      lib/CGameState.cpp
  4. 33 3
      lib/NetPacksLib.cpp
  5. 8 7
      lib/StackFeature.h
  6. 19 1
      server/CGameHandler.cpp

+ 3 - 1
client/CBattleInterface.cpp

@@ -1462,6 +1462,8 @@ bool CBattleInterface::isTileAttackable(const int & number) const
 void CBattleInterface::handleEndOfMove(int stackNumber, int destinationTile)
 void CBattleInterface::handleEndOfMove(int stackNumber, int destinationTile)
 {
 {
 	const CStack * movedStack = LOCPLINT->cb->battleGetStackByID(stackNumber);
 	const CStack * movedStack = LOCPLINT->cb->battleGetStackByID(stackNumber);
+	if(!movedStack)
+		return;
 	if(creAnims[stackNumber]->framesInGroup(21)!=0) // some units don't have this animation (ie. halberdier)
 	if(creAnims[stackNumber]->framesInGroup(21)!=0) // some units don't have this animation (ie. halberdier)
 	{
 	{
 		if (movedStack->creature->sounds.endMoving)
 		if (movedStack->creature->sounds.endMoving)
@@ -2199,7 +2201,7 @@ void CBattleInterface::redrawBackgroundWithHexes(int activeStack)
 void CBattleInterface::printConsoleAttacked(int ID, int dmg, int killed, int IDby)
 void CBattleInterface::printConsoleAttacked(int ID, int dmg, int killed, int IDby)
 {
 {
 	char tabh[200];
 	char tabh[200];
-	const CStack * attacker = LOCPLINT->cb->battleGetStackByID(IDby);
+	const CStack * attacker = LOCPLINT->cb->battleGetStackByID(IDby, false);
 	const CStack * defender = LOCPLINT->cb->battleGetStackByID(ID, false);
 	const CStack * defender = LOCPLINT->cb->battleGetStackByID(ID, false);
 	int end = sprintf(tabh, CGI->generaltexth->allTexts[attacker->amount > 1 ? 377 : 376].c_str(),
 	int end = sprintf(tabh, CGI->generaltexth->allTexts[attacker->amount > 1 ? 377 : 376].c_str(),
 		(attacker->amount > 1 ? attacker->creature->namePl.c_str() : attacker->creature->nameSing.c_str()),
 		(attacker->amount > 1 ? attacker->creature->namePl.c_str() : attacker->creature->nameSing.c_str()),

+ 5 - 5
config/spell_info.txt

@@ -29,7 +29,7 @@
 26 -1 12 X X X X
 26 -1 12 X X X X
 27 1 27 0 0 0 X
 27 1 27 0 0 0 X
 28 1 2 0 0 0 X
 28 1 2 0 0 0 X
-29 1 -1 0 0 0 X
+29 1 11 0 0 0 X
 30 1 22 0 0 0 X
 30 1 22 0 0 0 X
 31 1 24 0 0 0 X
 31 1 24 0 0 0 X
 32 1 23 0 0 0 X
 32 1 23 0 0 0 X
@@ -58,11 +58,11 @@
 55 1 28 0 0 0 0
 55 1 28 0 0 0 0
 56 1 17 0 0 0 0
 56 1 17 0 0 0 0
 57 -1 -1 0 0 0 0
 57 -1 -1 0 0 0 0
-58 1 -1 0 0 0 X
-59 -1 -1 0 0 0-1 0-2
-60 -1 -1 0 0 0 0
+58 1 7 0 0 0 X
+59 -1 35 0 0 0-1 0-2
+60 -1 21 0 0 0 0
 61 -1 42 0 0 0 X
 61 -1 42 0 0 0 X
-62 -1 -1 0 0 0 0
+62 -1 6 0 0 0 0
 63 1 -1 0 0 0 0
 63 1 -1 0 0 0 0
 64 0 -1 X X X X
 64 0 -1 X X X X
 65 1 -1 0 0 0 0
 65 1 -1 0 0 0 0

+ 11 - 1
lib/CGameState.cpp

@@ -1861,7 +1861,7 @@ bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
 
 
 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->Attack() - defender->Defense(),
+	int attackDefenseBonus,
 		minDmg = attacker->creature->damageMin * attacker->amount, 
 		minDmg = attacker->creature->damageMin * attacker->amount, 
 		maxDmg = attacker->creature->damageMax * attacker->amount;
 		maxDmg = attacker->creature->damageMax * attacker->amount;
 
 
@@ -1871,6 +1871,15 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 		maxDmg *= attackerHero->getPrimSkillLevel(0) + 1; 
 		maxDmg *= attackerHero->getPrimSkillLevel(0) + 1; 
 	}
 	}
 
 
+	if(attacker->hasFeatureOfType(StackFeature::GENERAL_ATTACK_REDUCTION))
+	{
+		attackDefenseBonus = attacker->Attack() * (attacker->valOfFeatures(StackFeature::GENERAL_ATTACK_REDUCTION, -1024) / 100.0f) - defender->Defense();
+	}
+	else
+	{
+		attackDefenseBonus = attacker->Attack() - defender->Defense();
+	}
+
 	//calculating total attack/defense skills modifier
 	//calculating total attack/defense skills modifier
 
 
 	if(!shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 0)) //bloodlust handling (etc.)
 	if(!shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 0)) //bloodlust handling (etc.)
@@ -1883,6 +1892,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 		attackDefenseBonus += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 1);
 		attackDefenseBonus += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 1);
 	}
 	}
 
 
+
 	if(attacker->getEffect(55)) //slayer handling
 	if(attacker->getEffect(55)) //slayer handling
 	{
 	{
 		std::vector<int> affectedIds;
 		std::vector<int> affectedIds;

+ 33 - 3
lib/NetPacksLib.cpp

@@ -600,7 +600,7 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
 		s->features.clear();
 		s->features.clear();
 		for(int i=0; i < tmpFeatures.size(); i++)
 		for(int i=0; i < tmpFeatures.size(); i++)
 		{
 		{
-			if(tmpFeatures[i].duration == StackFeature::N_TURNS)
+			if((tmpFeatures[i].duration & StackFeature::N_TURNS) != 0)
 			{
 			{
 				tmpFeatures[i].turnsRemain--;
 				tmpFeatures[i].turnsRemain--;
 				if(tmpFeatures[i].turnsRemain > 0)
 				if(tmpFeatures[i].turnsRemain > 0)
@@ -663,6 +663,29 @@ DLL_EXPORT void BattleAttack::applyGs( CGameState *gs )
 		attacker->shots--;
 		attacker->shots--;
 	BOOST_FOREACH(BattleStackAttacked stackAttacked, bsa)
 	BOOST_FOREACH(BattleStackAttacked stackAttacked, bsa)
 		stackAttacked.applyGs(gs);
 		stackAttacked.applyGs(gs);
+
+	for(int g=0; g<attacker->features.size(); ++g)
+	{
+		if((attacker->features[g].duration & StackFeature::UNTIL_ATTACK) != 0)
+		{
+			attacker->features.erase(attacker->features.begin() + g);
+			g = 0;
+		}
+	}
+
+	for(std::set<BattleStackAttacked>::const_iterator it = bsa.begin(); it != bsa.end(); ++it)
+	{
+		CStack * stack = gs->curB->getStack(it->stackAttacked, false);
+
+		for(int g=0; g<stack->features.size(); ++g)
+		{
+			if((stack->features[g].duration & StackFeature::UNITL_BEING_ATTACKED) != 0)
+			{
+				stack->features.erase(stack->features.begin() + g);
+				g = 0;
+			}
+		}
+	}
 }
 }
 
 
 DLL_EXPORT void StartAction::applyGs( CGameState *gs )
 DLL_EXPORT void StartAction::applyGs( CGameState *gs )
@@ -841,12 +864,19 @@ static std::vector<StackFeature> stackEffectToFeature(const CStack::StackEffect
 	case 55: //slayer
 	case 55: //slayer
 		sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
 		sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
 		break;
 		break;
-	case 61: //forgetfulness
+	case 56: //frenzy
 		sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
 		sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
 		break;
 		break;
-	case 56: //frenzy
+	case 60: //hypnotize
+		break;
+		sf.push_back(featureGenerator(StackFeature::HYPNOTIZED, 0, sse.level, sse.turnsRemain));
+	case 61: //forgetfulness
 		sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
 		sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
 		break;
 		break;
+	case 62: //blind
+		sf.push_back(makeFeature(StackFeature::NOT_ACTIVE, StackFeature::UNITL_BEING_ATTACKED | StackFeature::N_TURNS, 0, 0, StackFeature::SPELL_EFFECT, sse.turnsRemain, 0));
+		sf.push_back(makeFeature(StackFeature::GENERAL_ATTACK_REDUCTION, StackFeature::UNTIL_ATTACK | StackFeature::N_TURNS, 0, VLC->spellh->spells[sse.id].powers[sse.level], StackFeature::SPELL_EFFECT, sse.turnsRemain, 0));
+		break;
 	}
 	}
 
 
 	//setting positiveness
 	//setting positiveness

+ 8 - 7
lib/StackFeature.h

@@ -49,7 +49,8 @@ struct StackFeature
 	VCMI_CREATURE_ABILITY_NAME(SPELLCASTER) /*subtype - spell id, value - level of school, additional info - spell power*/ \
 	VCMI_CREATURE_ABILITY_NAME(SPELLCASTER) /*subtype - spell id, value - level of school, additional info - spell power*/ \
 	VCMI_CREATURE_ABILITY_NAME(CATAPULT)								\
 	VCMI_CREATURE_ABILITY_NAME(CATAPULT)								\
 	VCMI_CREATURE_ABILITY_NAME(ENEMY_DEFENCE_REDUCTION) /*in % (value) eg. behemots*/ \
 	VCMI_CREATURE_ABILITY_NAME(ENEMY_DEFENCE_REDUCTION) /*in % (value) eg. behemots*/ \
-	VCMI_CREATURE_ABILITY_NAME(GENERAL_DAMAGE_REDUCTION) /*eg. while stoned or blinded - in %, subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage*/ \
+	VCMI_CREATURE_ABILITY_NAME(GENERAL_DAMAGE_REDUCTION) /* shield / air shield effect */ \
+	VCMI_CREATURE_ABILITY_NAME(GENERAL_ATTACK_REDUCTION) /*eg. while stoned or blinded - in %, subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage*/ \
 	VCMI_CREATURE_ABILITY_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/		\
 	VCMI_CREATURE_ABILITY_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/		\
 	VCMI_CREATURE_ABILITY_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \
 	VCMI_CREATURE_ABILITY_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \
 	VCMI_CREATURE_ABILITY_NAME(CASTS_SPELL_WHEN_KILLED) /*similar to spell after attack*/ \
 	VCMI_CREATURE_ABILITY_NAME(CASTS_SPELL_WHEN_KILLED) /*similar to spell after attack*/ \
@@ -92,10 +93,10 @@ struct StackFeature
 
 
 	enum EDuration
 	enum EDuration
 	{
 	{
-		WHOLE_BATTLE,
-		N_TURNS,
-		UNITL_BEING_ATTACKED,/*removed after attack and counterattacks are performed*/
-		UNTIL_ATTACK /*removed after attack and counterattacks are performed*/
+		WHOLE_BATTLE = 1,
+		N_TURNS = 2,
+		UNITL_BEING_ATTACKED = 4,/*removed after attack and counterattacks are performed*/
+		UNTIL_ATTACK = 8 /*removed after attack and counterattacks are performed*/
 	};
 	};
 
 
 	enum ESource
 	enum ESource
@@ -107,7 +108,7 @@ struct StackFeature
 	};
 	};
 
 
 	ui8 type;//ECombatFeatures
 	ui8 type;//ECombatFeatures
-	ui8 duration;//EDuration
+	ui8 duration;//EDuration //bitfield
 	ui8 source;//ESource
 	ui8 source;//ESource
 	si8 positiveness; //+1 - positive, 0 - neutral, -1 - negative; used mostly for spell features
 	si8 positiveness; //+1 - positive, 0 - neutral, -1 - negative; used mostly for spell features
 	ui16 turnsRemain; //if duration is N_TURNS it describes how long the effect will last
 	ui16 turnsRemain; //if duration is N_TURNS it describes how long the effect will last
@@ -129,7 +130,7 @@ struct StackFeature
 };
 };
 
 
 //generates StackFeature from given data
 //generates StackFeature from given data
-inline StackFeature makeFeature(StackFeature::ECombatFeatures type, StackFeature::EDuration duration, si16 subtype, si32 value, StackFeature::ESource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
+inline StackFeature makeFeature(StackFeature::ECombatFeatures type, ui8 duration, si16 subtype, si32 value, StackFeature::ESource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
 {
 {
 	StackFeature sf;
 	StackFeature sf;
 	sf.type = type;
 	sf.type = type;

+ 19 - 1
server/CGameHandler.cpp

@@ -2332,7 +2332,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 			if(!curStack->hasFeatureOfType(StackFeature::BLOCKS_RETALIATION)
 			if(!curStack->hasFeatureOfType(StackFeature::BLOCKS_RETALIATION)
 				&& stackAtEnd->alive()
 				&& stackAtEnd->alive()
 				&& stackAtEnd->counterAttacks
 				&& stackAtEnd->counterAttacks
-				&& !stackAtEnd->hasFeatureOfType(StackFeature::SIEGE_WEAPON)) //TODO: support for multiple retaliatons per turn
+				&& !stackAtEnd->hasFeatureOfType(StackFeature::SIEGE_WEAPON)
+				&& !stackAtEnd->hasFeatureOfType(StackFeature::HYPNOTIZED)) //TODO: support for multiple retaliatons per turn
 			{
 			{
 				prepareAttack(bat,stackAtEnd,curStack);
 				prepareAttack(bat,stackAtEnd,curStack);
 				bat.flags |= 2;
 				bat.flags |= 2;
@@ -2654,6 +2655,21 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
 			ret.push_back((*it)->ID);
 			ret.push_back((*it)->ID);
 
 
 	}
 	}
+
+	if(sp->id == 60) //hypnotize
+	{
+		for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
+		{
+			if( (*it)->amount * (*it)->MaxHealth() + (*it)->firstHPleft 
+				> 
+				caster->getPrimSkillLevel(2) * 25 + sp->powers[caster->getSpellSchoolLevel(sp)]
+			)
+			{
+				ret.push_back((*it)->ID);
+			}
+		}
+	}
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -2767,7 +2783,9 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 			case 54: //slow
 			case 54: //slow
 			case 55: //slayer
 			case 55: //slayer
 			case 56: //frenzy
 			case 56: //frenzy
+			case 60: //hypnotize
 			case 61: //forgetfulness
 			case 61: //forgetfulness
+			case 62: //blind
 				{
 				{
 					SetStackEffect sse;
 					SetStackEffect sse;
 					for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
 					for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)