1 #include "game_player.h"
2 #include "doctest.h"
3 #include "options.h"
4 #include "game_map.h"
5 #include "game_vehicle.h"
6 #include "main_data.h"
7 #include "game_switches.h"
8 #include <climits>
9 #include <initializer_list>
10 
11 #include "test_move_route.h"
12 
13 TEST_SUITE_BEGIN("MoveRoute");
14 
MakeRoute(std::initializer_list<lcf::rpg::MoveCommand> cmds,bool repeat=false,bool skip=false)15 lcf::rpg::MoveRoute MakeRoute(std::initializer_list<lcf::rpg::MoveCommand> cmds, bool repeat = false, bool skip = false) {
16 	lcf::rpg::MoveRoute mr;
17 	mr.move_commands = cmds;
18 	mr.repeat = repeat;
19 	mr.skippable = skip;
20 	return mr;
21 }
22 
testMoveRoute(const Game_Character & ch,bool paused,int move_frequency,int stop_count,int max_stop_count,int move_route_idx,bool overwritten,bool done,const lcf::rpg::MoveRoute & mr)23 static void testMoveRoute(
24 		const Game_Character& ch,
25 		bool paused, int move_frequency,
26 		int stop_count, int max_stop_count,
27 		int move_route_idx, bool overwritten, bool done,
28 		const lcf::rpg::MoveRoute& mr)
29 {
30 	CAPTURE(paused);
31 	CAPTURE(move_frequency);
32 	CAPTURE(stop_count);
33 	CAPTURE(max_stop_count);
34 	CAPTURE(move_route_idx);
35 	CAPTURE(overwritten);
36 	CAPTURE(done);
37 	CAPTURE(mr);
38 
39 	REQUIRE_EQ(ch.IsPaused(), paused);
40 	REQUIRE_EQ(ch.GetMoveFrequency(), move_frequency);
41 	REQUIRE_EQ(ch.GetStopCount(), stop_count);
42 	REQUIRE_EQ(ch.GetMaxStopCount(), max_stop_count);
43 	REQUIRE_EQ(ch.GetMoveRouteIndex(), move_route_idx);
44 	REQUIRE_EQ(ch.IsMoveRouteOverwritten(), overwritten);
45 	REQUIRE_EQ(ch.IsMoveRouteRepeated(), done);
46 	REQUIRE_EQ(ch.GetMoveRoute(), mr);
47 	REQUIRE_EQ(ch.IsStopCountActive(), stop_count < max_stop_count);
48 }
49 
50 template <typename... Args>
testMoveRouteDir(const Game_Character & ch,int dir,int face,Args &&...args)51 static void testMoveRouteDir(const Game_Character& ch,
52 		int dir, int face,
53 		Args&&... args) {
54 
55 	CAPTURE(dir);
56 	CAPTURE(face);
57 
58 	REQUIRE_EQ(ch.GetDirection(), dir);
59 	REQUIRE_EQ(ch.GetFacing(), face);
60 	testMoveRoute(ch, std::forward<Args>(args)...);
61 }
62 
63 template <typename... Args>
testMoveRouteMove(const Game_Character & ch,int x,int y,int remaining_step,Args &&...args)64 static void testMoveRouteMove(const Game_Character& ch,
65 		int x, int y, int remaining_step,
66 		Args&&... args) {
67 
68 	CAPTURE(x);
69 	CAPTURE(y);
70 	CAPTURE(remaining_step);
71 
72 	REQUIRE_EQ(ch.GetX(), x);
73 	REQUIRE_EQ(ch.GetY(), y);
74 	REQUIRE_GE(ch.GetRemainingStep(), 0);
75 	REQUIRE_EQ(ch.GetRemainingStep(), remaining_step);
76 	REQUIRE(!ch.IsJumping());
77 	if (remaining_step > 0) {
78 		REQUIRE(ch.IsMoving());
79 	} else {
80 		REQUIRE(ch.IsStopping());
81 		REQUIRE(!ch.IsMoving());
82 	}
83 	testMoveRouteDir(ch, std::forward<Args>(args)...);
84 }
85 
86 template <typename... Args>
testMoveRouteJump(const Game_Character & ch,int x,int y,int remaining_step,bool is_jumping,int begin_jump_x,int begin_jump_y,Args &&...args)87 static void testMoveRouteJump(const Game_Character& ch,
88 		int x, int y, int remaining_step,
89 		bool is_jumping, int begin_jump_x, int begin_jump_y,
90 		Args&&... args) {
91 
92 	CAPTURE(x);
93 	CAPTURE(y);
94 	CAPTURE(remaining_step);
95 	CAPTURE(is_jumping);
96 	CAPTURE(begin_jump_x);
97 	CAPTURE(begin_jump_y);
98 
99 	REQUIRE_EQ(ch.GetX(), x);
100 	REQUIRE_EQ(ch.GetY(), y);
101 	REQUIRE_GE(ch.GetRemainingStep(), 0);
102 	REQUIRE_EQ(ch.GetRemainingStep(), remaining_step);
103 
104 	REQUIRE_EQ(ch.GetBeginJumpX(), begin_jump_x);
105 	REQUIRE_EQ(ch.GetBeginJumpY(), begin_jump_y);
106 
107 	if (remaining_step > 0) {
108 		REQUIRE_EQ(ch.IsJumping(), is_jumping);
109 		REQUIRE_EQ(ch.IsMoving(), !is_jumping);
110 	} else {
111 		REQUIRE(ch.IsStopping());
112 		REQUIRE(!ch.IsJumping());
113 		REQUIRE(!ch.IsMoving());
114 	}
115 	testMoveRouteDir(ch, std::forward<Args>(args)...);
116 }
117 
118 TEST_CASE("DefaultMoveRoute") {
119 	auto ch = MoveRouteVehicle();
120 	testMoveRoute(ch, false, 2, 0, 0, 0, false, false, lcf::rpg::MoveRoute());
121 }
122 
123 TEST_CASE("ForceMoveRouteEmpty") {
124 	auto ch = MoveRouteVehicle();
125 	ch.ForceMoveRoute(lcf::rpg::MoveRoute(), 2);
126 	testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, false, false, lcf::rpg::MoveRoute());
127 }
128 
129 TEST_CASE("ForceMoveRouteSameFreq") {
130 	auto ch = MoveRouteVehicle();
131 	lcf::rpg::MoveRoute mr;
132 	mr.move_commands.push_back({});
133 
134 	ch.ForceMoveRoute(mr, 2);
135 	// Note: Same freq means don't reset max stop count
136 	testMoveRoute(ch, false, 2, 0xFFFF, 0, 0, true, false, mr);
137 
138 	ch.CancelMoveRoute();
139 	testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, false, false, mr);
140 }
141 
142 TEST_CASE("ForceMoveRouteDiffFreq") {
143 	auto ch = MoveRouteVehicle();
144 	auto mr = MakeRoute({{}});
145 	mr.move_commands.push_back({});
146 
147 	ch.ForceMoveRoute(mr, 3);
148 	testMoveRoute(ch, false, 3, 0xFFFF, 64, 0, true, false, mr);
149 
150 	// FIXME: Test original move frequency is robust to save games
151 	ch.CancelMoveRoute();
152 	testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, false, false, mr);
153 }
154 
testInvalidCmd(bool repeat,bool skip)155 static void testInvalidCmd(bool repeat, bool skip) {
156 	auto ch = MoveRouteVehicle();
157 	auto mr = MakeRoute({{ -1 }}, repeat, skip);
158 
159 	ch.ForceMoveRoute(mr, 3);
160 	testMoveRoute(ch, false, 3, 0xFFFF, 64, 0, true, false, mr);
161 
162 	ForceUpdate(ch);
163 	if (repeat) {
164 		testMoveRoute(ch, false, 3, 0xFFFF + 1, 64, 0, true, true, mr);
165 	} else {
166 		testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
167 	}
168 }
169 
170 TEST_CASE("TestMoveRouteInvalidCmd") {
171 	const MapGuard mg;
172 
173 	testInvalidCmd(false, false);
174 	testInvalidCmd(false, true);
175 	testInvalidCmd(true, false);
176 	testInvalidCmd(true, true);
177 }
178 
179 template <bool success, bool repeat, bool skip>
testMove(lcf::rpg::MoveCommand::Code code,int x,int y,int dir,int face,int tx,int ty,int tdir,int tface,int px=0,int py=0)180 static void testMove(lcf::rpg::MoveCommand::Code code, int x, int y, int dir, int face, int tx, int ty, int tdir, int tface, int px = 0, int py = 0) {
181 	Main_Data::game_player->SetX(px);
182 	Main_Data::game_player->SetY(py);
183 
184 	auto ch = MoveRouteVehicle();
185 	ch.SetX(x);
186 	ch.SetY(y);
187 	ch.SetDirection(dir);
188 	ch.SetFacing(face);
189 	ch.SetAllowMovement(success);
190 
191 	auto mr = MakeRoute({{ static_cast<int>(code) }}, repeat, skip);
192 
193 	CAPTURE(code);
194 	CAPTURE(x);
195 	CAPTURE(y);
196 	CAPTURE(dir);
197 	CAPTURE(face);
198 	CAPTURE(tx);
199 	CAPTURE(ty);
200 	CAPTURE(tdir);
201 	CAPTURE(tface);
202 	CAPTURE(px);
203 	CAPTURE(py);
204 	CAPTURE(success);
205 	CAPTURE(repeat);
206 	CAPTURE(skip);
207 
208 	auto dx = tx - x;
209 	auto dy = ty - y;
210 
211 	ch.ForceMoveRoute(mr, 3);
212 	testMoveRouteMove(ch, x, y, 0, dir, face, false, 3, 0xFFFF, 64, 0, true, false, mr);
213 
214 	if (success) {
215 		bool repeated = false;
216 		for(int n = (repeat ? 3 : 1); n > 0; --n) {
217 			CAPTURE(n);
218 			for(int i = 224; i > 0; i -= 32) {
219 				ForceUpdate(ch);
220 				testMoveRouteMove(ch, tx, ty, i, tdir, tface, false, 3, 0, 64, 1, true, repeated, mr);
221 			}
222 
223 			if (!repeat) {
224 				ForceUpdate(ch);
225 				testMoveRouteMove(ch, tx, ty, 0, tdir, tface, false, 2, 0, 128, 0, false, false, mr);
226 				break;
227 			}
228 
229 			repeated = true;
230 			for (int i = 0; i <= 64; ++i) {
231 				ForceUpdate(ch);
232 				testMoveRouteMove(ch, tx, ty, 0, tdir, tface, false, 3, i, 64, 0, true, repeated, mr);
233 			}
234 
235 			tx += dx;
236 			ty += dy;
237 		}
238 	} else {
239 		ForceUpdate(ch);
240 		if (skip) {
241 			if (repeat) {
242 				for (int i = 1; i <= 3; ++i) {
243 					testMoveRouteMove(ch, tx, ty, 0, tdir, tface, false, 3, 0xFFFF + i, 64, 0, true, true, mr);
244 					ForceUpdate(ch);
245 				}
246 			} else {
247 				testMoveRouteMove(ch, tx, ty, 0, tdir, tface, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
248 			}
249 		} else {
250 			testMoveRouteMove(ch, tx, ty, 0, tdir, tface, false, 3, 0xFFFF + 1, 64, 0, true, false, mr);
251 		}
252 	}
253 }
254 
255 template <typename... Args>
testMoveSuccess(const Args &...args)256 static void testMoveSuccess(const Args&... args) {
257 	testMove<true, false, false>(args...);
258 	testMove<true, false, true>(args...);
259 	testMove<true, true, false>(args...);
260 	testMove<true, true, true>(args...);
261 }
262 
263 template <typename... Args>
testMoveSuccessNoRepeat(const Args &...args)264 static void testMoveSuccessNoRepeat(const Args&... args) {
265 	testMove<true, false, false>(args...);
266 	testMove<true, false, true>(args...);
267 }
268 
testMoveFail(lcf::rpg::MoveCommand::Code code,int x,int y,int dir,int face,int tdir,int tface,int px=0,int py=0)269 static void testMoveFail(lcf::rpg::MoveCommand::Code code, int x, int y, int dir, int face, int tdir, int tface, int px = 0, int py = 0) {
270 	testMove<false, false, false>(code, x, y, dir, face, x, y, tdir, tface, px, py);
271 	testMove<false, true, false>(code, x, y, dir, face, x, y, tdir, tface, px, py);
272 }
273 
testMoveSkip(lcf::rpg::MoveCommand::Code code,int x,int y,int dir,int face,int px=0,int py=0)274 static void testMoveSkip(lcf::rpg::MoveCommand::Code code, int x, int y, int dir, int face, int px = 0, int py = 0) {
275 	testMove<false, false, true>(code, x, y, dir, face, x, y, dir, face, px, py);
276 	testMove<false, true, true>(code, x, y, dir, face, x, y, dir, face, px, py);
277 }
278 
279 
280 TEST_CASE("CommandMove") {
281 	const MapGuard mg;
282 
283 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_up, 8, 8, Down, Down, 8, 7, Up, Up);
284 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_right, 8, 8, Down, Down, 9, 8, Right, Right);
285 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_down, 8, 8, Down, Down, 8, 9, Down, Down);
286 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_left, 8, 8, Down, Down, 7, 8, Left, Left);
287 }
288 
289 TEST_CASE("CommandMoveFail") {
290 	const MapGuard mg;
291 
292 	testMoveFail(lcf::rpg::MoveCommand::Code::move_up, 8, 8, Down, Down, Up, Up);
293 	testMoveFail(lcf::rpg::MoveCommand::Code::move_right, 8, 8, Down, Down, Right, Right);
294 	testMoveFail(lcf::rpg::MoveCommand::Code::move_down, 8, 8, Down, Down, Down, Down);
295 	testMoveFail(lcf::rpg::MoveCommand::Code::move_left, 8, 8, Down, Down, Left, Left);
296 }
297 
298 TEST_CASE("CommandMoveSkip") {
299 	const MapGuard mg;
300 
301 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_up, 8, 8, Down, Down);
302 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_right, 8, 8, Down, Down);
303 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_down, 8, 8, Down, Down);
304 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_left, 8, 8, Down, Down);
305 }
306 
307 TEST_CASE("CommandMoveDiagonal") {
308 	const MapGuard mg;
309 
310 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Up, Up, 9, 7, UpRight, Up);
311 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Right, Right, 9, 7, UpRight, Right);
312 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Down, Down, 9, 7, UpRight, Up);
313 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Left, Left, 9, 7, UpRight, Right);
314 
315 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Up, Up, 9, 9, DownRight, Down);
316 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Right, Right, 9, 9, DownRight, Right);
317 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Down, Down, 9, 9, DownRight, Down);
318 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Left, Left, 9, 9, DownRight, Right);
319 
320 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Up, Up, 7, 9, DownLeft, Down);
321 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Right, Right, 7, 9, DownLeft, Left);
322 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Down, Down, 7, 9, DownLeft, Down);
323 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Left, Left, 7, 9, DownLeft, Left);
324 
325 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Up, Up, 7, 7, UpLeft, Up);
326 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Right, Right, 7, 7, UpLeft, Left);
327 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Down, Down, 7, 7, UpLeft, Up);
328 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Left, Left, 7, 7, UpLeft, Left);
329 }
330 
331 TEST_CASE("CommandMoveDiagonalFail") {
332 	const MapGuard mg;
333 
334 	testMoveFail(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Up, Up, UpRight, Up);
335 	testMoveFail(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Right, Right, UpRight, Right);
336 	testMoveFail(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Down, Down, UpRight, Up);
337 	testMoveFail(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Left, Left, UpRight, Right);
338 
339 	testMoveFail(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Up, Up, DownRight, Down);
340 	testMoveFail(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Right, Right, DownRight, Right);
341 	testMoveFail(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Down, Down, DownRight, Down);
342 	testMoveFail(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Left, Left, DownRight, Right);
343 
344 	testMoveFail(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Up, Up, DownLeft, Down);
345 	testMoveFail(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Right, Right, DownLeft, Left);
346 	testMoveFail(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Down, Down, DownLeft, Down);
347 	testMoveFail(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Left, Left, DownLeft, Left);
348 
349 	testMoveFail(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Up, Up, UpLeft, Up);
350 	testMoveFail(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Right, Right, UpLeft, Left);
351 	testMoveFail(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Down, Down, UpLeft, Up);
352 	testMoveFail(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Left, Left, UpLeft, Left);
353 }
354 
355 TEST_CASE("CommandMoveDiagonalSkip") {
356 	const MapGuard mg;
357 
358 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Up, Up);
359 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Right, Right);
360 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Down, Down);
361 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Left, Left);
362 
363 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Up, Up);
364 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Right, Right);
365 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Down, Down);
366 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Left, Left);
367 
368 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Up, Up);
369 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Right, Right);
370 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Down, Down);
371 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Left, Left);
372 
373 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Up, Up);
374 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Right, Right);
375 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Down, Down);
376 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Left, Left);
377 }
378 
379 TEST_CASE("CommandMoveForward") {
380 	const MapGuard mg;
381 
382 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Up, Up, 8, 7, Up, Up);
383 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Right, Right, 9, 8, Right, Right);
384 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Down, Down, 8, 9, Down, Down);
385 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Left, Left, 7, 8, Left, Left);
386 
387 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Up, 9, 7, UpRight, Up);
388 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Right, 9, 7, UpRight, Right);
389 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Down, 9, 9, DownRight, Down);
390 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Right, 9, 9, DownRight, Right);
391 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Up, 7, 7, UpLeft, Up);
392 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Left, 7, 7, UpLeft, Left);
393 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Down, 7, 9, DownLeft, Down);
394 	testMoveSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Left, 7, 9, DownLeft, Left);
395 }
396 
397 TEST_CASE("CommandMoveForwardFail") {
398 	const MapGuard mg;
399 
400 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Up, Up, Up, Up);
401 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Right, Right, Right, Right);
402 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Down, Down, Down, Down);
403 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Left, Left, Left, Left);
404 
405 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Up, UpRight, Up);
406 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Right, UpRight, Right);
407 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Down, DownRight, Down);
408 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Right, DownRight, Right);
409 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Up, UpLeft, Up);
410 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Left, UpLeft, Left);
411 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Down, DownLeft, Down);
412 	testMoveFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Left, DownLeft, Left);
413 }
414 
415 TEST_CASE("CommandMoveForwardSkip") {
416 	const MapGuard mg;
417 
418 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Up, Up);
419 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Right, Right);
420 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Down, Down);
421 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Left, Left);
422 
423 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Up);
424 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Right);
425 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Down);
426 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Right);
427 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Up);
428 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Left);
429 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Down);
430 	testMoveSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Left);
431 }
432 
433 TEST_CASE("CommandMoveRandom") {
434 	// FIXME: TBD
435 }
436 
437 
testTurn(lcf::rpg::MoveCommand::Code code,int orig_dir,int dir,int face,int x=0,int y=0,int px=0,int py=0)438 static void testTurn(lcf::rpg::MoveCommand::Code code, int orig_dir, int dir, int face, int x = 0, int y = 0, int px = 0, int py = 0) {
439 	Main_Data::game_player->SetX(px);
440 	Main_Data::game_player->SetY(py);
441 
442 	auto ch = MoveRouteVehicle();
443 	ch.SetX(x);
444 	ch.SetY(y);
445 	ch.SetDirection(orig_dir);
446 	ch.SetFacing(orig_dir);
447 	auto mr = MakeRoute({{ static_cast<int>(code) }});
448 
449 	CAPTURE(code);
450 	CAPTURE(orig_dir);
451 	CAPTURE(dir);
452 	CAPTURE(face);
453 	CAPTURE(x);
454 	CAPTURE(y);
455 	CAPTURE(px);
456 	CAPTURE(py);
457 
458 	ch.ForceMoveRoute(mr, 2);
459 	testMoveRouteDir(ch, orig_dir, orig_dir, false, 2, 0xFFFF, 0, 0, true, false, mr);
460 
461 	for(int i = 1; i <= 64; ++i) {
462 		ForceUpdate(ch);
463 		testMoveRouteDir(ch, dir, face, false, 2, i, 64, 1, true, false, mr);
464 	}
465 
466 	ForceUpdate(ch);
467 	testMoveRouteDir(ch, dir, face, false, 2, 65, 128, 1, false, false, mr);
468 }
469 
470 TEST_CASE("CommandTurn") {
471 	const MapGuard mg;
472 
473 	testTurn(lcf::rpg::MoveCommand::Code::face_up, Down, Up, Up);
474 	testTurn(lcf::rpg::MoveCommand::Code::face_left, Down, Left, Left);
475 	testTurn(lcf::rpg::MoveCommand::Code::face_right, Down, Right, Right);
476 	testTurn(lcf::rpg::MoveCommand::Code::face_down, Down, Down, Down);
477 
478 	testTurn(lcf::rpg::MoveCommand::Code::turn_180_degree, Down, Up, Up);
479 	testTurn(lcf::rpg::MoveCommand::Code::turn_180_degree, Up, Down, Down);
480 	testTurn(lcf::rpg::MoveCommand::Code::turn_180_degree, Left, Right, Right);
481 	testTurn(lcf::rpg::MoveCommand::Code::turn_180_degree, Right, Left, Left);
482 
483 	testTurn(lcf::rpg::MoveCommand::Code::turn_90_degree_right, Down, Left, Left);
484 	testTurn(lcf::rpg::MoveCommand::Code::turn_90_degree_right, Left, Up, Up);
485 	testTurn(lcf::rpg::MoveCommand::Code::turn_90_degree_right, Up, Right, Right);
486 	testTurn(lcf::rpg::MoveCommand::Code::turn_90_degree_right, Right, Down, Down);
487 
488 	testTurn(lcf::rpg::MoveCommand::Code::turn_90_degree_left, Down, Right, Right);
489 	testTurn(lcf::rpg::MoveCommand::Code::turn_90_degree_left, Right, Up, Up);
490 	testTurn(lcf::rpg::MoveCommand::Code::turn_90_degree_left, Up, Left, Left);
491 	testTurn(lcf::rpg::MoveCommand::Code::turn_90_degree_left, Left, Down, Down);
492 }
493 
494 TEST_CASE("CommandTurnRandom") {
495 	const MapGuard mg;
496 
497 	for (int i = 0; i < 10; ++i) {
498 		auto ch = MoveRouteVehicle();
499 		auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::face_random_direction) }});
500 
501 		ch.ForceMoveRoute(mr, 3);
502 		testMoveRouteDir(ch, Down, Down, false, 3, 0xFFFF, 64, 0, true, false, mr);
503 
504 		ForceUpdate(ch);
505 		testMoveRoute(ch, false, 3, 1, 32, 1, true, false, mr);
506 
507 		REQUIRE_GE(ch.GetDirection(), Up);
508 		REQUIRE_LE(ch.GetDirection(), Left);
509 	}
510 }
511 
512 
513 TEST_CASE("CommandWait") {
514 	const MapGuard mg;
515 
516 	auto ch = MoveRouteVehicle();
517 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::wait) }});
518 
519 	ch.ForceMoveRoute(mr, 2);
520 	testMoveRouteDir(ch, Down, Down, false, 2, 0xFFFF, 0, 0, true, false, mr);
521 
522 	for(int i = 1; i <= 84; ++i) {
523 		ForceUpdate(ch);
524 		testMoveRouteDir(ch, Down, Down, false, 2, i, 84, 1, true, false, mr);
525 	}
526 
527 	ForceUpdate(ch);
528 	testMoveRouteDir(ch, Down, Down, false, 2, 85, 128, 1, false, false, mr);
529 }
530 
531 template <bool success, bool repeat, bool skip, bool end>
testJump(lcf::rpg::MoveCommand::Code code,int x,int y,int dir,int face,int tx,int ty,int tdir,int tface,int px=0,int py=0)532 static void testJump(lcf::rpg::MoveCommand::Code code, int x, int y, int dir, int face, int tx, int ty, int tdir, int tface, int px = 0, int py = 0) {
533 	Main_Data::game_player->SetX(px);
534 	Main_Data::game_player->SetY(py);
535 
536 	auto ch = MoveRouteVehicle();
537 	ch.SetX(x);
538 	ch.SetY(y);
539 	ch.SetDirection(dir);
540 	ch.SetFacing(face);
541 	ch.SetAllowMovement(success);
542 
543 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::begin_jump) }}, repeat, skip);
544 	if (code != lcf::rpg::MoveCommand::Code::end_jump) {
545 		mr.move_commands.push_back({  static_cast<int>(code) });
546 	}
547 	if (end) {
548 		mr.move_commands.push_back({ static_cast<int>(lcf::rpg::MoveCommand::Code::end_jump) });
549 	}
550 	auto num_cmds = static_cast<int>(mr.move_commands.size());
551 
552 	CAPTURE(code);
553 	CAPTURE(x);
554 	CAPTURE(y);
555 	CAPTURE(dir);
556 	CAPTURE(face);
557 	CAPTURE(tx);
558 	CAPTURE(ty);
559 	CAPTURE(tdir);
560 	CAPTURE(tface);
561 	CAPTURE(px);
562 	CAPTURE(py);
563 	CAPTURE(success);
564 	CAPTURE(repeat);
565 	CAPTURE(skip);
566 
567 	auto dx = tx - x;
568 	auto dy = ty - y;
569 
570 	ch.ForceMoveRoute(mr, 3);
571 	testMoveRouteJump(ch, x, y, 0, false, 0, 0, dir, face, false, 3, 0xFFFF, 64, 0, true, false, mr);
572 
573 	if (!end) {
574 		ForceUpdate(ch);
575 		if (repeat) {
576 			testMoveRouteJump(ch, x, y, 0, false, 0, 0, dir, face, false, 3, 0xFFFF + 1, 64, 0, true, true, mr);
577 		} else {
578 			testMoveRouteJump(ch, x, y, 0, false, 0, 0, dir, face, false, 2, 0xFFFF + 1, 128, num_cmds, false, false, mr);
579 		}
580 
581 		return;
582 	}
583 
584 	if (success) {
585 		bool repeated = false;
586 		for(int n = (repeat ? 3 : 1); n > 0; --n) {
587 			CAPTURE(n);
588 			for(int i = 232; i > 0; i -= 24) {
589 				ForceUpdate(ch);
590 				testMoveRouteJump(ch, tx, ty, i, true, x, y, tdir, tface, false, 3, 0, 64, num_cmds, true, repeated, mr);
591 			}
592 
593 			if (!repeat) {
594 				ForceUpdate(ch);
595 				testMoveRouteJump(ch, tx, ty, 0, false, x, y, tdir, tface, false, 2, 0, 128, 0, false, false, mr);
596 				break;
597 			}
598 
599 			repeated = true;
600 			for (int i = 0; i <= 64; ++i) {
601 				ForceUpdate(ch);
602 				testMoveRouteMove(ch, tx, ty, 0, tdir, tface, false, 3, i, 64, 0, true, repeated, mr);
603 			}
604 
605 			x = tx;
606 			y = ty;
607 			tx += dx;
608 			ty += dy;
609 		}
610 	} else {
611 		ForceUpdate(ch);
612 		if (skip) {
613 			if (repeat) {
614 				for (int i = 1; i <= 3; ++i) {
615 					testMoveRouteJump(ch, tx, ty, 0, false, 0, 0, tdir, tface, false, 3, 0xFFFF + i, 64, 0, true, true, mr);
616 					ForceUpdate(ch);
617 				}
618 			} else {
619 				testMoveRouteJump(ch, tx, ty, 0, false, 0, 0, tdir, tface, false, 2, 0xFFFF + 1, 128, num_cmds, false, false, mr);
620 			}
621 		} else {
622 			testMoveRouteJump(ch, tx, ty, 0, false, 0, 0, tdir, tface, false, 3, 0xFFFF + 1, 64, 0, true, false, mr);
623 		}
624 	}
625 }
626 
627 template <typename... Args>
testJumpSuccess(const Args &...args)628 static void testJumpSuccess(const Args&... args) {
629 	testJump<true, false, false, true>(args...);
630 	testJump<true, false, true, true>(args...);
631 	testJump<true, true, false, true>(args...);
632 	testJump<true, true, true, true>(args...);
633 }
634 
635 template <typename... Args>
testJumpSuccessNoRepeat(const Args &...args)636 static void testJumpSuccessNoRepeat(const Args&... args) {
637 	testJump<true, false, false, true>(args...);
638 	testJump<true, false, true, true>(args...);
639 }
640 
testJumpFail(lcf::rpg::MoveCommand::Code code,int x,int y,int dir,int face,int tdir,int tface,int px=0,int py=0)641 static void testJumpFail(lcf::rpg::MoveCommand::Code code, int x, int y, int dir, int face, int tdir, int tface, int px = 0, int py = 0) {
642 	testJump<false, false, false, true>(code, x, y, dir, face, x, y, tdir, tface, px, py);
643 	testJump<false, true, false, true>(code, x, y, dir, face, x, y, tdir, tface, px, py);
644 }
645 
testJumpSkip(lcf::rpg::MoveCommand::Code code,int x,int y,int dir,int face,int px=0,int py=0)646 static void testJumpSkip(lcf::rpg::MoveCommand::Code code, int x, int y, int dir, int face, int px = 0, int py = 0) {
647 	testJump<false, false, true, true>(code, x, y, dir, face, x, y, dir, face, px, py);
648 	testJump<false, true, true, true>(code, x, y, dir, face, x, y, dir, face, px, py);
649 }
650 
testJumpNoEnd(lcf::rpg::MoveCommand::Code code,int x,int y,int dir,int face,int px=0,int py=0)651 static void testJumpNoEnd(lcf::rpg::MoveCommand::Code code, int x, int y, int dir, int face, int px = 0, int py = 0) {
652 	testJump<false, false, true, false>(code, x, y, dir, face, x, y, dir, face, px, py);
653 	testJump<false, true, true, false>(code, x, y, dir, face, x, y, dir, face, px, py);
654 }
655 
656 TEST_CASE("CommandJumpInPlace") {
657 	const MapGuard mg;
658 
659 	// FIXME: Verify this behavior
660 	testJumpSuccess(lcf::rpg::MoveCommand::Code::end_jump, 8, 8, Up, Up, 8, 8, Down, Up);
661 	testJumpSuccess(lcf::rpg::MoveCommand::Code::end_jump, 8, 8, Right, Right, 8, 8, Down, Right);
662 	testJumpSuccess(lcf::rpg::MoveCommand::Code::end_jump, 8, 8, Down, Down, 8, 8, Down, Down);
663 	testJumpSuccess(lcf::rpg::MoveCommand::Code::end_jump, 8, 8, Left, Left, 8, 8, Down, Left);
664 
665 	// FIXME: Test no collision
666 }
667 
668 TEST_CASE("CommandJump") {
669 	const MapGuard mg;
670 
671 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_up, 8, 8, Down, Down, 8, 7, Up, Up);
672 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_right, 8, 8, Down, Down, 9, 8, Right, Right);
673 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_down, 8, 8, Down, Down, 8, 9, Down, Down);
674 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_left, 8, 8, Down, Down, 7, 8, Left, Left);
675 }
676 
677 TEST_CASE("CommandJumpFail") {
678 	const MapGuard mg;
679 
680 	testJumpFail(lcf::rpg::MoveCommand::Code::move_up, 8, 8, Down, Down, Up, Up);
681 	testJumpFail(lcf::rpg::MoveCommand::Code::move_right, 8, 8, Down, Down, Right, Right);
682 	testJumpFail(lcf::rpg::MoveCommand::Code::move_down, 8, 8, Down, Down, Down, Down);
683 	testJumpFail(lcf::rpg::MoveCommand::Code::move_left, 8, 8, Down, Down, Left, Left);
684 }
685 
686 TEST_CASE("CommandJumpSkip") {
687 	const MapGuard mg;
688 
689 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_up, 8, 8, Down, Down);
690 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_right, 8, 8, Down, Down);
691 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_down, 8, 8, Down, Down);
692 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_left, 8, 8, Down, Down);
693 }
694 
695 TEST_CASE("CommandJumpDiagonal") {
696 	const MapGuard mg;
697 
698 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Up, Up, 9, 7, Up, Up);
699 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Right, Right, 9, 7, Up, Up);
700 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Down, Down, 9, 7, Up, Up);
701 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Left, Left, 9, 7, Up, Up);
702 
703 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Up, Up, 9, 9, Down, Down);
704 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Right, Right, 9, 9, Down, Down);
705 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Down, Down, 9, 9, Down, Down);
706 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Left, Left, 9, 9, Down, Down);
707 
708 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Up, Up, 7, 9, Down, Down);
709 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Right, Right, 7, 9, Down, Down);
710 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Down, Down, 7, 9, Down, Down);
711 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Left, Left, 7, 9, Down, Down);
712 
713 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Up, Up, 7, 7, Up, Up);
714 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Right, Right, 7, 7, Up, Up);
715 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Down, Down, 7, 7, Up, Up);
716 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Left, Left, 7, 7, Up, Up);
717 }
718 
719 TEST_CASE("CommandJumpDiagonalFail") {
720 	const MapGuard mg;
721 
722 	testJumpFail(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Up, Up, Up, Up);
723 	testJumpFail(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Right, Right, Up, Up);
724 	testJumpFail(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Down, Down, Up, Up);
725 	testJumpFail(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Left, Left, Up, Up);
726 
727 	testJumpFail(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Up, Up, Down, Down);
728 	testJumpFail(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Right, Right, Down, Down);
729 	testJumpFail(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Down, Down, Down, Down);
730 	testJumpFail(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Left, Left, Down, Down);
731 
732 	testJumpFail(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Up, Up, Down, Down);
733 	testJumpFail(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Right, Right, Down, Down);
734 	testJumpFail(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Down, Down, Down, Down);
735 	testJumpFail(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Left, Left, Down, Down);
736 
737 	testJumpFail(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Up, Up, Up, Up);
738 	testJumpFail(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Right, Right, Up, Up);
739 	testJumpFail(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Down, Down, Up, Up);
740 	testJumpFail(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Left, Left, Up, Up);
741 }
742 
743 TEST_CASE("CommandJumpDiagonalSkip") {
744 	const MapGuard mg;
745 
746 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Up, Up);
747 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Right, Right);
748 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Down, Down);
749 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_upright, 8, 8, Left, Left);
750 
751 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Up, Up);
752 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Right, Right);
753 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Down, Down);
754 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_downright, 8, 8, Left, Left);
755 
756 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Up, Up);
757 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Right, Right);
758 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Down, Down);
759 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_downleft, 8, 8, Left, Left);
760 
761 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Up, Up);
762 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Right, Right);
763 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Down, Down);
764 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_upleft, 8, 8, Left, Left);
765 }
766 
767 TEST_CASE("CommandJumpForward") {
768 	const MapGuard mg;
769 
770 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Up, Up, 8, 7, Up, Up);
771 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Right, Right, 9, 8, Right, Right);
772 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Down, Down, 8, 9, Down, Down);
773 	testJumpSuccess(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Left, Left, 7, 8, Left, Left);
774 
775 	// FIXME: For repeat, these will move diag and then up or down afterwards.
776 	testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Up, 9, 7, Up, Up);
777 	testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Right, 9, 7, Up, Up);
778 	testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Down, 9, 9, Down, Down);
779 	testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Right, 9, 9, Down, Down);
780 	testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Up, 7, 7, Up, Up);
781 	testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Left, 7, 7, Up, Up);
782 	testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Down, 7, 9, Down, Down);
783 	testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Left, 7, 9, Down, Down);
784 }
785 
786 TEST_CASE("CommandJumpForwardFail") {
787 	const MapGuard mg;
788 
789 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Up, Up, Up, Up);
790 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Right, Right, Right, Right);
791 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Down, Down, Down, Down);
792 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Left, Left, Left, Left);
793 
794 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Up, Up, Up);
795 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Right, Up, Up);
796 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Down, Down, Down);
797 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Right, Down, Down);
798 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Up, Up, Up);
799 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Left, Up, Up);
800 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Down, Down, Down);
801 	testJumpFail(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Left, Down, Down);
802 }
803 
804 TEST_CASE("CommandJumpForwardSkip") {
805 	const MapGuard mg;
806 
807 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Up, Up);
808 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Right, Right);
809 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Down, Down);
810 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, Left, Left);
811 
812 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Up);
813 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpRight, Right);
814 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Down);
815 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownRight, Right);
816 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Up);
817 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, UpLeft, Left);
818 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Down);
819 	testJumpSkip(lcf::rpg::MoveCommand::Code::move_forward, 8, 8, DownLeft, Left);
820 }
821 
822 TEST_CASE("CommandJumpRandom") {
823 	// FIXME: TBD
824 }
825 
826 TEST_CASE("CommandJumpNoEnd") {
827 	const MapGuard mg;
828 
829 	// This makes a move route with just "Jump"
830 	testJumpNoEnd(lcf::rpg::MoveCommand::Code::end_jump, 8, 8, Down, Down);
831 }
832 
833 
834 TEST_CASE("CommandMoveTurnJumpHero") {
835 	const MapGuard mg;
836 
837 	int x = 8;
838 	int y = 8;
839 	for (int dx = -2; dx <= 2; ++dx) {
840 		for (int dy = -2; dy <= 2; ++dy) {
841 			auto step_x = 0;
842 			auto step_y = 0;
843 			auto dir = Down;
844 
845 			if (std::abs(dx) > std::abs(dy)) {
846 				dir = (dx > 0 ? Right : Left);
847 				step_x = (dx > 0 ? 1 : -1);
848 			} else {
849 				dir = (dy >= 0 ? Down : Up);
850 				step_y = (dy >= 0 ? 1 : -1);
851 			}
852 			auto rdir = Game_Character::GetDirection180Degree(dir);
853 
854 			auto px = x + dx;
855 			auto py = y + dy;
856 
857 			testTurn(lcf::rpg::MoveCommand::Code::face_hero, Left, dir, dir, x, y, px, py);
858 			testTurn(lcf::rpg::MoveCommand::Code::face_away_from_hero, Left, rdir, rdir, x, y, px, py);
859 
860 			testMoveSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_towards_hero, x, y, Left, Left, x + step_x, y + step_y, dir, dir, px, py);
861 			testMoveSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_away_from_hero, x, y, Left, Left, x - step_x, y - step_y, rdir, rdir, px, py);
862 
863 			testMoveFail(lcf::rpg::MoveCommand::Code::move_towards_hero, x, y, Left, Left, dir, dir, px, py);
864 			testMoveFail(lcf::rpg::MoveCommand::Code::move_away_from_hero, x, y, Left, Left, rdir, rdir, px, py);
865 
866 			testMoveSkip(lcf::rpg::MoveCommand::Code::move_towards_hero, x, y, Left, Left, px, py);
867 			testMoveSkip(lcf::rpg::MoveCommand::Code::move_away_from_hero, x, y, Left, Left, px, py);
868 
869 			testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_towards_hero, x, y, Left, Left, x + step_x, y + step_y, dir, dir, px, py);
870 			testJumpSuccessNoRepeat(lcf::rpg::MoveCommand::Code::move_away_from_hero, x, y, Left, Left, x - step_x, y - step_y, rdir, rdir, px, py);
871 
872 			testJumpFail(lcf::rpg::MoveCommand::Code::move_towards_hero, x, y, Left, Left, dir, dir, px, py);
873 			testJumpFail(lcf::rpg::MoveCommand::Code::move_away_from_hero, x, y, Left, Left, rdir, rdir, px, py);
874 
875 			testJumpSkip(lcf::rpg::MoveCommand::Code::move_towards_hero, x, y, Left, Left, px, py);
876 			testJumpSkip(lcf::rpg::MoveCommand::Code::move_away_from_hero, x, y, Left, Left, px, py);
877 		}
878 	}
879 }
880 
testLockFacing(lcf::rpg::EventPage::AnimType at)881 void testLockFacing(lcf::rpg::EventPage::AnimType at) {
882 	const MapGuard mg;
883 
884 	auto ch = MoveRouteVehicle();
885 	ch.SetAnimationType(at);
886 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::lock_facing) }});
887 
888 	ch.ForceMoveRoute(mr, 2);
889 	testMoveRoute(ch, false, 2, 0xFFFF, 0, 0, true, false, mr);
890 	REQUIRE_EQ(ch.IsFacingLocked(), Game_Character::IsDirectionFixedAnimationType(at));
891 
892 	ForceUpdate(ch);
893 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
894 	REQUIRE(ch.IsFacingLocked());
895 
896 	mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::unlock_facing) }});
897 	ch.ForceMoveRoute(mr, 2);
898 	testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, true, false, mr);
899 	REQUIRE(ch.IsFacingLocked());
900 
901 	ForceUpdate(ch);
902 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
903 	REQUIRE_EQ(ch.IsFacingLocked(), Game_Character::IsDirectionFixedAnimationType(at));
904 }
905 
906 TEST_CASE("CommandLockFacing") {
907 	for (int i = 0; i <= static_cast<int>(lcf::rpg::EventPage::AnimType_step_frame_fix); ++i) {
908 		testLockFacing(static_cast<lcf::rpg::EventPage::AnimType>(i));
909 	}
910 }
911 
912 TEST_CASE("CommandSpeedChange") {
913 	const MapGuard mg;
914 
915 	auto ch = MoveRouteVehicle();
916 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::increase_movement_speed) }});
917 	const int n = 10;
918 
919 	ch.SetMoveSpeed(1);
920 	int prev = ch.GetMoveSpeed();
921 	for (int i = 0; i < 10; ++i) {
922 		ch.ForceMoveRoute(mr, 2);
923 		testMoveRoute(ch, false, 2, 0xFFFF, (i == 0 ? 0 : 128), 0, true, false, mr);
924 		REQUIRE_EQ(ch.GetMoveSpeed(), prev);
925 
926 		ForceUpdate(ch);
927 		testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
928 		REQUIRE_EQ(ch.GetMoveSpeed(), std::min(prev + 1, 6));
929 
930 		prev= ch.GetMoveSpeed();
931 	}
932 
933 	mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::decrease_movement_speed) }});
934 	for (int i = 0; i < 10; ++i) {
935 		ch.ForceMoveRoute(mr, 2);
936 		testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, true, false, mr);
937 		REQUIRE_EQ(ch.GetMoveSpeed(), prev);
938 
939 		ForceUpdate(ch);
940 		testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
941 		REQUIRE_EQ(ch.GetMoveSpeed(), std::max(prev - 1, 1));
942 
943 		prev= ch.GetMoveSpeed();
944 	}
945 }
946 
947 TEST_CASE("CommandFreqChange") {
948 	const MapGuard mg;
949 
950 	auto ch = MoveRouteVehicle();
951 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::increase_movement_frequence) }});
952 	const int n = 10;
953 
954 	for (int i = 1; i < 10; ++i) {
955 		const int freq = Utils::Clamp(i, 1, 8);
956 
957 		ch.ForceMoveRoute(mr, freq);
958 		testMoveRoute(ch, false, freq, 0xFFFF, (i == 0 && freq == 2 ? 0 : Game_Character::GetMaxStopCountForStep(freq)), 0, true, false, mr);
959 
960 		const int next_freq = Utils::Clamp(freq + 1, 1, 8);
961 		ForceUpdate(ch);
962 		// FIXME: Need another command for the frequency to not get reset when move route is done.
963 		//testMoveRoute(ch, false, next_freq, 0xFFFF + 1, Game_Character::GetMaxStopCountForStep(next_freq), 1, false, false, mr);
964 
965 		testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
966 
967 	}
968 
969 	mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::decrease_movement_frequence) }});
970 
971 	for (int i = 1; i < 10; ++i) {
972 		const int freq = Utils::Clamp(i, 1, 8);
973 
974 		ch.ForceMoveRoute(mr, freq);
975 		testMoveRoute(ch, false, freq, 0xFFFF, Game_Character::GetMaxStopCountForStep(freq), 0, true, false, mr);
976 
977 		const int next_freq = Utils::Clamp(freq - 1, 1, 8);
978 		ForceUpdate(ch);
979 		// FIXME: Need another command for the frequency to not get reset when move route is done.
980 		//testMoveRoute(ch, false, next_freq, 0xFFFF + 1, Game_Character::GetMaxStopCountForStep(next_freq), 1, false, false, mr);
981 		testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
982 	}
983 }
984 
985 TEST_CASE("CommandTranspChange") {
986 	const MapGuard mg;
987 
988 	auto ch = MoveRouteVehicle();
989 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::increase_transp) }});
990 	const int n = 10;
991 
992 	ch.SetTransparency(0);
993 	int prev = ch.GetTransparency();
994 	for (int i = 0; i < 10; ++i) {
995 		ch.ForceMoveRoute(mr, 2);
996 		testMoveRoute(ch, false, 2, 0xFFFF, (i == 0 ? 0 : 128), 0, true, false, mr);
997 		REQUIRE_EQ(ch.GetTransparency(), prev);
998 
999 		ForceUpdate(ch);
1000 		testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1001 		REQUIRE_EQ(ch.GetTransparency(), std::min(prev + 1, 7));
1002 
1003 		prev = ch.GetTransparency();
1004 	}
1005 
1006 	mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::decrease_transp) }});
1007 	for (int i = 0; i < 10; ++i) {
1008 		ch.ForceMoveRoute(mr, 2);
1009 		testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, true, false, mr);
1010 		REQUIRE_EQ(ch.GetTransparency(), prev);
1011 
1012 		ForceUpdate(ch);
1013 		testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1014 		REQUIRE_EQ(ch.GetTransparency(), std::max(prev - 1, 0));
1015 
1016 		prev = ch.GetTransparency();
1017 	}
1018 }
1019 
1020 TEST_CASE("CommandThrough") {
1021 	const MapGuard mg;
1022 
1023 	auto ch = MoveRouteVehicle();
1024 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::walk_everywhere_on) }});
1025 
__anoncd9cbc7e0102() 1026 	auto testoff = [&]() {
1027 		REQUIRE(!ch.GetThrough());
1028 		ch.SetThrough(true);
1029 		REQUIRE(ch.GetThrough());
1030 		ch.ResetThrough();
1031 		REQUIRE(!ch.GetThrough());
1032 	};
1033 
__anoncd9cbc7e0202() 1034 	auto teston = [&]() {
1035 		REQUIRE(ch.GetThrough());
1036 		ch.SetThrough(false);
1037 		REQUIRE(!ch.GetThrough());
1038 		ch.ResetThrough();
1039 		REQUIRE(ch.GetThrough());
1040 	};
1041 
1042 	ch.ForceMoveRoute(mr, 2);
1043 	testMoveRoute(ch, false, 2, 0xFFFF, 0, 0, true, false, mr);
1044 	testoff();
1045 
1046 	ForceUpdate(ch);
1047 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1048 	teston();
1049 
1050 	mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::walk_everywhere_off) }});
1051 	ch.ForceMoveRoute(mr, 2);
1052 	testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, true, false, mr);
1053 	teston();
1054 
1055 	ForceUpdate(ch);
1056 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1057 	testoff();
1058 
1059 	ch.SetThrough(true);
1060 
1061 	mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::walk_everywhere_off) }});
1062 	ch.ForceMoveRoute(mr, 2);
1063 	testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, true, false, mr);
1064 	REQUIRE(ch.GetThrough());
1065 
1066 	ForceUpdate(ch);
1067 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1068 	testoff();
1069 
1070 	ch.SetThrough(true);
1071 	mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::walk_everywhere_on) }});
1072 	ch.ForceMoveRoute(mr, 2);
1073 	REQUIRE(ch.GetThrough());
1074 
1075 	ForceUpdate(ch);
1076 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1077 	teston();
1078 }
1079 
1080 TEST_CASE("CommandStopAnimation") {
1081 	const MapGuard mg;
1082 
1083 	auto ch = MoveRouteVehicle();
1084 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::stop_animation) }});
1085 
1086 	ch.ForceMoveRoute(mr, 2);
1087 	testMoveRoute(ch, false, 2, 0xFFFF, 0, 0, true, false, mr);
1088 	REQUIRE(!ch.IsAnimPaused());
1089 
1090 	ForceUpdate(ch);
1091 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1092 	REQUIRE(ch.IsAnimPaused());
1093 
1094 	mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::start_animation) }});
1095 	ch.ForceMoveRoute(mr, 2);
1096 	testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, true, false, mr);
1097 	REQUIRE(ch.IsAnimPaused());
1098 
1099 	ForceUpdate(ch);
1100 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1101 	REQUIRE(!ch.IsAnimPaused());
1102 }
1103 
1104 TEST_CASE("CommandSwitchToggle") {
1105 	const MapGuard mg;
1106 
1107 	auto ch = MoveRouteVehicle();
1108 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::switch_on), "", 3 }});
1109 
1110 	REQUIRE_NE(Main_Data::game_switches, nullptr);
1111 
1112 	ch.ForceMoveRoute(mr, 2);
1113 	testMoveRoute(ch, false, 2, 0xFFFF, 0, 0, true, false, mr);
1114 	REQUIRE(!Main_Data::game_switches->Get(3));
1115 
1116 	ForceUpdate(ch);
1117 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1118 	REQUIRE(Main_Data::game_switches->Get(3));
1119 
1120 	mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::switch_off), "", 3 }});
1121 	ch.ForceMoveRoute(mr, 2);
1122 	testMoveRoute(ch, false, 2, 0xFFFF, 128, 0, true, false, mr);
1123 	REQUIRE(Main_Data::game_switches->Get(3));
1124 
1125 	ForceUpdate(ch);
1126 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1127 	REQUIRE(!Main_Data::game_switches->Get(3));
1128 }
1129 
1130 TEST_CASE("CommandChangeGraphic") {
1131 	const MapGuard mg;
1132 
1133 	auto ch = MoveRouteVehicle();
1134 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::change_graphic), "x", 3 }});
1135 
1136 	ch.ForceMoveRoute(mr, 2);
1137 	testMoveRoute(ch, false, 2, 0xFFFF, 0, 0, true, false, mr);
1138 	REQUIRE_EQ(ch.GetSpriteName(), "");
1139 	REQUIRE_EQ(ch.GetSpriteIndex(), 0);
1140 
1141 	ForceUpdate(ch);
1142 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1143 	REQUIRE_EQ(ch.GetSpriteName(), "x");
1144 	REQUIRE_EQ(ch.GetSpriteIndex(), 3);
1145 }
1146 
1147 TEST_CASE("CommandPlaySound") {
1148 	const MapGuard mg;
1149 
1150 	auto ch = MoveRouteVehicle();
1151 	auto mr = MakeRoute({{ static_cast<int>(lcf::rpg::MoveCommand::Code::play_sound_effect), "", 100, 100, 100 }});
1152 
1153 	ch.ForceMoveRoute(mr, 2);
1154 	testMoveRoute(ch, false, 2, 0xFFFF, 0, 0, true, false, mr);
1155 
1156 	ForceUpdate(ch);
1157 	testMoveRoute(ch, false, 2, 0xFFFF + 1, 128, 1, false, false, mr);
1158 
1159 	// FIXME: Check mocked audio subsystem?
1160 }
1161 
1162 TEST_CASE("ClearPause") {
1163 	auto ch = MoveRouteVehicle();
1164 
1165 	ch.SetPaused(true);
1166 	REQUIRE(ch.IsPaused());
1167 
1168 	auto mr = MakeRoute({{}});
1169 	ch.ForceMoveRoute(mr, 3);
1170 
1171 	REQUIRE(!ch.IsPaused());
1172 }
1173 
1174 TEST_SUITE_END();
1175