12 constexpr
float FreqRange =
static_cast<float>(std::numeric_limits<std::uint16_t>::max() - 1);
14 bool isnum(
const std::string& n) {
16 if (!std::isdigit(c))
return false;
18 if (n.empty())
return false;
23 using namespace bl::gui;
28 Window::create(LinePacker::create(LinePacker::Vertical, 4.f),
"Peoplemon Region Editor");
29 window->getSignal(Event::Closed).willAlwaysCall(std::bind(&CatchRegionWindow::close,
this));
30 window->setRequisition({700.f, 600.f});
32 Box::Ptr row = Box::create(LinePacker::create(LinePacker::Horizontal, 4.f));
33 row->pack(Label::create(
"Name:"),
false,
true);
34 nameEntry = TextEntry::create();
35 row->pack(nameEntry,
true,
true);
36 window->pack(row,
true,
false);
38 peopleScroll = ScrollArea::create(LinePacker::create(LinePacker::Vertical, 8.f));
39 peopleScroll->setMaxSize({700.f, 550.f});
40 window->pack(peopleScroll,
true,
true);
42 row = Box::create(LinePacker::create(LinePacker::Horizontal, 4.f));
43 Button::Ptr addBut = Button::create(
"Add Peoplemon");
44 addBut->getSignal(Event::LeftClicked).willAlwaysCall(std::bind(&CatchRegionWindow::add,
this));
45 row->pack(addBut,
false,
true);
47 Box::Ptr subrow = Box::create(LinePacker::create(
48 LinePacker::Horizontal, 4.f, LinePacker::Compact, LinePacker::RightAlign));
49 Button::Ptr cancelBut = Button::create(
"Cancel");
50 cancelBut->setColor(sf::Color::Red, sf::Color::Black);
51 cancelBut->getSignal(Event::LeftClicked)
52 .willAlwaysCall(std::bind(&CatchRegionWindow::close,
this));
53 subrow->pack(cancelBut,
false,
true);
54 Button::Ptr saveBut = Button::create(
"Save");
55 saveBut->setColor(sf::Color(3, 252, 244), sf::Color::Black);
56 saveBut->getSignal(Event::LeftClicked)
57 .willAlwaysCall(std::bind(&CatchRegionWindow::save,
this));
58 subrow->pack(saveBut,
false,
true);
59 row->pack(subrow,
true,
true);
60 window->pack(row,
true,
false);
64 nameEntry->setInput(v.
name);
65 rows.reserve(v.
wilds.size());
67 rows.emplace_back(std::bind(&CatchRegionWindow::freqChange,
this, std::placeholders::_1),
68 std::bind(&CatchRegionWindow::remove,
this, std::placeholders::_1));
69 rows.back().idSelect->setPeoplemon(wild.
id);
70 rows.back().minLevel->setInput(std::to_string(wild.
minLevel));
71 rows.back().maxLevel->setInput(std::to_string(wild.
maxLevel));
72 rows.back().freqSlider->setValue(
static_cast<float>(wild.
frequency) / FreqRange);
73 peopleScroll->pack(rows.back().row,
true,
false);
77 window->setForceFocus(
true);
83 value.
name = nameEntry->getInput();
85 value.
wilds.reserve(rows.size());
86 for (
const Row& row : rows) {
87 value.
wilds.emplace_back();
88 value.
wilds.back().id = row.idSelect->currentPeoplemon();
89 value.
wilds.back().minLevel = std::atoi(row.minLevel->getInput().c_str());
90 value.
wilds.back().maxLevel = std::atoi(row.maxLevel->getInput().c_str());
91 value.
wilds.back().frequency =
92 static_cast<std::uint16_t
>(row.freqSlider->getValue() * FreqRange);
98 void CatchRegionWindow::close() {
99 window->setForceFocus(
false);
101 for (
auto& row : rows) { row.row->remove(); }
105 CatchRegionWindow::Row::Row(
const Callback& cb,
const Callback& delcb) {
106 row = Box::create(LinePacker::create(LinePacker::Horizontal, 8.f));
107 row->setColor(sf::Color(119, 252, 35, 100), sf::Color::Green);
108 row->setOutlineThickness(1.f);
110 Box::Ptr col = Box::create(LinePacker::create(LinePacker::Vertical, 4.f));
111 col->pack(Label::create(
"Peoplemon"));
113 idSelect->setVerticalAlignment(RenderSettings::Bottom);
114 idSelect->setMaxHeight(300.f);
115 col->pack(idSelect,
true,
false);
116 row->pack(col,
false,
true);
118 col = Box::create(LinePacker::create(LinePacker::Vertical, 4.f));
119 col->pack(Label::create(
"Min Lvl"),
true,
false);
120 minLevel = TextEntry::create();
121 minLevel->setMode(TextEntry::Mode::Integer | TextEntry::Mode::Unsigned);
122 col->pack(minLevel,
true,
false);
123 row->pack(col,
false,
true);
125 col = Box::create(LinePacker::create(LinePacker::Vertical, 4.f));
126 col->pack(Label::create(
"Max Lvl"),
true,
false);
127 maxLevel = TextEntry::create();
128 maxLevel->setMode(TextEntry::Mode::Integer | TextEntry::Mode::Unsigned);
129 col->pack(maxLevel,
true,
false);
130 row->pack(col,
false,
true);
132 col = Box::create(LinePacker::create(LinePacker::Vertical, 4.f));
133 Box::Ptr subrow = Box::create(LinePacker::create(LinePacker::Horizontal, 10.f));
134 freqLabel = Label::create(
"Freq: 0%");
135 freqLabel->setRequisition({90.f, 10.f});
136 lockBut = CheckButton::create(
"Lock");
137 freqLabel->setHorizontalAlignment(RenderSettings::Left);
138 subrow->pack(freqLabel,
true,
true);
139 subrow->pack(lockBut,
false,
true);
140 col->pack(subrow,
true,
false);
141 freqSlider = Slider::create(Slider::Horizontal);
142 freqSlider->getSignal(Event::ValueChanged).willAlwaysCall(std::bind(cb, std::placeholders::_2));
143 freqSlider->setRequisition({200.f, 20.f});
144 freqSlider->setSliderIncrement(0.001f);
145 col->pack(freqSlider,
true,
false);
146 row->pack(col,
false,
true);
148 col = Box::create(LinePacker::create(
149 LinePacker::Vertical, 4.f, LinePacker::Compact, LinePacker::BottomAlign));
150 delBut = Button::create(
"Remove");
151 delBut->setColor(sf::Color::Red, sf::Color::Black);
152 delBut->getSignal(Event::LeftClicked).willAlwaysCall(std::bind(delcb, std::placeholders::_2));
154 row->pack(col,
false,
true);
157 void CatchRegionWindow::save() {
164 void CatchRegionWindow::add() {
165 unsigned int unlocked = 1;
166 float unlockedAmount = 0.f;
167 for (
const auto& row : rows) {
168 if (!row.lockBut->getValue()) {
170 unlockedAmount += row.freqSlider->getValue();
173 const float avg = unlockedAmount /
static_cast<float>(unlocked);
175 rows.emplace_back(std::bind(&CatchRegionWindow::freqChange,
this, std::placeholders::_1),
176 std::bind(&CatchRegionWindow::remove,
this, std::placeholders::_1));
177 rows.back().minLevel->setInput(
"20");
178 rows.back().maxLevel->setInput(
"30");
179 peopleScroll->pack(rows.back().row,
true,
false);
181 if (rows.size() == 1) { rows.front().freqSlider->setValue(1.f); }
183 for (
auto& row : rows) {
184 if (!row.lockBut->getValue()) {
185 row.freqSlider->setValue(avg,
false);
186 std::stringstream ss;
188 ss << std::setprecision(5) << (row.freqSlider->getValue() * 100.f) <<
"%";
189 row.freqLabel->setText(ss.str());
195 void CatchRegionWindow::remove(bl::gui::Element* e) {
196 for (
auto it = rows.begin(); it != rows.end(); ++it) {
197 if (
static_cast<Element*
>(it->delBut.get()) == e) {
204 unsigned int unlocked = 0;
205 float unlockedAmount = 0.f;
206 for (
const auto& row : rows) {
207 if (!row.lockBut->getValue()) {
209 unlockedAmount += row.freqSlider->getValue();
212 const float avg = unlockedAmount /
static_cast<float>(unlocked);
214 for (
auto& row : rows) {
215 if (!row.lockBut->getValue()) {
216 row.freqSlider->setValue(avg,
false);
217 std::stringstream ss;
219 ss << std::setprecision(5) << (row.freqSlider->getValue() * 100.f) <<
"%";
220 row.freqLabel->setText(ss.str());
225 void CatchRegionWindow::freqChange(Element* e) {
227 unsigned int unlocked = 0;
228 for (
const auto& row : rows) {
229 sum += row.freqSlider->getValue();
230 if (
static_cast<Element*
>(row.freqSlider.get()) != e && !row.lockBut->getValue()) {
235 const float diff = 1.f - sum;
236 const float shared = diff /
static_cast<float>(unlocked);
238 for (
auto& row : rows) {
239 if (
static_cast<Element*
>(row.freqSlider.get()) != e && !row.lockBut->getValue()) {
240 float f = row.freqSlider->getValue() + shared;
241 if (f <= 0.f) f = 0.001f;
242 if (f > 1.f) f = 1.f;
243 row.freqSlider->setValue(f,
false);
245 std::stringstream ss;
247 ss << std::setprecision(5) << (row.freqSlider->getValue() * 100.f) <<
"%";
248 row.freqLabel->setText(ss.str());
252 bool CatchRegionWindow::validate()
const {
254 bl::dialog::tinyfd_messageBox(
255 "Error",
"Region must have at least one Peoplemon",
"ok",
"error", 1);
258 if (nameEntry->getInput().empty()) {
259 bl::dialog::tinyfd_messageBox(
"Error",
"Please enter a name",
"ok",
"error", 1);
264 for (
const Row& row : rows) {
266 bl::dialog::tinyfd_messageBox(
"Error",
"Peoplemon cannot be blank",
"ok",
"error", 1);
269 if (!isnum(row.minLevel->getInput()) || !isnum(row.maxLevel->getInput())) {
270 bl::dialog::tinyfd_messageBox(
"Error",
"Levels must be numbers",
"ok",
"error", 1);
273 const int mn = std::atoi(row.minLevel->getInput().c_str());
274 const int mx = std::atoi(row.maxLevel->getInput().c_str());
275 if (mn <= 0 || mx <= 0) {
276 bl::dialog::tinyfd_messageBox(
"Error",
"Levels must be non-zero",
"ok",
"error", 1);
279 if (mn > 100 || mx > 100) {
280 bl::dialog::tinyfd_messageBox(
281 "Error",
"Levels must be less than or equal to 100",
"ok",
"error", 1);
285 bl::dialog::tinyfd_messageBox(
286 "Error",
"Min level must be below max level",
"ok",
"error", 1);
289 sum += row.freqSlider->getValue();
292 if (std::abs(1.f - sum) > 0.001f) {
293 bl::dialog::tinyfd_messageBox(
"Error",
"Frequencies must sum to 100%",
"ok",
"error", 1);
All classes and functionality used for implementing the game editor.
Represents a class of catchable peoplemon.
std::vector< pplmn::WildPeoplemon > wilds
Template struct to generate OwnedPeoplemon for random encounters.
Id id
The type of peoplemon to generate.
std::uint8_t minLevel
The minimum level that may spawn, inclusive.
std::uint8_t maxLevel
The maximum level that may spawn, inclusive.
std::uint16_t frequency
Frequency of spawns relative to other wild peoplemon in the region.
CatchRegionWindow(const TriggerCb &onSave)
Construct a new Catch Region Window.
std::function< void()> TriggerCb
Called when the region is saved.
const core::map::CatchRegion & getValue()
Returns the current region value as inputed by the user.
void open(bl::gui::GUI *gui, const core::map::CatchRegion ®ion)
Opens the window with the given region value.
static Ptr create(bool allowUnknown=false)
Creates a new peoplemon selector.