mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge remote-tracking branch 'vcmi/develop' into battle_improvements
This commit is contained in:
commit
bb65246aa3
2
.github/workflows/github.yml
vendored
2
.github/workflows/github.yml
vendored
@ -244,7 +244,7 @@ jobs:
|
||||
|
||||
- name: Trigger Android
|
||||
uses: peter-evans/repository-dispatch@v1
|
||||
if: ${{ (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master') && matrix.platform == 'mxe' }}
|
||||
if: ${{ (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/master') && matrix.platform == 'mxe' }}
|
||||
with:
|
||||
token: ${{ secrets.VCMI_ANDROID_ACCESS_TOKEN }}
|
||||
repository: vcmi/vcmi-android
|
||||
|
@ -1,7 +1,8 @@
|
||||
[![GitHub](https://github.com/vcmi/vcmi/actions/workflows/github.yml/badge.svg)](https://github.com/vcmi/vcmi/actions/workflows/github.yml)
|
||||
[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/github/vcmi/vcmi?branch=develop&svg=true)](https://ci.appveyor.com/project/vcmi/vcmi)
|
||||
[![Coverity Scan Build Status](https://scan.coverity.com/projects/vcmi/badge.svg)](https://scan.coverity.com/projects/vcmi)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.0.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.0.0)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.1.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.1.0)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/total)](https://github.com/vcmi/vcmi/releases)
|
||||
# VCMI Project
|
||||
VCMI is work-in-progress attempt to recreate engine for Heroes III, giving it new and extended possibilities.
|
||||
|
||||
|
@ -26,6 +26,7 @@ set(client_SRCS
|
||||
gui/Geometries.cpp
|
||||
gui/SDL_Extensions.cpp
|
||||
gui/NotificationHandler.cpp
|
||||
gui/InterfaceObjectConfigurable.cpp
|
||||
|
||||
widgets/AdventureMapClasses.cpp
|
||||
widgets/Buttons.cpp
|
||||
@ -113,6 +114,7 @@ set(client_HEADERS
|
||||
gui/SDL_Extensions.h
|
||||
gui/SDL_Pixels.h
|
||||
gui/NotificationHandler.h
|
||||
gui/InterfaceObjectConfigurable.h
|
||||
|
||||
widgets/AdventureMapClasses.h
|
||||
widgets/Buttons.h
|
||||
|
@ -165,6 +165,7 @@ struct SSetCaptureState
|
||||
};
|
||||
|
||||
#define OBJ_CONSTRUCTION SObjectConstruction obj__i(this)
|
||||
#define OBJ_CONSTRUCTION_TARGETED(obj) SObjectConstruction obj__i(obj)
|
||||
#define OBJECT_CONSTRUCTION_CAPTURING(actions) defActions = actions; SSetCaptureState obj__i1(true, actions); SObjectConstruction obj__i(this)
|
||||
#define OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(actions) SSetCaptureState obj__i1(true, actions); SObjectConstruction obj__i(this)
|
||||
|
||||
|
389
client/gui/InterfaceObjectConfigurable.cpp
Normal file
389
client/gui/InterfaceObjectConfigurable.cpp
Normal file
@ -0,0 +1,389 @@
|
||||
/*
|
||||
* InterfaceBuilder.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
|
||||
#include "InterfaceObjectConfigurable.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../gui/CAnimation.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../widgets/CComponent.h"
|
||||
#include "../widgets/Buttons.h"
|
||||
#include "../widgets/MiscWidgets.h"
|
||||
#include "../widgets/ObjectLists.h"
|
||||
#include "../widgets/TextControls.h"
|
||||
#include "../windows/GUIClasses.h"
|
||||
#include "../windows/InfoWindows.h"
|
||||
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
|
||||
|
||||
InterfaceObjectConfigurable::InterfaceObjectConfigurable(const JsonNode & config, int used, Point offset):
|
||||
InterfaceObjectConfigurable(used, offset)
|
||||
{
|
||||
init(config);
|
||||
}
|
||||
|
||||
InterfaceObjectConfigurable::InterfaceObjectConfigurable(int used, Point offset):
|
||||
CIntObject(used, offset)
|
||||
{
|
||||
REGISTER_BUILDER("picture", &InterfaceObjectConfigurable::buildPicture);
|
||||
REGISTER_BUILDER("image", &InterfaceObjectConfigurable::buildImage);
|
||||
REGISTER_BUILDER("texture", &InterfaceObjectConfigurable::buildTexture);
|
||||
REGISTER_BUILDER("animation", &InterfaceObjectConfigurable::buildAnimation);
|
||||
REGISTER_BUILDER("label", &InterfaceObjectConfigurable::buildLabel);
|
||||
REGISTER_BUILDER("toggleGroup", &InterfaceObjectConfigurable::buildToggleGroup);
|
||||
REGISTER_BUILDER("toggleButton", &InterfaceObjectConfigurable::buildToggleButton);
|
||||
REGISTER_BUILDER("button", &InterfaceObjectConfigurable::buildButton);
|
||||
REGISTER_BUILDER("labelGroup", &InterfaceObjectConfigurable::buildLabelGroup);
|
||||
REGISTER_BUILDER("slider", &InterfaceObjectConfigurable::buildSlider);
|
||||
}
|
||||
|
||||
void InterfaceObjectConfigurable::registerBuilder(const std::string & type, BuilderFunction f)
|
||||
{
|
||||
builders[type] = f;
|
||||
}
|
||||
|
||||
void InterfaceObjectConfigurable::addCallback(const std::string & callbackName, std::function<void(int)> callback)
|
||||
{
|
||||
callbacks[callbackName] = callback;
|
||||
}
|
||||
|
||||
void InterfaceObjectConfigurable::init(const JsonNode &config)
|
||||
{
|
||||
OBJ_CONSTRUCTION;
|
||||
logGlobal->debug("Building configurable interface object");
|
||||
for(auto & item : config["variables"].Struct())
|
||||
{
|
||||
logGlobal->debug("Read variable named %s", item.first);
|
||||
variables[item.first] = item.second;
|
||||
}
|
||||
|
||||
int unnamedObjectId = 0;
|
||||
const std::string unnamedObjectPrefix = "__widget_";
|
||||
for(const auto & item : config["items"].Vector())
|
||||
{
|
||||
std::string name = item["name"].isNull()
|
||||
? unnamedObjectPrefix + std::to_string(unnamedObjectId++)
|
||||
: item["name"].String();
|
||||
logGlobal->debug("Building widget with name %s", name);
|
||||
widgets[name] = buildWidget(item);
|
||||
}
|
||||
}
|
||||
|
||||
std::string InterfaceObjectConfigurable::readText(const JsonNode & config) const
|
||||
{
|
||||
if(config.isNull())
|
||||
return "";
|
||||
|
||||
if(config.isNumber())
|
||||
{
|
||||
logGlobal->debug("Reading text from generaltext handler id:%d", config.Integer());
|
||||
return CGI->generaltexth->allTexts[config.Integer()];
|
||||
}
|
||||
|
||||
const std::string delimiter = "/";
|
||||
std::string s = config.String();
|
||||
logGlobal->debug("Reading text from translations by key: %s", s);
|
||||
JsonNode translated = CGI->generaltexth->localizedTexts;
|
||||
for(size_t p = s.find(delimiter); p != std::string::npos; p = s.find(delimiter))
|
||||
{
|
||||
translated = translated[s.substr(0, p)];
|
||||
s.erase(0, p + delimiter.length());
|
||||
}
|
||||
if(s == config.String())
|
||||
{
|
||||
logGlobal->warn("Reading non-translated text: %s", s);
|
||||
return s;
|
||||
}
|
||||
return translated[s].String();
|
||||
}
|
||||
|
||||
Point InterfaceObjectConfigurable::readPosition(const JsonNode & config) const
|
||||
{
|
||||
Point p;
|
||||
logGlobal->debug("Reading point");
|
||||
p.x = config["x"].Integer();
|
||||
p.y = config["y"].Integer();
|
||||
return p;
|
||||
}
|
||||
|
||||
Rect InterfaceObjectConfigurable::readRect(const JsonNode & config) const
|
||||
{
|
||||
Rect p;
|
||||
logGlobal->debug("Reading rect");
|
||||
p.x = config["x"].Integer();
|
||||
p.y = config["y"].Integer();
|
||||
p.w = config["w"].Integer();
|
||||
p.h = config["h"].Integer();
|
||||
return p;
|
||||
}
|
||||
|
||||
ETextAlignment InterfaceObjectConfigurable::readTextAlignment(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Reading text alignment");
|
||||
if(!config.isNull())
|
||||
{
|
||||
if(config.String() == "center")
|
||||
return ETextAlignment::CENTER;
|
||||
if(config.String() == "left")
|
||||
return ETextAlignment::TOPLEFT;
|
||||
if(config.String() == "right")
|
||||
return ETextAlignment::BOTTOMRIGHT;
|
||||
}
|
||||
logGlobal->debug("Uknown text alignment attribute");
|
||||
return ETextAlignment::CENTER;
|
||||
}
|
||||
|
||||
SDL_Color InterfaceObjectConfigurable::readColor(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Reading color");
|
||||
if(!config.isNull())
|
||||
{
|
||||
if(config.String() == "yellow")
|
||||
return Colors::YELLOW;
|
||||
if(config.String() == "white")
|
||||
return Colors::WHITE;
|
||||
if(config.String() == "gold")
|
||||
return Colors::METALLIC_GOLD;
|
||||
if(config.String() == "green")
|
||||
return Colors::GREEN;
|
||||
if(config.String() == "orange")
|
||||
return Colors::ORANGE;
|
||||
if(config.String() == "bright-yellow")
|
||||
return Colors::BRIGHT_YELLOW;
|
||||
}
|
||||
logGlobal->debug("Uknown color attribute");
|
||||
return Colors::DEFAULT_KEY_COLOR;
|
||||
|
||||
}
|
||||
EFonts InterfaceObjectConfigurable::readFont(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Reading font");
|
||||
if(!config.isNull())
|
||||
{
|
||||
if(config.String() == "big")
|
||||
return EFonts::FONT_BIG;
|
||||
if(config.String() == "medium")
|
||||
return EFonts::FONT_MEDIUM;
|
||||
if(config.String() == "small")
|
||||
return EFonts::FONT_SMALL;
|
||||
if(config.String() == "tiny")
|
||||
return EFonts::FONT_TINY;
|
||||
}
|
||||
logGlobal->debug("Uknown font attribute");
|
||||
return EFonts::FONT_TIMES;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> InterfaceObjectConfigurable::readHintText(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Reading hint text");
|
||||
std::pair<std::string, std::string> result;
|
||||
if(!config.isNull())
|
||||
{
|
||||
if(config.isNumber())
|
||||
{
|
||||
logGlobal->debug("Reading hint text (zelp) from generaltext handler id:%d", config.Integer());
|
||||
return CGI->generaltexth->zelp[config.Integer()];
|
||||
}
|
||||
|
||||
if(config.getType() == JsonNode::JsonType::DATA_STRUCT)
|
||||
{
|
||||
result.first = readText(config["hover"]);
|
||||
result.second = readText(config["help"]);
|
||||
return result;
|
||||
}
|
||||
if(config.getType() == JsonNode::JsonType::DATA_STRING)
|
||||
{
|
||||
logGlobal->debug("Reading non-translated hint: %s", config.String());
|
||||
result.first = result.second = config.String();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<CPicture> InterfaceObjectConfigurable::buildPicture(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CPicture");
|
||||
auto image = config["image"].String();
|
||||
auto position = readPosition(config["position"]);
|
||||
auto pic = std::make_shared<CPicture>(image, position.x, position.y);
|
||||
if(!config["visible"].isNull())
|
||||
pic->visible = config["visible"].Bool();
|
||||
return pic;
|
||||
}
|
||||
|
||||
std::shared_ptr<CLabel> InterfaceObjectConfigurable::buildLabel(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CLabel");
|
||||
auto font = readFont(config["font"]);
|
||||
auto alignment = readTextAlignment(config["alignment"]);
|
||||
auto color = readColor(config["color"]);
|
||||
auto text = readText(config["text"]);
|
||||
auto position = readPosition(config["position"]);
|
||||
return std::make_shared<CLabel>(position.x, position.y, font, alignment, color, text);
|
||||
}
|
||||
|
||||
std::shared_ptr<CToggleGroup> InterfaceObjectConfigurable::buildToggleGroup(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CToggleGroup");
|
||||
auto position = readPosition(config["position"]);
|
||||
auto group = std::make_shared<CToggleGroup>(0);
|
||||
group->pos += position;
|
||||
if(!config["items"].isNull())
|
||||
{
|
||||
OBJ_CONSTRUCTION_TARGETED(group.get());
|
||||
int itemIdx = -1;
|
||||
for(const auto & item : config["items"].Vector())
|
||||
{
|
||||
itemIdx = item["index"].isNull() ? itemIdx + 1 : item["index"].Integer();
|
||||
group->addToggle(itemIdx, std::dynamic_pointer_cast<CToggleBase>(buildWidget(item)));
|
||||
}
|
||||
}
|
||||
if(!config["selected"].isNull())
|
||||
group->setSelected(config["selected"].Integer());
|
||||
if(!config["callback"].isNull())
|
||||
group->addCallback(callbacks.at(config["callback"].String()));
|
||||
return group;
|
||||
}
|
||||
|
||||
std::shared_ptr<CToggleButton> InterfaceObjectConfigurable::buildToggleButton(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CToggleButton");
|
||||
auto position = readPosition(config["position"]);
|
||||
auto image = config["image"].String();
|
||||
auto zelp = readHintText(config["zelp"]);
|
||||
auto button = std::make_shared<CToggleButton>(position, image, zelp);
|
||||
if(!config["selected"].isNull())
|
||||
button->setSelected(config["selected"].Bool());
|
||||
if(!config["imageOrder"].isNull())
|
||||
{
|
||||
auto imgOrder = config["imageOrder"].Vector();
|
||||
assert(imgOrder.size() >= 4);
|
||||
button->setImageOrder(imgOrder[0].Integer(), imgOrder[1].Integer(), imgOrder[2].Integer(), imgOrder[3].Integer());
|
||||
}
|
||||
if(!config["callback"].isNull())
|
||||
button->addCallback(callbacks.at(config["callback"].String()));
|
||||
return button;
|
||||
}
|
||||
|
||||
std::shared_ptr<CButton> InterfaceObjectConfigurable::buildButton(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CButton");
|
||||
auto position = readPosition(config["position"]);
|
||||
auto image = config["image"].String();
|
||||
auto zelp = readHintText(config["zelp"]);
|
||||
auto button = std::make_shared<CButton>(position, image, zelp);
|
||||
if(!config["items"].isNull())
|
||||
{
|
||||
for(const auto & item : config["items"].Vector())
|
||||
{
|
||||
button->addOverlay(buildWidget(item));
|
||||
}
|
||||
}
|
||||
if(!config["callback"].isNull())
|
||||
button->addCallback(std::bind(callbacks.at(config["callback"].String()), 0));
|
||||
return button;
|
||||
}
|
||||
|
||||
std::shared_ptr<CLabelGroup> InterfaceObjectConfigurable::buildLabelGroup(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CLabelGroup");
|
||||
auto font = readFont(config["font"]);
|
||||
auto alignment = readTextAlignment(config["alignment"]);
|
||||
auto color = readColor(config["color"]);
|
||||
auto group = std::make_shared<CLabelGroup>(font, alignment, color);
|
||||
if(!config["items"].isNull())
|
||||
{
|
||||
for(const auto & item : config["items"].Vector())
|
||||
{
|
||||
auto position = readPosition(item["position"]);
|
||||
auto text = readText(item["text"]);
|
||||
group->add(position.x, position.y, text);
|
||||
}
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
std::shared_ptr<CSlider> InterfaceObjectConfigurable::buildSlider(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CSlider");
|
||||
auto position = readPosition(config["position"]);
|
||||
int length = config["size"].Integer();
|
||||
auto style = config["style"].String() == "brown" ? CSlider::BROWN : CSlider::BLUE;
|
||||
auto itemsVisible = config["itemsVisible"].Integer();
|
||||
auto itemsTotal = config["itemsTotal"].Integer();
|
||||
auto value = config["selected"].Integer();
|
||||
bool horizontal = config["orientation"].String() == "horizontal";
|
||||
return std::make_shared<CSlider>(position, length, callbacks.at(config["callback"].String()), itemsVisible, itemsTotal, value, horizontal, style);
|
||||
}
|
||||
|
||||
std::shared_ptr<CAnimImage> InterfaceObjectConfigurable::buildImage(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CAnimImage");
|
||||
auto position = readPosition(config["position"]);
|
||||
auto image = config["image"].String();
|
||||
int group = config["group"].isNull() ? 0 : config["group"].Integer();
|
||||
int frame = config["frame"].isNull() ? 0 : config["frame"].Integer();
|
||||
return std::make_shared<CAnimImage>(image, frame, group, position.x, position.y);
|
||||
}
|
||||
|
||||
std::shared_ptr<CFilledTexture> InterfaceObjectConfigurable::buildTexture(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CFilledTexture");
|
||||
auto image = config["image"].String();
|
||||
auto rect = readRect(config["rect"]);
|
||||
return std::make_shared<CFilledTexture>(image, rect);
|
||||
}
|
||||
|
||||
std::shared_ptr<CShowableAnim> InterfaceObjectConfigurable::buildAnimation(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget CShowableAnim");
|
||||
auto position = readPosition(config["position"]);
|
||||
auto image = config["image"].String();
|
||||
ui8 flags = 0;
|
||||
if(!config["repeat"].Bool())
|
||||
flags |= CShowableAnim::EFlags::PLAY_ONCE;
|
||||
|
||||
int group = config["group"].isNull() ? 0 : config["group"].Integer();
|
||||
auto anim = std::make_shared<CShowableAnim>(position.x, position.y, image, flags, 4, group);
|
||||
if(!config["alpha"].isNull())
|
||||
anim->setAlpha(config["alpha"].Integer());
|
||||
if(!config["callback"].isNull())
|
||||
anim->callback = std::bind(callbacks.at(config["callback"].String()), 0);
|
||||
if(!config["frames"].isNull())
|
||||
{
|
||||
auto b = config["frames"]["start"].Integer();
|
||||
auto e = config["frames"]["end"].Integer();
|
||||
anim->set(group, b, e);
|
||||
}
|
||||
return anim;
|
||||
}
|
||||
|
||||
std::shared_ptr<CIntObject> InterfaceObjectConfigurable::buildWidget(JsonNode config) const
|
||||
{
|
||||
assert(!config.isNull());
|
||||
logGlobal->debug("Building widget from config");
|
||||
//overrides from variables
|
||||
for(auto & item : config["overrides"].Struct())
|
||||
{
|
||||
logGlobal->debug("Config attribute %s was overriden by variable %s", item.first, item.second.String());
|
||||
config[item.first] = variables[item.second.String()];
|
||||
}
|
||||
|
||||
auto type = config["type"].String();
|
||||
auto buildIterator = builders.find(type);
|
||||
if(buildIterator != builders.end())
|
||||
return (buildIterator->second)(config);
|
||||
|
||||
logGlobal->error("Builder with type %s is not registered", type);
|
||||
return nullptr;
|
||||
}
|
85
client/gui/InterfaceObjectConfigurable.h
Normal file
85
client/gui/InterfaceObjectConfigurable.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* InterfaceBuilder.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CIntObject.h"
|
||||
|
||||
#include "../../lib/JsonNode.h"
|
||||
|
||||
class CPicture;
|
||||
class CLabel;
|
||||
class CToggleGroup;
|
||||
class CToggleButton;
|
||||
class CButton;
|
||||
class CLabelGroup;
|
||||
class CSlider;
|
||||
class CAnimImage;
|
||||
class CShowableAnim;
|
||||
class CFilledTexture;
|
||||
|
||||
#define REGISTER_BUILDER(type, method) registerBuilder(type, std::bind(method, this, std::placeholders::_1))
|
||||
|
||||
class InterfaceObjectConfigurable: public CIntObject
|
||||
{
|
||||
public:
|
||||
InterfaceObjectConfigurable(int used=0, Point offset=Point());
|
||||
InterfaceObjectConfigurable(const JsonNode & config, int used=0, Point offset=Point());
|
||||
|
||||
protected:
|
||||
|
||||
using BuilderFunction = std::function<std::shared_ptr<CIntObject>(const JsonNode &)>;
|
||||
void registerBuilder(const std::string &, BuilderFunction);
|
||||
|
||||
//must be called after adding callbacks
|
||||
void init(const JsonNode & config);
|
||||
|
||||
void addCallback(const std::string & callbackName, std::function<void(int)> callback);
|
||||
JsonNode variables;
|
||||
|
||||
template<class T>
|
||||
const std::shared_ptr<T> widget(const std::string & name) const
|
||||
{
|
||||
auto iter = widgets.find(name);
|
||||
if(iter == widgets.end())
|
||||
return nullptr;
|
||||
return std::dynamic_pointer_cast<T>(iter->second);
|
||||
}
|
||||
|
||||
//basic serializers
|
||||
Point readPosition(const JsonNode &) const;
|
||||
Rect readRect(const JsonNode &) const;
|
||||
ETextAlignment readTextAlignment(const JsonNode &) const;
|
||||
SDL_Color readColor(const JsonNode &) const;
|
||||
EFonts readFont(const JsonNode &) const;
|
||||
std::string readText(const JsonNode &) const;
|
||||
std::pair<std::string, std::string> readHintText(const JsonNode &) const;
|
||||
|
||||
//basic widgets
|
||||
std::shared_ptr<CPicture> buildPicture(const JsonNode &) const;
|
||||
std::shared_ptr<CLabel> buildLabel(const JsonNode &) const;
|
||||
std::shared_ptr<CToggleGroup> buildToggleGroup(const JsonNode &) const;
|
||||
std::shared_ptr<CToggleButton> buildToggleButton(const JsonNode &) const;
|
||||
std::shared_ptr<CButton> buildButton(const JsonNode &) const;
|
||||
std::shared_ptr<CLabelGroup> buildLabelGroup(const JsonNode &) const;
|
||||
std::shared_ptr<CSlider> buildSlider(const JsonNode &) const;
|
||||
std::shared_ptr<CAnimImage> buildImage(const JsonNode &) const;
|
||||
std::shared_ptr<CShowableAnim> buildAnimation(const JsonNode &) const;
|
||||
std::shared_ptr<CFilledTexture> buildTexture(const JsonNode &) const;
|
||||
|
||||
//composite widgets
|
||||
std::shared_ptr<CIntObject> buildWidget(JsonNode config) const;
|
||||
|
||||
private:
|
||||
|
||||
std::map<std::string, BuilderFunction> builders;
|
||||
std::map<std::string, std::shared_ptr<CIntObject>> widgets;
|
||||
std::map<std::string, std::function<void(int)>> callbacks;
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* NotificationHandler.cpp, part of VCMI engine
|
||||
* NotificationHandler.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
|
@ -27,127 +27,68 @@
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/mapping/CMapInfo.h"
|
||||
#include "../../lib/rmg/CMapGenOptions.h"
|
||||
#include "../../lib/CModHandler.h"
|
||||
#include "../../lib/rmg/CRmgTemplateStorage.h"
|
||||
|
||||
RandomMapTab::RandomMapTab()
|
||||
RandomMapTab::RandomMapTab():
|
||||
InterfaceObjectConfigurable()
|
||||
{
|
||||
recActions = 0;
|
||||
mapGenOptions = std::make_shared<CMapGenOptions>();
|
||||
OBJ_CONSTRUCTION;
|
||||
background = std::make_shared<CPicture>("RANMAPBK", 0, 6);
|
||||
|
||||
labelHeadlineBig = std::make_shared<CLabel>(222, 36, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[738]);
|
||||
labelHeadlineSmall = std::make_shared<CLabel>(222, 56, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[739]);
|
||||
|
||||
labelMapSize = std::make_shared<CLabel>(104, 97, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[752]);
|
||||
groupMapSize = std::make_shared<CToggleGroup>(0);
|
||||
groupMapSize->pos.y += 81;
|
||||
groupMapSize->pos.x += 158;
|
||||
const std::vector<std::string> mapSizeBtns = {"RANSIZS", "RANSIZM", "RANSIZL", "RANSIZX"};
|
||||
addButtonsToGroup(groupMapSize.get(), mapSizeBtns, 0, 3, 47, 198);
|
||||
groupMapSize->setSelected(1);
|
||||
groupMapSize->addCallback([&](int btnId)
|
||||
|
||||
const JsonNode config(ResourceID("config/widgets/randomMapTab.json"));
|
||||
addCallback("toggleMapSize", [&](int btnId)
|
||||
{
|
||||
auto mapSizeVal = getPossibleMapSizes();
|
||||
mapGenOptions->setWidth(mapSizeVal[btnId]);
|
||||
mapGenOptions->setHeight(mapSizeVal[btnId]);
|
||||
if(mapGenOptions->getMapTemplate())
|
||||
if(!mapGenOptions->getMapTemplate()->matchesSize(int3{mapGenOptions->getWidth(), mapGenOptions->getHeight(), 1 + mapGenOptions->getHasTwoLevels()}))
|
||||
setTemplate(nullptr);
|
||||
updateMapInfoByHost();
|
||||
});
|
||||
|
||||
buttonTwoLevels = std::make_shared<CToggleButton>(Point(346, 81), "RANUNDR", CGI->generaltexth->zelp[202]);
|
||||
buttonTwoLevels->setSelected(true);
|
||||
buttonTwoLevels->addCallback([&](bool on)
|
||||
addCallback("toggleTwoLevels", [&](bool on)
|
||||
{
|
||||
mapGenOptions->setHasTwoLevels(on);
|
||||
if(mapGenOptions->getMapTemplate())
|
||||
if(!mapGenOptions->getMapTemplate()->matchesSize(int3{mapGenOptions->getWidth(), mapGenOptions->getHeight(), 1 + mapGenOptions->getHasTwoLevels()}))
|
||||
setTemplate(nullptr);
|
||||
updateMapInfoByHost();
|
||||
});
|
||||
|
||||
labelGroupForOptions = std::make_shared<CLabelGroup>(FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
|
||||
// Create number defs list
|
||||
std::vector<std::string> numberDefs;
|
||||
for(int i = 0; i <= 8; ++i)
|
||||
{
|
||||
numberDefs.push_back("RANNUM" + boost::lexical_cast<std::string>(i));
|
||||
}
|
||||
|
||||
const int NUMBERS_WIDTH = 32;
|
||||
const int BTNS_GROUP_LEFT_MARGIN = 67;
|
||||
labelGroupForOptions->add(68, 133, CGI->generaltexth->allTexts[753]);
|
||||
groupMaxPlayers = std::make_shared<CToggleGroup>(0);
|
||||
groupMaxPlayers->pos.y += 153;
|
||||
groupMaxPlayers->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(groupMaxPlayers.get(), numberDefs, 1, 8, NUMBERS_WIDTH, 204, 212);
|
||||
groupMaxPlayers->addCallback([&](int btnId)
|
||||
|
||||
addCallback("setPlayersCount", [&](int btnId)
|
||||
{
|
||||
mapGenOptions->setPlayerCount(btnId);
|
||||
deactivateButtonsFrom(groupMaxTeams.get(), btnId);
|
||||
|
||||
// deactive some CompOnlyPlayers buttons to prevent total number of players exceeds PlayerColor::PLAYER_LIMIT_I
|
||||
deactivateButtonsFrom(groupCompOnlyPlayers.get(), PlayerColor::PLAYER_LIMIT_I - btnId + 1);
|
||||
|
||||
validatePlayersCnt(btnId);
|
||||
setMapGenOptions(mapGenOptions);
|
||||
updateMapInfoByHost();
|
||||
});
|
||||
|
||||
labelGroupForOptions->add(68, 199, CGI->generaltexth->allTexts[754]);
|
||||
groupMaxTeams = std::make_shared<CToggleGroup>(0);
|
||||
groupMaxTeams->pos.y += 219;
|
||||
groupMaxTeams->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(groupMaxTeams.get(), numberDefs, 0, 7, NUMBERS_WIDTH, 214, 222);
|
||||
groupMaxTeams->addCallback([&](int btnId)
|
||||
|
||||
addCallback("setTeamsCount", [&](int btnId)
|
||||
{
|
||||
mapGenOptions->setTeamCount(btnId);
|
||||
updateMapInfoByHost();
|
||||
});
|
||||
|
||||
labelGroupForOptions->add(68, 265, CGI->generaltexth->allTexts[755]);
|
||||
groupCompOnlyPlayers = std::make_shared<CToggleGroup>(0);
|
||||
groupCompOnlyPlayers->pos.y += 285;
|
||||
groupCompOnlyPlayers->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(groupCompOnlyPlayers.get(), numberDefs, 0, 7, NUMBERS_WIDTH, 224, 232);
|
||||
groupCompOnlyPlayers->addCallback([&](int btnId)
|
||||
|
||||
addCallback("setCompOnlyPlayers", [&](int btnId)
|
||||
{
|
||||
mapGenOptions->setCompOnlyPlayerCount(btnId);
|
||||
|
||||
// deactive some MaxPlayers buttons to prevent total number of players exceeds PlayerColor::PLAYER_LIMIT_I
|
||||
deactivateButtonsFrom(groupMaxPlayers.get(), PlayerColor::PLAYER_LIMIT_I - btnId + 1);
|
||||
|
||||
deactivateButtonsFrom(groupCompOnlyTeams.get(), (btnId == 0 ? 1 : btnId));
|
||||
validateCompOnlyPlayersCnt(btnId);
|
||||
setMapGenOptions(mapGenOptions);
|
||||
updateMapInfoByHost();
|
||||
});
|
||||
|
||||
labelGroupForOptions->add(68, 331, CGI->generaltexth->allTexts[756]);
|
||||
groupCompOnlyTeams = std::make_shared<CToggleGroup>(0);
|
||||
groupCompOnlyTeams->pos.y += 351;
|
||||
groupCompOnlyTeams->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(groupCompOnlyTeams.get(), numberDefs, 0, 6, NUMBERS_WIDTH, 234, 241);
|
||||
deactivateButtonsFrom(groupCompOnlyTeams.get(), 1);
|
||||
groupCompOnlyTeams->addCallback([&](int btnId)
|
||||
|
||||
addCallback("setCompOnlyTeams", [&](int btnId)
|
||||
{
|
||||
mapGenOptions->setCompOnlyTeamCount(btnId);
|
||||
updateMapInfoByHost();
|
||||
});
|
||||
|
||||
labelGroupForOptions->add(68, 398, CGI->generaltexth->allTexts[757]);
|
||||
const int WIDE_BTN_WIDTH = 85;
|
||||
groupWaterContent = std::make_shared<CToggleGroup>(0);
|
||||
groupWaterContent->pos.y += 419;
|
||||
groupWaterContent->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
const std::vector<std::string> waterContentBtns = {"RANNONE", "RANNORM", "RANISLD"};
|
||||
addButtonsWithRandToGroup(groupWaterContent.get(), waterContentBtns, 0, 2, WIDE_BTN_WIDTH, 243, 246);
|
||||
groupWaterContent->addCallback([&](int btnId)
|
||||
|
||||
addCallback("setWaterContent", [&](int btnId)
|
||||
{
|
||||
mapGenOptions->setWaterContent(static_cast<EWaterContent::EWaterContent>(btnId));
|
||||
updateMapInfoByHost();
|
||||
});
|
||||
|
||||
labelGroupForOptions->add(68, 465, CGI->generaltexth->allTexts[758]);
|
||||
groupMonsterStrength = std::make_shared<CToggleGroup>(0);
|
||||
groupMonsterStrength->pos.y += 485;
|
||||
groupMonsterStrength->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
const std::vector<std::string> monsterStrengthBtns = {"RANWEAK", "RANNORM", "RANSTRG"};
|
||||
addButtonsWithRandToGroup(groupMonsterStrength.get(), monsterStrengthBtns, 2, 4, WIDE_BTN_WIDTH, 248, 251, EMonsterStrength::RANDOM, false);
|
||||
groupMonsterStrength->addCallback([&](int btnId)
|
||||
|
||||
addCallback("setMonsterStrength", [&](int btnId)
|
||||
{
|
||||
if(btnId < 0)
|
||||
mapGenOptions->setMonsterStrength(EMonsterStrength::RANDOM);
|
||||
@ -155,9 +96,31 @@ RandomMapTab::RandomMapTab()
|
||||
mapGenOptions->setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId)); //value 2 to 4
|
||||
updateMapInfoByHost();
|
||||
});
|
||||
|
||||
buttonShowRandomMaps = std::make_shared<CButton>(Point(54, 535), "RANSHOW", CGI->generaltexth->zelp[252]);
|
||||
|
||||
|
||||
//new callbacks available only from mod
|
||||
addCallback("templateSelection", [&](int)
|
||||
{
|
||||
GH.pushIntT<TemplatesDropBox>(*this, int3{mapGenOptions->getWidth(), mapGenOptions->getHeight(), 1 + mapGenOptions->getHasTwoLevels()});
|
||||
});
|
||||
|
||||
addCallback("teamAlignments", [&](int)
|
||||
{
|
||||
GH.pushIntT<TeamAlignmentsWidget>(*this);
|
||||
});
|
||||
|
||||
for(auto road : VLC->terrainTypeHandler->roads())
|
||||
{
|
||||
std::string cbRoadType = "selectRoad_" + road.name;
|
||||
addCallback(cbRoadType, [&, road](bool on)
|
||||
{
|
||||
mapGenOptions->setRoadEnabled(road.name, on);
|
||||
updateMapInfoByHost();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
init(config);
|
||||
|
||||
updateMapInfoByHost();
|
||||
}
|
||||
|
||||
@ -192,6 +155,7 @@ void RandomMapTab::updateMapInfoByHost()
|
||||
|
||||
mapInfo->mapHeader->howManyTeams = playersToGen;
|
||||
|
||||
std::set<TeamID> occupiedTeams;
|
||||
for(int i = 0; i < playersToGen; ++i)
|
||||
{
|
||||
PlayerInfo player;
|
||||
@ -205,60 +169,153 @@ void RandomMapTab::updateMapInfoByHost()
|
||||
{
|
||||
player.canHumanPlay = true;
|
||||
}
|
||||
player.team = TeamID(i);
|
||||
auto team = mapGenOptions->getPlayersSettings().at(PlayerColor(i)).getTeam();
|
||||
player.team = team;
|
||||
occupiedTeams.insert(team);
|
||||
player.hasMainTown = true;
|
||||
player.generateHeroAtMainTown = true;
|
||||
mapInfo->mapHeader->players.push_back(player);
|
||||
}
|
||||
for(auto & player : mapInfo->mapHeader->players)
|
||||
{
|
||||
for(int i = 0; player.team == TeamID::NO_TEAM; ++i)
|
||||
{
|
||||
TeamID team(i);
|
||||
if(!occupiedTeams.count(team))
|
||||
{
|
||||
player.team = team;
|
||||
occupiedTeams.insert(team);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapInfoChanged(mapInfo, mapGenOptions);
|
||||
}
|
||||
|
||||
void RandomMapTab::setMapGenOptions(std::shared_ptr<CMapGenOptions> opts)
|
||||
{
|
||||
groupMapSize->setSelected(vstd::find_pos(getPossibleMapSizes(), opts->getWidth()));
|
||||
buttonTwoLevels->setSelected(opts->getHasTwoLevels());
|
||||
groupMaxPlayers->setSelected(opts->getPlayerCount());
|
||||
groupMaxTeams->setSelected(opts->getTeamCount());
|
||||
groupCompOnlyPlayers->setSelected(opts->getCompOnlyPlayerCount());
|
||||
groupCompOnlyTeams->setSelected(opts->getCompOnlyTeamCount());
|
||||
groupWaterContent->setSelected(opts->getWaterContent());
|
||||
groupMonsterStrength->setSelected(opts->getMonsterStrength());
|
||||
}
|
||||
|
||||
void RandomMapTab::addButtonsWithRandToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex, int helpRandIndex, int randIndex, bool animIdfromBtnId) const
|
||||
{
|
||||
addButtonsToGroup(group, defs, nStart, nEnd, btnWidth, helpStartIndex, animIdfromBtnId);
|
||||
|
||||
// Buttons are relative to button group, TODO better solution?
|
||||
SObjectConstruction obj__i(group);
|
||||
const std::string RANDOM_DEF = "RANRAND";
|
||||
group->addToggle(randIndex, std::make_shared<CToggleButton>(Point(256, 0), RANDOM_DEF, CGI->generaltexth->zelp[helpRandIndex]));
|
||||
group->setSelected(randIndex);
|
||||
}
|
||||
|
||||
void RandomMapTab::addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex, bool animIdfromBtnId) const
|
||||
{
|
||||
// Buttons are relative to button group, TODO better solution?
|
||||
SObjectConstruction obj__i(group);
|
||||
int cnt = nEnd - nStart + 1;
|
||||
for(int i = 0; i < cnt; ++i)
|
||||
mapGenOptions = opts;
|
||||
|
||||
//prepare allowed options
|
||||
for(int i = 0; i <= PlayerColor::PLAYER_LIMIT_I; ++i)
|
||||
{
|
||||
auto button = std::make_shared<CToggleButton>(Point(i * btnWidth, 0), animIdfromBtnId ? defs[i + nStart] : defs[i], CGI->generaltexth->zelp[helpStartIndex + i]);
|
||||
// For blocked state we should use pressed image actually
|
||||
button->setImageOrder(0, 1, 1, 3);
|
||||
group->addToggle(i + nStart, button);
|
||||
playerCountAllowed.insert(i);
|
||||
compCountAllowed.insert(i);
|
||||
playerTeamsAllowed.insert(i);
|
||||
compTeamsAllowed.insert(i);
|
||||
}
|
||||
auto * tmpl = mapGenOptions->getMapTemplate();
|
||||
if(tmpl)
|
||||
{
|
||||
playerCountAllowed = tmpl->getPlayers().getNumbers();
|
||||
compCountAllowed = tmpl->getCpuPlayers().getNumbers();
|
||||
}
|
||||
if(mapGenOptions->getPlayerCount() != CMapGenOptions::RANDOM_SIZE)
|
||||
{
|
||||
vstd::erase_if(compCountAllowed,
|
||||
[opts](int el){
|
||||
return PlayerColor::PLAYER_LIMIT_I - opts->getPlayerCount() < el;
|
||||
});
|
||||
vstd::erase_if(playerTeamsAllowed,
|
||||
[opts](int el){
|
||||
return opts->getPlayerCount() <= el;
|
||||
});
|
||||
|
||||
if(!playerTeamsAllowed.count(opts->getTeamCount()))
|
||||
opts->setTeamCount(CMapGenOptions::RANDOM_SIZE);
|
||||
}
|
||||
if(mapGenOptions->getCompOnlyPlayerCount() != CMapGenOptions::RANDOM_SIZE)
|
||||
{
|
||||
vstd::erase_if(playerCountAllowed,
|
||||
[opts](int el){
|
||||
return PlayerColor::PLAYER_LIMIT_I - opts->getCompOnlyPlayerCount() < el;
|
||||
});
|
||||
vstd::erase_if(compTeamsAllowed,
|
||||
[opts](int el){
|
||||
return opts->getCompOnlyPlayerCount() <= el;
|
||||
});
|
||||
|
||||
if(!compTeamsAllowed.count(opts->getCompOnlyTeamCount()))
|
||||
opts->setCompOnlyTeamCount(CMapGenOptions::RANDOM_SIZE);
|
||||
}
|
||||
|
||||
if(auto w = widget<CToggleGroup>("groupMapSize"))
|
||||
w->setSelected(vstd::find_pos(getPossibleMapSizes(), opts->getWidth()));
|
||||
if(auto w = widget<CToggleButton>("buttonTwoLevels"))
|
||||
w->setSelected(opts->getHasTwoLevels());
|
||||
if(auto w = widget<CToggleGroup>("groupMaxPlayers"))
|
||||
{
|
||||
w->setSelected(opts->getPlayerCount());
|
||||
deactivateButtonsFrom(*w, playerCountAllowed);
|
||||
}
|
||||
if(auto w = widget<CToggleGroup>("groupMaxTeams"))
|
||||
{
|
||||
w->setSelected(opts->getTeamCount());
|
||||
deactivateButtonsFrom(*w, playerTeamsAllowed);
|
||||
}
|
||||
if(auto w = widget<CToggleGroup>("groupCompOnlyPlayers"))
|
||||
{
|
||||
w->setSelected(opts->getCompOnlyPlayerCount());
|
||||
deactivateButtonsFrom(*w, compCountAllowed);
|
||||
}
|
||||
if(auto w = widget<CToggleGroup>("groupCompOnlyTeams"))
|
||||
{
|
||||
w->setSelected(opts->getCompOnlyTeamCount());
|
||||
deactivateButtonsFrom(*w, compTeamsAllowed);
|
||||
}
|
||||
if(auto w = widget<CToggleGroup>("groupWaterContent"))
|
||||
{
|
||||
w->setSelected(opts->getWaterContent());
|
||||
if(opts->getMapTemplate())
|
||||
{
|
||||
std::set<int> allowedWater(opts->getMapTemplate()->getWaterContentAllowed().begin(), opts->getMapTemplate()->getWaterContentAllowed().end());
|
||||
deactivateButtonsFrom(*w, allowedWater);
|
||||
}
|
||||
else
|
||||
deactivateButtonsFrom(*w, {-1});
|
||||
}
|
||||
if(auto w = widget<CToggleGroup>("groupMonsterStrength"))
|
||||
w->setSelected(opts->getMonsterStrength());
|
||||
if(auto w = widget<CButton>("templateButton"))
|
||||
{
|
||||
if(tmpl)
|
||||
w->addTextOverlay(tmpl->getName(), EFonts::FONT_SMALL);
|
||||
else
|
||||
w->addTextOverlay(readText(variables["defaultTemplate"]), EFonts::FONT_SMALL);
|
||||
}
|
||||
for(auto r : VLC->terrainTypeHandler->roads())
|
||||
{
|
||||
if(auto w = widget<CToggleButton>(r.name))
|
||||
{
|
||||
w->setSelected(opts->isRoadEnabled(r.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RandomMapTab::deactivateButtonsFrom(CToggleGroup * group, int startId)
|
||||
void RandomMapTab::setTemplate(const CRmgTemplate * tmpl)
|
||||
{
|
||||
logGlobal->debug("Blocking buttons from %d", startId);
|
||||
for(auto toggle : group->buttons)
|
||||
mapGenOptions->setMapTemplate(tmpl);
|
||||
setMapGenOptions(mapGenOptions);
|
||||
if(auto w = widget<CButton>("templateButton"))
|
||||
{
|
||||
if(tmpl)
|
||||
w->addTextOverlay(tmpl->getName(), EFonts::FONT_SMALL);
|
||||
else
|
||||
w->addTextOverlay(readText(variables["defaultTemplate"]), EFonts::FONT_SMALL);
|
||||
}
|
||||
updateMapInfoByHost();
|
||||
}
|
||||
|
||||
void RandomMapTab::deactivateButtonsFrom(CToggleGroup & group, const std::set<int> & allowed)
|
||||
{
|
||||
logGlobal->debug("Blocking buttons");
|
||||
for(auto toggle : group.buttons)
|
||||
{
|
||||
if(auto button = std::dynamic_pointer_cast<CToggleButton>(toggle.second))
|
||||
{
|
||||
if(startId == CMapGenOptions::RANDOM_SIZE || toggle.first < startId)
|
||||
if(allowed.count(CMapGenOptions::RANDOM_SIZE)
|
||||
|| allowed.count(toggle.first)
|
||||
|| toggle.first == CMapGenOptions::RANDOM_SIZE)
|
||||
{
|
||||
button->block(false);
|
||||
}
|
||||
@ -270,45 +327,243 @@ void RandomMapTab::deactivateButtonsFrom(CToggleGroup * group, int startId)
|
||||
}
|
||||
}
|
||||
|
||||
void RandomMapTab::validatePlayersCnt(int playersCnt)
|
||||
{
|
||||
if(playersCnt == CMapGenOptions::RANDOM_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(mapGenOptions->getTeamCount() >= playersCnt)
|
||||
{
|
||||
mapGenOptions->setTeamCount(playersCnt - 1);
|
||||
groupMaxTeams->setSelected(mapGenOptions->getTeamCount());
|
||||
}
|
||||
// total players should not exceed PlayerColor::PLAYER_LIMIT_I (8 in homm3)
|
||||
if(mapGenOptions->getCompOnlyPlayerCount() + playersCnt > PlayerColor::PLAYER_LIMIT_I)
|
||||
{
|
||||
mapGenOptions->setCompOnlyPlayerCount(PlayerColor::PLAYER_LIMIT_I - playersCnt);
|
||||
groupCompOnlyPlayers->setSelected(mapGenOptions->getCompOnlyPlayerCount());
|
||||
}
|
||||
|
||||
validateCompOnlyPlayersCnt(mapGenOptions->getCompOnlyPlayerCount());
|
||||
}
|
||||
|
||||
void RandomMapTab::validateCompOnlyPlayersCnt(int compOnlyPlayersCnt)
|
||||
{
|
||||
if(compOnlyPlayersCnt == CMapGenOptions::RANDOM_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(mapGenOptions->getCompOnlyTeamCount() >= compOnlyPlayersCnt)
|
||||
{
|
||||
int compOnlyTeamCount = compOnlyPlayersCnt == 0 ? 0 : compOnlyPlayersCnt - 1;
|
||||
mapGenOptions->setCompOnlyTeamCount(compOnlyTeamCount);
|
||||
updateMapInfoByHost();
|
||||
groupCompOnlyTeams->setSelected(compOnlyTeamCount);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> RandomMapTab::getPossibleMapSizes()
|
||||
{
|
||||
return {CMapHeader::MAP_SIZE_SMALL, CMapHeader::MAP_SIZE_MIDDLE, CMapHeader::MAP_SIZE_LARGE, CMapHeader::MAP_SIZE_XLARGE};
|
||||
return {CMapHeader::MAP_SIZE_SMALL, CMapHeader::MAP_SIZE_MIDDLE, CMapHeader::MAP_SIZE_LARGE, CMapHeader::MAP_SIZE_XLARGE, CMapHeader::MAP_SIZE_HUGE, CMapHeader::MAP_SIZE_XHUGE, CMapHeader::MAP_SIZE_GIANT};
|
||||
}
|
||||
|
||||
TemplatesDropBox::ListItem::ListItem(const JsonNode & config, TemplatesDropBox & _dropBox, Point position)
|
||||
: InterfaceObjectConfigurable(LCLICK | HOVER, position),
|
||||
dropBox(_dropBox)
|
||||
{
|
||||
OBJ_CONSTRUCTION;
|
||||
|
||||
init(config);
|
||||
|
||||
if(auto w = widget<CPicture>("hoverImage"))
|
||||
{
|
||||
pos.w = w->pos.w;
|
||||
pos.h = w->pos.h;
|
||||
}
|
||||
type |= REDRAW_PARENT;
|
||||
}
|
||||
|
||||
void TemplatesDropBox::ListItem::updateItem(int idx, const CRmgTemplate * _item)
|
||||
{
|
||||
if(auto w = widget<CLabel>("labelName"))
|
||||
{
|
||||
item = _item;
|
||||
if(item)
|
||||
{
|
||||
w->setText(item->getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(idx)
|
||||
w->setText("");
|
||||
else
|
||||
w->setText(readText(dropBox.variables["defaultTemplate"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TemplatesDropBox::ListItem::hover(bool on)
|
||||
{
|
||||
auto h = widget<CPicture>("hoverImage");
|
||||
auto w = widget<CLabel>("labelName");
|
||||
if(h && w)
|
||||
{
|
||||
if(w->getText().empty())
|
||||
{
|
||||
hovered = false;
|
||||
h->visible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
h->visible = on;
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
}
|
||||
|
||||
void TemplatesDropBox::ListItem::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if(down && hovered)
|
||||
{
|
||||
dropBox.setTemplate(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TemplatesDropBox::TemplatesDropBox(RandomMapTab & randomMapTab, int3 size):
|
||||
InterfaceObjectConfigurable(LCLICK | HOVER),
|
||||
randomMapTab(randomMapTab)
|
||||
{
|
||||
REGISTER_BUILDER("templateListItem", &TemplatesDropBox::buildListItem);
|
||||
|
||||
curItems = VLC->tplh->getTemplates();
|
||||
vstd::erase_if(curItems, [size](const CRmgTemplate * t){return !t->matchesSize(size);});
|
||||
curItems.insert(curItems.begin(), nullptr); //default template
|
||||
|
||||
const JsonNode config(ResourceID("config/widgets/randomMapTemplateWidget.json"));
|
||||
|
||||
addCallback("sliderMove", std::bind(&TemplatesDropBox::sliderMove, this, std::placeholders::_1));
|
||||
|
||||
OBJ_CONSTRUCTION;
|
||||
pos = randomMapTab.pos.topLeft();
|
||||
pos.w = randomMapTab.pos.w;
|
||||
pos.h = randomMapTab.pos.h;
|
||||
|
||||
init(config);
|
||||
|
||||
if(auto w = widget<CSlider>("slider"))
|
||||
{
|
||||
w->setAmount(curItems.size());
|
||||
}
|
||||
|
||||
updateListItems();
|
||||
}
|
||||
|
||||
std::shared_ptr<CIntObject> TemplatesDropBox::buildListItem(const JsonNode & config)
|
||||
{
|
||||
auto position = readPosition(config["position"]);
|
||||
listItems.push_back(std::make_shared<ListItem>(config, *this, position));
|
||||
return listItems.back();
|
||||
}
|
||||
|
||||
void TemplatesDropBox::sliderMove(int slidPos)
|
||||
{
|
||||
auto w = widget<CSlider>("slider");
|
||||
if(!w)
|
||||
return; // ignore spurious call when slider is being created
|
||||
updateListItems();
|
||||
redraw();
|
||||
}
|
||||
|
||||
void TemplatesDropBox::hover(bool on)
|
||||
{
|
||||
hovered = on;
|
||||
}
|
||||
|
||||
void TemplatesDropBox::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if(down && !hovered)
|
||||
{
|
||||
assert(GH.topInt().get() == this);
|
||||
GH.popInt(GH.topInt());
|
||||
}
|
||||
}
|
||||
|
||||
void TemplatesDropBox::updateListItems()
|
||||
{
|
||||
if(auto w = widget<CSlider>("slider"))
|
||||
{
|
||||
int elemIdx = w->getValue();
|
||||
for(auto item : listItems)
|
||||
{
|
||||
if(elemIdx < curItems.size())
|
||||
{
|
||||
item->updateItem(elemIdx, curItems[elemIdx]);
|
||||
elemIdx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->updateItem(elemIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TemplatesDropBox::setTemplate(const CRmgTemplate * tmpl)
|
||||
{
|
||||
randomMapTab.setTemplate(tmpl);
|
||||
assert(GH.topInt().get() == this);
|
||||
GH.popInt(GH.topInt());
|
||||
}
|
||||
|
||||
TeamAlignmentsWidget::TeamAlignmentsWidget(RandomMapTab & randomMapTab):
|
||||
InterfaceObjectConfigurable(),
|
||||
randomMapTab(randomMapTab)
|
||||
{
|
||||
const JsonNode config(ResourceID("config/widgets/randomMapTeamsWidget.json"));
|
||||
variables = config["variables"];
|
||||
|
||||
int humanPlayers = randomMapTab.obtainMapGenOptions().getPlayerCount();
|
||||
int cpuPlayers = randomMapTab.obtainMapGenOptions().getCompOnlyPlayerCount();
|
||||
int totalPlayers = humanPlayers == CMapGenOptions::RANDOM_SIZE || cpuPlayers == CMapGenOptions::RANDOM_SIZE
|
||||
? PlayerColor::PLAYER_LIMIT_I : humanPlayers + cpuPlayers;
|
||||
assert(totalPlayers <= PlayerColor::PLAYER_LIMIT_I);
|
||||
auto settings = randomMapTab.obtainMapGenOptions().getPlayersSettings();
|
||||
variables["totalPlayers"].Integer() = totalPlayers;
|
||||
|
||||
pos.w = variables["windowSize"]["x"].Integer() + totalPlayers * variables["cellMargin"]["x"].Integer();
|
||||
pos.h = variables["windowSize"]["y"].Integer() + totalPlayers * variables["cellMargin"]["y"].Integer();
|
||||
variables["backgroundRect"]["x"].Integer() = pos.x;
|
||||
variables["backgroundRect"]["y"].Integer() = pos.y;
|
||||
variables["backgroundRect"]["w"].Integer() = pos.w;
|
||||
variables["backgroundRect"]["h"].Integer() = pos.h;
|
||||
variables["okButtonPosition"]["x"].Integer() = variables["buttonsOffset"]["ok"]["x"].Integer();
|
||||
variables["okButtonPosition"]["y"].Integer() = variables["buttonsOffset"]["ok"]["y"].Integer() + totalPlayers * variables["cellMargin"]["y"].Integer();
|
||||
variables["cancelButtonPosition"]["x"].Integer() = variables["buttonsOffset"]["cancel"]["x"].Integer();
|
||||
variables["cancelButtonPosition"]["y"].Integer() = variables["buttonsOffset"]["cancel"]["y"].Integer() + totalPlayers * variables["cellMargin"]["y"].Integer();
|
||||
|
||||
addCallback("ok", [&](int)
|
||||
{
|
||||
for(int plId = 0; plId < players.size(); ++plId)
|
||||
{
|
||||
randomMapTab.obtainMapGenOptions().setPlayerTeam(PlayerColor(plId), TeamID(players[plId]->getSelected()));
|
||||
}
|
||||
randomMapTab.updateMapInfoByHost();
|
||||
assert(GH.topInt().get() == this);
|
||||
GH.popInt(GH.topInt());
|
||||
});
|
||||
|
||||
addCallback("cancel", [&](int)
|
||||
{
|
||||
assert(GH.topInt().get() == this);
|
||||
GH.popInt(GH.topInt());
|
||||
});
|
||||
|
||||
init(config);
|
||||
|
||||
center(pos);
|
||||
|
||||
OBJ_CONSTRUCTION;
|
||||
|
||||
for(int plId = 0; plId < totalPlayers; ++plId)
|
||||
{
|
||||
players.push_back(std::make_shared<CToggleGroup>([&, totalPlayers, plId](int sel)
|
||||
{
|
||||
variables["player_id"].Integer() = plId;
|
||||
OBJ_CONSTRUCTION_TARGETED(players[plId].get());
|
||||
for(int teamId = 0; teamId < totalPlayers; ++teamId)
|
||||
{
|
||||
auto button = std::dynamic_pointer_cast<CToggleButton>(players[plId]->buttons[teamId]);
|
||||
assert(button);
|
||||
if(sel == teamId)
|
||||
{
|
||||
button->addOverlay(buildWidget(variables["flagsAnimation"]));
|
||||
}
|
||||
else
|
||||
{
|
||||
button->addOverlay(nullptr);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
OBJ_CONSTRUCTION_TARGETED(players.back().get());
|
||||
for(int teamId = 0; teamId < totalPlayers; ++teamId)
|
||||
{
|
||||
variables["point"]["x"].Integer() = variables["cellOffset"]["x"].Integer() + plId * variables["cellMargin"]["x"].Integer();
|
||||
variables["point"]["y"].Integer() = variables["cellOffset"]["y"].Integer() + teamId * variables["cellMargin"]["y"].Integer();
|
||||
auto button = buildWidget(variables["button"]);
|
||||
players.back()->addToggle(teamId, std::dynamic_pointer_cast<CToggleBase>(button));
|
||||
}
|
||||
|
||||
auto team = settings.at(PlayerColor(plId)).getTeam();
|
||||
if(team == TeamID::NO_TEAM)
|
||||
players.back()->setSelected(plId);
|
||||
else
|
||||
players.back()->setSelected(team.getNum());
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#include "../../lib/FunctionList.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
#include "../../lib/rmg/CRmgTemplate.h"
|
||||
#include "../gui/InterfaceObjectConfigurable.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -23,42 +25,80 @@ VCMI_LIB_NAMESPACE_END
|
||||
class CToggleButton;
|
||||
class CLabel;
|
||||
class CLabelGroup;
|
||||
class CSlider;
|
||||
class CPicture;
|
||||
|
||||
class RandomMapTab : public CIntObject
|
||||
class RandomMapTab : public InterfaceObjectConfigurable
|
||||
{
|
||||
public:
|
||||
RandomMapTab();
|
||||
|
||||
void updateMapInfoByHost();
|
||||
void setMapGenOptions(std::shared_ptr<CMapGenOptions> opts);
|
||||
void setTemplate(const CRmgTemplate *);
|
||||
CMapGenOptions & obtainMapGenOptions() {return *mapGenOptions;}
|
||||
|
||||
CFunctionList<void(std::shared_ptr<CMapInfo>, std::shared_ptr<CMapGenOptions>)> mapInfoChanged;
|
||||
|
||||
private:
|
||||
void addButtonsWithRandToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex, int helpRandIndex, int randIndex = -1, bool animIdfromBtnId = true) const;
|
||||
void addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex, bool animIdfromBtnId = true) const;
|
||||
void deactivateButtonsFrom(CToggleGroup * group, int startId);
|
||||
void validatePlayersCnt(int playersCnt);
|
||||
void validateCompOnlyPlayersCnt(int compOnlyPlayersCnt);
|
||||
void deactivateButtonsFrom(CToggleGroup & group, const std::set<int> & allowed);
|
||||
std::vector<int> getPossibleMapSizes();
|
||||
|
||||
|
||||
std::shared_ptr<CPicture> background;
|
||||
std::shared_ptr<CLabel> labelHeadlineBig;
|
||||
std::shared_ptr<CLabel> labelHeadlineSmall;
|
||||
|
||||
std::shared_ptr<CLabel> labelMapSize;
|
||||
std::shared_ptr<CToggleGroup> groupMapSize;
|
||||
std::shared_ptr<CToggleButton> buttonTwoLevels;
|
||||
|
||||
std::shared_ptr<CLabelGroup> labelGroupForOptions;
|
||||
std::shared_ptr<CToggleGroup> groupMaxPlayers;
|
||||
std::shared_ptr<CToggleGroup> groupMaxTeams;
|
||||
std::shared_ptr<CToggleGroup> groupCompOnlyPlayers;
|
||||
std::shared_ptr<CToggleGroup> groupCompOnlyTeams;
|
||||
std::shared_ptr<CToggleGroup> groupWaterContent;
|
||||
std::shared_ptr<CToggleGroup> groupMonsterStrength;
|
||||
std::shared_ptr<CButton> buttonShowRandomMaps;
|
||||
std::shared_ptr<CMapGenOptions> mapGenOptions;
|
||||
std::shared_ptr<CMapInfo> mapInfo;
|
||||
|
||||
//options allowed - need to store as impact each other
|
||||
std::set<int> playerCountAllowed, playerTeamsAllowed, compCountAllowed, compTeamsAllowed;
|
||||
};
|
||||
|
||||
class TemplatesDropBox : public InterfaceObjectConfigurable
|
||||
{
|
||||
struct ListItem : public InterfaceObjectConfigurable
|
||||
{
|
||||
TemplatesDropBox & dropBox;
|
||||
const CRmgTemplate * item = nullptr;
|
||||
|
||||
ListItem(const JsonNode &, TemplatesDropBox &, Point position);
|
||||
void updateItem(int index, const CRmgTemplate * item = nullptr);
|
||||
|
||||
void hover(bool on) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
};
|
||||
|
||||
friend struct ListItem;
|
||||
|
||||
public:
|
||||
TemplatesDropBox(RandomMapTab & randomMapTab, int3 size);
|
||||
|
||||
void hover(bool on) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void setTemplate(const CRmgTemplate *);
|
||||
|
||||
private:
|
||||
std::shared_ptr<CIntObject> buildListItem(const JsonNode & config);
|
||||
|
||||
void sliderMove(int slidPos);
|
||||
void updateListItems();
|
||||
|
||||
RandomMapTab & randomMapTab;
|
||||
std::vector<std::shared_ptr<ListItem>> listItems;
|
||||
|
||||
std::vector<const CRmgTemplate *> curItems;
|
||||
|
||||
};
|
||||
|
||||
class TeamAlignmentsWidget: public InterfaceObjectConfigurable
|
||||
{
|
||||
public:
|
||||
TeamAlignmentsWidget(RandomMapTab & randomMapTab);
|
||||
|
||||
private:
|
||||
|
||||
RandomMapTab & randomMapTab;
|
||||
|
||||
std::shared_ptr<CFilledTexture> background;
|
||||
std::shared_ptr<CLabelGroup> labels;
|
||||
std::shared_ptr<CButton> buttonOk, buttonCancel;
|
||||
std::vector<std::shared_ptr<CToggleGroup>> players;
|
||||
std::vector<std::shared_ptr<CIntObject>> placeholders;
|
||||
};
|
||||
|
@ -84,8 +84,11 @@ void CButton::addTextOverlay(const std::string & Text, EFonts font, SDL_Color co
|
||||
void CButton::addOverlay(std::shared_ptr<CIntObject> newOverlay)
|
||||
{
|
||||
overlay = newOverlay;
|
||||
addChild(newOverlay.get());
|
||||
overlay->moveTo(overlay->pos.centerIn(pos).topLeft());
|
||||
if(overlay)
|
||||
{
|
||||
addChild(newOverlay.get());
|
||||
overlay->moveTo(overlay->pos.centerIn(pos).topLeft());
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
@ -449,6 +452,11 @@ void CToggleGroup::selectionChanged(int to)
|
||||
parent->redraw();
|
||||
}
|
||||
|
||||
int CToggleGroup::getSelected() const
|
||||
{
|
||||
return selectedID;
|
||||
}
|
||||
|
||||
CVolumeSlider::CVolumeSlider(const Point & position, const std::string & defName, const int value, const std::pair<std::string, std::string> * const help)
|
||||
: CIntObject(LCLICK | RCLICK | WHEEL),
|
||||
value(value),
|
||||
@ -566,16 +574,21 @@ void CSlider::setScrollStep(int to)
|
||||
scrollStep = to;
|
||||
}
|
||||
|
||||
int CSlider::getAmount()
|
||||
int CSlider::getAmount() const
|
||||
{
|
||||
return amount;
|
||||
}
|
||||
|
||||
int CSlider::getValue()
|
||||
int CSlider::getValue() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
int CSlider::getCapacity() const
|
||||
{
|
||||
return capacity;
|
||||
}
|
||||
|
||||
void CSlider::moveLeft()
|
||||
{
|
||||
moveTo(value-1);
|
||||
|
@ -185,6 +185,7 @@ public:
|
||||
/// in some cases, e.g. LoadGame difficulty selection, after refreshing the UI, the ToggleGroup should
|
||||
/// reset all of it's child buttons to BLOCK state, then make selection again
|
||||
void setSelectedOnly(int id);
|
||||
int getSelected() const;
|
||||
};
|
||||
|
||||
/// A typical slider for volume with an animated indicator
|
||||
@ -256,8 +257,9 @@ public:
|
||||
void setAmount(int to);
|
||||
|
||||
/// Accessors
|
||||
int getAmount();
|
||||
int getValue();
|
||||
int getAmount() const;
|
||||
int getValue() const;
|
||||
int getCapacity() const;
|
||||
|
||||
void addCallback(std::function<void(int)> callback);
|
||||
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
};
|
||||
|
||||
/// area filled with specific texture
|
||||
class CFilledTexture : CIntObject
|
||||
class CFilledTexture : public CIntObject
|
||||
{
|
||||
SDL_Surface * texture;
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
"extraResourcesLimit" : 3
|
||||
},
|
||||
"minGuardStrength" : 2000,
|
||||
"defaultRoadType" : "pc", //pd - dirt, pg - gravel, pc - cobblestone
|
||||
"secondaryRoadType": "pd",
|
||||
"defaultRoadType" : "cobblestoneRoad",
|
||||
"secondaryRoadType": "dirtRoad",
|
||||
"treasureValueLimit" : 20000, //generate pandora with gold for treasure above this limit
|
||||
"prisons" :
|
||||
{
|
||||
|
@ -113,5 +113,15 @@
|
||||
"label" : "Hide complete quests",
|
||||
"help" : "Hide all quests that already completed"
|
||||
}
|
||||
},
|
||||
"randomMapTab":
|
||||
{
|
||||
"widgets":
|
||||
{
|
||||
"defaultTemplate": "default",
|
||||
"templateLabel": "Template",
|
||||
"teamAlignmentsButton": "Setup...",
|
||||
"teamAlignmentsLabel": "Team alignments"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
510
config/widgets/randomMapTab.json
Normal file
510
config/widgets/randomMapTab.json
Normal file
@ -0,0 +1,510 @@
|
||||
{
|
||||
"items":
|
||||
[
|
||||
{
|
||||
"name": "background",
|
||||
"type": "picture",
|
||||
"image": "RANMAPBK",
|
||||
"position": {"x": 0, "y": 6}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "labelHeadlineBig",
|
||||
"type": "label",
|
||||
"font": "big",
|
||||
"alignment": "center",
|
||||
"color": "yellow",
|
||||
"text": 738,
|
||||
"position": {"x": 222, "y": 36}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "labelHeadlineSmall",
|
||||
"type": "label",
|
||||
"font": "small",
|
||||
"alignment": "center",
|
||||
"color": "white",
|
||||
"text": 739,
|
||||
"position": {"x": 222, "y": 56}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "labelMapSize",
|
||||
"type": "label",
|
||||
"font": "small",
|
||||
"alignment": "center",
|
||||
"color": "white",
|
||||
"text": 752,
|
||||
"position": {"x": 104, "y": 97}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "groupMapSize",
|
||||
"type": "toggleGroup",
|
||||
"position": {"x": 158, "y": 81},
|
||||
"items":
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"type": "toggleButton",
|
||||
"image": "RANSIZS",
|
||||
"zelp": 198,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 0, "y": 0},
|
||||
},
|
||||
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANSIZM",
|
||||
"zelp": 199,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 47, "y": 0},
|
||||
},
|
||||
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANSIZL",
|
||||
"zelp": 200,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 94, "y": 0},
|
||||
},
|
||||
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANSIZX",
|
||||
"zelp": 201,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 141, "y": 0}
|
||||
}
|
||||
],
|
||||
"selected": 1,
|
||||
"callback": "toggleMapSize"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "buttonTwoLevels",
|
||||
"type": "toggleButton",
|
||||
"image": "RANUNDR",
|
||||
"position": {"x": 346, "y": 81},
|
||||
"selected": true,
|
||||
"callback": "toggleTwoLevels"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "groupMaxPlayers",
|
||||
"type": "toggleGroup",
|
||||
"position": {"x": 67, "y": 153},
|
||||
"items":
|
||||
[
|
||||
{
|
||||
"index": 1,
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM1",
|
||||
"zelp": 204,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 0, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM2",
|
||||
"zelp": 205,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 32, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM3",
|
||||
"zelp": 206,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 64, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM4",
|
||||
"zelp": 207,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 96, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM5",
|
||||
"zelp": 208,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 128, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM6",
|
||||
"zelp": 209,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 160, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM7",
|
||||
"zelp": 210,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 192, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM8",
|
||||
"zelp": 211,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 224, "y": 0}
|
||||
},
|
||||
{
|
||||
"index": -1,
|
||||
"type": "toggleButton",
|
||||
"image": "RANRAND",
|
||||
"zelp": 212,
|
||||
"position": {"x": 256, "y": 0},
|
||||
}
|
||||
],
|
||||
"selected": 7,
|
||||
"callback": "setPlayersCount"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "groupMaxTeams",
|
||||
"type": "toggleGroup",
|
||||
"position": {"x": 67, "y": 219},
|
||||
"items":
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM0",
|
||||
"zelp": 214,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 0, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM1",
|
||||
"zelp": 215,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 32, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM2",
|
||||
"zelp": 216,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 64, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM3",
|
||||
"zelp": 217,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 96, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM4",
|
||||
"zelp": 218,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 128, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM5",
|
||||
"zelp": 219,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 160, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM6",
|
||||
"zelp": 220,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 192, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM7",
|
||||
"zelp": 221,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 224, "y": 0}
|
||||
},
|
||||
{
|
||||
"index": -1,
|
||||
"type": "toggleButton",
|
||||
"image": "RANRAND",
|
||||
"zelp": 222,
|
||||
"position": {"x": 256, "y": 0},
|
||||
}
|
||||
],
|
||||
"selected": 7,
|
||||
"callback": "setTeamsCount"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "groupCompOnlyPlayers",
|
||||
"type": "toggleGroup",
|
||||
"position": {"x": 67, "y": 285},
|
||||
"items":
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM0",
|
||||
"zelp": 224,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 0, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM1",
|
||||
"zelp": 225,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 32, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM2",
|
||||
"zelp": 226,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 64, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM3",
|
||||
"zelp": 227,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 96, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM4",
|
||||
"zelp": 228,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 128, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM5",
|
||||
"zelp": 229,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 160, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM6",
|
||||
"zelp": 230,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 192, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM7",
|
||||
"zelp": 231,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 224, "y": 0}
|
||||
},
|
||||
{
|
||||
"index": -1,
|
||||
"type": "toggleButton",
|
||||
"image": "RANRAND",
|
||||
"zelp": 232,
|
||||
"position": {"x": 256, "y": 0},
|
||||
}
|
||||
],
|
||||
"selected": 7,
|
||||
"callback": "setCompOnlyPlayers"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "groupCompOnlyTeams",
|
||||
"type": "toggleGroup",
|
||||
"position": {"x": 67, "y": 351},
|
||||
"items":
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM0",
|
||||
"zelp": 234,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 0, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM1",
|
||||
"zelp": 235,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 32, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM2",
|
||||
"zelp": 236,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 64, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM3",
|
||||
"zelp": 237,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 96, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM4",
|
||||
"zelp": 238,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 128, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM5",
|
||||
"zelp": 239,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 160, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNUM6",
|
||||
"zelp": 240,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 192, "y": 0}
|
||||
},
|
||||
{
|
||||
"index": -1,
|
||||
"type": "toggleButton",
|
||||
"image": "RANRAND",
|
||||
"zelp": 241,
|
||||
"position": {"x": 256, "y": 0},
|
||||
}
|
||||
],
|
||||
"selected": 7,
|
||||
"callback": "setCompOnlyTeams"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "groupWaterContent",
|
||||
"type": "toggleGroup",
|
||||
"position": {"x": 67, "y": 419},
|
||||
"items":
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"type": "toggleButton",
|
||||
"image": "RANNONE",
|
||||
"zelp": 243,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 0, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANNORM",
|
||||
"zelp": 244,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 85, "y": 0}
|
||||
},
|
||||
{
|
||||
"type": "toggleButton",
|
||||
"image": "RANISLD",
|
||||
"zelp": 245,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 170, "y": 0}
|
||||
},
|
||||
{
|
||||
"index": -1,
|
||||
"type": "toggleButton",
|
||||
"image": "RANRAND",
|
||||
"zelp": 246,
|
||||
"position": {"x": 256, "y": 0},
|
||||
}
|
||||
],
|
||||
"selected": 3,
|
||||
"callback": "setWaterContent"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "groupMonsterStrength",
|
||||
"type": "toggleGroup",
|
||||
"position": {"x": 67, "y": 485},
|
||||
"items":
|
||||
[
|
||||
{
|
||||
"index": 2,
|
||||
"type": "toggleButton",
|
||||
"image": "RANWEAK",
|
||||
"zelp": 248,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 0, "y": 0}
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"type": "toggleButton",
|
||||
"image": "RANNORM",
|
||||
"zelp": 249,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 85, "y": 0}
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"type": "toggleButton",
|
||||
"image": "RANSTRG",
|
||||
"zelp": 250,
|
||||
"imageOrder": [0, 1, 1, 3],
|
||||
"position": {"x": 170, "y": 0}
|
||||
},
|
||||
{
|
||||
"index": -2,
|
||||
"type": "toggleButton",
|
||||
"image": "RANRAND",
|
||||
"zelp": 251,
|
||||
"position": {"x": 256, "y": 0},
|
||||
}
|
||||
],
|
||||
"selected": 3,
|
||||
"callback": "setMonsterStrength"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "buttonShowRandomMaps",
|
||||
"type": "button",
|
||||
"position": {"x": 54, "y": 535},
|
||||
"image": "RANSHOW",
|
||||
"zelp": 252
|
||||
},
|
||||
|
||||
{
|
||||
"type": "labelGroup",
|
||||
"font": "small",
|
||||
"alignment": "left",
|
||||
"color": "white",
|
||||
"items":
|
||||
[
|
||||
{
|
||||
"position": {"x": 68, "y": 133},
|
||||
"text": 753
|
||||
},
|
||||
{
|
||||
"position": {"x": 68, "y": 199},
|
||||
"text": 754
|
||||
},
|
||||
{
|
||||
"position": {"x": 68, "y": 265},
|
||||
"text": 755
|
||||
},
|
||||
{
|
||||
"position": {"x": 68, "y": 331},
|
||||
"text": 756
|
||||
},
|
||||
{
|
||||
"position": {"x": 68, "y": 398},
|
||||
"text": 757
|
||||
},
|
||||
{
|
||||
"position": {"x": 68, "y": 465},
|
||||
"text": 758
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
6
debian/changelog
vendored
6
debian/changelog
vendored
@ -1,3 +1,9 @@
|
||||
vcmi (1.2.0) jammy; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 23 Dec 2022 16:00:00 +0200
|
||||
|
||||
vcmi (1.1.0) jammy; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
@ -38,6 +38,7 @@
|
||||
<url type="bugtracker">https://github.com/vcmi/vcmi/issues</url>
|
||||
<url type="faq">https://vcmi.eu/faq/</url>
|
||||
<releases>
|
||||
<release version="1.2.0" date="2022-12-24" type="development" />
|
||||
<release version="1.1.0" date="2022-12-23" />
|
||||
<release version="1.0.0" date="2022-09-11" />
|
||||
<release version="0.99" date="2016-11-01" />
|
||||
|
@ -220,6 +220,7 @@ void TerrainTypeHandler::initRivers(const std::vector<std::string> & allConfigs)
|
||||
{
|
||||
RiverType info;
|
||||
|
||||
info.name = river.first;
|
||||
info.fileName = river.second["animation"].String();
|
||||
info.code = river.second["code"].String();
|
||||
info.deltaName = river.second["delta"].String();
|
||||
@ -255,6 +256,7 @@ void TerrainTypeHandler::initRoads(const std::vector<std::string> & allConfigs)
|
||||
{
|
||||
RoadType info;
|
||||
|
||||
info.name = road.first;
|
||||
info.fileName = road.second["animation"].String();
|
||||
info.code = road.second["code"].String();
|
||||
info.movementCost = static_cast<ui8>(road.second["moveCost"].Float());
|
||||
@ -295,7 +297,7 @@ void TerrainTypeHandler::recreateRiverMaps()
|
||||
{
|
||||
const auto * riverInfo = &riverTypes[i];
|
||||
|
||||
riverInfoByName[riverInfo->fileName] = riverInfo;
|
||||
riverInfoByName[riverInfo->name] = riverInfo;
|
||||
riverInfoByCode[riverInfo->code] = riverInfo;
|
||||
riverInfoById[riverInfo->id] = riverInfo;
|
||||
}
|
||||
@ -307,7 +309,7 @@ void TerrainTypeHandler::recreateRoadMaps()
|
||||
{
|
||||
const auto * roadInfo = &roadTypes[i];
|
||||
|
||||
roadInfoByName[roadInfo->fileName] = roadInfo;
|
||||
roadInfoByName[roadInfo->name] = roadInfo;
|
||||
roadInfoByCode[roadInfo->code] = roadInfo;
|
||||
roadInfoById[roadInfo->id] = roadInfo;
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
class DLL_LINKAGE RiverType
|
||||
{
|
||||
public:
|
||||
|
||||
std::string name;
|
||||
std::string fileName;
|
||||
std::string code;
|
||||
std::string deltaName;
|
||||
@ -99,6 +99,10 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler& h, const int version)
|
||||
{
|
||||
if(version >= 806)
|
||||
{
|
||||
h & name;
|
||||
}
|
||||
h & fileName;
|
||||
h & code;
|
||||
h & deltaName;
|
||||
@ -109,6 +113,7 @@ public:
|
||||
class DLL_LINKAGE RoadType
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
std::string fileName;
|
||||
std::string code;
|
||||
RoadId id;
|
||||
@ -118,6 +123,10 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler& h, const int version)
|
||||
{
|
||||
if(version >= 806)
|
||||
{
|
||||
h & name;
|
||||
}
|
||||
h & fileName;
|
||||
h & code;
|
||||
h & id;
|
||||
|
@ -284,6 +284,9 @@ public:
|
||||
static const int MAP_SIZE_MIDDLE = 72;
|
||||
static const int MAP_SIZE_LARGE = 108;
|
||||
static const int MAP_SIZE_XLARGE = 144;
|
||||
static const int MAP_SIZE_HUGE = 180;
|
||||
static const int MAP_SIZE_XHUGE = 216;
|
||||
static const int MAP_SIZE_GIANT = 252;
|
||||
|
||||
CMapHeader();
|
||||
virtual ~CMapHeader();
|
||||
|
@ -134,6 +134,12 @@ int CMapInfo::getMapSizeIconId() const
|
||||
return 2;
|
||||
case CMapHeader::MAP_SIZE_XLARGE:
|
||||
return 3;
|
||||
case CMapHeader::MAP_SIZE_HUGE:
|
||||
return 4;
|
||||
case CMapHeader::MAP_SIZE_XHUGE:
|
||||
return 5;
|
||||
case CMapHeader::MAP_SIZE_GIANT:
|
||||
return 6;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
@ -180,6 +186,12 @@ std::string CMapInfo::getMapSizeName() const
|
||||
return "L";
|
||||
case CMapHeader::MAP_SIZE_XLARGE:
|
||||
return "XL";
|
||||
case CMapHeader::MAP_SIZE_HUGE:
|
||||
return "H";
|
||||
case CMapHeader::MAP_SIZE_XHUGE:
|
||||
return "XH";
|
||||
case CMapHeader::MAP_SIZE_GIANT:
|
||||
return "G";
|
||||
default:
|
||||
return "C";
|
||||
}
|
||||
|
@ -136,12 +136,14 @@ void CMapGenOptions::resetPlayersMap()
|
||||
{
|
||||
|
||||
std::map<PlayerColor, TFaction> rememberTownTypes;
|
||||
std::map<PlayerColor, TeamID> rememberTeam;
|
||||
|
||||
for (auto p : players)
|
||||
{
|
||||
auto town = p.second.getStartingTown();
|
||||
if (town != RANDOM_SIZE)
|
||||
rememberTownTypes[p.first] = town;
|
||||
rememberTeam[p.first] = p.second.getTeam();
|
||||
}
|
||||
|
||||
|
||||
@ -169,6 +171,7 @@ void CMapGenOptions::resetPlayersMap()
|
||||
playerType = EPlayerType::COMP_ONLY;
|
||||
}
|
||||
player.setPlayerType(playerType);
|
||||
player.setTeam(rememberTeam[pc]);
|
||||
players[pc] = player;
|
||||
|
||||
if (vstd::contains(rememberTownTypes, pc))
|
||||
@ -204,8 +207,50 @@ const CRmgTemplate * CMapGenOptions::getMapTemplate() const
|
||||
void CMapGenOptions::setMapTemplate(const CRmgTemplate * value)
|
||||
{
|
||||
mapTemplate = value;
|
||||
//TODO validate & adapt options according to template
|
||||
//assert(0);
|
||||
//validate & adapt options according to template
|
||||
if(mapTemplate)
|
||||
{
|
||||
if(!mapTemplate->matchesSize(int3(getWidth(), getHeight(), 1 + getHasTwoLevels())))
|
||||
{
|
||||
auto sizes = mapTemplate->getMapSizes();
|
||||
setWidth(sizes.first.x);
|
||||
setHeight(sizes.first.y);
|
||||
setHasTwoLevels(sizes.first.z - 1);
|
||||
}
|
||||
|
||||
if(!mapTemplate->getPlayers().isInRange(getPlayerCount()))
|
||||
setPlayerCount(RANDOM_SIZE);
|
||||
if(!mapTemplate->getCpuPlayers().isInRange(getCompOnlyPlayerCount()))
|
||||
setCompOnlyPlayerCount(RANDOM_SIZE);
|
||||
if(!mapTemplate->getWaterContentAllowed().count(getWaterContent()))
|
||||
setWaterContent(EWaterContent::RANDOM);
|
||||
}
|
||||
}
|
||||
|
||||
void CMapGenOptions::setMapTemplate(const std::string & name)
|
||||
{
|
||||
if(!name.empty())
|
||||
setMapTemplate(VLC->tplh->getTemplate(name));
|
||||
}
|
||||
|
||||
void CMapGenOptions::setRoadEnabled(const std::string & roadName, bool enable)
|
||||
{
|
||||
if(enable)
|
||||
disabledRoads.erase(roadName);
|
||||
else
|
||||
disabledRoads.insert(roadName);
|
||||
}
|
||||
|
||||
bool CMapGenOptions::isRoadEnabled(const std::string & roadName) const
|
||||
{
|
||||
return !disabledRoads.count(roadName);
|
||||
}
|
||||
|
||||
void CMapGenOptions::setPlayerTeam(PlayerColor color, TeamID team)
|
||||
{
|
||||
auto it = players.find(color);
|
||||
if(it == players.end()) assert(0);
|
||||
it->second.setTeam(team);
|
||||
}
|
||||
|
||||
void CMapGenOptions::finalize(CRandomGenerator & rand)
|
||||
@ -391,7 +436,6 @@ PlayerColor CMapGenOptions::getNextPlayerColor() const
|
||||
|
||||
bool CMapGenOptions::checkOptions() const
|
||||
{
|
||||
assert(countHumanPlayers() > 0);
|
||||
if(mapTemplate)
|
||||
{
|
||||
return true;
|
||||
@ -452,7 +496,7 @@ const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & rand
|
||||
return *RandomGeneratorUtil::nextItem(templates, rand);
|
||||
}
|
||||
|
||||
CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI)
|
||||
CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI), team(TeamID::NO_TEAM)
|
||||
{
|
||||
|
||||
}
|
||||
@ -494,4 +538,14 @@ void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType val
|
||||
playerType = value;
|
||||
}
|
||||
|
||||
TeamID CMapGenOptions::CPlayerSettings::getTeam() const
|
||||
{
|
||||
return team;
|
||||
}
|
||||
|
||||
void CMapGenOptions::CPlayerSettings::setTeam(TeamID value)
|
||||
{
|
||||
team = value;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -11,37 +11,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "../GameConstants.h"
|
||||
#include "CRmgTemplate.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CRmgTemplate;
|
||||
class CRandomGenerator;
|
||||
|
||||
namespace EWaterContent
|
||||
{
|
||||
enum EWaterContent
|
||||
{
|
||||
RANDOM = -1,
|
||||
NONE,
|
||||
NORMAL,
|
||||
ISLANDS
|
||||
};
|
||||
}
|
||||
|
||||
namespace EMonsterStrength
|
||||
{
|
||||
enum EMonsterStrength
|
||||
{
|
||||
RANDOM = -2,
|
||||
ZONE_WEAK = -1,
|
||||
ZONE_NORMAL = 0,
|
||||
ZONE_STRONG = 1,
|
||||
GLOBAL_WEAK = 2,
|
||||
GLOBAL_NORMAL = 3,
|
||||
GLOBAL_STRONG = 4
|
||||
};
|
||||
}
|
||||
|
||||
namespace EPlayerType
|
||||
{
|
||||
enum EPlayerType
|
||||
@ -76,6 +51,10 @@ public:
|
||||
/// The default value is EPlayerType::AI.
|
||||
EPlayerType::EPlayerType getPlayerType() const;
|
||||
void setPlayerType(EPlayerType::EPlayerType value);
|
||||
|
||||
/// Team id for this player. TeamID::NO_TEAM by default - team will be randomly assigned
|
||||
TeamID getTeam() const;
|
||||
void setTeam(TeamID value);
|
||||
|
||||
/// Constant for a random town selection.
|
||||
static const si32 RANDOM_TOWN = -1;
|
||||
@ -84,6 +63,7 @@ public:
|
||||
PlayerColor color;
|
||||
si32 startingTown;
|
||||
EPlayerType::EPlayerType playerType;
|
||||
TeamID team;
|
||||
|
||||
public:
|
||||
template <typename Handler>
|
||||
@ -92,6 +72,8 @@ public:
|
||||
h & color;
|
||||
h & startingTown;
|
||||
h & playerType;
|
||||
if(version >= 806)
|
||||
h & team;
|
||||
}
|
||||
};
|
||||
|
||||
@ -130,6 +112,9 @@ public:
|
||||
|
||||
EMonsterStrength::EMonsterStrength getMonsterStrength() const;
|
||||
void setMonsterStrength(EMonsterStrength::EMonsterStrength value);
|
||||
|
||||
bool isRoadEnabled(const std::string & roadName) const;
|
||||
void setRoadEnabled(const std::string & roadName, bool enable);
|
||||
|
||||
/// The first player colors belong to standard players and the last player colors belong to comp only players.
|
||||
/// All standard players are by default of type EPlayerType::AI.
|
||||
@ -138,11 +123,14 @@ public:
|
||||
/// Sets a player type for a standard player. A standard player is the opposite of a computer only player. The
|
||||
/// values which can be chosen for the player type are EPlayerType::AI or EPlayerType::HUMAN.
|
||||
void setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType);
|
||||
|
||||
void setPlayerTeam(PlayerColor color, TeamID team = TeamID::NO_TEAM);
|
||||
|
||||
/// The random map template to generate the map with or empty/not set if the template should be chosen randomly.
|
||||
/// Default: Not set/random.
|
||||
const CRmgTemplate * getMapTemplate() const;
|
||||
void setMapTemplate(const CRmgTemplate * value);
|
||||
void setMapTemplate(const std::string & name);
|
||||
|
||||
std::vector<const CRmgTemplate *> getPossibleTemplates() const;
|
||||
|
||||
@ -171,6 +159,8 @@ private:
|
||||
EWaterContent::EWaterContent waterContent;
|
||||
EMonsterStrength::EMonsterStrength monsterStrength;
|
||||
std::map<PlayerColor, CPlayerSettings> players;
|
||||
std::set<std::string> disabledRoads;
|
||||
|
||||
const CRmgTemplate * mapTemplate;
|
||||
|
||||
public:
|
||||
@ -187,7 +177,21 @@ public:
|
||||
h & waterContent;
|
||||
h & monsterStrength;
|
||||
h & players;
|
||||
//TODO add name of template to class, enables selection of a template by a user
|
||||
std::string templateName;
|
||||
if(mapTemplate && h.saving)
|
||||
{
|
||||
templateName = mapTemplate->getId();
|
||||
}
|
||||
if(version >= 806)
|
||||
{
|
||||
h & templateName;
|
||||
if(!h.saving)
|
||||
{
|
||||
setMapTemplate(templateName);
|
||||
}
|
||||
|
||||
h & disabledRoads;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -76,6 +76,11 @@ void CMapGenerator::loadConfig()
|
||||
config.pandoraMultiplierSpells = randomMapJson["pandoras"]["valueMultiplierSpells"].Integer();
|
||||
config.pandoraSpellSchool = randomMapJson["pandoras"]["valueSpellSchool"].Integer();
|
||||
config.pandoraSpell60 = randomMapJson["pandoras"]["valueSpell60"].Integer();
|
||||
//override config with game options
|
||||
if(!mapGenOptions.isRoadEnabled(config.secondaryRoadType))
|
||||
config.secondaryRoadType = "";
|
||||
if(!mapGenOptions.isRoadEnabled(config.defaultRoadType))
|
||||
config.defaultRoadType = config.secondaryRoadType;
|
||||
}
|
||||
|
||||
const CMapGenerator::Config & CMapGenerator::getConfig() const
|
||||
@ -183,6 +188,7 @@ void CMapGenerator::addPlayerInfo()
|
||||
|
||||
enum ETeams {CPHUMAN = 0, CPUONLY = 1, AFTER_LAST = 2};
|
||||
std::array<std::list<int>, 2> teamNumbers;
|
||||
std::set<int> teamsTotal;
|
||||
|
||||
int teamOffset = 0;
|
||||
int playerCount = 0;
|
||||
@ -238,19 +244,26 @@ void CMapGenerator::addPlayerInfo()
|
||||
player.canHumanPlay = true;
|
||||
}
|
||||
|
||||
if (teamNumbers[j].empty())
|
||||
if(pSettings.getTeam() != TeamID::NO_TEAM)
|
||||
{
|
||||
logGlobal->error("Not enough places in team for %s player", ((j == CPUONLY) ? "CPU" : "CPU or human"));
|
||||
assert (teamNumbers[j].size());
|
||||
player.team = pSettings.getTeam();
|
||||
}
|
||||
auto itTeam = RandomGeneratorUtil::nextItem(teamNumbers[j], rand);
|
||||
player.team = TeamID(*itTeam);
|
||||
teamNumbers[j].erase(itTeam);
|
||||
else
|
||||
{
|
||||
if (teamNumbers[j].empty())
|
||||
{
|
||||
logGlobal->error("Not enough places in team for %s player", ((j == CPUONLY) ? "CPU" : "CPU or human"));
|
||||
assert (teamNumbers[j].size());
|
||||
}
|
||||
auto itTeam = RandomGeneratorUtil::nextItem(teamNumbers[j], rand);
|
||||
player.team = TeamID(*itTeam);
|
||||
teamNumbers[j].erase(itTeam);
|
||||
}
|
||||
teamsTotal.insert(player.team.getNum());
|
||||
map->map().players[pSettings.getColor().getNum()] = player;
|
||||
}
|
||||
|
||||
map->map().howManyTeams = (mapGenOptions.getTeamCount() == 0 ? mapGenOptions.getPlayerCount() : mapGenOptions.getTeamCount())
|
||||
+ (mapGenOptions.getCompOnlyTeamCount() == 0 ? mapGenOptions.getCompOnlyPlayerCount() : mapGenOptions.getCompOnlyTeamCount());
|
||||
map->map().howManyTeams = teamsTotal.size();
|
||||
}
|
||||
|
||||
void CMapGenerator::genZones()
|
||||
|
@ -501,9 +501,19 @@ void CRmgTemplate::setId(const std::string & value)
|
||||
id = value;
|
||||
}
|
||||
|
||||
void CRmgTemplate::setName(const std::string & value)
|
||||
{
|
||||
name = value;
|
||||
}
|
||||
|
||||
const std::string & CRmgTemplate::getName() const
|
||||
{
|
||||
return name.empty() ? id : name;
|
||||
return name;
|
||||
}
|
||||
|
||||
const std::string & CRmgTemplate::getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getPlayers() const
|
||||
@ -531,6 +541,11 @@ void CRmgTemplate::validate() const
|
||||
//TODO add some validation checks, throw on failure
|
||||
}
|
||||
|
||||
std::pair<int3, int3> CRmgTemplate::getMapSizes() const
|
||||
{
|
||||
return {minSize, maxSize};
|
||||
}
|
||||
|
||||
void CRmgTemplate::CPlayerCountRange::addRange(int lower, int upper)
|
||||
{
|
||||
range.push_back(std::make_pair(lower, upper));
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "../GameConstants.h"
|
||||
#include "../ResourceSet.h"
|
||||
#include "../Terrain.h"
|
||||
#include "CMapGenOptions.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -32,6 +31,31 @@ namespace ETemplateZoneType
|
||||
};
|
||||
}
|
||||
|
||||
namespace EWaterContent
|
||||
{
|
||||
enum EWaterContent
|
||||
{
|
||||
RANDOM = -1,
|
||||
NONE,
|
||||
NORMAL,
|
||||
ISLANDS
|
||||
};
|
||||
}
|
||||
|
||||
namespace EMonsterStrength
|
||||
{
|
||||
enum EMonsterStrength
|
||||
{
|
||||
RANDOM = -2,
|
||||
ZONE_WEAK = -1,
|
||||
ZONE_NORMAL = 0,
|
||||
ZONE_STRONG = 1,
|
||||
GLOBAL_WEAK = 2,
|
||||
GLOBAL_NORMAL = 3,
|
||||
GLOBAL_STRONG = 4
|
||||
};
|
||||
}
|
||||
|
||||
class DLL_LINKAGE CTreasureInfo
|
||||
{
|
||||
public:
|
||||
@ -194,10 +218,13 @@ public:
|
||||
const std::set<EWaterContent::EWaterContent> & getWaterContentAllowed() const;
|
||||
|
||||
void setId(const std::string & value);
|
||||
void setName(const std::string & value);
|
||||
const std::string & getId() const;
|
||||
const std::string & getName() const;
|
||||
|
||||
const CPlayerCountRange & getPlayers() const;
|
||||
const CPlayerCountRange & getCpuPlayers() const;
|
||||
std::pair<int3, int3> getMapSizes() const;
|
||||
const Zones & getZones() const;
|
||||
const std::vector<rmg::ZoneConnection> & getConnections() const;
|
||||
|
||||
|
@ -32,8 +32,9 @@ void CRmgTemplateStorage::loadObject(std::string scope, std::string name, const
|
||||
{
|
||||
JsonDeserializer handler(nullptr, data);
|
||||
auto fullKey = normalizeIdentifier(scope, CModHandler::scopeBuiltin(), name); //actually it's not used
|
||||
templates[fullKey].setId(name);
|
||||
templates[fullKey].setId(fullKey);
|
||||
templates[fullKey].serializeJson(handler);
|
||||
templates[fullKey].setName(name);
|
||||
templates[fullKey].validate();
|
||||
}
|
||||
catch(const std::exception & e)
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "CZonePlacer.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "CMapGenOptions.h"
|
||||
#include "RmgMap.h"
|
||||
#include "Zone.h"
|
||||
#include "Functions.h"
|
||||
|
@ -19,6 +19,7 @@ class RmgMap;
|
||||
class ObjectManager;
|
||||
class ObjectTemplate;
|
||||
class CMapGenerator;
|
||||
class CRandomGenerator;
|
||||
|
||||
class rmgException : public std::exception
|
||||
{
|
||||
|
@ -22,6 +22,9 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void RoadPlacer::process()
|
||||
{
|
||||
if(generator.getConfig().defaultRoadType.empty() && generator.getConfig().secondaryRoadType.empty())
|
||||
return; //do not generate roads at all
|
||||
|
||||
connectRoads();
|
||||
}
|
||||
|
||||
@ -68,11 +71,15 @@ bool RoadPlacer::createRoad(const int3 & dst)
|
||||
|
||||
void RoadPlacer::drawRoads(bool secondary)
|
||||
{
|
||||
if((secondary && generator.getConfig().secondaryRoadType.empty())
|
||||
|| (!secondary && generator.getConfig().defaultRoadType.empty()))
|
||||
return;
|
||||
|
||||
zone.areaPossible().subtract(roads);
|
||||
zone.freePaths().unite(roads);
|
||||
map.getEditManager()->getTerrainSelection().setSelection(roads.getTilesVector());
|
||||
std::string roadCode = (secondary ? generator.getConfig().secondaryRoadType : generator.getConfig().defaultRoadType);
|
||||
RoadId roadType = VLC->terrainTypeHandler->getRoadByCode(roadCode)->id;
|
||||
std::string roadName = (secondary ? generator.getConfig().secondaryRoadType : generator.getConfig().defaultRoadType);
|
||||
RoadId roadType = VLC->terrainTypeHandler->getRoadByName(roadName)->id;
|
||||
map.getEditManager()->drawRoad(roadType, &generator.rand);
|
||||
}
|
||||
|
||||
|
@ -1118,14 +1118,11 @@ int main(int argc, char * argv[])
|
||||
}
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
void CVCMIServer::create(const std::vector<std::string> & args)
|
||||
void CVCMIServer::create()
|
||||
{
|
||||
const char * foo = "android-server";
|
||||
std::vector<const void *> argv = {foo};
|
||||
for(auto & a : args)
|
||||
argv.push_back(a.c_str());
|
||||
|
||||
main(argv.size(), const_cast<char **>(foo));
|
||||
main(argv.size(), reinterpret_cast<char **>(const_cast<void **>(&*argv.begin())));
|
||||
}
|
||||
#elif defined(SINGLE_PROCESS_APP)
|
||||
void CVCMIServer::create(boost::condition_variable * cond, const std::vector<std::string> & args)
|
||||
|
@ -114,7 +114,7 @@ public:
|
||||
ui8 getIdOfFirstUnallocatedPlayer() const;
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
static void create(const std::vector<std::string> & args);
|
||||
static void create();
|
||||
#elif defined(SINGLE_PROCESS_APP)
|
||||
static void create(boost::condition_variable * cond, const std::vector<std::string> & args);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user