bool ActionSpellSetGuardian(Heroes & hero, const Spell & spell, u8 id)
{
    Maps::Tiles & tile = world.GetTiles(hero.GetIndex());

    if(MP2::OBJ_MINES != tile.GetObject(false))
    {
        Dialog::Message("", _("You must be standing on the entrance to a mine (sawmills and alchemists don't count) to cast this spell."), Font::BIG, Dialog::OK);
        return false;
    }

    const u16 count = hero.GetPower() * spell.ExtraValue();

    if(count)
    {
        Maps::TilesAddon* addon = tile.FindObject(MP2::OBJ_MINES);

        if(addon)
            addon->tmp = spell();

        if(spell == Spell::HAUNT)
        {
            world.CaptureObject(tile.GetIndex(), Color::UNUSED);
            tile.SetObject(MP2::OBJ_ABANDONEDMINE);
        }

        Army::Troop troop = world.GetCapturedObject(tile.GetIndex()).GetTroop();
        troop.Set(Monster(spell), count);
    }

    return false;
}
bool ActionSpellDimensionDoor(Heroes & hero)
{
    const u8 distance = Spell::CalculateDimensionDoorDistance(hero.GetPower(), hero.GetArmy().GetHitPoints());

    Interface::Basic & I = Interface::Basic::Get();
    Cursor & cursor = Cursor::Get();

    // center hero
    cursor.Hide();
    I.gameArea.SetCenter(hero.GetCenter());
    GameFocus::SetRedraw();
    I.Redraw();

    const s32 src = hero.GetIndex();
    // get destination
    const s32 dst = I.GetDimensionDoorDestination(src, distance, hero.isShipMaster());

    if(Maps::isValidAbsIndex(src) && Maps::isValidAbsIndex(dst))
    {
        AGG::PlaySound(M82::KILLFADE);
        hero.GetPath().Reset();
        hero.FadeOut();

        hero.SpellCasted(Spell::DIMENSIONDOOR);

        cursor.Hide();
        hero.Move2Dest(dst, true);

        I.gameArea.SetCenter(hero.GetCenter());
        GameFocus::SetRedraw();
        I.Redraw();

        AGG::PlaySound(M82::KILLFADE);
        hero.FadeIn();

        hero.ActionNewPosition();

        return false; /* SpellCasted apply */
    }

    return false;
}
Dialog::answer_t PocketPC::HeroesOpenDialog(Heroes & hero, bool readonly)
{
    Cursor & cursor = Cursor::Get();
    Display & display = Display::Get();
    LocalEvent & le = LocalEvent::Get();

    cursor.Hide();
    cursor.SetThemes(cursor.POINTER);

    const u16 window_w = 320;
    const u16 window_h = 224;

    Dialog::FrameBorder frameborder;
    frameborder.SetPosition((display.w() - window_w) / 2 - BORDERWIDTH, (display.h() - window_h) / 2 - BORDERWIDTH, window_w, window_h);
    frameborder.Redraw();

    const Rect & dst_rt = frameborder.GetArea();
    const Sprite & background = AGG::GetICN(ICN::STONEBAK, 0);
    const Sprite & backSprite = AGG::GetICN(ICN::SWAPWIN, 0);
    background.Blit(Rect(0, 0, window_w, window_h), dst_rt);

    // portrait
    AGG::GetICN(ICN::BRCREST, 6).Blit(dst_rt.x + 8, dst_rt.y, display);
    hero.GetPortrait50x46().Blit(dst_rt.x + 12, dst_rt.y + 4, display);

    // name
    std::string message = _("%{name} the %{race} ( Level %{level} )");
    String::Replace(message, "%{name}", hero.GetName());
    String::Replace(message, "%{race}", Race::String(hero.GetRace()));
    String::Replace(message, "%{level}", hero.GetLevel());
    Text text(message, Font::SMALL);
    text.Blit(dst_rt.x + 73, dst_rt.y + 1);

    // experience
    ExperienceIndicator experienceInfo(hero);
    experienceInfo.SetPos(Point(dst_rt.x + 205, dst_rt.y + 14));
    experienceInfo.Redraw();

    // spell points
    SpellPointsIndicator spellPointsInfo(hero);
    spellPointsInfo.SetPos(Point(dst_rt.x + 238, dst_rt.y + 16));
    spellPointsInfo.Redraw();

    // morale
    MoraleIndicator moraleIndicator(hero);
    moraleIndicator.SetPos(Point(dst_rt.x + 280, dst_rt.y + 20));
    moraleIndicator.Redraw();

    // luck
    LuckIndicator luckIndicator(hero);
    luckIndicator.SetPos(Point(dst_rt.x + 280, dst_rt.y + 60));
    luckIndicator.Redraw();

    // prim skill
    const Rect ras(dst_rt.x + 74, dst_rt.y + 14, 34, 34);
    backSprite.Blit(Rect(216, 51, ras.w, ras.h),  ras);
    text.Set(GetString(hero.GetAttack()));
    text.Blit(dst_rt.x + 74 + (34 - text.w()) / 2, dst_rt.y + 47);

    const Rect rds(dst_rt.x + 107, dst_rt.y + 14, 34, 34);
    backSprite.Blit(Rect(216, 84, rds.w, rds.h),  rds);
    text.Set(GetString(hero.GetDefense()));
    text.Blit(dst_rt.x + 107 + (34 - text.w()) / 2, dst_rt.y + 47);

    const Rect rps(dst_rt.x + 140, dst_rt.y + 14, 34, 34);
    backSprite.Blit(Rect(216, 117, rps.w, rps.h), rps);
    text.Set(GetString(hero.GetPower()));
    text.Blit(dst_rt.x + 140 + (34 - text.w()) / 2, dst_rt.y + 47);

    const Rect rks(dst_rt.x + 173, dst_rt.y + 14, 34, 34);
    backSprite.Blit(Rect(216, 150, rks.w, rks.h), rks);
    text.Set(GetString(hero.GetKnowledge()));
    text.Blit(dst_rt.x + 173 + (34 - text.w()) / 2, dst_rt.y + 47);

    // sec skill
    backSprite.Blit(Rect(21, 198, 267, 36), dst_rt.x + 7, dst_rt.y + 57);
    // secondary skill
    SecondarySkillBar secskill_bar;
    secskill_bar.SetPos(dst_rt.x + 9, dst_rt.y + 59);
    secskill_bar.SetUseMiniSprite();
    secskill_bar.SetInterval(1);
    secskill_bar.SetSkills(hero.GetSecondarySkills());
    secskill_bar.Redraw();

    // army bar
    const Rect rt1(36, 267, 43, 53);
    Surface sfb1(rt1.w, rt1.h);
    backSprite.Blit(rt1, 0, 0, sfb1);
    Surface sfc1(rt1.w, rt1.h - 10);
    Cursor::DrawCursor(sfc1, 0xd6, true);

    SelectArmyBar selectArmy;
    selectArmy.SetArmy(hero.GetArmy());
    selectArmy.SetPos(dst_rt.x + 50, dst_rt.y + 170);
    selectArmy.SetInterval(2);
    selectArmy.SetBackgroundSprite(sfb1);
    selectArmy.SetCursorSprite(sfc1);
    selectArmy.SetUseMons32Sprite();
    selectArmy.SetSaveLastTroop();
    if(readonly) selectArmy.SetReadOnly();
    const Castle* castle = hero.inCastle();
    if(castle) selectArmy.SetCastle(*castle);
    selectArmy.Redraw();
            
    // art bar
    const Rect rt2(23, 347, 34, 34);
    Surface sfb2(rt2.w, rt2.h);
    backSprite.Blit(rt2, 0, 0, sfb2);
    Surface sfc2(rt2.w, rt2.h);
    Cursor::DrawCursor(sfc2, 0xd6, true);

    SelectArtifactsBar selectArtifacts(hero);
    selectArtifacts.SetPos(dst_rt.x + 37, dst_rt.y + 95);
    selectArtifacts.SetInterval(2);
    selectArtifacts.SetBackgroundSprite(sfb2);
    selectArtifacts.SetCursorSprite(sfc2);
    selectArtifacts.SetUseArts32Sprite();
    if(readonly) selectArtifacts.SetReadOnly();
    selectArtifacts.Redraw();

    Button buttonDismiss(dst_rt.x + dst_rt.w / 2 - 160, dst_rt.y + dst_rt.h - 125, ICN::HSBTNS, 0, 1);
    Button buttonExit(dst_rt.x + dst_rt.w / 2 + 130, dst_rt.y + dst_rt.h - 125, ICN::HSBTNS, 2, 3);

    Button buttonPrev(dst_rt.x + 34, dst_rt.y + 200, ICN::TRADPOST, 3, 4);
    Button buttonNext(dst_rt.x + 275, dst_rt.y + 200, ICN::TRADPOST, 5, 6);

    if(castle || readonly)
    {
	buttonDismiss.Press();
        buttonDismiss.SetDisable(true);
    }

    if(readonly || 2 > world.GetKingdom(hero.GetColor()).GetHeroes().size())
    {
	buttonNext.Press();
	buttonPrev.Press();
        buttonNext.SetDisable(true);
        buttonPrev.SetDisable(true);
    }

    buttonDismiss.Draw();
    buttonExit.Draw();
    buttonNext.Draw();
    buttonPrev.Draw();

    cursor.Show();
    display.Flip();

    while(le.HandleEvents())
    {
        le.MousePressLeft(buttonNext) ? buttonNext.PressDraw() : buttonNext.ReleaseDraw();
        le.MousePressLeft(buttonPrev) ? buttonPrev.PressDraw() : buttonPrev.ReleaseDraw();
        le.MousePressLeft(buttonExit) ? buttonExit.PressDraw() : buttonExit.ReleaseDraw();
        if(buttonDismiss.isEnable()) le.MousePressLeft(buttonDismiss) ? buttonDismiss.PressDraw() : buttonDismiss.ReleaseDraw();

        if(buttonNext.isEnable() && le.MouseClickLeft(buttonNext)) return Dialog::NEXT;
        else
        if(buttonPrev.isEnable() && le.MouseClickLeft(buttonPrev)) return Dialog::PREV;
	else
        // exit
        if(le.MouseClickLeft(buttonExit) ||
		Game::HotKeyPress(Game::EVENT_DEFAULT_EXIT)) return Dialog::CANCEL;
	else
        // dismiss
	if(buttonDismiss.isEnable() && le.MouseClickLeft(buttonDismiss) &&
	    Dialog::YES == Dialog::Message(hero.GetName(), _("Are you sure you want to dismiss this Hero?"), Font::BIG, Dialog::YES | Dialog::NO))
        { return Dialog::DISMISS; }

        // primary click info
        if(le.MouseClickLeft(ras)) Dialog::Message(_("Attack Skill"), _("Your attack skill is a bonus added to each creature's attack skill."), Font::BIG, Dialog::OK);
        else
        if(le.MouseClickLeft(rds)) Dialog::Message(_("Defense Skill"), _("Your defense skill is a bonus added to each creature's defense skill."), Font::BIG, Dialog::OK);
        else
        if(le.MouseClickLeft(rps)) Dialog::Message(_("Spell Power"), _("Your spell power determines the length or power of a spell."), Font::BIG, Dialog::OK);
        else
        if(le.MouseClickLeft(rks)) Dialog::Message(_("Knowledge"), _("Your knowledge determines how many spell points your hero may have. Under normal cirumstances, a hero is limited to 10 spell points per level of knowledge."), Font::BIG, Dialog::OK);

	if(le.MouseCursor(secskill_bar.GetArea())) secskill_bar.QueueEventProcessing();

        // selector troops event
        if(le.MouseCursor(selectArmy.GetArea()))
        {
            if(selectArtifacts.isSelected()) selectArtifacts.Reset();
	    if(SelectArmyBar::QueueEventProcessing(selectArmy))
            {
                cursor.Hide();
                moraleIndicator.Redraw();
                luckIndicator.Redraw();
                cursor.Show();
        	display.Flip();
            }
        }

        // selector artifacts event
        if(le.MouseCursor(selectArtifacts.GetArea()))
        {
            if(selectArmy.isSelected()) selectArmy.Reset();
            SelectArtifactsBar::QueueEventProcessing(selectArtifacts);
        }

        if(le.MouseCursor(moraleIndicator.GetArea())) MoraleIndicator::QueueEventProcessing(moraleIndicator);
        else
        if(le.MouseCursor(luckIndicator.GetArea())) LuckIndicator::QueueEventProcessing(luckIndicator);
        else
	if(le.MouseCursor(experienceInfo.GetArea())) experienceInfo.QueueEventProcessing();
        else
	if(le.MouseCursor(spellPointsInfo.GetArea())) spellPointsInfo.QueueEventProcessing();
    }

    return Dialog::ZERO;
}
void Dialog::QuickInfo(const Heroes & hero)
{
    Display & display = Display::Get();

    Cursor & cursor = Cursor::Get();
    cursor.Hide();

    const ICN::icn_t qwikhero = ICN::QWIKHERO;
    AGG::PreloadObject(qwikhero);

    // image box
    const Sprite &box = AGG::GetICN(qwikhero, 0);
    const Interface::GameArea & gamearea = Interface::GameArea::Get();
    const Rect ar(BORDERWIDTH, BORDERWIDTH, gamearea.GetArea().w, gamearea.GetArea().h);

    LocalEvent & le = LocalEvent::Get();
    const Point & mp = le.GetMouseCursor();
    
    Rect cur_rt; 
    u16 mx = (mp.x - BORDERWIDTH) / TILEWIDTH;
    mx *= TILEWIDTH;
    u16 my = (mp.y - BORDERWIDTH) / TILEWIDTH;
    my *= TILEWIDTH;

    // top left
    if(mx <= ar.x + ar.w / 2 && my <= ar.y + ar.h / 2)
	cur_rt = Rect(mx + TILEWIDTH, my + TILEWIDTH, box.w(), box.h());
    else
    // top right
    if(mx > ar.x + ar.w / 2 && my <= ar.y + ar.h / 2)
	cur_rt = Rect(mx - box.w(), my + TILEWIDTH, box.w(), box.h());
    else
    // bottom left
    if(mx <= ar.x + ar.w / 2 && my > ar.y + ar.h / 2)
	cur_rt = Rect(mx + TILEWIDTH, my - box.h(), box.w(), box.h());
    else
    // bottom right
	cur_rt = Rect(mx - box.w(), my - box.h(), box.w(), box.h());

    if(Settings::Get().QVGA())
    {
	cur_rt = Rect((display.w() - box.w()) / 2, (display.h() - box.h()) / 2, box.w(), box.h());
    }
    
    Background back(cur_rt);
    back.Save();

    display.Blit(box, cur_rt.x, cur_rt.y);

    cur_rt = Rect(back.GetRect().x + 28 , back.GetRect().y + 10, 146, 144);
    Point dst_pt;
    Text text;

    // heroes name
    text.Set(hero.GetName(), Font::SMALL);
    dst_pt.x = cur_rt.x + (cur_rt.w - text.w()) / 2;
    dst_pt.y = cur_rt.y + 2;
    text.Blit(dst_pt);

    // mini port heroes
    const Surface & port = hero.GetPortrait30x22();
    dst_pt.x = cur_rt.x + (cur_rt.w - port.w()) / 2;
    dst_pt.y += 15;
    display.Blit(port, dst_pt);

    // color flags
    u8 index = 0;

    switch(hero.GetColor())
    {
	case Color::BLUE:	index = 0; break;
	case Color::GREEN:	index = 2; break;
	case Color::RED:	index = 4; break;
	case Color::YELLOW:	index = 6; break;
	case Color::ORANGE:	index = 8; break;
	case Color::PURPLE:	index = 10; break;
	case Color::GRAY:	index = 12; break;
    }

    const Sprite & l_flag = AGG::GetICN(ICN::FLAG32, index);
    dst_pt.x = cur_rt.x + (cur_rt.w - 40) / 2 - l_flag.w();
    display.Blit(l_flag, dst_pt);

    const Sprite & r_flag = AGG::GetICN(ICN::FLAG32, index + 1);
    dst_pt.x = cur_rt.x + (cur_rt.w + 40) / 2;
    display.Blit(r_flag, dst_pt);
    std::string message;

    // attack
    message = _("Attack");
    message += ":";
    text.Set(message);
    dst_pt.x = cur_rt.x + 35;
    dst_pt.y += port.h() + 4;
    text.Blit(dst_pt);

    message.clear();
    String::AddInt(message, hero.GetAttack());
    text.Set(message);
    dst_pt.x += 75;
    text.Blit(dst_pt);

    // defense
    message = _("Defense");
    message += ":";
    text.Set(message);
    dst_pt.x = cur_rt.x + 35;
    dst_pt.y += 12;
    text.Blit(dst_pt);

    message.clear();
    String::AddInt(message, hero.GetDefense());
    text.Set(message);
    dst_pt.x += 75;
    text.Blit(dst_pt);

    // power
    message = _("Spell Power");
    message += ":";
    text.Set(message);
    dst_pt.x = cur_rt.x + 35;
    dst_pt.y += 12;
    text.Blit(dst_pt);

    message.clear();
    String::AddInt(message, hero.GetPower());
    text.Set(message);
    dst_pt.x += 75;
    text.Blit(dst_pt);

    // knowledge
    message = _("Knowledge");
    message += ":";
    text.Set(message);
    dst_pt.x = cur_rt.x + 35;
    dst_pt.y += 12;
    text.Blit(dst_pt);

    message.clear();
    String::AddInt(message, hero.GetKnowledge());
    text.Set(message);
    dst_pt.x += 75;
    text.Blit(dst_pt);
    
    // spell point
    message = _("Spell Points");
    message += ":";
    text.Set(message);
    dst_pt.x = cur_rt.x + 35;
    dst_pt.y += 12;
    text.Blit(dst_pt);

    message.clear();
    String::AddInt(message, hero.GetSpellPoints());
    message += "/";
    String::AddInt(message, hero.GetMaxSpellPoints());
    text.Set(message);
    dst_pt.x += 75;
    text.Blit(dst_pt);

    // draw monster sprite in one string
    const u8 mycolor = Settings::Get().MyColor();
    const bool hide = mycolor != hero.GetColor() && !world.GetKingdom(mycolor).Modes(Kingdom::IDENTIFYHERO);
    hero.GetArmy().DrawMons32Line(cur_rt.x - 5, cur_rt.y + 114, 160, 0, 0, hide);

    cursor.Show();
    display.Flip();

    // quick info loop
    while(le.HandleEvents() && le.MousePressRight());

    // restore background
    cursor.Hide();
    back.Restore();
    cursor.Show();
    display.Flip();
}