Peoplemon  0.1.0
Peoplemon 3 game source documentation
MoveEditorWindow.cpp
Go to the documentation of this file.
2 
3 #include <BLIB/Interfaces.hpp>
4 #include <Core/Files/MoveDB.hpp>
7 
8 namespace editor
9 {
10 namespace component
11 {
12 namespace
13 {
14 const char* moveEffectNames[] = {"None",
15  "Heal",
16  "Poison",
17  "Burn",
18  "Paralyze",
19  "Freeze",
20  "Confuse",
21  "LeechSeed",
22  "Flinch",
23  "Trap",
24  "Sleep",
25  "Protection",
26  "Safegaurd",
27  "Substitute",
28  "HealBell",
29  "CritUp",
30  "AtkUp",
31  "DefUp",
32  "AccUp",
33  "EvdUp",
34  "SpdUp",
35  "SpAtkUp",
36  "SpDefUp",
37  "CritDown",
38  "AtkDown",
39  "DefDown",
40  "AccDown",
41  "EvdDown",
42  "SpdDown",
43  "SpAtkDown",
44  "SpDefDown",
45  "Recoil",
46  "Charge",
47  "Suicide",
48  "Counter",
49  "MirrorCoat",
50  "OnlySleeping",
51  "Peanut",
52  "SetBall",
53  "WakeBoth",
54  "Absorb",
55  "Encore",
56  "RandomMove",
57  "BatonPass",
58  "DieIn3Turns",
59  "CritEvdUp",
60  "BumpBall",
61  "SpikeBall",
62  "DeathSwap",
63  "Gamble",
64  "StayAlive",
65  "MaxAtkMinAcc",
66  "FrustConfuse",
67  "Spikes",
68  "DoubleFamily",
69  "EnemyPPDown",
70  "HealNext",
71  "Roar",
72  "FailOnMove64",
73  "SleepHeal",
74  "SpdAtkUp",
75  "StealStats",
76  "BlockBall",
77  "SwipeBall",
78  "DamageThenSwitch",
79  "RoarCancelBallSpikes"};
80 constexpr std::size_t moveEffectCount = sizeof(moveEffectNames) / sizeof(moveEffectNames[0]);
81 
82 int effectToIndex(core::pplmn::MoveEffect ef) {
83  const unsigned int i = static_cast<unsigned int>(ef);
84  return i < moveEffectCount ? i : 0;
85 }
86 
87 template<typename T>
88 T parseInput(const bl::gui::TextEntry::Ptr& input) {
89  const long long val = std::atoll(input->getInput().c_str());
90  return static_cast<T>(val);
91 }
92 
93 } // namespace
94 
95 using namespace bl::gui;
96 
98 : moveDb(moveDb)
99 , onChange(onChange)
100 , doingNewMove(false)
101 , dirty(false) {
102  window = Window::create(LinePacker::create(LinePacker::Vertical, 4.f), "Editing Move");
103  window->getSignal(Event::Closed).willAlwaysCall(std::bind(&MoveEditorWindow::onCancel, this));
104 
105  LinePacker::Ptr rowPack = LinePacker::create(LinePacker::Horizontal, 4.f);
106  const auto onEdit = std::bind(&MoveEditorWindow::makeDirty, this);
107  applyBut = Button::create("Save");
108 
109  Box::Ptr row = Box::create(rowPack);
110  idEntry = TextEntry::create();
111  idEntry->setMode(TextEntry::Mode::Unsigned | TextEntry::Mode::Integer);
112  idEntry->getSignal(Event::TextEntered).willAlwaysCall(onEdit);
113  idEntry->setRequisition({60.f, 1.f});
114  nameEntry = TextEntry::create();
115  nameEntry->getSignal(Event::TextEntered).willAlwaysCall(onEdit);
116  nameEntry->setRequisition({160.f, 1.f});
117  row->pack(Label::create("Id:"), false, true);
118  row->pack(idEntry, false, true);
119  row->pack(Label::create("Name:"), false, true);
120  row->pack(nameEntry, false, true);
121  window->pack(row, true, false);
122 
123  row = Box::create(rowPack);
124  descEntry = TextEntry::create();
125  descEntry->getSignal(Event::TextEntered).willAlwaysCall(onEdit);
126  descEntry->setRequisition({400.f, 1.f});
127  row->pack(Label::create("Description:"), false, true);
128  row->pack(descEntry, false, true);
129  window->pack(row, true, false);
130 
131  row = Box::create(rowPack);
132  typeSelect = TypeSelector::create();
133  typeSelect->getSignal(Event::ValueChanged).willAlwaysCall(onEdit);
134  row->pack(Label::create("Type:"), false, true);
135  row->pack(typeSelect, false, true);
136  priorityEntry = TextEntry::create();
137  priorityEntry->setMode(TextEntry::Mode::Integer);
138  priorityEntry->getSignal(Event::TextEntered).willAlwaysCall(onEdit);
139  priorityEntry->setRequisition({60.f, 1.f});
140  row->pack(Label::create("Priority (-7 - 5):"));
141  row->pack(priorityEntry, false, true);
142  contactCheck = CheckButton::create("Makes contact");
143  contactCheck->getSignal(Event::ValueChanged).willAlwaysCall(onEdit);
144  row->pack(contactCheck, false, true);
145  specialCheck = CheckButton::create("Special");
146  specialCheck->getSignal(Event::ValueChanged).willAlwaysCall(onEdit);
147  row->pack(specialCheck, false, true);
148  window->pack(row, true, false);
149 
150  row = Box::create(rowPack);
151  dmgEntry = TextEntry::create();
152  dmgEntry->setMode(TextEntry::Mode::Unsigned | TextEntry::Mode::Integer);
153  dmgEntry->getSignal(Event::TextEntered).willAlwaysCall(onEdit);
154  dmgEntry->setRequisition({60.f, 1.f});
155  row->pack(Label::create("Power:"), false, true);
156  row->pack(dmgEntry, false, true);
157  accEntry = TextEntry::create();
158  accEntry->setMode(TextEntry::Mode::Unsigned | TextEntry::Mode::Integer);
159  accEntry->getSignal(Event::TextEntered).willAlwaysCall(onEdit);
160  accEntry->setRequisition({60.f, 1.f});
161  row->pack(Label::create("Accuracy:"), false, true);
162  row->pack(accEntry, false, true);
163  ppEntry = TextEntry::create();
164  ppEntry->setMode(TextEntry::Mode::Unsigned | TextEntry::Mode::Integer);
165  ppEntry->getSignal(Event::TextEntered).willAlwaysCall(onEdit);
166  ppEntry->setRequisition({60.f, 1.f});
167  row->pack(Label::create("PP:"), false, true);
168  row->pack(ppEntry, false, true);
169  window->pack(row, true, false);
170 
171  row = Box::create(rowPack);
172  effectSelect = ComboBox::create();
173  effectSelect->getSignal(Event::ValueChanged).willAlwaysCall(onEdit);
174  effectSelect->setMaxHeight(300.f);
175  for (std::size_t i = 0; i < moveEffectCount; ++i) {
176  effectSelect->addOption(moveEffectNames[i]);
177  }
178  effectSelect->setSelectedOption(0);
179  row->pack(Label::create("Effect"), false, true);
180  row->pack(effectSelect, false, true);
181  effectSelfCheck = CheckButton::create("Effects user");
182  effectSelfCheck->getSignal(Event::ValueChanged).willAlwaysCall(onEdit);
183  row->pack(effectSelfCheck, false, true);
184  window->pack(row, true, false);
185 
186  row = Box::create(rowPack);
187  effectChanceEntry = TextEntry::create();
188  effectChanceEntry->setMode(TextEntry::Mode::Unsigned | TextEntry::Mode::Integer);
189  effectChanceEntry->getSignal(Event::TextEntered).willAlwaysCall(onEdit);
190  effectChanceEntry->setRequisition({60.f, 1.f});
191  row->pack(Label::create("Effect chance (0-100):"), false, true);
192  row->pack(effectChanceEntry, false, true);
193  effectIntenseEntry = TextEntry::create();
194  effectIntenseEntry->setMode(TextEntry::Mode::Integer);
195  effectIntenseEntry->getSignal(Event::TextEntered).willAlwaysCall(onEdit);
196  effectIntenseEntry->setRequisition({60.f, 1.f});
197  row->pack(Label::create("Effect intensity:"), false, true);
198  row->pack(effectIntenseEntry, false, true);
199  window->pack(row, true, false);
200 
201  row = Box::create(LinePacker::create(
202  LinePacker::Horizontal, 4.f, LinePacker::Compact, LinePacker::RightAlign));
203  Button::Ptr cancelBut = Button::create("Cancel");
204  cancelBut->getSignal(Event::LeftClicked)
205  .willAlwaysCall(std::bind(&MoveEditorWindow::onCancel, this));
206  row->pack(cancelBut, false, true);
207  applyBut->getSignal(Event::LeftClicked)
208  .willAlwaysCall(std::bind(&MoveEditorWindow::onSave, this));
209  row->pack(applyBut, false, true);
210  window->pack(row, true, false);
211 }
212 
213 void MoveEditorWindow::open(bl::gui::GUI* parent, core::pplmn::MoveId move) {
214  using Move = core::pplmn::Move;
215 
216  openId = move;
217  doingNewMove = move == core::pplmn::MoveId::Unknown;
218 
219  idEntry->setInput(doingNewMove ? "" : std::to_string(static_cast<int>(move)));
220  nameEntry->setInput(doingNewMove ? "" : Move::name(move));
221  descEntry->setInput(doingNewMove ? "" : Move::description(move));
222  typeSelect->setCurrentType(doingNewMove ? core::pplmn::Type::Normal : Move::type(move));
223  dmgEntry->setInput(doingNewMove ? "100" : std::to_string(Move::damage(move)));
224  accEntry->setInput(doingNewMove ? "100" : std::to_string(Move::accuracy(move)));
225  priorityEntry->setInput(doingNewMove ? "0" : std::to_string(Move::priority(move)));
226  ppEntry->setInput(doingNewMove ? "15" : std::to_string(Move::pp(move)));
227  contactCheck->setValue(doingNewMove ? true : Move::makesContact(move));
228  specialCheck->setValue(doingNewMove ? false : Move::isSpecial(move));
229  effectSelect->setSelectedOption(doingNewMove ? 0 : effectToIndex(Move::effect(move)));
230  effectSelfCheck->setValue(doingNewMove ? false : Move::affectsUser(move));
231  effectChanceEntry->setInput(doingNewMove ? "0" : std::to_string(Move::effectChance(move)));
232  effectIntenseEntry->setInput(doingNewMove ? "0" : std::to_string(Move::effectIntensity(move)));
233 
234  dirty = false;
235  applyBut->setColor(sf::Color(20, 240, 50), sf::Color::Black);
236  parent->pack(window);
237  window->setForceFocus(true);
238 }
239 
240 void MoveEditorWindow::makeDirty() {
241  dirty = true;
242  applyBut->setColor(sf::Color(230, 30, 30), sf::Color::Black);
243 }
244 
245 void MoveEditorWindow::onSave() {
246  using namespace core::pplmn;
247  const auto error = [](const std::string& e) {
248  bl::dialog::tinyfd_messageBox("Error", e.c_str(), "ok", "error", 1);
249  };
250 
251  const MoveId id = parseInput<MoveId>(idEntry);
252  const int dmg = parseInput<int>(dmgEntry);
253  const int acc = parseInput<int>(accEntry);
254  const int pri = parseInput<int>(priorityEntry);
255  const int pp = parseInput<int>(ppEntry);
256  const MoveEffect effect = static_cast<MoveEffect>(effectSelect->getSelectedOption());
257  const int effectChance = parseInput<int>(effectChanceEntry);
258  const int effectIntense = parseInput<int>(effectIntenseEntry);
259 
260  if (idEntry->getInput().empty()) {
261  error("Please enter an id");
262  return;
263  }
264  if (openId != id && moveDb.names.find(id) != moveDb.names.end()) {
265  if (1 != bl::dialog::tinyfd_messageBox(
266  "Warning", "Id already exists. Overwrite it?", "yesno", "warning", 0)) {
267  return;
268  }
269  }
270  if (id == MoveId::Unknown) {
271  error("Invalid id");
272  return;
273  }
274  if (nameEntry->getInput().empty()) {
275  error("Please enter a name");
276  return;
277  }
278  if (descEntry->getInput().empty()) {
279  error("Please enter a description");
280  return;
281  }
282  if (typeSelect->currentType() == Type::None) {
283  error("Please select a type");
284  return;
285  }
286  if (effectSelect->getSelectedOption() < 0) {
287  error("Please select an effect or None");
288  return;
289  }
290  if (pri < -7 || pri > 5) {
291  error("Priority out of range");
292  return;
293  }
294  if (pp <= 0) {
295  error("Invalid PP");
296  return;
297  }
298 
299  moveDb.names[id] = nameEntry->getInput();
300  moveDb.descriptions[id] = descEntry->getInput();
301  moveDb.types[id] = typeSelect->currentType();
302  moveDb.damages[id] = dmg;
303  moveDb.accuracies[id] = acc;
304  moveDb.priorities[id] = pri;
305  moveDb.pps[id] = pp;
306  moveDb.contactors[id] = contactCheck->getValue();
307  moveDb.specials[id] = specialCheck->getValue();
308  moveDb.effects[id] = effect;
309  moveDb.effectChances[id] = effectChance;
310  moveDb.effectIntensities[id] = effectIntense;
311  moveDb.effectSelves[id] = effectSelfCheck->getValue();
312 
313  onChange();
314  close();
315 }
316 
317 void MoveEditorWindow::onCancel() {
318  if (dirty) {
319  if (1 != bl::dialog::tinyfd_messageBox(
320  "Warning", "Discard unsaved changes?", "yesno", "warning", 0)) {
321  return;
322  }
323  }
324  close();
325 }
326 
327 void MoveEditorWindow::close() {
328  window->setForceFocus(false);
329  window->remove();
330 }
331 
332 } // namespace component
333 } // namespace editor
MoveId
The id of a move.
Definition: MoveId.hpp:16
MoveEffect
Represents an effect that a move can have. Copied verbatim from Peoplemon 2, may refactor later when ...
Definition: MoveEffect.hpp:17
All classes and functionality used for implementing the game editor.
Definition: Tile.hpp:11
Collection of classes and enums pertaining to Peoplemon themselves.
Definition: Ailment.hpp:9
Stores the metadata of all peoplemon moves.
Definition: MoveDB.hpp:22
Encapsulates the move datastore.
Definition: Move.hpp:21
static unsigned int pp(MoveId move)
Returns the max pp of the given move.
Definition: Move.cpp:101
static int damage(MoveId move)
Returns the damage of the given move.
Definition: Move.cpp:86
static const std::string & description(MoveId move)
Returns the description of the given move.
Definition: Move.cpp:76
static int accuracy(MoveId move)
Returns the accuracy of the given move.
Definition: Move.cpp:91
static int priority(MoveId move)
Returns the priority of the given move.
Definition: Move.cpp:96
static bool makesContact(MoveId move)
Returns whether or not the given move makes physical contact when used.
Definition: Move.cpp:106
static int effectIntensity(MoveId move)
Returns the effect intensity of the given move.
Definition: Move.cpp:126
static MoveEffect effect(MoveId move)
Returns the effect of the given move.
Definition: Move.cpp:116
static const std::string & name(MoveId move)
Returns the name of the given move.
Definition: Move.cpp:71
static Type type(MoveId move)
Returns the type of the given move.
Definition: Move.cpp:81
static int effectChance(MoveId move)
Returns the effect chance of the given move.
Definition: Move.cpp:121
static bool isSpecial(MoveId move)
Returns whether or not the given move is special.
Definition: Move.cpp:111
static bool affectsUser(MoveId move)
Returns whether or not the given move affects the user or the opponent.
Definition: Move.cpp:131
MoveEditorWindow(core::file::MoveDB &moveDb, const OnChange &onChange)
Construct a new Move Editor Window.
void open(bl::gui::GUI *parent, core::pplmn::MoveId move)
Opens the window and populates for the given move. Pass MoveId::Unknown for a new move.
std::function< void()> OnChange
Callback signature on move change.
static Ptr create()
Create a new TypeSelector.