Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add campaign menu and mission selection screen
- Loading branch information
Showing
4 changed files
with
496 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
// Copyright (C) 2005 - 2023 Settlers Freaks (sf-team at siedler25.org) | ||
// | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#include "dskCampaignMissionSelection.h" | ||
#include "Loader.h" | ||
#include "WindowManager.h" | ||
#include "commonDefines.h" | ||
#include "controls/ctrlGroup.h" | ||
#include "controls/ctrlImageButton.h" | ||
#include "controls/ctrlText.h" | ||
#include "dskCampaignSelection.h" | ||
#include "ingameWindows/iwConnecting.h" | ||
#include "ingameWindows/iwMsgbox.h" | ||
#include "lua/CampaignDataLoader.h" | ||
#include "network/GameClient.h" | ||
#include "ogl/glFont.h" | ||
#include "gameData/CampaignDescription.h" | ||
#include "libsiedler2/ArchivItem_Map.h" | ||
#include "libsiedler2/ArchivItem_Map_Header.h" | ||
#include "libsiedler2/ErrorCodes.h" | ||
#include "libsiedler2/prototypen.h" | ||
#include "s25util/Log.h" | ||
#include "s25util/utf8.h" | ||
|
||
namespace bfs = boost::filesystem; | ||
constexpr unsigned ID_msgBoxError = 0; | ||
|
||
namespace { | ||
enum | ||
{ | ||
ID_Back, | ||
ID_FirstPage, | ||
ID_NextPage, | ||
ID_PageLabel, | ||
ID_PreviousPage, | ||
ID_LastPage, | ||
ID_ChooseMissionLabel, | ||
ID_GroupStart | ||
}; | ||
|
||
constexpr int startOffsetY = 70; | ||
constexpr int distanceBetweenElementsY = 10; | ||
constexpr int distanceBetweenMissionButtonsY = 10; | ||
constexpr Extent buttonSize(22, 20); | ||
constexpr int spacingBetweenButtons = 2; | ||
|
||
int getStartOffsetMissionButtonsY() | ||
{ | ||
return startOffsetY + LargeFont->getHeight() + distanceBetweenElementsY + 8; | ||
} | ||
} // namespace | ||
|
||
dskCampaignMissionSelection::dskCampaignMissionSelection(CreateServerInfo csi, boost::filesystem::path campaignFolder) | ||
: Desktop(LOADER.GetImageN("setup015", 0)), campaignFolder_(std::move(campaignFolder)), csi_(std::move(csi)), | ||
currentPage_(0), lastPage_(0), missionsPerPage_(10) | ||
{ | ||
const unsigned int btOffset = getStartOffsetMissionButtonsY() | ||
+ missionsPerPage_ * (buttonSize.y + distanceBetweenMissionButtonsY) | ||
+ distanceBetweenElementsY; | ||
AddTextButton(ID_Back, DrawPoint(300, 560), Extent(200, 22), TextureColor::Red1, _("Back"), NormalFont); | ||
|
||
AddImageButton(ID_FirstPage, DrawPoint(400 - buttonSize.x * 3 - 2 * spacingBetweenButtons, btOffset), buttonSize, | ||
TextureColor::Green2, LOADER.GetImageN("io", 102)); | ||
|
||
AddImageButton(ID_PreviousPage, DrawPoint(400 - buttonSize.x * 2, btOffset), buttonSize, TextureColor::Green2, | ||
LOADER.GetImageN("io", 103)); | ||
|
||
AddImageButton(ID_NextPage, DrawPoint(400 + buttonSize.x, btOffset), buttonSize, TextureColor::Green2, | ||
LOADER.GetImageN("io", 104)); | ||
|
||
AddImageButton(ID_LastPage, DrawPoint(400 + buttonSize.x * 2 + 2 * spacingBetweenButtons, btOffset), buttonSize, | ||
TextureColor::Green2, LOADER.GetImageN("io", 105)); | ||
|
||
settings_ = std::make_unique<CampaignDescription>(); | ||
CampaignDataLoader loader(*settings_, campaignFolder_); | ||
if(!loader.Load() || settings_->getNumMaps() == 0) | ||
LOG.write(_("Failed to load campaign %1%.\n")) % campaignFolder_; | ||
else | ||
lastPage_ = (settings_->getNumMaps() - 1) / missionsPerPage_; | ||
|
||
UpdateEnabledStateOfNextPreviousButton(); | ||
|
||
AddText(ID_PageLabel, DrawPoint(400, btOffset + buttonSize.y / 2), | ||
std::to_string(currentPage_ + 1) + "/" + std::to_string(lastPage_ + 1), COLOR_YELLOW, | ||
FontStyle::CENTER | FontStyle::VCENTER, LargeFont); | ||
|
||
AddText(ID_ChooseMissionLabel, DrawPoint(400, startOffsetY), _("Choose mission"), COLOR_YELLOW, FontStyle::CENTER, | ||
LargeFont); | ||
|
||
UpdateMissionPage(); | ||
} | ||
|
||
void dskCampaignMissionSelection::UpdateMissionPage() | ||
{ | ||
ctrlGroup* group = AddGroup(ID_GroupStart + currentPage_); | ||
Extent catBtSize = Extent(300, buttonSize.y); | ||
DrawPoint curBtPos(250, getStartOffsetMissionButtonsY()); | ||
for(unsigned int i = 0; i < missionsPerPage_; i++) | ||
{ | ||
unsigned int missionIndex = currentPage_ * missionsPerPage_ + i; | ||
if(missionIndex >= settings_->getNumMaps()) | ||
break; | ||
|
||
const bfs::path& mapFilePath = settings_->getMapFilePath(missionIndex); | ||
|
||
libsiedler2::Archiv map; | ||
if(int ec = libsiedler2::loader::LoadMAP(mapFilePath, map, true)) | ||
{ | ||
LOG.write(_("Failed to load map %1%: %2%\n")) % mapFilePath % libsiedler2::getErrorString(ec); | ||
continue; | ||
} | ||
|
||
const libsiedler2::ArchivItem_Map_Header& header = | ||
checkedCast<const libsiedler2::ArchivItem_Map*>(map[0])->getHeader(); | ||
|
||
group->AddTextButton(i, curBtPos, catBtSize, TextureColor::Grey, s25util::ansiToUTF8(header.getName()), | ||
NormalFont); | ||
|
||
curBtPos.y += catBtSize.y + distanceBetweenMissionButtonsY; | ||
} | ||
} | ||
|
||
void dskCampaignMissionSelection::StartServer(const boost::filesystem::path& mapPath) | ||
{ | ||
// Start server | ||
if(!GAMECLIENT.HostGame(csi_, mapPath, MapType::OldMap)) | ||
{ | ||
WINDOWMANAGER.Show(std::make_unique<iwMsgbox>(_("Error"), _("Hosting of game not possible"), this, | ||
MsgboxButton::Ok, MsgboxIcon::ExclamationRed, ID_msgBoxError)); | ||
} else | ||
{ | ||
iwConnecting& wnd = | ||
WINDOWMANAGER.Show(std::make_unique<iwConnecting>(csi_.type, std::unique_ptr<ILobbyClient>())); | ||
onErrorConnection_ = wnd.onError.connect([this](ClientError error) { | ||
WINDOWMANAGER.Show(std::make_unique<iwMsgbox>(_("Error"), ClientErrorToStr(error), this, MsgboxButton::Ok, | ||
MsgboxIcon::ExclamationRed, ID_msgBoxError)); | ||
}); | ||
} | ||
} | ||
|
||
void dskCampaignMissionSelection::UpdateEnabledStateOfNextPreviousButton() | ||
{ | ||
GetCtrl<ctrlImageButton>(ID_PreviousPage)->SetEnabled(currentPage_ > 0); | ||
GetCtrl<ctrlImageButton>(ID_NextPage)->SetEnabled(currentPage_ < lastPage_); | ||
GetCtrl<ctrlImageButton>(ID_FirstPage)->SetEnabled(currentPage_ > 0); | ||
GetCtrl<ctrlImageButton>(ID_LastPage)->SetEnabled(currentPage_ < lastPage_); | ||
} | ||
|
||
void dskCampaignMissionSelection::Msg_Group_ButtonClick(unsigned group_id, unsigned ctrl_id) | ||
{ | ||
unsigned int missionIndex = (group_id - ID_GroupStart) * missionsPerPage_ + ctrl_id; | ||
const bfs::path mapPath = settings_->getMapFilePath(missionIndex); | ||
const bfs::path luaPath = settings_->getLuaFilePath(missionIndex); | ||
StartServer(mapPath, luaPath); | ||
} | ||
|
||
void dskCampaignMissionSelection::Msg_ButtonClick(unsigned ctrl_id) | ||
{ | ||
if(ctrl_id == ID_Back) | ||
WINDOWMANAGER.Switch(std::make_unique<dskCampaignSelection>(csi_)); | ||
else if(ctrl_id >= ID_FirstPage && ctrl_id <= ID_LastPage) | ||
{ | ||
// Destroy all controls first (the whole group) | ||
DeleteCtrl(ID_GroupStart + currentPage_); | ||
|
||
switch(ctrl_id) | ||
{ | ||
case ID_FirstPage: currentPage_ = 0; break; | ||
case ID_NextPage: | ||
if(currentPage_ < lastPage_) | ||
currentPage_++; | ||
break; | ||
case ID_PreviousPage: | ||
if(currentPage_ > 0) | ||
currentPage_--; | ||
break; | ||
case ID_LastPage: currentPage_ = lastPage_; break; | ||
} | ||
UpdateMissionPage(); | ||
GetCtrl<ctrlText>(ID_PageLabel) | ||
->SetText(std::to_string(currentPage_ + 1) + "/" + std::to_string(lastPage_ + 1)); | ||
UpdateEnabledStateOfNextPreviousButton(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Copyright (C) 2005 - 2023 Settlers Freaks (sf-team at siedler25.org) | ||
// | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#pragma once | ||
|
||
#include "desktops/Desktop.h" | ||
#include "network/CreateServerInfo.h" | ||
#include <boost/filesystem.hpp> | ||
#include <boost/signals2/connection.hpp> | ||
|
||
struct CampaignDescription; | ||
|
||
class dskCampaignMissionSelection : public Desktop | ||
{ | ||
public: | ||
dskCampaignMissionSelection(CreateServerInfo csi, boost::filesystem::path campaignFolder); | ||
|
||
private: | ||
void UpdateMissionPage(); | ||
void Msg_ButtonClick(unsigned ctrl_id) override; | ||
void Msg_Group_ButtonClick(unsigned group_id, unsigned ctrl_id) override; | ||
void StartServer(const boost::filesystem::path& mapPath); | ||
void UpdateEnabledStateOfNextPreviousButton(); | ||
boost::filesystem::path campaignFolder_; | ||
CreateServerInfo csi_; | ||
unsigned currentPage_; | ||
unsigned lastPage_; | ||
std::unique_ptr<CampaignDescription> settings_; | ||
unsigned missionsPerPage_; | ||
boost::signals2::scoped_connection onErrorConnection_; | ||
}; |
Oops, something went wrong.