diff --git a/CCallback.cpp b/CCallback.cpp index d18ba60d2..a7dd7eff7 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -527,11 +527,13 @@ bool CCallback::battleCanShoot(int ID, int dest) CStack *our = battleGetStackByID(ID), *dst = battleGetStackByPos(dest); if(!our || !dst || !gs->curB) return false; - for(size_t g=0; geffects.size(); ++g) - { - if(61 == our->effects[g].id) //forgetfulness - return false; - } + //for(size_t g=0; geffects.size(); ++g) + //{ + // if(61 == our->effects[g].id) //forgetfulness + // return false; + //} + if(our->hasFeatureOfType(StackFeature::FORGETFULL)) //forgetfulness + return false; if(our->hasFeatureOfType(StackFeature::SHOOTER)//it's shooter && our->owner != dst->owner diff --git a/CGameState.cpp b/CGameState.cpp index 4d56cd53b..76182ef19 100644 --- a/CGameState.cpp +++ b/CGameState.cpp @@ -480,7 +480,7 @@ bool CStack::hasFeatureOfType(StackFeature::ECombatFeatures type, int subtype) c CStack::CStack(CCreature * C, int A, int O, int I, bool AO, int S) :ID(I), creature(C), amount(A), baseAmount(A), firstHPleft(C->hitPoints), owner(O), slot(S), attackerOwned(AO), position(-1), - counterAttacks(1), shots(C->shots), state(), effects(), speed(creature->speed), features(C->abilities), attack(C->attack), defense(C->defence) + counterAttacks(1), shots(C->shots), speed(creature->speed), features(C->abilities), attack(C->attack), defense(C->defence) { state.insert(ALIVE); } diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index f2ce8298c..f44e12aac 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -475,6 +475,23 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs ) if(tmpEffects[i].turnsRemain > 0) s->effects.push_back(tmpEffects[i]); } + + //the same as above for features + std::vector tmpFeatures = s->features; + s->features.clear(); + for(int i=0; i < tmpEffects.size(); i++) + { + if(tmpFeatures[i].duration == StackFeature::N_TURNS) + { + tmpFeatures[i].turnsRemain--; + if(tmpEffects[i].turnsRemain > 0) + s->features.push_back(tmpFeatures[i]); + } + else + { + s->features.push_back(tmpFeatures[i]); + } + } } } @@ -564,10 +581,106 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs ) if(s) { s->effects.clear(); //removing all effects + //removing all features from spells + std::vector tmpFeatures = s->features; + s->features.clear(); + for(int i=0; i < tmpFeatures.size(); i++) + { + if(tmpFeatures[i].source != StackFeature::SPELL_EFFECT) + { + s->features.push_back(tmpFeatures[i]); + } + } } } } +StackFeature featureGenerator(StackFeature::ECombatFeatures type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0) +{ + return makeFeature(type, StackFeature::N_TURNS, subtype, value, StackFeature::SPELL_EFFECT, turnsRemain, additionalInfo); +} + +std::vector stackEffectToFeature(const CStack::StackEffect & sse) +{ + std::vector sf; + switch(sse.id) + { + case 27: //shield + sf.push_back(featureGenerator(StackFeature::GENERAL_DAMAGE_REDUCTION, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 28: //air shield + sf.push_back(featureGenerator(StackFeature::GENERAL_DAMAGE_REDUCTION, 1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 30: //protection from air + sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 31: //protection from fire + sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 32: //protection from water + sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 2, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 33: //protection from earth + sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 3, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 41: //bless + sf.push_back(featureGenerator(StackFeature::ALWAYS_MAXIMUM_DAMAGE, -1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 42: //curse + sf.push_back(featureGenerator(StackFeature::ALWAYS_MINUMUM_DAMAGE, -1, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain, sse.level >= 2 ? 20 : 0)); + break; + case 43: //bloodlust + sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 44: //precision + sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, 1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 45: //weakness + sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, -1, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 46: //stone skin + sf.push_back(featureGenerator(StackFeature::DEFENCE_BONUS, -1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 47: //disrupting ray + sf.push_back(featureGenerator(StackFeature::DEFENCE_BONUS, -1, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 48: //prayer + sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + sf.push_back(featureGenerator(StackFeature::DEFENCE_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + sf.push_back(featureGenerator(StackFeature::SPEED_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 49: //mirth + sf.push_back(featureGenerator(StackFeature::MORALE_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 50: //sorrow + sf.push_back(featureGenerator(StackFeature::MORALE_BONUS, 0, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 51: //fortune + sf.push_back(featureGenerator(StackFeature::LUCK_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 52: //misfortune + sf.push_back(featureGenerator(StackFeature::LUCK_BONUS, 0, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 53: //haste + sf.push_back(featureGenerator(StackFeature::SPEED_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); + break; + case 54: //slow + sf.push_back(featureGenerator(StackFeature::SPEED_BONUS, 0, 0, sse.turnsRemain, -1 * VLC->spellh->spells[sse.id].powers[sse.level])); + break; + case 55: //slayer + sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain)); + break; + case 61: //forgetfulness + sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain)); + break; + case 56: //frenzy + sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain)); + break; + } + + return sf; +} + DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs ) { BOOST_FOREACH(ui32 id, stacks) @@ -576,6 +689,32 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs ) if(s) { s->effects.push_back(effect); //adding effect + std::vector sf = stackEffectToFeature(effect); + for(int n=0; nfeatures.push_back(sf[n]); + } + else + { + //don't add multiple instances of the same feature from spell source + bool added = false; + for(int f=0; ffeatures.size(); ++f) + { + if(s->features[f].source == StackFeature::SPELL_EFFECT && s->features[f].type == sf[n].type) + { + s->features[f].turnsRemain = std::max(s->features[f].turnsRemain, effect.turnsRemain); + added = true; + break; + } + } + if(!added) + { + s->features.push_back(sf[n]); + } + } + } } else tlog1 << "Cannot find stack " << id << std::endl; diff --git a/lib/StackFeature.h b/lib/StackFeature.h index 8d024989b..eb4938387 100644 --- a/lib/StackFeature.h +++ b/lib/StackFeature.h @@ -8,7 +8,8 @@ struct StackFeature { NO_TYPE, DOUBLE_WIDE, FLYING, SHOOTER, CHARGE_IMMUNITY, ADDITIONAL_ATTACK, UNLIMITED_RETAILATIONS, - NO_MELEE_PENALTY, JOUSTING /*for champions*/, + NO_MELEE_PENALTY, + JOUSTING /*for champions*/, RAISING_MORALE /*value - how much raises*/, HATE /*eg. angels hate devils, subtype - ID of hated creature*/, KING1, @@ -28,11 +29,15 @@ struct StackFeature SPELL_LIKE_ATTACK /*value - spell id; range is taken from spell, but damage from creature; eg. magog*/, THREE_HEADED_ATTACK /*eg. cerberus*/, DEAMON_SUMMONING /*pit lord*/, - FIRE_IMMUNITY, FIRE_SHIELD, ENEMY_MORALE_DECREASING /*value - how much it decreases*/, - ENEMY_LUCK_DECREASING, UNDEAD, REGENERATION, MANA_DRAIN /*value - spell points per turn*/, LIFE_DRAIN, + FIRE_IMMUNITY, FIRE_SHIELD, + ENEMY_MORALE_DECREASING /*value - how much it decreases*/, + ENEMY_LUCK_DECREASING, UNDEAD, + REGENERATION, MANA_DRAIN /*value - spell points per turn*/, + LIFE_DRAIN, DOUBLE_DAMAGE_CHANCE /*value in %, eg. dread knight*/, RETURN_AFTER_STRIKE, SELF_MORALE /*eg. minotaur*/, - SPELLCASTER /*subtype - spell id, value - level of school, additional info - spell power*/, CATAPULT, + SPELLCASTER /*subtype - spell id, value - level of school, additional info - spell power*/, + CATAPULT, ENEMY_DEFENCE_REDUCTION /*in % (value), eg. behemots*/, GENERAL_DAMAGE_REDUCTION /*eg. while stoned or blinded - in %, subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage*/, ATTACKS_ALL_ADAJCENT /*eg. hydra*/, @@ -40,14 +45,19 @@ struct StackFeature CASTS_SPELL_WHEN_KILLED /*similar to spell after attack*/, FEAR, FEARLESS, NO_DISTANCE_PENALTY, NO_OBSTACLES_PENALTY, SELF_LUCK /*halfling*/, - ATTACK_BONUS, DEFENCE_BONUS, SPEED_BONUS, HP_BONUS, ENCHANTER, HEALER, SIEGE_WEAPON, LUCK_BONUS, MORALE_BONUS, HYPNOTIZED, + ATTACK_BONUS /*subtype: -1 - any attack, 0 - melee, 1 - ranged*/, + DEFENCE_BONUS /*subtype: -1 - any attack, 0 - melee, 1 - ranged*/, + SPEED_BONUS /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - substracted*/, + HP_BONUS, ENCHANTER, HEALER, SIEGE_WEAPON, LUCK_BONUS, MORALE_BONUS, HYPNOTIZED, ADDITIONAL_RETAILATION /*value - number of additional retailations*/, MAGIC_MIRROR /* value - chance of redirecting in %*/, - SUMMONED, ALWAYS_MINUMUM_DAMAGE /*unit does its minimum damage from range; -1 - any attack, 0 - melee, 1 - ranged*/, - ALWAYS_MAXIMUM_DAMAGE /*eg. bless effect, -1 - any attack, 0 - melee, 1 - ranged*/, - ATTACKS_NEAREST_CREATURE /*while in berserk*/, IN_FRENZY, + SUMMONED, + ALWAYS_MINUMUM_DAMAGE /*unit does its minimum damage from range; subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative anti-bonus for dmg in % [eg 20 means that creature will inflict 80% of normal dmg]*/, + ALWAYS_MAXIMUM_DAMAGE /*eg. bless effect, subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative bonus for dmg in %*/, + ATTACKS_NEAREST_CREATURE /*while in berserk*/, + IN_FRENZY /*value - level*/, SLAYER /*value - level*/, - FORGETFULL /*forgetfullnes spell effect*/, + FORGETFULL /*forgetfullnes spell effect, value - level*/, CLONED, NOT_ACTIVE }; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index c9c1cf346..4a2e94f2a 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2130,11 +2130,13 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) || !curStack->hasFeatureOfType(StackFeature::SHOOTER) //our stack is shooting unit ) break; - for(int g=0; geffects.size(); ++g) - { - if(61 == curStack->effects[g].id) //forgetfulness - break; - } + //for(int g=0; geffects.size(); ++g) + //{ + // if(61 == curStack->effects[g].id) //forgetfulness + // break; + //} + if(curStack->hasFeatureOfType(StackFeature::FORGETFULL)) //forgetfulness + break; sendAndApply(&StartAction(ba)); //start shooting