浏览代码

- Drain Life now has % effect depending on bonus value
- Stack can use more than 2 attacks. Additional attacks can now be seperated as "ONLY_MELEE_FIGHT and "ONLY_DISTANCE_FIGHT".

DjWarmonger 12 年之前
父节点
当前提交
140786a04b

+ 1 - 1
config/bonusnames.json

@@ -15,7 +15,7 @@
 			{ "id": "DEFENSIVE_STANCE", "name": "Defense Bonus", "description": "+%d Defense when defending" },
 			{ "id": "ADDITIONAL_ATTACK", "name": "Double Strike", "description": "Attacks twice" },
 			{ "id": "DRAGON_NATURE", "name": "Dragon", "description": "Creature has a Dragon Nature" },
-			{ "id": "LIFE_DRAIN", "name": "Drain life", "description": "Drains life equal to damage dealt" },
+			{ "id": "LIFE_DRAIN", "name": "Drain life (%d%)", "description": "Drains life equal to damage dealt" },
 			{ "id": "FEAR", "name": "Fear", "description": "Causes Fear on an enemy stack" },
 			{ "id": "FEARLESS", "name": "Fearless", "description": "Immune to Fear ability" },
 			{ "id": "FLYING", "name": "Fly", "description": "Can Fly (ignores obstacles)" },

+ 1 - 0
config/creatures/castle.json

@@ -152,6 +152,7 @@
 		"id": 7,
 		"level": 4,
 		"faction": "castle",
+		"abilities": [ [ "ADDITIONAL_ATTACK", 1, 0, 0 ] ],
 		"graphics" :
 		{
 			"animation": "CCRUSD.DEF"

+ 1 - 1
config/creatures/necropolis.json

@@ -142,7 +142,7 @@
 		"id": 63,
 		"level": 4,
 		"faction": "necropolis",
-		"abilities": [ [ "LIFE_DRAIN", 0, 0, 0 ],
+		"abilities": [ [ "LIFE_DRAIN", 100, 0, 0 ], //drain 100% of damage dealt
 						 [ "BLOCKS_RETALIATION", 0, 0, 0 ] ],		//vampire lords
 		"graphics" :
 		{

+ 7 - 0
config/creatures/rampart.json

@@ -107,6 +107,13 @@
 		"id": 19,
 		"level": 3,
 		"faction": "rampart",
+		"abilities": [
+						{
+							"type": "ADDITIONAL_ATTACK",
+							"val" : 1,
+							"effectRange": "ONLY_DISTANCE_FIGHT"
+						}
+					],	
 		"graphics" :
 		{
 			"animation": "CGRELF.DEF",

+ 2 - 1
config/creatures/wog.json

@@ -50,7 +50,8 @@
 		"id": 154,
 		"level": 8,
 		"faction": "necropolis",
-		"abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ] ],			//blood dragon is a dragon
+		"abilities": [ [ "LIFE_DRAIN", 40, 0, 0 ], //40%
+						[ "DRAGON_NATURE", 0, 0, 0 ] ],			//blood dragon is a dragon
 		"graphics" :
 		{
 			"animation": "ZM154Z.DEF"

+ 4 - 3
lib/CCreatureHandler.cpp

@@ -263,8 +263,6 @@ void CCreatureHandler::loadCreatures()
 				ncre.addBonus(0, Bonus::SHOOTER);
 			if(boost::algorithm::find_first(ncre.abilityRefs, "SIEGE_WEAPON"))
 				ncre.addBonus(0, Bonus::SIEGE_WEAPON);
-			if(boost::algorithm::find_first(ncre.abilityRefs, "const_two_attacks"))
-				ncre.addBonus(1, Bonus::ADDITIONAL_ATTACK);
 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_free_attack"))
 				ncre.addBonus(0, Bonus::BLOCKS_RETALIATION);
 			if(boost::algorithm::find_first(ncre.abilityRefs, "IS_UNDEAD"))
@@ -324,7 +322,10 @@ void CCreatureHandler::loadCreatures()
 		}
 		BOOST_FOREACH(const JsonNode &ability, node.second["abilities"].Vector())
 		{
-			AddAbility(c, ability.Vector());
+			if (ability.getType() == JsonNode::DATA_VECTOR)
+				AddAbility(c, ability.Vector());
+			else
+				c->addNewBonus(JsonUtils::parseBonus(ability));
 		}
 
 		loadCreatureJson(c, node.second);

+ 5 - 2
lib/CCreatureSet.cpp

@@ -593,8 +593,9 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
 				case Bonus::ATTACKS_ALL_ADJACENT:
 				case Bonus::ADDITIONAL_ATTACK: //TODO: what with more than one attack? Axe of Ferocity for example
 				case Bonus::FULL_HP_REGENERATION:
+				case Bonus::MANA_DRAIN:
+				case Bonus::LIFE_DRAIN:
 				case Bonus::REBIRTH:
-				case Bonus::LIFE_DRAIN: //TODO: chance, hp percentage?
 				case Bonus::SELF_MORALE:
 				case Bonus::SELF_LUCK:
 				case Bonus::FEAR:
@@ -616,7 +617,6 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
 				case Bonus::SPELL_RESISTANCE_AURA:
 				case Bonus::SPELL_DAMAGE_REDUCTION:
 				case Bonus::LEVEL_SPELL_IMMUNITY:
-				case Bonus::MANA_DRAIN:
 				case Bonus::HP_REGENERATION:
 				case Bonus::ADDITIONAL_RETALIATION:
 				case Bonus::DEFENSIVE_STANCE:
@@ -667,6 +667,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
 				case Bonus::ENEMY_DEFENCE_REDUCTION:
 				case Bonus::REBIRTH:
 				case Bonus::DEATH_STARE:
+				case Bonus::LIFE_DRAIN:
 					boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(valOfBonuses(Selector::typeSubtype(bonus->type, bonus->subtype))));
 					break;
 				case Bonus::HATE:
@@ -905,6 +906,8 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
 			fileName = "ManaChannel.bmp"; break;
 		case Bonus::MANA_DRAIN:
 			fileName = "ManaDrain.bmp"; break;
+		case Bonus::LIFE_DRAIN:
+			fileName = "DrainLife.bmp"; break;
 	}
 	if(!fileName.empty())
 		fileName = "zvs/Lib1.res/" + fileName;

+ 42 - 41
server/CGameHandler.cpp

@@ -863,7 +863,8 @@ void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, cons
 
 		StacksHealedOrResurrected::HealInfo hi;
 		hi.stackID = att->ID;
-		hi.healedHP = std::min<int>(bsa.damageAmount, att->MaxHealth() - att->firstHPleft + att->MaxHealth() * (att->baseAmount - att->count) );
+		hi.healedHP = std::min<int> (bsa.damageAmount * att->valOfBonuses (Bonus::LIFE_DRAIN) / 100,
+			att->MaxHealth() - att->firstHPleft + att->MaxHealth() * (att->baseAmount - att->count) );
 		hi.lowLevelResurrection = false;
 		shi.healedStacks.push_back(hi);
 
@@ -3457,38 +3458,32 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 			}
 
 			//attack
-			if(stack->alive()) //move can cause death, eg. by walking into the moat
-			{
-				BattleAttack bat;
-				prepareAttack(bat, stack, stackAtEnd, distance, ba.additionalInfo);
-				handleAttackBeforeCasting(bat); //only before first attack
-				sendAndApply(&bat);
-				handleAfterAttackCasting(bat);
-			}
 
-			//counterattack
-			if(!stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
-				&& stackAtEnd->ableToRetaliate()
-				&& stack->alive()) //attacker may have died (fire shield)
-			{
-				BattleAttack bat;
-				prepareAttack(bat, stackAtEnd, stack, 0, stack->position);
-				bat.flags |= BattleAttack::COUNTER;
-				sendAndApply(&bat);
-				handleAfterAttackCasting(bat);
-			}
+			int totalAttacks = 1 + stack->getBonuses(Selector::type (Bonus::ADDITIONAL_ATTACK),
+				(Selector::effectRange (Bonus::NO_LIMIT) || Selector::effectRange(Bonus::ONLY_MELEE_FIGHT)))->totalValue(); //all unspicified attacks + melee attacks
 
-			//second attack
-			if(stack //FIXME: clones tend to disapear during actions
-				&& stack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0
-				&& !stack->hasBonusOfType(Bonus::SHOOTER)
-				&& stack->alive()
-				&& stackAtEnd->alive()  )
+			for (int i = 0; i < totalAttacks; ++i)
 			{
-				BattleAttack bat;
-				prepareAttack(bat, stack, stackAtEnd, 0, ba.additionalInfo);
-				sendAndApply(&bat);
-				handleAfterAttackCasting(bat);
+				if( stack &&stack->alive()) //move can cause death, eg. by walking into the moat
+				{
+					BattleAttack bat;
+					prepareAttack(bat, stack, stackAtEnd, distance, ba.additionalInfo);
+					handleAttackBeforeCasting(bat); //only before first attack
+					sendAndApply(&bat);
+					handleAfterAttackCasting(bat);
+				}
+
+				//counterattack
+				if(!stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
+					&& stackAtEnd->ableToRetaliate()
+					&& stack->alive()) //attacker may have died (fire shield)
+				{
+					BattleAttack bat;
+					prepareAttack(bat, stackAtEnd, stack, 0, stack->position);
+					bat.flags |= BattleAttack::COUNTER;
+					sendAndApply(&bat);
+					handleAfterAttackCasting(bat);
+				}
 			}
 
 			//return
@@ -3529,18 +3524,24 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 				prepareAttack(bat2, stack, destStack, 0, ba.destinationTile);
 				sendAndApply(&bat2);
 			}
-			//TODO: allow more than one additional attack
-			if(stack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
-				&& stack->alive()
-				&& destStack->alive()
-				&& stack->shots
-				)
+			//allow more than one additional attack
+
+			int additionalAttacks = stack->getBonuses(Selector::type (Bonus::ADDITIONAL_ATTACK),
+				(Selector::effectRange (Bonus::NO_LIMIT) || Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT)))->totalValue();
+			for (int i = 0; i < additionalAttacks; ++i)
 			{
-				BattleAttack bat;
-				bat.flags |= BattleAttack::SHOT;
-				prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
-				sendAndApply(&bat);
-				handleAfterAttackCasting(bat);
+				if(
+					stack->alive()
+					&& destStack->alive()
+					&& stack->shots
+					)
+				{
+					BattleAttack bat;
+					bat.flags |= BattleAttack::SHOT;
+					prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
+					sendAndApply(&bat);
+					handleAfterAttackCasting(bat);
+				}
 			}
 
 			sendAndApply(&end_action);