1 /*
2 * This file is part of EasyRPG Player.
3 *
4 * EasyRPG Player is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * EasyRPG Player is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 // Headers
19 #define _USE_MATH_DEFINES
20 #include <vector>
21 #include <sstream>
22 #include <cmath>
23 #include <iomanip>
24 #include "baseui.h"
25 #include "cache.h"
26 #include "input.h"
27 #include "game_variables.h"
28 #include "game_switches.h"
29 #include "game_map.h"
30 #include "game_system.h"
31 #include "game_battle.h"
32 #include "scene_debug.h"
33 #include "scene_load.h"
34 #include "scene_save.h"
35 #include "scene_map.h"
36 #include "scene_battle.h"
37 #include "player.h"
38 #include "window_command.h"
39 #include "window_varlist.h"
40 #include "window_numberinput.h"
41 #include "bitmap.h"
42 #include "game_party.h"
43 #include "game_player.h"
44 #include <lcf/data.h>
45 #include "output.h"
46 #include "transition.h"
47
48 namespace {
49 struct IndexSet {
50 int range_index = 0;
51 int range_page = 0;
52 int range_page_index = 0;
53 };
54
55 std::array<IndexSet,Scene_Debug::eLastMainMenuOption> prev = {};
56 }
57
58 constexpr int arrow_animation_frames = 20;
59
Scene_Debug()60 Scene_Debug::Scene_Debug() {
61 Scene::type = Scene::Debug;
62 }
63
ResetPrevIndices()64 void Scene_Debug::ResetPrevIndices() {
65 prev = {};
66 }
67
Start()68 void Scene_Debug::Start() {
69 CreateRangeWindow();
70 CreateVarListWindow();
71 CreateNumberInputWindow();
72
73 SetupUiRangeList();
74
75 range_window->SetActive(true);
76 var_window->SetActive(false);
77
78 UpdateRangeListWindow();
79 var_window->Refresh();
80 }
81
GetFrame(int n)82 Scene_Debug::StackFrame& Scene_Debug::GetFrame(int n) {
83 auto i = stack_index - n;
84 assert(i >= 0 && i < static_cast<int>(stack.size()));
85 return stack[i];
86 }
87
GetFrame(int n) const88 const Scene_Debug::StackFrame& Scene_Debug::GetFrame(int n) const {
89 auto i = stack_index - n;
90 assert(i >= 0 && i < static_cast<int>(stack.size()));
91 return stack[i];
92 }
93
GetStackSize() const94 int Scene_Debug::GetStackSize() const {
95 return stack_index + 1;
96 }
97
GetWindowMode() const98 Window_VarList::Mode Scene_Debug::GetWindowMode() const {
99 switch (mode) {
100 case eSwitch:
101 return Window_VarList::eSwitch;
102 case eVariable:
103 return Window_VarList::eVariable;
104 case eItem:
105 return Window_VarList::eItem;
106 case eBattle:
107 return Window_VarList::eTroop;
108 case eMap:
109 return Window_VarList::eMap;
110 case eFullHeal:
111 return Window_VarList::eHeal;
112 case eLevel:
113 return Window_VarList::eLevel;
114 case eCallCommonEvent:
115 return Window_VarList::eCommonEvent;
116 case eCallMapEvent:
117 return Window_VarList::eMapEvent;
118 default:
119 return Window_VarList::eNone;
120 }
121 }
122
UpdateFrameValueFromUi()123 void Scene_Debug::UpdateFrameValueFromUi() {
124 auto& frame = GetFrame();
125 auto& idx = prev[mode];
126 switch (frame.uimode) {
127 case eUiMain:
128 idx.range_index = range_index;
129 idx.range_page = range_page;
130 break;
131 case eUiRangeList:
132 idx.range_index = range_index;
133 idx.range_page = range_page;
134 frame.value = range_page * 100 + range_index * 10;
135 break;
136 case eUiVarList:
137 idx.range_page_index = var_window->GetIndex();
138 frame.value = range_page * 100 + range_index * 10 + var_window->GetIndex() + 1;
139 break;
140 case eUiNumberInput:
141 frame.value = numberinput_window->GetNumber();
142 break;
143 }
144 }
145
Push(UiMode ui)146 void Scene_Debug::Push(UiMode ui) {
147 ++stack_index;
148 assert(stack_index < static_cast<int>(stack.size()));
149 stack[stack_index] = { ui, 0 };
150
151 range_window->SetActive(false);
152 var_window->SetActive(false);
153 numberinput_window->SetActive(false);
154 numberinput_window->SetVisible(false);
155 }
156
SetupUiRangeList()157 void Scene_Debug::SetupUiRangeList() {
158 auto& idx = prev[mode];
159 auto vmode = GetWindowMode();
160
161 range_index = idx.range_index;
162 range_page = idx.range_page;
163
164 var_window->SetMode(vmode);
165 var_window->UpdateList(range_page * 100 + range_index * 10 + 1);
166
167 range_window->SetIndex(range_index);
168 }
169
PushUiRangeList()170 void Scene_Debug::PushUiRangeList() {
171 Push(eUiRangeList);
172
173 SetupUiRangeList();
174
175 range_window->SetActive(true);
176
177 UpdateRangeListWindow();
178 var_window->Refresh();
179
180 }
181
PushUiVarList()182 void Scene_Debug::PushUiVarList() {
183 const bool was_range_list = (GetFrame().uimode == eUiRangeList);
184
185 Push(eUiVarList);
186
187 auto& idx = prev[mode];
188
189 if (!was_range_list) {
190 SetupUiRangeList();
191 }
192
193 var_window->SetActive(true);
194 var_window->SetIndex(idx.range_page_index);
195
196 UpdateRangeListWindow();
197 var_window->Refresh();
198
199 }
200
PushUiNumberInput(int init_value,int digits,bool show_operator)201 void Scene_Debug::PushUiNumberInput(int init_value, int digits, bool show_operator) {
202 Push(eUiNumberInput);
203
204 numberinput_window->SetNumber(init_value);
205 numberinput_window->SetShowOperator(show_operator);
206 numberinput_window->SetVisible(true);
207 numberinput_window->SetActive(true);
208 numberinput_window->SetMaxDigits(digits);
209 numberinput_window->Refresh();
210
211 var_window->Refresh();
212 UpdateRangeListWindow();
213 }
214
Pop()215 void Scene_Debug::Pop() {
216 auto pui = GetFrame().uimode;
217
218 if (pui == eUiVarList) {
219 var_window->SetIndex(-1);
220 }
221
222 range_window->SetActive(false);
223 var_window->SetActive(false);
224 numberinput_window->SetActive(false);
225 numberinput_window->SetVisible(false);
226
227 if (stack_index == 0) {
228 Scene::Pop();
229 return;
230 }
231
232 --stack_index;
233
234 auto nui = GetFrame().uimode;
235 switch (nui) {
236 case eUiMain:
237 var_window->SetMode(Window_VarList::eNone);
238 range_index = (static_cast<int>(mode) - 1) % 10;
239 range_page = (static_cast<int>(mode) - 1) / 10;
240 range_window->SetActive(true);
241 range_window->SetIndex(range_index);
242 break;
243 case eUiRangeList:
244 range_window->SetActive(true);
245 range_index = (GetFrame().value % 100) / 10;
246 range_page = GetFrame().value / 100;
247 range_window->SetIndex(range_index);
248 break;
249 case eUiVarList:
250 var_window->SetActive(true);
251 var_window->SetIndex((GetFrame().value - 1) % 10);
252 break;
253 case eUiNumberInput:
254 numberinput_window->SetNumber(GetFrame().value);
255 numberinput_window->SetActive(true);
256 numberinput_window->SetVisible(true);
257 break;
258 }
259
260 if (stack_index == 0) {
261 mode = eMain;
262 }
263
264 UpdateRangeListWindow();
265 var_window->Refresh();
266 }
267
Update()268 void Scene_Debug::Update() {
269 range_window->Update();
270 if (range_index != range_window->GetIndex()){
271 range_index = range_window->GetIndex();
272 var_window->UpdateList(range_page * 100 + range_index * 10 + 1);
273 var_window->Refresh();
274 }
275 var_window->Update();
276
277 if (numberinput_window->GetActive())
278 numberinput_window->Update();
279
280 if (Input::IsTriggered(Input::CANCEL)) {
281 UpdateFrameValueFromUi();
282 Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cancel));
283 Pop();
284 } else if (Input::IsTriggered(Input::DECISION)) {
285 UpdateFrameValueFromUi();
286 if (mode == eMain) {
287 auto next_mode = static_cast<Mode>(range_window->GetIndex() + range_page * 10 + 1);
288 if (next_mode > eMain && next_mode < eLastMainMenuOption) {
289 const auto is_battle = Game_Battle::IsBattleRunning();
290 if (
291 (is_battle && (next_mode == eSave || next_mode == eBattle || next_mode == eMap || next_mode == eCallMapEvent))
292 || (!is_battle && (next_mode == eCallBattleEvent))
293 )
294 {
295 Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Buzzer));
296 } else {
297 Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
298 mode = next_mode;
299 }
300 }
301 }
302
303 const auto sz = GetStackSize();
304 const auto& frame = GetFrame();
305 switch (mode) {
306 case eMain:
307 case eLastMainMenuOption:
308 break;
309 case eSave:
310 Scene::PopUntil(Scene::Map);
311 Scene::Push(std::make_shared<Scene_Save>());
312 break;
313 case eLoad:
314 Scene::Push(std::make_shared<Scene_Load>());
315 mode = eMain;
316 break;
317 case eSwitch:
318 if (sz > 2) {
319 DoSwitch();
320 } else if (sz > 1) {
321 PushUiVarList();
322 } else if (sz > 0) {
323 PushUiRangeList();
324 }
325 break;
326 case eVariable:
327 if (sz > 3) {
328 DoVariable();
329 } else if (sz > 2) {
330 if (Main_Data::game_variables->IsValid(frame.value)) {
331 PushUiNumberInput(Main_Data::game_variables->Get(frame.value), Main_Data::game_variables->GetMaxDigits(), true);
332 }
333 } else if (sz > 1) {
334 PushUiVarList();
335 } else {
336 PushUiRangeList();
337 }
338 break;
339 case eGold:
340 if (sz > 1) {
341 DoGold();
342 } else {
343 PushUiNumberInput(Main_Data::game_party->GetGold(), 6, false);
344 range_index = 0;
345 range_window->SetIndex(range_index);
346 }
347 break;
348 case eItem:
349 if (sz > 3) {
350 DoItem();
351 } else if (sz > 2) {
352 if (frame.value <= static_cast<int>(lcf::Data::items.size())) {
353 PushUiNumberInput(Main_Data::game_party->GetItemCount(frame.value), Main_Data::game_party->GetMaxItemCount(frame.value) >= 100 ? 3 : 2, false);
354 }
355 } else if (sz > 1) {
356 PushUiVarList();
357 } else {
358 PushUiRangeList();
359 }
360 break;
361 case eBattle:
362 if (sz > 2) {
363 DoBattle();
364 } else if (sz > 1) {
365 PushUiVarList();
366 } else {
367 PushUiRangeList();
368 }
369 break;
370 case eMap:
371 if (sz > 4) {
372 DoMap();
373 } else if (sz > 3) {
374 // FIXME: Remember previous y
375 PushUiNumberInput(GetFrame(-1).value, 4, false);
376 } else if (sz > 2) {
377 const auto map_id = GetFrame().value;
378 if (IsValidMapId(map_id)) {
379 // Reset x and y values
380 GetFrame(-1).value = 0;
381 GetFrame(-2).value = 0;
382 PushUiNumberInput(GetFrame(-1).value, 4, false);
383 }
384 } else if (sz > 1) {
385 PushUiVarList();
386 } else {
387 PushUiRangeList();
388 }
389 break;
390 case eFullHeal:
391 if (sz > 1) {
392 DoFullHeal();
393 } else {
394 PushUiVarList();
395 }
396 break;
397 case eLevel:
398 if (sz > 2) {
399 DoLevel();
400 } else if (sz > 1) {
401 if (frame.value <= static_cast<int>(Main_Data::game_party->GetActors().size())) {
402 auto* actor = Main_Data::game_party->GetActors()[frame.value - 1];
403 PushUiNumberInput(actor->GetLevel(), actor->GetMaxLevel() >= 100 ? 3 : 2, false);
404 }
405 } else {
406 PushUiVarList();
407 }
408 break;
409 case eCallCommonEvent:
410 if (sz > 2) {
411 DoCallCommonEvent();
412 } else if (sz > 1) {
413 PushUiVarList();
414 } else {
415 PushUiRangeList();
416 }
417 break;
418 case eCallMapEvent:
419 if (sz > 3) {
420 DoCallMapEvent();
421 } else if (sz > 2) {
422 auto* event = Game_Map::GetEvent(GetFrame().value);
423 if (event) {
424 const auto num_digits = static_cast<int>(std::log10(event->GetNumPages()) + 1);
425 PushUiNumberInput(1, num_digits, false);
426 }
427 } else if (sz > 1) {
428 PushUiVarList();
429 } else {
430 PushUiRangeList();
431 }
432 break;
433 case eCallBattleEvent:
434 if (sz > 1) {
435 DoCallBattleEvent();
436 } else {
437 auto* troop = Game_Battle::GetActiveTroop();
438 if (troop) {
439 const auto num_digits = static_cast<int>(std::log10(troop->pages.size()) + 1);
440 PushUiNumberInput(0, num_digits, false);
441 }
442 }
443 break;
444 }
445 Game_Map::SetNeedRefresh(true);
446 } else if (range_window->GetActive() && Input::IsRepeated(Input::RIGHT)) {
447 if (range_page < GetLastPage()) {
448 ++range_page;
449 } else {
450 range_page = 0;
451 }
452 var_window->UpdateList(range_page * 100 + range_index * 10 + 1);
453 UpdateRangeListWindow();
454 var_window->Refresh();
455 } else if (range_window->GetActive() && Input::IsRepeated(Input::LEFT)) {
456 if (range_page > 0) {
457 --range_page;
458 } else {
459 range_page = GetLastPage();
460 }
461 var_window->UpdateList(range_page * 100 + range_index * 10 + 1);
462 UpdateRangeListWindow();
463 var_window->Refresh();
464 }
465
466 UpdateArrows();
467 }
468
CreateRangeWindow()469 void Scene_Debug::CreateRangeWindow() {
470
471 std::vector<std::string> ranges;
472 for (int i = 0; i < 10; i++)
473 ranges.push_back("");
474 range_window.reset(new Window_Command(ranges, 96));
475
476 range_window->SetHeight(176);
477 range_window->SetY(32);
478 }
479
UpdateRangeListWindow()480 void Scene_Debug::UpdateRangeListWindow() {
481 int idx = 0;
482 const bool is_battle = Game_Battle::IsBattleRunning();
483
484 auto addItem = [&](const auto& name, bool enabled = true) {
485 range_window->SetItemText(idx, name);
486 if (!enabled) {
487 range_window->DisableItem(idx);
488 }
489 ++idx;
490 };
491
492 auto fillRange = [&](const auto& prefix) {
493 for (int i = 0; i < 10; i++){
494 const auto st = range_page * 100 + i * 10 + 1;
495 addItem(fmt::format("{}[{:04d}-{:04d}]", prefix, st, st + 9));
496 }
497 };
498
499 switch (mode) {
500 case eMain:
501 if (range_page == 0) {
502 addItem("Save", !is_battle);
503 addItem("Load");
504 addItem("Switches");
505 addItem("Variables");
506 addItem(lcf::Data::terms.gold.c_str());
507 addItem("Items");
508 addItem("Battle", !is_battle);
509 addItem("Goto Map", !is_battle);
510 addItem("Full Heal");
511 addItem("Level");
512 } else {
513 addItem("Call ComEvent");
514 addItem("Call MapEvent", !is_battle);
515 addItem("Call BtlEvent", is_battle);
516 }
517 break;
518 case eSwitch:
519 fillRange("Sw");
520 break;
521 case eVariable:
522 fillRange("Vr");
523 break;
524 case eItem:
525 fillRange("It");
526 break;
527 case eBattle:
528 fillRange("Bt");
529 break;
530 case eMap:
531 if (GetStackSize() > 3) {
532 if (GetStackSize() > 4) {
533 addItem("Map: " + std::to_string(GetFrame(2).value));
534 addItem("X: " + std::to_string(GetFrame(1).value));
535 addItem("Y: ");
536 } else {
537 addItem("Map: " + std::to_string(GetFrame(1).value));
538 addItem("X: ");
539 }
540 } else {
541 fillRange("Mp");
542 }
543 break;
544 case eCallCommonEvent:
545 fillRange("Ce");
546 break;
547 case eCallMapEvent:
548 if (GetStackSize() > 3) {
549 auto* event = Game_Map::GetEvent(GetFrame(1).value);
550 if (event) {
551 addItem(fmt::format("{:04d}: {}", event->GetId(), event->GetName()));
552 addItem(fmt::format("NumPages: {}", event->GetNumPages()));
553 const auto* page = event->GetActivePage();
554 const auto page_id = page ? page->ID : 0;
555 addItem(fmt::format("ActvPage: {}", page_id));
556 addItem(fmt::format("Enabled: {}", event->IsActive() ? 'Y' : 'N'));
557 addItem(fmt::format("X: {}", event->GetX()));
558 addItem(fmt::format("Y: {}", event->GetY()));
559 }
560 } else {
561 fillRange("Me");
562 }
563 break;
564 case eGold:
565 addItem(lcf::Data::terms.gold);
566 for (int i = 1; i < 10; i++){
567 range_window->SetItemText(i, "");
568 }
569 break;
570 case eFullHeal:
571 addItem("Full Heal");
572 break;
573 case eLevel:
574 addItem("Level");
575 break;
576 case eCallBattleEvent:
577 if (is_battle) {
578 auto* troop = Game_Battle::GetActiveTroop();
579 if (troop) {
580 addItem(troop->name);
581 addItem(fmt::format("TroopId: {}", troop->ID));
582 addItem(fmt::format("NumEnemies: {}", troop->members.size()));
583 addItem(fmt::format("NumPages: {}", troop->pages.size()));
584 }
585 }
586 break;
587 default:
588 break;
589 }
590
591 while (idx < 10) {
592 addItem("", true);
593 }
594 }
595
CreateVarListWindow()596 void Scene_Debug::CreateVarListWindow() {
597 std::vector<std::string> vars;
598 for (int i = 0; i < 10; i++)
599 vars.push_back("");
600 var_window.reset(new Window_VarList(vars));
601 var_window->SetX(range_window->GetWidth());
602 var_window->SetY(range_window->GetY());
603 var_window->SetVisible(false);
604 var_window->SetIndex(-1);
605
606 var_window->UpdateList(range_page * 100 + range_index * 10 + 1);
607 }
608
CreateNumberInputWindow()609 void Scene_Debug::CreateNumberInputWindow() {
610 numberinput_window.reset(new Window_NumberInput(160 - (Main_Data::game_variables->GetMaxDigits() + 1) * 6 - 8, 104,
611 (Main_Data::game_variables->GetMaxDigits() + 1) * 12 + 16, 32));
612 numberinput_window->SetVisible(false);
613 numberinput_window->SetOpacity(255);
614 numberinput_window->SetShowOperator(true);
615 }
616
GetNumMainMenuItems() const617 int Scene_Debug::GetNumMainMenuItems() const {
618 return static_cast<int>(eLastMainMenuOption) - 1;
619 }
620
GetLastPage()621 int Scene_Debug::GetLastPage() {
622 size_t num_elements = 0;
623 switch (mode) {
624 case eMain:
625 return GetNumMainMenuItems() / 10;
626 case eSwitch:
627 num_elements = Main_Data::game_switches->GetSize();
628 break;
629 case eVariable:
630 num_elements = Main_Data::game_variables->GetSize();
631 break;
632 case eItem:
633 num_elements = lcf::Data::items.size();
634 break;
635 case eBattle:
636 num_elements = lcf::Data::troops.size();
637 break;
638 case eMap:
639 num_elements = lcf::Data::treemap.maps.size() > 0 ? lcf::Data::treemap.maps.back().ID : 0;
640 break;
641 case eFullHeal:
642 num_elements = Main_Data::game_party->GetBattlerCount() + 1;
643 break;
644 case eLevel:
645 num_elements = Main_Data::game_party->GetBattlerCount();
646 break;
647 case eCallCommonEvent:
648 num_elements = lcf::Data::commonevents.size();
649 break;
650 case eCallMapEvent:
651 num_elements = Game_Map::GetHighestEventId();
652 break;
653 default:
654 break;
655 }
656
657 if (num_elements > 0) {
658 return (static_cast<int>(num_elements) - 1) / 100;
659 }
660 return 0;
661 }
662
IsValidMapId(int map_id) const663 bool Scene_Debug::IsValidMapId(int map_id) const {
664 auto iter = std::lower_bound(lcf::Data::treemap.maps.begin(), lcf::Data::treemap.maps.end(), map_id,
665 [](const lcf::rpg::MapInfo& l, int r) { return l.ID < r; });
666 return (iter != lcf::Data::treemap.maps.end()
667 && iter->ID == map_id
668 && iter->type == lcf::rpg::TreeMap::MapType_map);
669 }
670
DoSwitch()671 void Scene_Debug::DoSwitch() {
672 const auto sw_id = GetFrame().value;
673 if (Main_Data::game_switches->IsValid(sw_id)) {
674 Main_Data::game_switches->Flip(sw_id);
675 Game_Map::SetNeedRefresh(true);
676
677 var_window->Refresh();
678 }
679 }
680
DoVariable()681 void Scene_Debug::DoVariable() {
682 const auto var_id = GetFrame(1).value;
683 const auto value = GetFrame(0).value;
684 Main_Data::game_variables->Set(var_id, value);
685 Game_Map::SetNeedRefresh(true);
686
687 Pop();
688 }
689
DoGold()690 void Scene_Debug::DoGold() {
691 const auto delta = GetFrame().value - Main_Data::game_party->GetGold();
692 Main_Data::game_party->GainGold(delta);
693
694 Pop();
695 }
696
DoItem()697 void Scene_Debug::DoItem() {
698 const auto item_id = GetFrame(1).value;
699 auto delta = GetFrame().value - Main_Data::game_party->GetItemCount(item_id);
700
701 Main_Data::game_party->AddItem(item_id, delta);
702
703 Game_Map::SetNeedRefresh(true);
704
705 Pop();
706 }
707
DoBattle()708 void Scene_Debug::DoBattle() {
709 auto troop_id = GetFrame(0).value;
710 if (troop_id > static_cast<int>(lcf::Data::troops.size())) {
711 return;
712 }
713
714 Scene::PopUntil(Scene::Map);
715 if (!Scene::instance) {
716 return;
717 }
718
719 BattleArgs args;
720 args.troop_id = troop_id;
721 args.first_strike = false;
722 args.allow_escape = true;
723
724 Output::Debug("Debug Scene starting battle {}.", troop_id);
725
726 Game_Map::SetupBattle(args);
727
728 Scene::Push(Scene_Battle::Create(std::move(args)));
729 }
730
DoMap()731 void Scene_Debug::DoMap() {
732 auto y = GetFrame(0).value;
733 auto x = GetFrame(1).value;
734 auto map_id = GetFrame(2).value;
735
736 Scene::PopUntil(Scene::Map);
737 if (Scene::instance) {
738 Main_Data::game_player->ReserveTeleport(map_id, x, y, -1, TeleportTarget::eSkillTeleport);
739 }
740 }
741
DoFullHeal()742 void Scene_Debug::DoFullHeal() {
743 const auto id = GetFrame(0).value;
744
745 Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_UseItem));
746 auto actors = Main_Data::game_party->GetActors();
747 if (id <= 1) {
748 for (auto& actor: actors) {
749 actor->FullHeal();
750 }
751 } else {
752 int idx = id - 2;
753 if (idx < static_cast<int>(actors.size())) {
754 actors[idx]->FullHeal();
755 }
756 }
757 var_window->UpdateList(1);
758 var_window->Refresh();
759 }
760
DoLevel()761 void Scene_Debug::DoLevel() {
762 const auto id = GetFrame(1).value;
763 const auto level = GetFrame(0).value;
764
765 auto actors = Main_Data::game_party->GetActors();
766 int idx = id - 1;
767 if (idx < static_cast<int>(actors.size())) {
768 if (actors[idx]->GetLevel() != level) {
769 actors[idx]->ChangeLevel(level, nullptr);
770 }
771 }
772
773 Pop();
774 }
775
DoCallCommonEvent()776 void Scene_Debug::DoCallCommonEvent() {
777 const auto ceid = GetFrame(0).value;
778
779 if (ceid > static_cast<int>(lcf::Data::commonevents.size())) {
780 return;
781 }
782
783 auto& ce = Game_Map::GetCommonEvents()[ceid - 1];
784
785 if (Game_Battle::IsBattleRunning()) {
786 Game_Battle::GetInterpreter().Push(&ce);
787 Scene::PopUntil(Scene::Battle);
788 Output::Debug("Debug Scene Forced execution of common event {} on the battle foreground interpreter.", ce.GetIndex());
789 } else {
790 Game_Map::GetInterpreter().Push(&ce);
791 Scene::PopUntil(Scene::Map);
792 Output::Debug("Debug Scene Forced execution of common event {} on the map foreground interpreter.", ce.GetIndex());
793 }
794 }
795
DoCallMapEvent()796 void Scene_Debug::DoCallMapEvent() {
797 if (Game_Battle::IsBattleRunning()) {
798 return;
799 }
800
801 const auto me_id = GetFrame(1).value;
802 const auto page_id = GetFrame(0).value;
803
804 auto* me = Game_Map::GetEvent(me_id);
805 if (!me) {
806 return;
807 }
808
809 auto* page = me->GetPage(page_id);
810 if (!page) {
811 return;
812 }
813
814 Game_Map::GetInterpreter().Push(me, page, false);
815 Scene::PopUntil(Scene::Map);
816 Output::Debug("Debug Scene Forced execution of map event {} page {} on the map foreground interpreter.", me->GetId(), page->ID);
817 }
818
DoCallBattleEvent()819 void Scene_Debug::DoCallBattleEvent() {
820 if (!Game_Battle::IsBattleRunning()) {
821 return;
822 }
823
824 auto* troop = Game_Battle::GetActiveTroop();
825 if (!troop) {
826 return;
827 }
828
829 const auto page_idx = GetFrame(0).value - 1;
830
831 if (page_idx < 0 || page_idx >= static_cast<int>(troop->pages.size())) {
832 return;
833 }
834
835 auto& page = troop->pages[page_idx];
836
837 Game_Battle::GetInterpreter().Push(page.event_commands, 0, false);
838 Scene::PopUntil(Scene::Battle);
839 Output::Debug("Debug Scene Forced execution of battle troop {} event page {} on the map foreground interpreter.", troop->ID, page.ID);
840 }
841
TransitionIn(SceneType)842 void Scene_Debug::TransitionIn(SceneType /* prev_scene */) {
843 Transition::instance().InitShow(Transition::TransitionCutIn, this);
844 }
845
TransitionOut(SceneType)846 void Scene_Debug::TransitionOut(SceneType /* next_scene */) {
847 Transition::instance().InitErase(Transition::TransitionCutOut, this);
848 }
849
UpdateArrows()850 void Scene_Debug::UpdateArrows() {
851 bool show_left_arrow = (range_page > 0);
852 bool show_right_arrow = (range_page < GetLastPage());
853
854 if (show_left_arrow || show_right_arrow) {
855 arrow_frame = (arrow_frame + 1) % (arrow_animation_frames * 2);
856 }
857 bool arrow_visible = (arrow_frame < arrow_animation_frames);
858 range_window->SetLeftArrow(show_left_arrow && arrow_visible);
859 range_window->SetRightArrow(show_right_arrow && arrow_visible);
860 }
861