1 #include "game_player.h"
2 #include "doctest.h"
3 #include "options.h"
4 #include "game_map.h"
5 #include "main_data.h"
6 #include "game_system.h"
7 #include "rand.h"
8 #include <climits>
9 
10 #include "mock_game.h"
11 
12 TEST_SUITE_BEGIN("Game_Player Input");
13 
14 static constexpr auto map_id = MockMap::ePassBlock20x15;
15 
16 // FIXME: Test conditions which disable input
17 
testPos(Game_Player & ch,int x,int y,int dir,int face,int remaining_step,bool jumping,int stop_count,int max_stop_count,int encounter_steps,bool encounter_calling,bool menu_calling,int vehicle,bool boarding,bool aboard)18 static void testPos(Game_Player& ch, int x, int y,
19 		int dir, int face,
20 		int remaining_step, bool jumping,
21 		int stop_count, int max_stop_count,
22 		int encounter_steps, bool encounter_calling,
23 		bool menu_calling,
24 		int vehicle, bool boarding, bool aboard)
25 {
26 
27 	REQUIRE_EQ(ch.GetX(), x);
28 	REQUIRE_EQ(ch.GetY(), y);
29 	REQUIRE_EQ(ch.GetDirection(), dir);
30 	REQUIRE_EQ(ch.GetFacing(), face);
31 	REQUIRE_EQ(ch.GetRemainingStep(), remaining_step);
32 	REQUIRE_EQ(ch.IsJumping(), jumping);
33 	REQUIRE_EQ(ch.GetStopCount(), stop_count);
34 	REQUIRE_EQ(ch.GetMaxStopCount(), max_stop_count);
35 	REQUIRE_EQ(ch.GetEncounterSteps(), encounter_steps);
36 	REQUIRE_EQ(ch.IsEncounterCalling(), encounter_calling);
37 	REQUIRE_EQ(ch.IsMenuCalling(), menu_calling);
38 	REQUIRE_EQ(ch.GetVehicleType(),vehicle);
39 	REQUIRE_EQ(ch.IsBoardingOrUnboarding(), boarding);
40 	REQUIRE_EQ(ch.IsAboard(), aboard);
41 }
42 
testMove(bool success,int input_dir,int dir,int x,int y,int dx,int dy,bool cheat,bool debug)43 static void testMove(bool success, int input_dir, int dir, int x, int y, int dx, int dy, bool cheat, bool debug) {
44 	DebugGuard dg(debug);
45 	const MockGame mg(map_id);
46 	auto& ch = *mg.GetPlayer();
47 
48 	CAPTURE(cheat);
49 	CAPTURE(debug);
50 	CAPTURE(input_dir);
51 	CAPTURE(dir);
52 	CAPTURE(x);
53 	CAPTURE(y);
54 
55 	ch.SetX(x);
56 	ch.SetY(y);
57 
58 	Input::ResetKeys();
59 
60 	Input::dir4 = input_dir;
61 
62 	if (cheat) {
63 		Input::press_time[Input::DEBUG_THROUGH] = 1;
64 	}
65 
66 	const auto tx = x + dx;
67 	const auto ty = y + dy;
68 
69 	// Force RNG to always fail to generate a random encounter
70 	Rand::LockGuard lk(INT32_MAX);
71 	ForceUpdate(ch);
72 	if (success) {
73 		int enc_steps = (cheat && debug) ? 0 : 100;
74 		testPos(ch, tx, ty, dir, dir, 224, false, 0, 0, enc_steps, false, false, 0, false, false);
75 	} else {
76 		testPos(ch, tx, ty, dir, dir, 0, false, 1, 0, 0, false, false, 0, false, false);
77 	}
78 }
79 
80 TEST_CASE("Move") {
81 	testMove(true, 8, Up, 4, 8, 0, -1, false, false);
82 	testMove(true, 6, Right, 4, 8, 1, 0, false, false);
83 	testMove(true, 2, Down, 4, 8, 0, 1, false, false);
84 	testMove(true, 4, Left, 4, 8, -1, 0, false, false);
85 
86 	testMove(false, 8, Up, 16, 8, 0, 0, false, false);
87 	testMove(false, 6, Right, 16, 8, 0, 0, false, false);
88 	testMove(false, 2, Down, 16, 8, 0, 0, false, false);
89 	testMove(false, 4, Left, 16, 8, 0, 0, false, false);
90 
91 	testMove(false, 8, Up, 16, 8, 0, 0, true, false);
92 	testMove(false, 6, Right, 16, 8, 0, 0, true, false);
93 	testMove(false, 2, Down, 16, 8, 0, 0, true, false);
94 	testMove(false, 4, Left, 16, 8, 0, 0, true, false);
95 
96 	testMove(true, 8, Up, 16, 8, 0, -1, true, true);
97 	testMove(true, 6, Right, 16, 8, 1, 0, true, true);
98 	testMove(true, 2, Down, 16, 8, 0, 1, true, true);
99 	testMove(true, 4, Left, 16, 8, -1, 0, true, true);
100 }
101 
testDecision(bool moved,int vehicle,bool boarding,bool aboard)102 static void testDecision(bool moved, int vehicle, bool boarding, bool aboard) {
103 	auto& ch = *MockGame::GetPlayer();
104 
105 	ch.SetX(8);
106 	ch.SetY(8);
107 
108 	Input::ResetKeys();
109 
110 	Input::triggered[Input::DECISION] = true;
111 
112 	ForceUpdate(ch);
113 
114 	int y = moved ? 9 : 8;
115 	int rs = moved ? 224 : 0;
116 	int stp = moved ? 0 : 1;
117 	testPos(ch, 8, y, Down, Down, rs, false, stp, 0, 0, false, false, vehicle, boarding, aboard);
118 }
119 
120 TEST_CASE("DecisionNone") {
121 	const MockGame mg(map_id);
122 
123 	testDecision(false, 0, false, false);
124 }
125 
126 TEST_CASE("DecisionEvent") {
127 	const MockGame mg(map_id);
128 
129 	auto* event = Game_Map::GetEvent(1);
130 	REQUIRE(event);
131 	event->MoveTo(1, 8, 9);
132 
133 	testDecision(false, 0, false, false);
134 
135 	// FIXME: Add map page which triggers
136 }
137 
138 TEST_CASE("DecisionBoard") {
139 	const MockGame mg(map_id);
140 	auto& ch = *Main_Data::game_player;
141 
142 	auto* vh = Game_Map::GetVehicle(Game_Vehicle::Boat);
143 	REQUIRE(vh);
144 	vh->MoveTo(1, 8, 9);
145 
146 	testDecision(true, Game_Vehicle::Boat, true, false);
147 
148 	while (!ch.IsStopping()) {
149 		ForceUpdate(ch);
150 	}
151 
152 	testPos(ch, 8, 9, Down, Left, 0, false, 0, 0, 0, false, false, Game_Vehicle::Boat, 0, true);
153 }
154 
155 TEST_CASE("DecisionUnboard") {
156 	const MockGame mg(map_id);
157 
158 	// FIXME: Implement
159 }
160 
testMenu(bool success)161 static void testMenu(bool success) {
162 	auto& ch = *Main_Data::game_player;
163 	ch.SetX(8);
164 	ch.SetY(8);
165 
166 	Input::ResetKeys();
167 
168 	Input::triggered[Input::CANCEL] = true;
169 
170 	ForceUpdate(ch);
171 	testPos(ch, 8, 8, Down, Down, 0, false, 1, 0, 0, false, success, 0, false, false);
172 
173 	// FIXME: Test conditions which disable menu calling
174 }
175 
176 TEST_CASE("CallMenu") {
177 	const MockGame mg(map_id);
178 
179 	testMenu(true);
180 }
181 
182 TEST_CASE("CallMenuDisabled") {
183 	const MockGame mg(map_id);
184 
185 	Main_Data::game_system->SetAllowMenu(false);
186 
187 	testMenu(false);
188 }
189 
190 TEST_SUITE_END();
191