Battle::Catapult::Catapult(const HeroBase & hero, bool fortification) : cat_shots(1), cat_first(20), cat_miss(true) /*, cat_fort(fortification) */ { switch(hero.GetLevelSkill(Skill::Secondary::BALLISTICS)) { case Skill::Level::BASIC: cat_first = 40; cat_miss = false; break; case Skill::Level::ADVANCED: cat_first = 80; cat_shots += 1; cat_miss = false; break; case Skill::Level::EXPERT: cat_first = 100; cat_shots += 1; cat_miss = false; break; default: break; } u32 acount = hero.HasArtifact(Artifact::BALLISTA); if(acount) cat_shots += acount * Artifact(Artifact::BALLISTA).ExtraValue(); }
void Battle::PickupArtifactsAction(HeroBase & hero1, HeroBase & hero2, bool local) { BagArtifacts & bag1 = hero1.GetBagArtifacts(); BagArtifacts & bag2 = hero2.GetBagArtifacts(); for(u8 ii = 0; ii < bag2.size(); ++ii) { Artifact & art = bag2[ii]; if(art.isUltimate()) { art = Artifact::UNKNOWN; } else if(art() != Artifact::UNKNOWN && art() != Artifact::MAGIC_BOOK) { BagArtifacts::iterator it = std::find(bag1.begin(), bag1.end(), Artifact((Artifact::UNKNOWN))); if(bag1.end() != it) { *it = art; if(local) { Game::PlayPickupSound(); Dialog::ArtifactInfo(_("You have captured an enemy artifact!"), "", art); } } art = Artifact::UNKNOWN; } } }
void Battle::EagleEyeSkillAction(HeroBase & hero, const SpellStorage & spells, bool local) { if(spells.empty() || !hero.HaveSpellBook()) return; SpellStorage new_spells; new_spells.reserve(10); const Skill::Secondary eagleeye(Skill::Secondary::EAGLEEYE, hero.GetLevelSkill(Skill::Secondary::EAGLEEYE)); // filter spells for(SpellStorage::const_iterator it = spells.begin(); it != spells.end(); ++it) { const Spell & sp = *it; if(!hero.HaveSpell(sp)) { switch(eagleeye.Level()) { case Skill::Level::BASIC: // 20% if(3 > sp.Level() && eagleeye.GetValues() >= Rand::Get(1, 100)) new_spells.push_back(sp); break; case Skill::Level::ADVANCED: // 30% if(4 > sp.Level() && eagleeye.GetValues() >= Rand::Get(1, 100)) new_spells.push_back(sp); break; case Skill::Level::EXPERT: // 40% if(5 > sp.Level() && eagleeye.GetValues() >= Rand::Get(1, 100)) new_spells.push_back(sp); break; default: break; } } } // add new spell for(SpellStorage::const_iterator it = new_spells.begin(); it != new_spells.end(); ++it) { const Spell & sp = *it; if(local) { std::string msg = _("Through eagle-eyed observation, %{name} is able to learn the magic spell %{spell}."); String::Replace(msg, "%{name}", hero.GetName()); String::Replace(msg, "%{spell}", sp.GetName()); Game::PlayPickupSound(); Dialog::SpellInfo("", msg, sp); } } hero.AppendSpellsToBook(new_spells, true); }
bool Battle::AIApplySpell(const Spell & spell, const Unit* b, const HeroBase & hero, Actions & a) { u8 mass = Spell::NONE; switch(spell()) { case Spell::CURE: mass = Spell::MASSCURE; break; case Spell::HASTE: mass = Spell::MASSHASTE; break; case Spell::SLOW: mass = Spell::MASSSLOW; break; case Spell::BLESS: mass = Spell::MASSBLESS; break; case Spell::CURSE: mass = Spell::MASSCURSE; break; case Spell::DISPEL: mass = Spell::MASSDISPEL; break; case Spell::SHIELD: mass = Spell::MASSSHIELD; break; default: break; } if(mass != Spell::NONE && AIApplySpell(mass, b, hero, a)) return true; if(hero.CanCastSpell(spell) && (!b || b->AllowApplySpell(spell, &hero))) { a.push_back(Battle::Command(MSG_BATTLE_CAST, spell(), (b ? b->GetHeadIndex() : -1))); return true; } return false; }
void Battle::NecromancySkillAction(HeroBase & hero, u32 killed, bool local) { Army & army = hero.GetArmy(); if(0 == killed || (army.isFullHouse() && !army.HasMonster(Monster::SKELETON))) return; // check necromancy shrine build u16 percent = 10 * world.GetKingdom(army.GetColor()).GetCountNecromancyShrineBuild(); // check artifact u8 acount = hero.HasArtifact(Artifact::SPADE_NECROMANCY); if(acount) percent += acount * 10; // fix over 60% if(percent > 60) percent = 60; percent += hero.GetSecondaryValues(Skill::Secondary::NECROMANCY); // hard fix overflow if(percent > 90) percent = 90; const Monster mons(Monster::SKELETON); const u32 count = Monster::GetCountFromHitPoints(Monster::SKELETON, mons.GetHitPoints() * killed * percent / 100); army.JoinTroop(mons, count); if(local) { std::string msg = _("Practicing the dark arts of necromancy, you are able to raise %{count} of the enemy's dead to return under your service as %{monster}"); String::Replace(msg, "%{count}", count); String::Replace(msg, "%{monster}", mons.GetMultiName()); Surface sf1(40, 45); const Sprite & sf2 = AGG::GetICN(ICN::MONS32, mons.GetSpriteIndex()); sf2.Blit((sf1.w() - sf2.w()) / 2, 0, sf1); Text text(GetString(count), Font::SMALL); text.Blit((sf1.w() - text.w()) / 2, sf2.h() + 3, sf1); Game::PlayPickupSound(); Dialog::SpriteInfo("", msg, sf1); } DEBUG(DBG_BATTLE, DBG_TRACE, "raise: " << count << mons.GetMultiName()); }
int ArtifactsModifiersResult(int type, const u8* arts, u32 size, const HeroBase & base, std::string* strs) { int result = 0; for(u32 ii = 0; ii < size; ++ii) { const Artifact art(arts[ii]); if(art.isValid()) { int acount = base.HasArtifact(art); if(acount) { s32 mod = art.ExtraValue(); switch(art()) { case Artifact::SWORD_BREAKER: if(type == MDF_ATTACK) mod = 1; break; // power case Artifact::BROACH_SHIELDING: if(type == MDF_POWER) mod = -2; break; // morale/luck case Artifact::BATTLE_GARB: if(type == MDF_MORALE || type == MDF_LUCK) mod = 10; break; case Artifact::MASTHEAD: if(type == MDF_MORALE || type == MDF_LUCK) mod = base.Modes(Heroes::SHIPMASTER) ? art.ExtraValue() : 0; break; // morale case Artifact::FIZBIN_MISFORTUNE: if(type == MDF_MORALE) mod = -art.ExtraValue(); break; default: break; } result += mod * acount; if(strs && mod) { strs->append(art.GetName()); StringAppendModifiers(*strs, mod); strs->append("\n"); } } } } return result; }
s16 Battle::AIAreaSpellDst(const HeroBase & hero) { std::map<s16, u8> dstcount; Arena* arena = GetArena(); Units enemies(arena->GetForce(hero.GetColor(), true), true); for(Units::const_iterator it1 = enemies.begin(); it1 != enemies.end(); ++it1) { const Indexes around = Board::GetAroundIndexes(**it1); for(Indexes::const_iterator it2 = around.begin(); it2 != around.end(); ++it2) dstcount[*it2] += 1; } // find max std::map<s16, u8>::const_iterator max = std::max_element(dstcount.begin(), dstcount.end(), MaxDstCount); return max != dstcount.end() ? (*max).first : -1; }
void AI::HeroesPreBattle(HeroBase & hero) { Castle* castle = world.GetCastle(hero.GetCenter()); if(castle && hero.GetType() != HeroBase::CAPTAIN) hero.GetArmy().JoinTroops(castle->GetArmy()); }
bool Battle2::DialogBattleSurrender(const HeroBase & hero, u32 cost) { Display & display = Display::Get(); Cursor & cursor = Cursor::Get(); LocalEvent & le = LocalEvent::Get(); Settings & conf = Settings::Get(); cursor.Hide(); cursor.SetThemes(Cursor::POINTER); const Sprite & dialog = AGG::GetICN(conf.EvilInterface() ? ICN::SURDRBKE : ICN::SURDRBKG, 0); Rect pos_rt; pos_rt.x = (display.w() - dialog.w() + 16) / 2; pos_rt.y = (display.h() - dialog.h() + 16) / 2; pos_rt.w = dialog.w(); pos_rt.h = dialog.h(); Background back(pos_rt); back.Save(); display.Blit(dialog, pos_rt.x, pos_rt.y); const ICN::icn_t icn = conf.EvilInterface() ? ICN::SURRENDE : ICN::SURRENDR; Button btnAccept(pos_rt.x + 90, pos_rt.y + 150, icn, 0, 1); Button btnDecline(pos_rt.x + 295, pos_rt.y + 150, icn, 2, 3); btnAccept.Draw(); btnDecline.Draw(); const Sprite & window = AGG::GetICN(icn, 4); display.Blit(window, pos_rt.x + 54, pos_rt.y + 30); display.Blit(Portrait::Get(hero, Portrait::BIG), pos_rt.x + 58, pos_rt.y + 38); std::string str = _("%{name} states:"); String::Replace(str, "%{name}", hero.GetName()); Text text(str, Font::BIG); text.Blit(pos_rt.x + 320 - text.w() / 2, pos_rt.y + 30); str = _("I will accept your surrender and grant you and your toops safe passage for the price of %{price} gold."); String::Replace(str, "%{price}", cost); TextBox box(str, Font::BIG, 275); box.Blit(pos_rt.x + 175, pos_rt.y + 65); u8 result = 0; cursor.Show(); display.Flip(); while(le.HandleEvents() && !result) { le.MousePressLeft(btnAccept) ? btnAccept.PressDraw() : btnAccept.ReleaseDraw(); le.MousePressLeft(btnDecline) ? btnDecline.PressDraw() : btnDecline.ReleaseDraw(); if(le.MouseClickLeft(btnAccept)) result = 1; // exit if(le.KeyPress(KEY_ESCAPE) || le.MouseClickLeft(btnDecline)) break; } cursor.Hide(); back.Restore(); cursor.Show(); display.Flip(); return result; }
u8 Battle2::Arena::DialogBattleHero(const HeroBase & hero) const { Display & display = Display::Get(); Cursor & cursor = Cursor::Get(); LocalEvent & le = LocalEvent::Get(); Settings & conf = Settings::Get(); cursor.Hide(); cursor.SetThemes(Cursor::POINTER); const bool readonly = conf.MyColor() != hero.GetColor(); const Sprite & dialog = AGG::GetICN((conf.EvilInterface() ? ICN::VGENBKGE : ICN::VGENBKG), 0); Rect pos_rt; pos_rt.x = (display.w() - dialog.w()) / 2; pos_rt.y = (display.h() - dialog.h()) / 2; pos_rt.w = dialog.w(); pos_rt.h = dialog.h(); Background back(pos_rt); back.Save(); display.Blit(dialog, pos_rt.x, pos_rt.y); display.Blit(Portrait::Get(hero, Portrait::BIG), pos_rt.x + 27, pos_rt.y + 42); u8 col = (Color::GRAY == hero.GetColor() ? 1 : Color::GetIndex(hero.GetColor()) + 1); display.Blit(AGG::GetICN(ICN::VIEWGEN, col), pos_rt.x + 148, pos_rt.y + 36); Point tp(pos_rt); std::string str; Text text; text.Set(Font::SMALL); str = _("%{name} the %{race}"); String::Replace(str, "%{name}", hero.GetName()); String::Replace(str, "%{race}", Race::String(hero.GetRace())); text.Set(str); tp.x = pos_rt.x + (pos_rt.w - text.w()) / 2; tp.y += 10; text.Blit(tp); str = _("Attack") + std::string(": "); String::AddInt(str, hero.GetAttack()); text.Set(str); tp.x = pos_rt.x + 205 - text.w() / 2; tp.y = pos_rt.y + 40; text.Blit(tp); str = _("Defense") + std::string(": "); String::AddInt(str, hero.GetDefense()); text.Set(str); tp.x = pos_rt.x + 205 - text.w() / 2; tp.y = pos_rt.y + 51; text.Blit(tp); str = _("Spell Power") + std::string(": "); String::AddInt(str, hero.GetPower()); text.Set(str); tp.x = pos_rt.x + 205 - text.w() / 2; tp.y = pos_rt.y + 62; text.Blit(tp); str = _("Knowledge") + std::string(": "); String::AddInt(str, hero.GetKnowledge()); text.Set(str); tp.x = pos_rt.x + 205 - text.w() / 2; tp.y = pos_rt.y + 73; text.Blit(tp); str = _("Morale") + std::string(": ") + Morale::String(hero.GetMorale()); text.Set(str); tp.x = pos_rt.x + 205 - text.w() / 2; tp.y = pos_rt.y + 84; text.Blit(tp); str = _("Luck") + std::string(": ") + Luck::String(hero.GetLuck()); text.Set(str); tp.x = pos_rt.x + 205 - text.w() / 2; tp.y = pos_rt.y + 95; text.Blit(tp); str = _("Spell Points") + std::string(": "); String::AddInt(str, hero.GetSpellPoints()); str += "/"; String::AddInt(str, hero.GetMaxSpellPoints()); text.Set(str); tp.x = pos_rt.x + 205 - text.w() / 2; tp.y = pos_rt.y + 117; text.Blit(tp); Button btnCast(pos_rt.x + 30, pos_rt.y + 148, ICN::VIEWGEN, 9, 10); Button btnRetreat(pos_rt.x + 89, pos_rt.y + 148, ICN::VIEWGEN, 11, 12); Button btnSurrender(pos_rt.x + 148, pos_rt.y + 148, ICN::VIEWGEN, 13, 14); Button btnClose(pos_rt.x + 207, pos_rt.y + 148, ICN::VIEWGEN, 15, 16); btnCast.SetDisable(readonly || !hero.HaveSpellBook() || hero.Modes(Heroes::SPELLCASTED)); btnRetreat.SetDisable(readonly || !CanRetreatOpponent(hero.GetColor())); btnSurrender.SetDisable(readonly || !CanSurrenderOpponent(hero.GetColor())); btnCast.Draw(); btnRetreat.Draw(); btnSurrender.Draw(); btnClose.Draw(); if(!conf.QVGA()) { Surface shadow(btnCast.w, btnCast.h); shadow.Fill(0, 0, 0); shadow.SetAlpha(80); if(btnCast.isDisable()) display.Blit(shadow, btnCast); if(btnRetreat.isDisable()) display.Blit(shadow, btnRetreat); if(btnSurrender.isDisable()) display.Blit(shadow, btnSurrender); } u8 result = 0; cursor.Show(); display.Flip(); while(le.HandleEvents() && !result) { btnCast.isEnable() && le.MousePressLeft(btnCast) ? btnCast.PressDraw() : btnCast.ReleaseDraw(); btnRetreat.isEnable() && le.MousePressLeft(btnRetreat) ? btnRetreat.PressDraw() : btnRetreat.ReleaseDraw(); btnSurrender.isEnable() && le.MousePressLeft(btnSurrender) ? btnSurrender.PressDraw() : btnSurrender.ReleaseDraw(); le.MousePressLeft(btnClose) ? btnClose.PressDraw() : btnClose.ReleaseDraw(); if(le.KeyPress(KEY_c) || (btnCast.isEnable() && le.MouseClickLeft(btnCast))) result = 1; if(le.KeyPress(KEY_r) || (btnRetreat.isEnable() && le.MouseClickLeft(btnRetreat))) result = 2; if(le.KeyPress(KEY_s) || (btnSurrender.isEnable() && le.MouseClickLeft(btnSurrender))) result = 3; if(le.MousePressRight(btnCast)) Dialog::Message(_("Cast Spell"), _("Cast a magical spell. You may only cast one spell per combat round. The round is reset when every creature has had a turn"), Font::BIG); else if(le.MousePressRight(btnRetreat)) Dialog::Message(_("Retreat"), _("Retreat your hero, abandoning your creatures. Your hero will be available for you to recruit again, however, the hero will have only a novice hero's forces."), Font::BIG); else if(le.MousePressRight(btnSurrender)) Dialog::Message(_("Surrender"), _("Surrendering costs gold. However if you pay the ransom, the hero and all of his or her surviving creatures will be available to recruit again."), Font::BIG); else if(le.MousePressRight(btnClose)) Dialog::Message(_("Cancel"), _("Return to the battle."), Font::BIG); // exit if(le.KeyPress(KEY_ESCAPE) || le.KeyPress(KEY_RETURN) || le.MouseClickLeft(btnClose)) break; } cursor.Hide(); back.Restore(); cursor.Show(); display.Flip(); return result; }
void ExperienceLayer::heroChangeExp(Ref * obj) { HeroBase * heroBase = dynamic_cast<HeroBase *>(obj); int heroExp = 100 * (1 - ((float)(heroBase->getExpValue() - heroBase->getNowExpValue()) /(float) heroBase->getNeedExpValue())); _fillExperience->setPercentage(heroExp); }
void AI::HeroesPreBattle(HeroBase & hero) { Castle* castle = world.GetCastle(hero.GetIndex()); if(castle && hero.GetType() != Skill::Primary::CAPTAIN) hero.GetArmy().JoinTroops(castle->GetArmy()); }