void Interface::Basic::EventDefaultAction(void) { Heroes* hero = GetFocusHeroes(); if(hero) { const Maps::Tiles & tile = world.GetTiles(hero->GetIndex()); // 1. action object if(MP2::isActionObject(hero->GetMapsObject(), hero->isShipMaster()) && (! MP2::isMoveObject(hero->GetMapsObject()) || hero->CanMove())) { hero->Action(hero->GetIndex()); if(MP2::OBJ_STONELIGHTS == tile.GetObject(false) || MP2::OBJ_WHIRLPOOL == tile.GetObject(false)) SetRedraw(REDRAW_HEROES); SetRedraw(REDRAW_GAMEAREA); } else // 2. continue if(hero->GetPath().isValid()) hero->SetMove(true); else // 3. hero dialog Game::OpenHeroesDialog(*hero); } else // 4. town dialog if(GetFocusCastle()) { Game::OpenCastleDialog(*GetFocusCastle()); } }
s32 GetRandomHeroesPosition(Heroes & hero, u32 scoute) { Maps::Indexes v = Maps::GetAroundIndexes(hero.GetIndex(), scoute, true); Maps::Indexes res; v.resize(std::distance(v.begin(), std::remove_if(v.begin(), v.end(), std::ptr_fun(&Maps::TileIsUnderProtection)))); #if defined(ANDROID) const MapsIndexes::const_reverse_iterator crend = v.rend(); for(MapsIndexes::const_reverse_iterator it = v.rbegin(); it != crend && res.size() < 4; ++it) #else for(MapsIndexes::const_reverse_iterator it = v.rbegin(); it != v.rend() && res.size() < 4; ++it) #endif { if(world.GetTiles(*it).isPassable(&hero, Direction::CENTER, true) && hero.GetPath().Calculate(*it)) res.push_back(*it); } const s32 result = res.size() ? *Rand::Get(res) : -1; if(0 <= result) { DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) << ", hero: " << hero.GetName() << ", added task: " << result); } return result; }
bool HeroesTownGate(Heroes & hero, const Castle* castle) { if(castle) { Interface::Basic & I = Interface::Basic::Get(); const s32 src = hero.GetIndex(); const s32 dst = castle->GetIndex(); if(!Maps::isValidAbsIndex(src) || !Maps::isValidAbsIndex(dst)) return false; AGG::PlaySound(M82::KILLFADE); hero.GetPath().Hide(); hero.FadeOut(); Cursor::Get().Hide(); hero.Move2Dest(dst); I.gameArea.SetCenter(hero.GetCenter()); GameFocus::SetRedraw(); I.Redraw(); AGG::PlaySound(M82::KILLFADE); hero.GetPath().Hide(); hero.FadeIn(); // educate spells if(! Settings::Get().ExtHeroLearnSpellsWithDay()) castle->MageGuildEducateHero(hero); return true; } return false; }
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; }
int Interface::Basic::EventDigArtifact(void) { Heroes* hero = GetFocusHeroes(); if(hero) { if(hero->isShipMaster()) Dialog::Message("", _("Try looking on land!!!"), Font::BIG, Dialog::OK); else if(hero->GetMaxMovePoints() <= hero->GetMovePoints()) { if(world.GetTiles(hero->GetIndex()).GoodForUltimateArtifact()) { AGG::PlaySound(M82::DIGSOUND); hero->ResetMovePoints(); if(world.DiggingForUltimateArtifact(hero->GetCenter())) { AGG::PlaySound(M82::TREASURE); const Artifact & ultimate = world.GetUltimateArtifact().GetArtifact(); hero->PickupArtifact(ultimate); std::string msg(_("After spending many hours digging here, you have uncovered the %{artifact}")); StringReplace(msg, "%{artifact}", ultimate.GetName()); Dialog::ArtifactInfo(_("Congratulations!"), msg, ultimate()); // set all obelisks visited Kingdom & kingdom = world.GetKingdom(hero->GetColor()); const MapsIndexes obelisks = Maps::GetObjectPositions(MP2::OBJ_OBELISK, true); for(MapsIndexes::const_iterator it = obelisks.begin(); it != obelisks.end(); ++it) if(!hero->isVisited(world.GetTiles(*it), Visit::GLOBAL)) hero->SetVisited(*it, Visit::GLOBAL); kingdom.PuzzleMaps().Update(kingdom.CountVisitedObjects(MP2::OBJ_OBELISK), world.CountObeliskOnMaps()); } else Dialog::Message("", _("Nothing here. Where could it be?"), Font::BIG, Dialog::OK); Cursor::Get().Hide(); iconsPanel.RedrawIcons(ICON_HEROES); Cursor::Get().Show(); Display::Get().Flip(); // check game over for ultimate artifact return GameOver::Result::Get().LocalCheckGameOver(); } else Dialog::Message("", _("Try searching on clear ground."), Font::BIG, Dialog::OK); } } else Dialog::Message("", _("Digging for artifacts requires a whole day, try again tomorrow."), Font::BIG, Dialog::OK); return Game::CANCEL; }
bool ActionSpellSummonBoat(Heroes & hero) { u8 chance = 0; switch(hero.GetLevelSkill(Skill::Secondary::WISDOM)) { case Skill::Level::BASIC: chance = 50; break; case Skill::Level::ADVANCED: chance = 75; break; case Skill::Level::EXPERT: chance = 100; break; default: chance = 30; break; } const s32 center = hero.GetIndex(); // find water s32 dst_water = -1; const MapsIndexes & v = Maps::ScanAroundObject(center, MP2::OBJ_ZERO); for(MapsIndexes::const_iterator it = v.begin(); it != v.end(); ++it) { if(world.GetTiles(*it).isWater()) { dst_water = *it; break; } } const MapsIndexes & boats = Maps::GetObjectPositions(center, MP2::OBJ_BOAT, false); if(boats.empty()) { DEBUG(DBG_GAME, DBG_WARN, "free boat: " << "not found"); } else { const s32 & src = boats.front(); if(Rand::Get(1, 100) <= chance && Maps::isValidAbsIndex(src) && Maps::isValidAbsIndex(dst_water)) { world.GetTiles(src).SetObject(MP2::OBJ_ZERO); world.GetTiles(dst_water).SetObject(MP2::OBJ_BOAT); } else DialogSpellFailed(Spell::SUMMONBOAT); } return true; }
void AIHeroesAddedRescueTask(Heroes & hero) { AIHero & ai_hero = AIHeroes::Get(hero); Queue & task = ai_hero.sheduled_visit; DEBUG(DBG_AI, DBG_TRACE, hero.GetName()); u32 scoute = hero.GetScoute(); switch(Settings::Get().GameDifficulty()) { case Difficulty::NORMAL: scoute += 2; break; case Difficulty::HARD: scoute += 3; break; case Difficulty::EXPERT: scoute += 4; break; case Difficulty::IMPOSSIBLE:scoute += 6; break; default: break; } // find unchartered territory s32 index = FindUncharteredTerritory(hero, scoute); const Maps::Tiles & tile = world.GetTiles(hero.GetIndex()); if(index < 0) { // check teleports if(MP2::OBJ_STONELIGHTS == tile.GetObject(false) || MP2::OBJ_WHIRLPOOL == tile.GetObject(false)) { AI::HeroesAction(hero, hero.GetIndex()); } else { // random index = GetRandomHeroesPosition(hero, scoute); } } if(0 <= index) task.push_back(index); }
void Interface::Basic::MoveHeroFromArrowKeys(Heroes & hero, int direct) { if(Maps::isValidDirection(hero.GetIndex(), direct)) { s32 dst = Maps::GetDirectionIndex(hero.GetIndex(), direct); const Maps::Tiles & tile = world.GetTiles(dst); bool allow = false; switch(tile.GetObject()) { case MP2::OBJN_CASTLE: { const Castle* to_castle = world.GetCastle(hero.GetCenter()); if(to_castle) { dst = to_castle->GetIndex(); allow = true; } break; } case MP2::OBJ_BOAT: case MP2::OBJ_CASTLE: case MP2::OBJ_HEROES: case MP2::OBJ_MONSTER: allow = true; break; default: allow = (tile.isPassable(&hero, Direction::CENTER, false) || MP2::isActionObject(tile.GetObject(), hero.isShipMaster())); break; } if(allow) ShowPathOrStartMoveHero(&hero, dst); } }
void AI::HeroesActionNewPosition(Heroes & hero) { AIHero & ai_hero = AIHeroes::Get(hero); //AIKingdom & ai_kingdom = AIKingdoms::Get(hero.GetColor()); Queue & task = ai_hero.sheduled_visit; const u8 objs[] = { MP2::OBJ_ARTIFACT, MP2::OBJ_RESOURCE, MP2::OBJ_CAMPFIRE, MP2::OBJ_TREASURECHEST, 0 }; Maps::Indexes pickups = Maps::ScanAroundObjects(hero.GetIndex(), objs); if(pickups.size() && hero.GetPath().isValid() && pickups.end() == std::find(pickups.begin(), pickups.end(), hero.GetPath().GetDestinationIndex())) hero.GetPath().Reset(); for(MapsIndexes::const_iterator it = pickups.begin(); it != pickups.end(); ++it) if(*it != hero.GetPath().GetDestinationIndex()) task.push_front(*it); }
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; }
bool ActionSpellTownGate(Heroes & hero) { const Kingdom & kingdom = world.GetKingdom(hero.GetColor()); const KingdomCastles & castles = kingdom.GetCastles(); KingdomCastles::const_iterator it; const Castle* castle = NULL; const s32 center = hero.GetIndex(); s32 min = -1; // find the nearest castle for(it = castles.begin(); it != castles.end(); ++it) if(*it && !(*it)->GetHeroes().Guest()) { const u16 min2 = Maps::GetApproximateDistance(center, (*it)->GetIndex()); if(0 > min || min2 < min) { min = min2; castle = *it; } } Interface::Basic & I = Interface::Basic::Get(); Cursor & cursor = Cursor::Get(); // center hero cursor.Hide(); I.gameArea.SetCenter(hero.GetCenter()); GameFocus::SetRedraw(); I.Redraw(); if(!castle) { Dialog::Message("", _("No avaialble town. Spell Failed!!!"), Font::BIG, Dialog::OK); return false; } return HeroesTownGate(hero, castle); }
s32 FindUncharteredTerritory(Heroes & hero, const u8 & scoute) { Maps::Indexes v = Maps::GetAroundIndexes(hero.GetIndex(), scoute, true); Maps::Indexes res; v.resize(std::distance(v.begin(), std::remove_if(v.begin(), v.end(), std::ptr_fun(&Maps::TileIsUnderProtection)))); #if (__GNUC__ == 3 && __GNUC_MINOR__ == 4) const MapsIndexes::const_reverse_iterator crend = v.rend(); for(MapsIndexes::const_reverse_iterator it = v.rbegin(); it != crend && res.size() < 4; ++it) #else MapsIndexes::reverse_iterator it = v.rbegin(); for(; it != v.rend() && (res.size() < 4); ++it) #endif { // find fogs if(world.GetTiles(*it).isFog(hero.GetColor()) && world.GetTiles(*it).isPassable(&hero, Direction::CENTER, true) && hero.GetPath().Calculate(*it)) res.push_back(*it); } const s32 result = res.size() ? *Rand::Get(res) : -1; if(0 <= result) { DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) << ", hero: " << hero.GetName() << ", added task: " << result); } return result; }
bool AI::HeroesGetTask(Heroes & hero) { std::vector<s32> results; results.reserve(5); const Settings & conf = Settings::Get(); AIHero & ai_hero = AIHeroes::Get(hero); AIKingdom & ai_kingdom = AIKingdoms::Get(hero.GetColor()); Queue & task = ai_hero.sheduled_visit; IndexObjectMap & ai_objects = ai_kingdom.scans; const u8 objs1[] = { MP2::OBJ_ARTIFACT, MP2::OBJ_RESOURCE, MP2::OBJ_CAMPFIRE, MP2::OBJ_TREASURECHEST, 0 }; const u8 objs2[] = { MP2::OBJ_SAWMILL, MP2::OBJ_MINES, MP2::OBJ_ALCHEMYLAB, 0 }; const u8 objs3[] = { MP2::OBJ_CASTLE, MP2::OBJ_HEROES, MP2::OBJ_MONSTER, 0 }; // rescan path hero.RescanPath(); Castle* castle = hero.inCastle(); // if hero in castle if(castle) { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", in castle"); castle->RecruitAllMonster(); hero.GetArmy().UpgradeTroops(*castle); // recruit army if(hero.Modes(AI::HEROES_HUNTER)) hero.GetArmy().JoinStrongestFromArmy(castle->GetArmy()); else if(hero.Modes(AI::HEROES_SCOUTER)) hero.GetArmy().KeepOnlyWeakestTroops(castle->GetArmy()); DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", " << hero.GetArmy().String()); } // patrol task if(hero.Modes(Heroes::PATROL)) { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", is patrol mode"); // goto patrol center if(hero.GetCenterPatrol() != hero.GetCenter() && hero.GetPath().Calculate(Maps::GetIndexFromAbsPoint(hero.GetCenterPatrol()))) return true; // scan enemy hero if(hero.GetSquarePatrol()) { const Maps::Indexes & results = Maps::ScanAroundObject(Maps::GetIndexFromAbsPoint(hero.GetCenterPatrol()), hero.GetSquarePatrol(), MP2::OBJ_HEROES); for(MapsIndexes::const_iterator it = results.begin(); it != results.end(); ++it) { const Heroes* enemy = world.GetTiles(*it).GetHeroes(); if(enemy && ! enemy->isFriends(hero.GetColor())) { if(hero.GetPath().Calculate(enemy->GetIndex())) { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", find enemy"); return true; } } } } // can pickup objects if(conf.ExtHeroPatrolAllowPickup()) { const Maps::Indexes & results = Maps::ScanAroundObjects(hero.GetIndex(), hero.GetSquarePatrol(), objs1); for(MapsIndexes::const_iterator it = results.begin(); it != results.end(); ++it) if(AI::HeroesValidObject(hero, *it) && hero.GetPath().Calculate(*it)) { ai_objects.erase(*it); DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ": find object: " << MP2::StringObject(world.GetTiles(*it).GetObject()) << "(" << *it << ")"); return true; } } // random move /* // disable move: https://sourceforge.net/tracker/?func=detail&aid=3157397&group_id=96859&atid=616180 { Maps::ScanAroundObject(hero.GetIndex(), hero.GetSquarePatrol(), MP2::OBJ_ZERO); if(results.size()) { std::random_shuffle(results.begin(), results.end()); std::vector<s32>::const_iterator it = results.begin(); for(; it != results.end(); ++it) if(world.GetTiles(*it).isPassable(&hero, Direction::CENTER, true) && hero.GetPath().Calculate(*it)) { DEBUG(DBG_AI, Color::String(hero.GetColor()) << ", Patrol " << hero.GetName() << ": move: " << *it); return; } } } */ hero.SetModes(AI::HEROES_STUPID); return false; } if(ai_hero.fix_loop > 3) { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ": loop"); hero.SetModes(hero.Modes(AI::HEROES_WAITING) ? AI::HEROES_STUPID : AI::HEROES_WAITING); return false; } // primary target if(Maps::isValidAbsIndex(ai_hero.primary_target)) { if(hero.GetIndex() == ai_hero.primary_target) { ai_hero.primary_target = -1; hero.GetPath().Reset(); DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", reset path"); } else { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", primary target: " << ai_hero.primary_target << ", " << MP2::StringObject(world.GetTiles(ai_hero.primary_target).GetObject())); const Castle* castle = NULL; if(NULL != (castle = world.GetCastle(Maps::GetPoint(ai_hero.primary_target))) && NULL != castle->GetHeroes().Guest() && castle->isFriends(hero.GetColor())) { hero.SetModes(AI::HEROES_WAITING); DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", castle busy.."); } // make path if(ai_hero.primary_target != hero.GetPath().GetDestinationIndex() && !hero.GetPath().Calculate(ai_hero.primary_target)) { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", path unknown, primary target reset"); ai_hero.primary_target = -1; } } if(hero.GetPath().isValid()) return true; } // scan heroes and castle const Maps::Indexes & enemies = Maps::ScanAroundObjects(hero.GetIndex(), hero.GetScoute(), objs3); for(MapsIndexes::const_iterator it = enemies.begin(); it != enemies.end(); ++it) if(AIHeroesPriorityObject(hero, *it) && hero.GetPath().Calculate(*it)) { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", set primary target: " << MP2::StringObject(world.GetTiles(*it).GetObject()) << "(" << *it << ")"); ai_hero.primary_target = *it; return true; } // check destination if(hero.GetPath().isValid()) { if(! AI::HeroesValidObject(hero, hero.GetPath().GetDestinationIndex())) hero.GetPath().Reset(); else if(hero.GetPath().size() < 5) { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", continue short"); ai_hero.fix_loop++; return true; } } // scan 2x2 pickup objects Maps::Indexes pickups = Maps::ScanAroundObjects(hero.GetIndex(), 2, objs1); // scan 3x3 capture objects const Maps::Indexes & captures = Maps::ScanAroundObjects(hero.GetIndex(), 3, objs2); if(captures.size()) pickups.insert(pickups.end(), captures.begin(), captures.end()); if(pickups.size()) { hero.GetPath().Reset(); for(MapsIndexes::const_iterator it = pickups.begin(); it != pickups.end(); ++it) if(AI::HeroesValidObject(hero, *it)) { task.push_front(*it); DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", find object: " << MP2::StringObject(world.GetTiles(*it).GetObject()) << "(" << *it << ")"); } } if(hero.GetPath().isValid()) { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", continue"); ai_hero.fix_loop++; return true; } if(task.empty()) { // get task from kingdom DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", empty task"); AIHeroesAddedTask(hero); } else // remove invalid task task.remove_if(std::not1(std::bind1st(std::ptr_fun(&AIHeroesValidObject2), &hero))); // random shuffle if(1 < task.size() && Rand::Get(1)) { Queue::iterator it1, it2; it2 = it1 = task.begin(); ++it2; std::swap(*it1, *it2); } // find passable index while(task.size()) { const s32 & index = task.front(); DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", look for: " << MP2::StringObject(world.GetTiles(index).GetObject()) << "(" << index << ")"); if(hero.GetPath().Calculate(index)) break; DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << " say: unable get object: " << index << ", remove task..."); task.pop_front(); } // success if(task.size()) { const s32 & index = task.front(); DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << " go to: " << index); ai_objects.erase(index); task.pop_front(); DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << ", route: " << hero.GetPath().String()); return true; } else if(hero.Modes(AI::HEROES_WAITING)) { hero.GetPath().Reset(); DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << " say: unknown task., help my please.."); hero.ResetModes(AI::HEROES_WAITING); hero.SetModes(AI::HEROES_STUPID); } else { DEBUG(DBG_AI, DBG_TRACE, hero.GetName() << " say: waiting..."); hero.SetModes(AI::HEROES_WAITING); } return false; }
void AIHeroesAddedTask(Heroes & hero) { AIHero & ai_hero = AIHeroes::Get(hero); AIKingdom & ai_kingdom = AIKingdoms::Get(hero.GetColor()); Queue & task = ai_hero.sheduled_visit; IndexObjectMap & ai_objects = ai_kingdom.scans; // load minimal distance tasks std::vector<IndexDistance> objs; objs.reserve(ai_objects.size()); for(std::map<s32, int>::const_iterator it = ai_objects.begin(); it != ai_objects.end(); ++it) { const Maps::Tiles & tile = world.GetTiles((*it).first); if(hero.isShipMaster()) { if(MP2::OBJ_COAST != tile.GetObject() && ! tile.isWater()) continue; // check previous positions if(MP2::OBJ_COAST == (*it).second && hero.isVisited(world.GetTiles((*it).first))) continue; } else { if(tile.isWater() && MP2::OBJ_BOAT != tile.GetObject()) continue; } objs.push_back(IndexDistance((*it).first, Maps::GetApproximateDistance(hero.GetIndex(), (*it).first))); } DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) << ", hero: " << hero.GetName() << ", task prepare: " << objs.size()); std::sort(objs.begin(), objs.end(), IndexDistance::Shortest); for(std::vector<IndexDistance>::const_iterator it = objs.begin(); it != objs.end(); ++it) { if(task.size() >= HERO_MAX_SHEDULED_TASK) break; const bool validobj = AI::HeroesValidObject(hero, (*it).first); if(validobj && hero.GetPath().Calculate((*it).first)) { DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) << ", hero: " << hero.GetName() << ", added tasks: " << MP2::StringObject(ai_objects[(*it).first]) << ", index: " << (*it).first << ", distance: " << (*it).second); task.push_back((*it).first); ai_objects.erase((*it).first); } else { DEBUG(DBG_AI, DBG_TRACE, Color::String(hero.GetColor()) << ", hero: " << hero.GetName() << (!validobj ? ", invalid: " : ", impossible: ") << MP2::StringObject(ai_objects[(*it).first]) << ", index: " << (*it).first << ", distance: " << (*it).second); } } if(task.empty()) AIHeroesAddedRescueTask(hero); }
bool PassableFromToTile(const Heroes & hero, s32 from, const s32 & to, int direct, s32 dst) { const Maps::Tiles & fromTile = world.GetTiles(from); const Maps::Tiles & toTile = world.GetTiles(to); // check start point if(hero.GetIndex() == from) { if(MP2::isActionObject(fromTile.GetObject(false), hero.isShipMaster())) { // check direct from object if(! (direct & fromTile.GetPassable())) return false; } else { // check from tile direct if(! fromTile.isPassable(&hero, direct, (hero.isControlAI() ? AI::HeroesSkipFog() : false))) return false; } } else { if(MP2::isActionObject(fromTile.GetObject(), hero.isShipMaster())) { // check direct from object if(! (direct & fromTile.GetPassable())) return false; } else { // check from tile direct if(! fromTile.isPassable(&hero, direct, (hero.isControlAI() ? AI::HeroesSkipFog() : false))) return false; } } if(fromTile.isWater() && !toTile.isWater()) { switch(toTile.GetObject()) { case MP2::OBJ_BOAT: case MP2::OBJ_MONSTER: case MP2::OBJ_HEROES: return false; case MP2::OBJ_COAST: return toTile.GetIndex() == dst; default: break; } } else if(!fromTile.isWater() && toTile.isWater()) { switch(toTile.GetObject()) { case MP2::OBJ_BOAT: return true; case MP2::OBJ_HEROES: return toTile.GetIndex() == dst; default: break; } } // check corner water/coast if(hero.isShipMaster() && (direct & (Direction::TOP_LEFT | Direction::TOP_RIGHT | Direction::BOTTOM_RIGHT | Direction::BOTTOM_LEFT))) { switch(direct) { case Direction::TOP_LEFT: if((Maps::isValidDirection(from, Direction::TOP) && ! world.GetTiles(Maps::GetDirectionIndex(from, Direction::TOP)).isWater()) || (Maps::isValidDirection(from, Direction::LEFT) && ! world.GetTiles(Maps::GetDirectionIndex(from, Direction::LEFT)).isWater())) return false; break; case Direction::TOP_RIGHT: if((Maps::isValidDirection(from, Direction::TOP) && ! world.GetTiles(Maps::GetDirectionIndex(from, Direction::TOP)).isWater()) || (Maps::isValidDirection(from, Direction::RIGHT) && ! world.GetTiles(Maps::GetDirectionIndex(from, Direction::RIGHT)).isWater())) return false; break; case Direction::BOTTOM_RIGHT: if((Maps::isValidDirection(from, Direction::BOTTOM) && ! world.GetTiles(Maps::GetDirectionIndex(from, Direction::BOTTOM)).isWater()) || (Maps::isValidDirection(from, Direction::RIGHT) && ! world.GetTiles(Maps::GetDirectionIndex(from, Direction::RIGHT)).isWater())) return false; break; case Direction::BOTTOM_LEFT: if((Maps::isValidDirection(from, Direction::BOTTOM) && ! world.GetTiles(Maps::GetDirectionIndex(from, Direction::BOTTOM)).isWater()) || (Maps::isValidDirection(from, Direction::LEFT) && ! world.GetTiles(Maps::GetDirectionIndex(from, Direction::LEFT)).isWater())) return false; break; default: break; } } return PassableToTile(hero, toTile, direct, dst); }
bool ActionSpellVisions(Heroes & hero) { const u16 dist = hero.GetVisionsDistance(); const MapsIndexes & monsters = Maps::ScanDistanceObject(hero.GetIndex(), MP2::OBJ_MONSTER, dist); if(monsters.size()) { for(MapsIndexes::const_iterator it = monsters.begin(); it != monsters.end(); ++it) { const Maps::Tiles & tile = world.GetTiles(*it); const Army::Troop & troop = tile.QuantityTroop(); u32 join = troop.GetCount(); Funds cost; const u8 reason = Army::GetJoinSolution(hero, tile, join, cost.gold); std::string hdr, msg; hdr = std::string("%{count} ") + String::Lower(troop.GetPluralName(join)); String::Replace(hdr, "%{count}", join); switch(reason) { case 0: msg = _("I fear these creatures are in the mood for a fight."); break; case 1: msg = _("The creatures are willing to join us!"); break; case 2: if(join == troop.GetCount()) msg = _("All the creatures will join us..."); else { msg = ngettext("The creature will join us...", "%{count} of the creatures will join us...", join); String::Replace(msg, "%{count}", join); } msg.append("\n"); msg.append("\n for a fee of %{gold} gold."); String::Replace(msg, "%{gold}", cost.gold); break; default: msg = _("These weak creatures will surely flee before us."); break; } Dialog::Message(hdr, msg, Font::BIG, Dialog::OK); } } else { std::string msg = _("You must be within %{count} spaces of a monster for the Visions spell to work."); String::Replace(msg, "%{count}", dist); Dialog::Message("", msg, Font::BIG, Dialog::OK); return false; } hero.SetModes(Heroes::VISIONS); return true; }