/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://gnu.org/licenses */ #include "ui/screen/screen_level_list.h" #include "app/app.h" #include "common/settings.h" #include "common/resources/resourcemanager.h" #include "level/player_profile.h" #include "level/parser/parser.h" #include "ui/maindialog.h" #include "ui/controls/button.h" #include "ui/controls/check.h" #include "ui/controls/edit.h" #include "ui/controls/interface.h" #include "ui/controls/label.h" #include "ui/controls/list.h" #include "ui/controls/window.h" #include namespace Ui { CScreenLevelList::CScreenLevelList(CMainDialog* mainDialog) : m_dialog(mainDialog), m_category{}, m_listCategory{}, m_sceneSoluce{false}, m_maxList{0}, m_accessChap{0} { } void CScreenLevelList::SetLevelCategory(LevelCategory category) { m_category = category; if ( static_cast(m_category) >= static_cast(LevelCategory::Max) ) { m_category = m_listCategory; } else { m_listCategory = m_category; } } void CScreenLevelList::CreateInterface() { CWindow* pw; CEdit* pe; CLabel* pl; CButton* pb; CCheck* pc; CList* pli; Math::Point pos, ddim; int res; std::string name; if ( m_category == LevelCategory::FreeGame ) { m_accessChap = m_main->GetPlayerProfile()->GetChapPassed(LevelCategory::Missions); } pos.x = 0.10f; pos.y = 0.10f; ddim.x = 0.80f; ddim.y = 0.80f; pw = m_interface->CreateWindows(pos, ddim, 12, EVENT_WINDOW5); pw->SetClosable(true); if ( m_category == LevelCategory::Exercises ) res = RT_TITLE_TRAINER; if ( m_category == LevelCategory::Challenges ) res = RT_TITLE_DEFI; if ( m_category == LevelCategory::Missions ) res = RT_TITLE_MISSION; if ( m_category == LevelCategory::FreeGame ) res = RT_TITLE_FREE; if ( m_category == LevelCategory::CodeBattles ) res = RT_TITLE_CODE_BATTLES; if ( m_category == LevelCategory::CustomLevels ) res = RT_TITLE_USER; GetResource(RES_TEXT, res, name); pw->SetName(name); pos.x = 0.10f; pos.y = 0.40f; ddim.x = 0.50f; ddim.y = 0.50f; pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // orange corner pos.x = 0.40f; pos.y = 0.10f; ddim.x = 0.50f; ddim.y = 0.50f; pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // blue corner // Displays a list of chapters: pos.x = ox+sx*3; pos.y = oy+sy*10.5f; ddim.x = dim.x*7.5f; ddim.y = dim.y*0.6f; res = RT_PLAY_CHAP_CHAPTERS; if ( m_category == LevelCategory::Missions ) res = RT_PLAY_CHAP_PLANETS; if ( m_category == LevelCategory::FreeGame ) res = RT_PLAY_CHAP_PLANETS; if ( m_category == LevelCategory::CustomLevels ) res = RT_PLAY_CHAP_USERLVL; GetResource(RES_TEXT, res, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, name); pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); pos.y = oy+sy*6.7f; ddim.y = dim.y*4.5f; ddim.x = dim.x*6.5f; pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_CHAP); pli->SetState(STATE_SHADOW); m_chap[m_category] = m_main->GetPlayerProfile()->GetSelectedChap(m_category)-1; UpdateSceneChap(m_chap[m_category]); if ( m_category != LevelCategory::FreeGame && m_category != LevelCategory::CustomLevels ) // Don't show completion marks in free game and userlevels { pli->SetState(STATE_EXTEND); } // Displays a list of missions: pos.x = ox+sx*9.5f; pos.y = oy+sy*10.5f; ddim.x = dim.x*7.5f; ddim.y = dim.y*0.6f; res = RT_PLAY_LIST_LEVELS; if ( m_category == LevelCategory::Exercises ) res = RT_PLAY_LIST_EXERCISES; if ( m_category == LevelCategory::Challenges ) res = RT_PLAY_LIST_CHALLENGES; if ( m_category == LevelCategory::Missions ) res = RT_PLAY_LIST_MISSIONS; if ( m_category == LevelCategory::FreeGame ) res = RT_PLAY_LIST_FREEGAME; GetResource(RES_TEXT, res, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, name); pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); pos.y = oy+sy*6.7f; ddim.y = dim.y*4.5f; ddim.x = dim.x*6.5f; pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_LIST); pli->SetState(STATE_SHADOW); m_sel[m_category] = m_main->GetPlayerProfile()->GetSelectedRank(m_category)-1; UpdateSceneList(m_chap[m_category], m_sel[m_category]); if ( m_category != LevelCategory::FreeGame && m_category != LevelCategory::CustomLevels ) // Don't show completion marks in free game and userlevels { pli->SetState(STATE_EXTEND); } pos = pli->GetPos(); ddim = pli->GetDim(); // Displays the summary: pos.x = ox+sx*3; pos.y = oy+sy*5.4f; ddim.x = dim.x*6.5f; ddim.y = dim.y*0.6f; GetResource(RES_TEXT, RT_PLAY_RESUME, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL13, name); pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); pos.x = ox+sx*3; pos.y = oy+sy*3.6f; ddim.x = dim.x*13.4f; ddim.y = dim.y*1.9f; pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_RESUME); pe->SetState(STATE_SHADOW); pe->SetMaxChar(500); pe->SetEditCap(false); // just to see pe->SetHighlightCap(false); // Button displays the "soluce": if ( m_category != LevelCategory::Exercises && m_category != LevelCategory::FreeGame ) { pos.x = ox+sx*9.5f; pos.y = oy+sy*5.8f; ddim.x = dim.x*6.5f; ddim.y = dim.y*0.5f; pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_SOLUCE); pc->SetState(STATE_SHADOW); pc->ClearState(STATE_CHECK); } m_sceneSoluce = false; UpdateSceneResume(m_chap[m_category]+1, m_sel[m_category]+1); if ( m_category == LevelCategory::Missions || m_category == LevelCategory::FreeGame || m_category == LevelCategory::CustomLevels ) { pos.x = ox+sx*9.5f; pos.y = oy+sy*2; ddim.x = dim.x*3.7f; ddim.y = dim.y*1; pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PLAY); pb->SetState(STATE_SHADOW); if ( m_maxList == 0 ) { pb->ClearState(STATE_ENABLE); } pos.x += dim.x*4.0f; ddim.x = dim.x*2.5f; pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_READ); pb->SetState(STATE_SHADOW); if ( !m_main->GetPlayerProfile()->HasAnySavedScene() ) // no file to read? { pb->ClearState(STATE_ENABLE); } } else { pos.x = ox+sx*9.5f; pos.y = oy+sy*2; ddim.x = dim.x*6.5f; ddim.y = dim.y*1; pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PLAY); pb->SetState(STATE_SHADOW); if ( m_maxList == 0 ) { pb->ClearState(STATE_ENABLE); } } pos.x = ox+sx*3; ddim.x = dim.x*4; pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK); pb->SetState(STATE_SHADOW); SetBackground("textures/interface/interface.png"); CreateVersionDisplay(); if (m_category == LevelCategory::CustomLevels) { if(m_customLevelList.size() == 0) { m_main->ChangePhase(PHASE_MAIN_MENU); std::string title, text; GetResource(RES_TEXT, RT_DIALOG_NOUSRLVL_TITLE, title); GetResource(RES_TEXT, RT_DIALOG_NOUSRLVL_TEXT, text); m_dialog->StartInformation(title, title, text); } } } bool CScreenLevelList::EventProcess(const Event &event) { CWindow* pw; CList* pl; CButton* pb; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return false; if ( event.type == pw->GetEventTypeClose() || event.type == EVENT_INTERFACE_BACK || (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(ESCAPE)) ) { m_main->ChangePhase(PHASE_MAIN_MENU); return false; } switch( event.type ) { case EVENT_INTERFACE_CHAP: pl = static_cast(pw->SearchControl(EVENT_INTERFACE_CHAP)); if ( pl == nullptr ) break; m_chap[m_category] = pl->GetSelect(); m_main->GetPlayerProfile()->SetSelectedChap(m_category, m_chap[m_category]+1); UpdateSceneList(m_chap[m_category], m_sel[m_category]); UpdateSceneResume(m_chap[m_category]+1, m_sel[m_category]+1); break; case EVENT_INTERFACE_LIST: pl = static_cast(pw->SearchControl(EVENT_INTERFACE_LIST)); if ( pl == nullptr ) break; m_sel[m_category] = pl->GetSelect(); m_main->GetPlayerProfile()->SetSelectedRank(m_category, m_sel[m_category]+1); UpdateSceneResume(m_chap[m_category]+1, m_sel[m_category]+1); break; case EVENT_INTERFACE_SOLUCE: pb = static_cast(pw->SearchControl(EVENT_INTERFACE_SOLUCE)); if ( pb == nullptr ) break; m_sceneSoluce = !m_sceneSoluce; pb->SetState(STATE_CHECK, m_sceneSoluce); break; case EVENT_INTERFACE_PLAY: m_main->SetLevel(m_category, m_chap[m_category]+1, m_sel[m_category]+1); m_main->ChangePhase(PHASE_SIMUL); break; case EVENT_INTERFACE_READ: m_main->ChangePhase(PHASE_READ); break; default: return true; } return false; } void CScreenLevelList::SetSelection(LevelCategory category, int chap, int rank) { m_chap[category] = chap; m_sel[category] = rank; } // Updates the lists according to the cheat code. void CScreenLevelList::AllMissionUpdate() { UpdateSceneChap(m_chap[m_category]); UpdateSceneList(m_chap[m_category], m_sel[m_category]); } // Whether to show the solution. bool CScreenLevelList::GetSceneSoluce() { return m_sceneSoluce; } // Updates the chapters of exercises or missions. void CScreenLevelList::UpdateSceneChap(int &chap) { CWindow* pw; CList* pl; std::string fileName; char line[500] = {0}; bool bPassed; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return; pl = static_cast(pw->SearchControl(EVENT_INTERFACE_CHAP)); if ( pl == nullptr ) return; pl->Flush(); int j; if ( m_category == LevelCategory::CustomLevels ) { UpdateCustomLevelList(); for ( j=0 ; j < static_cast(m_customLevelList.size()) ; j++ ) { try { CLevelParser levelParser("custom", j+1, 0); levelParser.Load(); pl->SetItemName(j, levelParser.Get("Title")->GetParam("text")->AsString().c_str()); pl->SetEnable(j, true); } catch (CLevelParserException& e) { pl->SetItemName(j, (std::string("[ERROR]: ")+e.what()).c_str()); pl->SetEnable(j, false); } } } else { for ( j=0 ; jGetParam("text")->AsString().c_str()); } catch (CLevelParserException& e) { sprintf(line, "%s", (std::string("[ERROR]: ")+e.what()).c_str()); } bPassed = m_main->GetPlayerProfile()->GetLevelPassed(m_category, j+1, 0); pl->SetItemName(j, line); pl->SetCheck(j, bPassed); pl->SetEnable(j, true); if ( m_category == LevelCategory::Missions && !m_main->GetShowAll() && !bPassed ) { j ++; break; } if ( m_category == LevelCategory::FreeGame && j == m_accessChap ) { j ++; break; } } } if ( chap > j-1 ) chap = j-1; pl->SetSelect(chap); pl->ShowSelect(false); // shows the selected columns } // Updates the list of exercises or missions. void CScreenLevelList::UpdateSceneList(int chap, int &sel) { CWindow* pw; CList* pl; std::string fileName; char line[500] = {0}; int j; bool bPassed; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return; pl = static_cast(pw->SearchControl(EVENT_INTERFACE_LIST)); if ( pl == nullptr ) return; pl->Flush(); bool readAll = true; for ( j=0 ; jGetParam("text")->AsString().c_str()); } catch (CLevelParserException& e) { sprintf(line, "%s", (std::string("[ERROR]: ")+e.what()).c_str()); } bPassed = m_main->GetPlayerProfile()->GetLevelPassed(m_category, chap+1, j+1); pl->SetItemName(j, line); pl->SetCheck(j, bPassed); pl->SetEnable(j, true); if ( m_category == LevelCategory::Missions && !m_main->GetShowAll() && !bPassed ) { readAll = false; } } if (readAll) { m_maxList = j; } else { m_maxList = j+1; // this is not the last! } if ( sel > j-1 ) sel = j-1; pl->SetSelect(sel); pl->ShowSelect(false); // shows the selected columns } // Updates the button "solution" according to cheat code. void CScreenLevelList::ShowSoluceUpdate() { CWindow* pw; CEdit* pe; CCheck* pc; m_sceneSoluce = false; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return; pe = static_cast(pw->SearchControl(EVENT_INTERFACE_RESUME)); if ( pe == nullptr ) return; pc = static_cast(pw->SearchControl(EVENT_INTERFACE_SOLUCE)); if ( pc == nullptr ) return; if ( m_main->GetShowSoluce() ) { pc->SetState(STATE_VISIBLE); pc->SetState(STATE_CHECK); m_sceneSoluce = true; } else { pc->ClearState(STATE_VISIBLE); pc->ClearState(STATE_CHECK); m_sceneSoluce = false; } } // Updates a summary of exercise or mission. void CScreenLevelList::UpdateSceneResume(int chap, int rank) { CWindow* pw; CEdit* pe; CCheck* pc; std::string fileName; int numTry; bool bPassed, bVisible; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return; pe = static_cast(pw->SearchControl(EVENT_INTERFACE_RESUME)); if ( pe == nullptr ) return; pc = static_cast(pw->SearchControl(EVENT_INTERFACE_SOLUCE)); if ( pc == nullptr ) { m_sceneSoluce = false; } else { numTry = m_main->GetPlayerProfile()->GetLevelTryCount(m_category, chap, rank); bPassed = m_main->GetPlayerProfile()->GetLevelPassed(m_category, chap, rank); bVisible = ( numTry > 2 || bPassed || m_main->GetShowSoluce() ); if ( !CSettings::GetInstancePointer()->GetSoluce4() ) bVisible = false; pc->SetState(STATE_VISIBLE, bVisible); if ( !bVisible ) { pc->ClearState(STATE_CHECK); m_sceneSoluce = false; } } if(chap == 0 || rank == 0) return; try { CLevelParser levelParser(m_category, chap, rank); levelParser.Load(); pe->SetText(levelParser.Get("Resume")->GetParam("text")->AsString().c_str()); } catch (CLevelParserException& e) { pe->SetText((std::string("[ERROR]: ")+e.what()).c_str()); } } void CScreenLevelList::UpdateChapterPassed() { // TODO: CScreenLevelList is a bad place for this function bool bAll = true; for ( int i=0 ; iGetPlayerProfile()->GetLevelPassed(m_category, m_chap[m_category]+1, i+1)) { bAll = false; break; } } m_main->GetPlayerProfile()->IncrementLevelTryCount(m_category, m_chap[m_category]+1, 0); m_main->GetPlayerProfile()->SetLevelPassed(m_category, m_chap[m_category]+1, 0, bAll); } // Passes to the next mission, and possibly in the next chapter. void CScreenLevelList::NextMission() { m_sel[m_category] ++; // next mission if ( m_sel[m_category] >= m_maxList ) // last mission of the chapter? { m_chap[m_category] ++; // next chapter m_sel[m_category] = 0; // first mission } m_main->GetPlayerProfile()->SetSelectedChap(m_category, m_chap[m_category]+1); m_main->GetPlayerProfile()->SetSelectedRank(m_category, m_sel[m_category]+1); } // TODO: Separate class for userlevels? void CScreenLevelList::UpdateCustomLevelList() { auto userLevelDirs = CResourceManager::ListDirectories("levels/custom/"); std::sort(userLevelDirs.begin(), userLevelDirs.end()); m_customLevelList = userLevelDirs; } std::string CScreenLevelList::GetCustomLevelName(int id) { if(id < 1 || id > static_cast(m_customLevelList.size())) return ""; return m_customLevelList[id-1]; } const std::vector& CScreenLevelList::GetCustomLevelList() { return m_customLevelList; } } // namespace Ui