optional<CampaignSetup> CampaignBuilder::prepareCampaign(function<optional<RetiredGames>(CampaignType)> genRetired, CampaignType type, string worldName) { Vec2 size(17, 9); int numBlocked = 0.6 * size.x * size.y; Table<Campaign::SiteInfo> terrain = getTerrain(random, size, numBlocked); auto retired = genRetired(type); View::CampaignMenuState menuState { true, false}; setCountLimits(options); const auto playerRole = getPlayerRole(); while (1) { Campaign campaign(terrain, type, playerRole, worldName); if (auto pos = considerStaticPlayerPos(campaign)) { campaign.clearSite(*pos); setPlayerPos(campaign, *pos, avatarInfo.playerCreature->getMaxViewIdUpgrade()); } placeVillains(campaign, getVillainCounts(type, options), retired, avatarInfo.tribeAlignment); while (1) { bool updateMap = false; campaign.influenceSize = options->getIntValue(OptionId::INFLUENCE_SIZE); campaign.refreshInfluencePos(); CampaignAction action = autoConfirm(type) ? CampaignActionId::CONFIRM : view->prepareCampaign({ campaign, (retired && type == CampaignType::FREE_PLAY) ? optional<RetiredGames&>(*retired) : none, avatarInfo.playerCreature.get(), getPrimaryOptions(), getSecondaryOptions(type), getSiteChoiceTitle(type), getIntroText(), getAvailableTypes().transform([](CampaignType t) -> View::CampaignOptions::CampaignTypeInfo { return {t, getCampaignTypeDescription(t)};}), getMenuWarning(type) }, options, menuState); switch (action.getId()) { case CampaignActionId::REROLL_MAP: terrain = getTerrain(random, size, numBlocked); updateMap = true; break; case CampaignActionId::UPDATE_MAP: updateMap = true; break; case CampaignActionId::CHANGE_TYPE: type = action.get<CampaignType>(); retired = genRetired(type); updateMap = true; break; case CampaignActionId::UPDATE_OPTION: switch (action.get<OptionId>()) { case OptionId::PLAYER_NAME: case OptionId::GENERATE_MANA: case OptionId::INFLUENCE_SIZE: break; default: updateMap = true; break; } break; case CampaignActionId::CANCEL: return none; case CampaignActionId::CHOOSE_SITE: if (!considerStaticPlayerPos(campaign)) setPlayerPos(campaign, action.get<Vec2>(), avatarInfo.playerCreature->getMaxViewIdUpgrade()); break; case CampaignActionId::CONFIRM: if (!retired || retired->getNumActive() > 0 || playerRole != PlayerRole::KEEPER || retired->getAllGames().empty() || view->yesOrNoPrompt("The imps are going to be sad if you don't add any retired dungeons. Continue?")) { string name = avatarInfo.playerCreature->getName().firstOrBare(); string gameIdentifier = name + "_" + campaign.worldName + getNewIdSuffix(); string gameDisplayName = name + " of " + campaign.worldName; return CampaignSetup{campaign, gameIdentifier, gameDisplayName, getIntroMessages(type)}; } } if (updateMap) break; } } }
optional<Campaign> Campaign::prepareCampaign(View* view, Options* options, RetiredGames&& retired, RandomGen& random) { Vec2 size(16, 9); int numBlocked = 0.6 * size.x * size.y; Table<SiteInfo> terrain = getTerrain(random, size, numBlocked); string worldName = NameGenerator::get(NameGeneratorId::WORLD)->getNext(); options->setDefaultString(OptionId::KEEPER_NAME, NameGenerator::get(NameGeneratorId::FIRST)->getNext()); while (1) { //options->setLimits(OptionId::RETIRED_VILLAINS, 0, min<int>(retired.size(), 4)); options->setLimits(OptionId::MAIN_VILLAINS, 0, 9); options->setLimits(OptionId::LESSER_VILLAINS, 0, 8); options->setLimits(OptionId::ALLIES, 0, 6); options->setLimits(OptionId::INFLUENCE_SIZE, 3, 6); int numRetired = min(retired.getNumActive(), options->getIntValue(OptionId::MAIN_VILLAINS)); int numMain = options->getIntValue(OptionId::MAIN_VILLAINS) - numRetired; int numLesser = options->getIntValue(OptionId::LESSER_VILLAINS); int numAllies = options->getIntValue(OptionId::ALLIES); vector<VillainInfo> mainVillains; while (mainVillains.size() < numMain) append(mainVillains, random.permutation(getMainVillains())); mainVillains.resize(numMain); vector<VillainInfo> lesserVillains; while (lesserVillains.size() < numLesser) append(lesserVillains, random.permutation(getLesserVillains())); lesserVillains.resize(numLesser); vector<VillainInfo> allies; while (allies.size() < numAllies) append(allies, random.permutation(getAllies())); allies.resize(numAllies); Campaign campaign(terrain); campaign.worldName = worldName; vector<Vec2> freePos; for (Vec2 v : Rectangle(size)) if (campaign.sites[v].canEmbark()) freePos.push_back(v); for (int i : All(mainVillains)) { Vec2 pos = random.choose(freePos); removeElement(freePos, pos); campaign.sites[pos].dweller = mainVillains[i]; } vector<RetiredGames::RetiredGame> activeGames = retired.getActiveGames(); for (int i : Range(numRetired)) { Vec2 pos = random.choose(freePos); removeElement(freePos, pos); campaign.sites[pos].dweller = RetiredInfo{activeGames[i].gameInfo, activeGames[i].fileInfo}; } for (int i : All(lesserVillains)) { Vec2 pos = random.choose(freePos); removeElement(freePos, pos); campaign.sites[pos].dweller = lesserVillains[i]; } for (int i : All(allies)) { Vec2 pos = random.choose(freePos); removeElement(freePos, pos); campaign.sites[pos].dweller = allies[i]; } while (1) { bool updateMap = false; campaign.influenceSize = options->getIntValue(OptionId::INFLUENCE_SIZE); campaign.refreshInfluencePos(); CampaignAction action = view->prepareCampaign(campaign, options, retired); switch (action.getId()) { case CampaignActionId::REROLL_MAP: terrain = getTerrain(random, size, numBlocked); worldName = NameGenerator::get(NameGeneratorId::WORLD)->getNext(); options->setDefaultString(OptionId::KEEPER_NAME, NameGenerator::get(NameGeneratorId::FIRST)->getNext()); case CampaignActionId::UPDATE_MAP: updateMap = true; break; case CampaignActionId::UPDATE_OPTION: switch (action.get<OptionId>()) { case OptionId::KEEPER_NAME: case OptionId::INFLUENCE_SIZE: break; default: updateMap = true; break; } break; case CampaignActionId::CANCEL: return none; case CampaignActionId::CHOOSE_SITE: if (campaign.playerPos) campaign.clearSite(*campaign.playerPos); campaign.playerPos = action.get<Vec2>(); campaign.sites[*campaign.playerPos].dweller = PlayerInfo{ViewId::KEEPER}; break; case CampaignActionId::CONFIRM: return campaign; } if (updateMap) break; } } }