1 /*
2  *  Copyright (C) 2000-2013  The Exult Team
3  *
4  *  This program 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 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program 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 this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22 
23 #include <cstring>
24 
25 #include "SDL_events.h"
26 #include "files/U7file.h"
27 #include "chunks.h"
28 #include "gamemap.h"
29 #include "gamewin.h"
30 #include "game.h"
31 #include "cheat_screen.h"
32 #include "font.h"
33 #include "actors.h"
34 #include "cheat.h"
35 #include "exult.h"
36 #include "imagewin.h"
37 #include "vgafile.h"
38 #include "gameclk.h"
39 #include "schedule.h"
40 #include "ucmachine.h"
41 #include "Configuration.h"
42 #include "SDL.h"
43 #include "party.h"
44 #include "miscinf.h"
45 #include "gump_utils.h"
46 #include "ignore_unused_variable_warning.h"
47 #include "touchui.h"
48 #include "Gump_manager.h"
49 
50 const char *CheatScreen::schedules[33] = {
51 	"Combat",
52 	"Hor. Pace",
53 	"Ver. Pace",
54 	"Talk",
55 	"Dance",
56 	"Eat",
57 	"Farm",
58 	"Tend Shop",
59 	"Miner",
60 	"Hound",
61 	"Stand",
62 	"Loiter",
63 	"Wander",
64 	"Blacksmith",
65 	"Sleep",
66 	"Wait",
67 	"Major Sit",
68 	"Graze",
69 	"Bake",
70 	"Sew",
71 	"Shy",
72 	"Lab",
73 	"Thief",
74 	"Waiter",
75 	"Special",
76 	"Kid Games",
77 	"Eat at Inn",
78 	"Duel",
79 	"Preach",
80 	"Patrol",
81 	"Desk Work",
82 	"Follow Avt",
83 	"Move2Sched"
84 };
85 
86 const char *CheatScreen::flag_names[64] = {
87 	"invisible",        // 0x00
88 	"asleep",       // 0x01
89 	"charmed",      // 0x02
90 	"cursed",       // 0x03
91 	"dead",         // 0x04
92 	nullptr,          // 0x05
93 	"in_party",     // 0x06
94 	"paralyzed",        // 0x07
95 
96 	"poisoned",     // 0x08
97 	"protection",       // 0x09
98 	"on_moving_barge",  // 0x0A
99 	"okay_to_take",     // 0x0B
100 	"might",        // 0x0C
101 	"immunities",   //0x0D
102 	"cant_die",     // 0x0E
103 	"dancing",      // 0x0F
104 
105 	"dont_move/bg_dont_render",     // 0x10
106 	"si_on_moving_barge",   // 0x11
107 	"is_temporary",     // 0x12
108 	nullptr,          // 0x13
109 	"sailor",          // 0x14
110 	"okay_to_land",     // 0x15
111 	"dont_render/bg_dont_move", // 0x16
112 	"in_dungeon",   // 0x17
113 
114 	nullptr,          // 0x18
115 	"confused",     // 0x19
116 	"in_motion",        // 0x1A
117 	nullptr,         // 0x1B
118 	"met",          // 0x1C
119 	"tournament",   // 0x1D
120 	"si_zombie",    // 0x1E
121 	"no_spell_casting",  // 0x1F
122 
123 	"polymorph",    // 0x20
124 	"tattooed",     // 0x21
125 	"read",         // 0x22
126 	"petra",        // 0x23
127 	"si_lizard_king",  // 0x24
128 	"freeze",       // 0x25
129 	"naked",    // 0x26
130 	nullptr,          // 0x27
131 
132 	nullptr,          // 0x28
133 	nullptr,          // 0x29
134 	nullptr,          // 0x2A
135 	nullptr,          // 0x2B
136 	nullptr,          // 0x2C
137 	nullptr,          // 0x2D
138 	nullptr,          // 0x2E
139 	nullptr,          // 0x2F
140 
141 	nullptr,          // 0x30
142 	nullptr,          // 0x31
143 	nullptr,          // 0x32
144 	nullptr,          // 0x33
145 	nullptr,          // 0x34
146 	nullptr,          // 0x35
147 	nullptr,          // 0x36
148 	nullptr,          // 0x37
149 
150 	nullptr,          // 0x38
151 	nullptr,          // 0x39
152 	nullptr,          // 0x3A
153 	nullptr,          // 0x3B
154 	nullptr,          // 0x3C
155 	nullptr,          // 0x3D
156 	nullptr,          // 0x3E
157 	nullptr,          // 0x3F
158 };
159 
160 const char *CheatScreen::alignments[4] = {
161 	"Neutral",
162 	"Good",
163 	"Evil",
164 	"Chaotic"
165 };
166 
Find_highest_map()167 static int Find_highest_map(
168 ) {
169 	int n = 0;
170 	int next;
171 	while ((next = Find_next_map(n + 1, 10)) != -1)
172 		n = next;
173 	return n;
174 }
175 
show_screen()176 void CheatScreen::show_screen() {
177 	gwin = Game_window::get_instance();
178 	ibuf = gwin->get_win()->get_ib8();
179 	font = fontManager.get_font("MENU_FONT");
180 	clock = gwin->get_clock();
181 	maxx = gwin->get_width();
182 #ifdef __IPHONEOS__
183 	maxy = 200;
184 #else
185 	maxy = gwin->get_height();
186 #endif
187 	centerx = maxx / 2;
188 	centery = maxy / 2;
189 	if (touchui != nullptr) {
190 		touchui->hideGameControls();
191 		SDL_StartTextInput();
192 	}
193 
194 	// Pause the game
195 	gwin->get_tqueue()->pause(SDL_GetTicks());
196 
197 	const str_int_pair &pal_tuple_static = game->get_resource("palettes/0");
198 	const str_int_pair &pal_tuple_patch = game->get_resource("palettes/patch/0");
199 	pal.load(pal_tuple_static.str, pal_tuple_patch.str, pal_tuple_static.num);
200 	pal.apply();
201 
202 	// Start the loop
203 	NormalLoop();
204 
205 	// Resume the game clock
206 	gwin->get_tqueue()->resume(SDL_GetTicks());
207 
208 	// Reset the palette
209 	clock->reset_palette();
210 	if (touchui != nullptr) {
211 		Gump_manager *gumpman = gwin->get_gump_man();
212 		if (!gumpman->gump_mode()) {
213 			touchui->showGameControls();
214 		}
215 		if (SDL_IsTextInputActive()) {
216 			SDL_StopTextInput();
217 		}
218 	}
219 }
220 
221 
222 //
223 // DISPLAYS
224 //
225 
226 //
227 // Shared
228 //
229 
SharedPrompt(char * input,const Cheat_Prompt & mode)230 void CheatScreen::SharedPrompt(char *input, const Cheat_Prompt &mode) {
231 	char buf[512];
232 
233 #ifdef __IPHONEOS__
234 	const int prompt = 81;
235 	const int promptmes = 90;
236 	const int offsetx = 15;
237 #else
238 	const int prompt = maxy - 18;
239 	const int promptmes = maxy - 9;
240 	const int offsetx = 0;
241 #endif
242 	font->paint_text_fixedwidth(ibuf, "Select->", offsetx, prompt, 8);
243 
244 	if (input && std::strlen(input)) {
245 		font->paint_text_fixedwidth(ibuf, input, 64 + offsetx , prompt, 8);
246 		font->paint_text_fixedwidth(ibuf, "_", 64 + offsetx + std::strlen(input) * 8, prompt, 8);
247 	} else
248 		font->paint_text_fixedwidth(ibuf, "_", 64 + offsetx, prompt, 8);
249 
250 	// ...and Prompt Message
251 	switch (mode) {
252 	default:
253 	case CP_Command:
254 		font->paint_text_fixedwidth(ibuf, "Enter Command.", offsetx, promptmes, 8);
255 		break;
256 
257 	case CP_HitKey:
258 		font->paint_text_fixedwidth(ibuf, "Hit a key.", offsetx, promptmes, 8);
259 		break;
260 
261 	case CP_NotAvail:
262 		font->paint_text_fixedwidth(ibuf, "Not yet available. Hit a key.", offsetx, promptmes, 8);
263 		break;
264 
265 	case CP_InvalidNPC:
266 		font->paint_text_fixedwidth(ibuf, "Invalid NPC. Hit a key", offsetx, promptmes, 8);
267 		break;
268 
269 	case CP_InvalidCom:
270 		font->paint_text_fixedwidth(ibuf, "Invalid Command. Hit a key.", offsetx, promptmes, 8);
271 		break;
272 
273 	case CP_Canceled:
274 		font->paint_text_fixedwidth(ibuf, "Canceled. Hit a key.", offsetx, promptmes, 8);
275 		break;
276 
277 	case CP_ClockSet:
278 		font->paint_text_fixedwidth(ibuf, "Clock Set. Hit a key.", offsetx, promptmes, 8);
279 		break;
280 
281 	case CP_InvalidTime:
282 		font->paint_text_fixedwidth(ibuf, "Invalid Time. Hit a key.", offsetx, promptmes, 8);
283 		break;
284 
285 	case CP_InvalidShape:
286 		font->paint_text_fixedwidth(ibuf, "Invalid Shape. Hit a key.", offsetx, promptmes, 8);
287 		break;
288 
289 	case CP_InvalidValue:
290 		font->paint_text_fixedwidth(ibuf, "Invalid Value. Hit a key.", offsetx, promptmes, 8);
291 		break;
292 
293 	case CP_Created:
294 		font->paint_text_fixedwidth(ibuf, "Item Created. Hit a key.", offsetx, promptmes, 8);
295 		break;
296 
297 	case CP_ShapeSet:
298 		font->paint_text_fixedwidth(ibuf, "Shape Set. Hit a key.", offsetx, promptmes, 8);
299 		break;
300 
301 	case CP_ValueSet:
302 		font->paint_text_fixedwidth(ibuf, "Clock Set. Hit a key.", offsetx, promptmes, 8);
303 		break;
304 
305 	case CP_NameSet:
306 		font->paint_text_fixedwidth(ibuf, "Name Changed. Hit a key.", offsetx, promptmes, 8);
307 		break;
308 
309 	case CP_WrongShapeFile:
310 		font->paint_text_fixedwidth(ibuf, "Wrong shape file. Must be SHAPES.VGA.", offsetx, promptmes, 8);
311 		break;
312 
313 
314 	case CP_ChooseNPC:
315 		font->paint_text_fixedwidth(ibuf, "Which NPC? (-1 to cancel.)", offsetx, promptmes, 8);
316 		break;
317 
318 	case CP_EnterValue:
319 		font->paint_text_fixedwidth(ibuf, "Enter Value. (-1 to cancel.)", offsetx, promptmes, 8);
320 		break;
321 
322 	case CP_EnterValueNoCancel:
323 		font->paint_text_fixedwidth(ibuf, "Enter Value.", offsetx, promptmes, 8);
324 		break;
325 
326 	case CP_Minute:
327 		font->paint_text_fixedwidth(ibuf, "Enter Minute. (-1 to cancel.)", offsetx, promptmes, 8);
328 		break;
329 
330 	case CP_Hour:
331 		font->paint_text_fixedwidth(ibuf, "Enter Hour. (-1 to cancel.)", offsetx, promptmes, 8);
332 		break;
333 
334 	case CP_Day:
335 		font->paint_text_fixedwidth(ibuf, "Enter Day. (-1 to cancel.)", offsetx, promptmes, 8);
336 		break;
337 
338 	case CP_Shape:
339 		font->paint_text_fixedwidth(ibuf, "Enter Shape (B=Browse or -1=Cancel)", offsetx, promptmes, 8);
340 		break;
341 
342 	case CP_Activity:
343 		font->paint_text_fixedwidth(ibuf, "Enter Activity 0-31. (-1 to cancel.)", offsetx, promptmes, 8);
344 		break;
345 
346 	case CP_XCoord:
347 		snprintf(buf, 512, "Enter X Coord. Max %i (-1 to cancel)", c_num_tiles);
348 		font->paint_text_fixedwidth(ibuf, buf, offsetx, promptmes, 8);
349 		break;
350 
351 	case CP_YCoord:
352 		snprintf(buf, 512, "Enter Y Coord. Max %i (-1 to cancel)", c_num_tiles);
353 		font->paint_text_fixedwidth(ibuf, buf, offsetx, promptmes, 8);
354 		break;
355 
356 	case CP_Lift:
357 		font->paint_text_fixedwidth(ibuf, "Enter Lift. (-1 to cancel)", offsetx, promptmes, 8);
358 		break;
359 
360 	case CP_GFlagNum: {
361 		char buf[50];
362 		snprintf(buf, 50, "Enter Global Flag 0-%d. (-1 to cancel)", c_last_gflag);
363 		font->paint_text_fixedwidth(ibuf, buf, offsetx, promptmes, 8);
364 		break;
365 	}
366 
367 	case CP_NFlagNum:
368 		font->paint_text_fixedwidth(ibuf, "Enter NPC Flag 0-63. (-1 to cancel)", offsetx, promptmes, 8);
369 		break;
370 
371 	case CP_TempNum:
372 		font->paint_text_fixedwidth(ibuf, "Enter Temperature 0-63. (-1 to cancel)", offsetx, promptmes, 8);
373 		break;
374 
375 	case CP_NLatitude:
376 		font->paint_text_fixedwidth(ibuf, "Enter Latitude. Max 113 (-1 to cancel)", offsetx, promptmes, 8);
377 		break;
378 
379 	case CP_SLatitude:
380 		font->paint_text_fixedwidth(ibuf, "Enter Latitude. Max 193 (-1 to cancel)", offsetx, promptmes, 8);
381 		break;
382 
383 	case CP_WLongitude:
384 		font->paint_text_fixedwidth(ibuf, "Enter Longitude. Max 93 (-1 to cancel)", offsetx, promptmes, 8);
385 		break;
386 
387 	case CP_ELongitude:
388 		font->paint_text_fixedwidth(ibuf, "Enter Longitude. Max 213 (-1 to cancel)", offsetx, promptmes, 8);
389 		break;
390 
391 	case CP_Name:
392 		font->paint_text_fixedwidth(ibuf, "Enter a new Name...", offsetx, promptmes, 8);
393 		break;
394 
395 	case CP_NorthSouth:
396 		font->paint_text_fixedwidth(ibuf, "Latitude [N]orth or [S]outh?", offsetx, promptmes, 8);
397 		break;
398 
399 	case CP_WestEast:
400 		font->paint_text_fixedwidth(ibuf, "Longitude [W]est or [E]ast?", offsetx, promptmes, 8);
401 		break;
402 
403 	case CP_HexXCoord:
404 		snprintf(buf, 512, "Enter X Coord. Max %04x (-1 to cancel)", c_num_tiles);
405 		font->paint_text_fixedwidth(ibuf, buf, offsetx, promptmes, 8);
406 		break;
407 
408 	case CP_HexYCoord:
409 		snprintf(buf, 512, "Enter Y Coord. Max %04x (-1 to cancel)", c_num_tiles);
410 		font->paint_text_fixedwidth(ibuf, buf, offsetx, promptmes, 8);
411 		break;
412 
413 	}
414 }
415 
SDLScanCodeToInt(SDL_Keycode sym)416 static int SDLScanCodeToInt(SDL_Keycode sym) {
417 	switch (sym) {
418 	case SDLK_KP_0:
419 		return '0';
420 	case SDLK_KP_1:
421 		return '1';
422 	case SDLK_KP_2:
423 		return '2';
424 	case SDLK_KP_3:
425 		return '3';
426 	case SDLK_KP_4:
427 		return '4';
428 	case SDLK_KP_5:
429 		return '5';
430 	case SDLK_KP_6:
431 		return '6';
432 	case SDLK_KP_7:
433 		return '7';
434 	case SDLK_KP_8:
435 		return '8';
436 	case SDLK_KP_9:
437 		return '9';
438 	default:
439 		return -1;
440 	}
441 }
442 
SharedInput(char * input,int len,int & command,Cheat_Prompt & mode,bool & activate)443 bool CheatScreen::SharedInput(char *input, int len, int &command, Cheat_Prompt &mode, bool &activate) {
444 	SDL_Event event;
445 
446 	while (true) {
447 		Delay();
448 		while (SDL_PollEvent(&event)) {
449 			// Touch on the cheat screen will bring up the keyboard
450 			if (event.type == SDL_MOUSEBUTTONDOWN) {
451 				if (SDL_IsTextInputActive())
452 					SDL_StopTextInput();
453 				else
454 					SDL_StartTextInput();
455 			}
456 
457 			if (event.type != SDL_KEYDOWN)
458 				continue;
459 			SDL_Keysym &key = event.key.keysym;
460 
461 			if ((key.sym == SDLK_s) && (key.mod & KMOD_ALT) && (key.mod & KMOD_CTRL)) {
462 				make_screenshot(true);
463 				return false;
464 			}
465 
466 			if (mode == CP_NorthSouth) {
467 				if (!input[0] && (key.sym == 'n' || key.sym == 's')) {
468 					input[0] = key.sym;
469 					activate = true;
470 				}
471 			} else if (mode == CP_WestEast) {
472 				if (!input[0] && (key.sym == 'w' || key.sym == 'e')) {
473 					input[0] = key.sym;
474 					activate = true;
475 				}
476 			} else if (mode >= CP_HexXCoord) { // Want hex input
477 				// Activate (if possible)
478 				if (key.sym == SDLK_RETURN || key.sym == SDLK_KP_ENTER) {
479 					activate = true;
480 				} else if ((key.sym == '-' || key.sym == SDLK_KP_MINUS) && !input[0]) {
481 					input[0] = '-';
482 				} else if (std::isxdigit(key.sym)) {
483 					int curlen = std::strlen(input);
484 					if (curlen < (len - 1)) {
485 						input[curlen] = std::tolower(key.sym);
486 						input[curlen + 1] = 0;
487 					}
488 				} else if ((key.sym >= SDLK_KP_1 && key.sym <= SDLK_KP_9) || key.sym == SDLK_KP_0) {
489 					int curlen = std::strlen(input);
490 					if (curlen < (len - 1)) {
491 						int sym = SDLScanCodeToInt(key.sym);
492 						input[curlen] = sym;
493 						input[curlen + 1] = 0;
494 					}
495 				} else if (key.sym == SDLK_BACKSPACE) {
496 					int curlen = std::strlen(input);
497 					if (curlen) input[curlen - 1] = 0;
498 				}
499 			} else if (mode >= CP_Name) {      // Want Text input (len chars)
500 				if (key.sym == SDLK_RETURN || key.sym == SDLK_KP_ENTER) {
501 					activate = true;
502 				} else if (std::isalnum(key.sym) || key.sym == ' ') {
503 					int curlen = std::strlen(input);
504 					char chr = key.sym;
505 					if (key.mod & KMOD_SHIFT) {
506 						chr = static_cast<char>(std::toupper(static_cast<unsigned char>(chr)));
507 					}
508 					if (curlen < (len - 1)) {
509 						input[curlen] = chr;
510 						input[curlen + 1] = 0;
511 					}
512 				} else if (key.sym == SDLK_BACKSPACE) {
513 					int curlen = std::strlen(input);
514 					if (curlen) input[curlen - 1] = 0;
515 				}
516 			} else if (mode >= CP_ChooseNPC) { // Need to grab numerical input
517 				// Browse shape
518 				if (mode == CP_Shape && !input[0] && key.sym == 'b') {
519 					cheat.shape_browser();
520 					input[0] = 'b';
521 					activate = true;
522 				}
523 
524 				// Activate (if possible)
525 				if (key.sym == SDLK_RETURN || key.sym == SDLK_KP_ENTER) {
526 					activate = true;
527 				} else if ((key.sym == '-' || key.sym == SDLK_KP_MINUS) && !input[0]) {
528 					input[0] = '-';
529 				} else if (std::isdigit(key.sym)) {
530 					int curlen = std::strlen(input);
531 					if (curlen < (len - 1)) {
532 						input[curlen] = key.sym;
533 						input[curlen + 1] = 0;
534 					}
535 				} else if ((key.sym >= SDLK_KP_1 && key.sym <= SDLK_KP_9) || key.sym == SDLK_KP_0) {
536 					int curlen = std::strlen(input);
537 					if (curlen < (len - 1)) {
538 						int sym = SDLScanCodeToInt(key.sym);
539 						input[curlen] = sym;
540 						input[curlen + 1] = 0;
541 					}
542 				} else if (key.sym == SDLK_BACKSPACE) {
543 					int curlen = std::strlen(input);
544 					if (curlen) input[curlen - 1] = 0;
545 				}
546 			} else if (mode) {      // Just want a key pressed
547 				mode = CP_Command;
548 				for (int i = 0; i < len; i++) input[i] = 0;
549 				command = 0;
550 			} else {            // Need the key pressed
551 				command = key.sym;
552 				return true;
553 			}
554 			return false;
555 		}
556 		gwin->paint_dirty();
557 	}
558 	return false;
559 }
560 
561 
562 //
563 // Normal
564 //
565 
NormalLoop()566 void CheatScreen::NormalLoop() {
567 	bool looping = true;
568 
569 	// This is for the prompt message
570 	Cheat_Prompt mode = CP_Command;
571 
572 	// This is the command
573 	char input[5] = { 0, 0, 0, 0, 0 };
574 	int command;
575 	bool activate = false;
576 
577 	while (looping) {
578 		gwin->clear_screen();
579 
580 		// First the display
581 		NormalDisplay();
582 
583 		// Now the Menu Column
584 		NormalMenu();
585 
586 		// Finally the Prompt...
587 		SharedPrompt(input, mode);
588 
589 		// Draw it!
590 		gwin->get_win()->show();
591 
592 		// Check to see if we need to change menus
593 		if (activate) {
594 			NormalActivate(input, command, mode);
595 			activate = false;
596 			continue;
597 		}
598 
599 		if (SharedInput(input, 5, command, mode, activate))
600 			looping = NormalCheck(input, command, mode, activate);
601 	}
602 }
603 
NormalDisplay()604 void CheatScreen::NormalDisplay() {
605 	char    buf[512];
606 #ifdef __IPHONEOS__
607 	const int offsetx = 15;
608 	const int offsety1 = 108;
609 	const int offsety2 = 54;
610 	const int offsety3 = 0;
611 #else
612 	const int offsetx = 0;
613 	const int offsety1 = 0;
614 	const int offsety2 = 0;
615 	const int offsety3 = 45;
616 #endif
617 	int curmap = gwin->get_map()->get_num();
618 	Tile_coord t = gwin->get_main_actor()->get_tile();
619 
620 	font->paint_text_fixedwidth(ibuf, "Colourless' Advanced Option Cheat Screen", 0, offsety1, 8);
621 
622 	if (Game::get_game_type() == BLACK_GATE)
623 		snprintf(buf, 512, "Running \"Ultima 7: The Black Gate\"");
624 	else if (Game::get_game_type() == SERPENT_ISLE)
625 		snprintf(buf, 512, "Running \"Ultima 7: Part 2: Serpent Isle\"");
626 	else
627 		snprintf(buf, 512, "Running Unknown Game Type %i", Game::get_game_type());
628 
629 	font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety1 + 18, 8);
630 
631 	snprintf(buf, 512, "Exult Version %s", VERSION);
632 	font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety1 + 27, 8);
633 
634 
635 	snprintf(buf, 512, "Current time: %i:%02i %s  Day: %i",
636 	         ((clock->get_hour() + 11) % 12) + 1,
637 	         clock->get_minute(),
638 	         clock->get_hour() < 12 ? "AM" : "PM",
639 	         clock->get_day());
640 	font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety3, 8);
641 
642 	int longi = ((t.tx - 0x3A5) / 10);
643 	int lati = ((t.ty - 0x46E) / 10);
644 	snprintf(buf, 512, "Coordinates %d %s %d %s, Map #%d",
645 		abs(lati), (lati < 0 ? "North" : "South"),
646 		abs(longi), (longi < 0 ? "West" : "East"), curmap);
647 	font->paint_text_fixedwidth(ibuf, buf, offsetx, 63 - offsety2, 8);
648 
649 	snprintf(buf, 512, "Coords in hex (%04x, %04x, %02x)",
650 	         t.tx, t.ty, t.tz);
651 	font->paint_text_fixedwidth(ibuf, buf, offsetx, 72 - offsety2, 8);
652 
653 	snprintf(buf, 512, "Coords in dec (%04i, %04i, %02i)",
654 	         t.tx, t.ty, t.tz);
655 	font->paint_text_fixedwidth(ibuf, buf, offsetx, 81 - offsety2, 8);
656 }
657 
NormalMenu()658 void CheatScreen::NormalMenu() {
659 	char    buf[512];
660 #ifdef __IPHONEOS__
661 	const int offsetx = 15;
662 	const int offsety1 = 73;
663 	const int offsety2 = 55;
664 	const int offsetx1 = 160;
665 	const int offsety4 = 36;
666 	const int offsety5 = 72;
667 #else
668 	const int offsetx = 0;
669 	const int offsety1 = 0;
670 	const int offsety2 = 0;
671 	const int offsetx1 = 0;
672 	const int offsety4 = maxy - 45;
673 	const int offsety5 = maxy - 36;
674 #endif
675 
676 	// Left Column
677 
678 	// Use
679 #ifndef __IPHONEOS__
680 	// Paperdolls can be toggled in the gumps, no need here for iOS
681 	Shape_manager *sman = Shape_manager::get_instance();
682 	if (sman->can_use_paperdolls() && sman->are_paperdolls_enabled())
683 		snprintf(buf, 512, "[P]aperdolls..: Yes");
684 	else
685 		snprintf(buf, 512, "[P]aperdolls..:  No");
686 	font->paint_text_fixedwidth(ibuf, buf, 0, maxy - 99, 8);
687 #endif
688 
689 	// GodMode
690 	snprintf(buf, 512, "[G]od Mode....: %3s", cheat.in_god_mode() ? "On" : "Off");
691 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 90, 8);
692 
693 	// Archwizzard Mode
694 	snprintf(buf, 512, "[W]izard Mode.: %3s", cheat.in_wizard_mode() ? "On" : "Off");
695 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 81, 8);
696 
697 	// Infravision
698 	snprintf(buf, 512, "[I]nfravision.: %3s", cheat.in_infravision() ? "On" : "Off");
699 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 72, 8);
700 
701 	// Hackmover
702 	snprintf(buf, 512, "[H]ack Mover..: %3s", cheat.in_hack_mover() ? "Yes" : "No");
703 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 63, 8);
704 
705 	// Eggs
706 	snprintf(buf, 512, "[E]ggs Visible: %3s", gwin->paint_eggs ? "Yes" : "No");
707 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 54, 8);
708 
709 	// Set Time
710 	font->paint_text_fixedwidth(ibuf, "[S]et Time", offsetx + offsetx1, offsety4, 8);
711 
712 #ifndef __IPHONEOS__
713 	// for iOS taking the liberty of leaving that out
714 	// Time Rate
715 	snprintf(buf, 512, "[+-] Time Rate: %3i", clock->get_time_rate());
716 	font->paint_text_fixedwidth(ibuf, buf, 0, maxy - 36, 8);
717 #endif
718 
719 
720 	// Right Column
721 
722 	// NPC Tool
723 	font->paint_text_fixedwidth(ibuf, "[N]PC Tool", offsetx + 160, maxy - offsety2 - 99, 8);
724 
725 	// Global Flag Modify
726 	font->paint_text_fixedwidth(ibuf, "[F]lag Modifier", offsetx + 160, maxy - offsety2 - 90, 8);
727 
728 	// Teleport
729 	font->paint_text_fixedwidth(ibuf, "[T]eleport", offsetx + 160, maxy - offsety2 - 81, 8);
730 
731 	// eXit
732 	font->paint_text_fixedwidth(ibuf, "[X]it", offsetx + 160, offsety5, 8);
733 }
734 
NormalActivate(char * input,int & command,Cheat_Prompt & mode)735 void CheatScreen::NormalActivate(char *input, int &command, Cheat_Prompt &mode) {
736 	int npc = std::atoi(input);
737 	Shape_manager *sman = Shape_manager::get_instance();
738 
739 	mode = CP_Command;
740 
741 	switch (command) {
742 		// God Mode
743 	case 'g':
744 		cheat.toggle_god();
745 		break;
746 
747 		// Wizard Mode
748 	case 'w':
749 		cheat.toggle_wizard();
750 		break;
751 
752 		// Infravision
753 	case 'i':
754 		cheat.toggle_infravision();
755 		pal.apply();
756 		break;
757 
758 		// Eggs
759 	case 'e':
760 		cheat.toggle_eggs();
761 		break;
762 
763 		// Hack mover
764 	case 'h':
765 		cheat.toggle_hack_mover();
766 		break;
767 
768 		// Set Time
769 	case 's':
770 		mode = TimeSetLoop();
771 		break;
772 
773 		// - Time Rate
774 	case '-':
775 		if (clock->get_time_rate() > 0)
776 			clock->set_time_rate(clock->get_time_rate() - 1);
777 		break;
778 
779 		// + Time Rate
780 	case '+':
781 		if (clock->get_time_rate() < 20)
782 			clock->set_time_rate(clock->get_time_rate() + 1);
783 		break;
784 
785 		// Teleport
786 	case 't':
787 		TeleportLoop();
788 		break;
789 
790 		// NPC Tool
791 	case 'n':
792 		if (npc < -1 || (npc >= 356 && npc <= 359)) mode = CP_InvalidNPC;
793 		else if (npc == -1) mode = CP_Canceled;
794 		else if (!input[0]) NPCLoop(-1);
795 		else mode = NPCLoop(npc);
796 		break;
797 
798 		// Global Flag Editor
799 	case 'f':
800 		if (npc < -1) mode = CP_InvalidValue;
801 		else if (npc > c_last_gflag) mode = CP_InvalidValue;
802 		else if (npc == -1 || !input[0]) mode = CP_Canceled;
803 		else mode = GlobalFlagLoop(npc);
804 		break;
805 
806 		// Paperdolls
807 	case 'p':
808 		if ((Game::get_game_type() == BLACK_GATE
809 		        || Game::get_game_type() == EXULT_DEVEL_GAME)
810 		        && sman->can_use_paperdolls()) {
811 			sman->set_paperdoll_status(!sman->are_paperdolls_enabled());
812 			config->set("config/gameplay/bg_paperdolls",
813 			            sman->are_paperdolls_enabled() ? "yes" : "no", true);
814 		}
815 		break;
816 
817 	default:
818 		break;
819 	}
820 
821 	input[0] = 0;
822 	input[1] = 0;
823 	input[2] = 0;
824 	input[3] = 0;
825 	command = 0;
826 }
827 
828 // Checks the input
NormalCheck(char * input,int & command,Cheat_Prompt & mode,bool & activate)829 bool CheatScreen::NormalCheck(char *input, int &command, Cheat_Prompt &mode, bool &activate) {
830 	switch (command) {
831 		// Simple commands
832 	case 't':   // Teleport
833 	case 'g':   // God Mode
834 	case 'w':   // Wizard
835 	case 'i':   // iNfravision
836 	case 's':   // Set Time
837 	case 'e':   // Eggs
838 	case 'h':   // Hack Mover
839 	case 'c':   // Create Item
840 	case 'p':   // Paperdolls
841 		input[0] = command;
842 		activate = true;
843 		break;
844 
845 		// - Time
846 	case SDLK_KP_MINUS:
847 	case '-':
848 		command = '-';
849 		input[0] = command;
850 		activate = true;
851 		break;
852 
853 		// + Time
854 	case SDLK_KP_PLUS:
855 	case '=':
856 		command = '+';
857 		input[0] = command;
858 		activate = true;
859 		break;
860 
861 		// NPC Tool
862 	case 'n':
863 		mode = CP_ChooseNPC;
864 		break;
865 
866 		// Global Flag Editor
867 	case 'f':
868 		mode = CP_GFlagNum;
869 		break;
870 
871 		// X and Escape leave
872 	case SDLK_ESCAPE:
873 	case 'x':
874 		input[0] = command;
875 		return false;
876 
877 	default:
878 		mode = CP_InvalidCom;
879 		input[0] = command;
880 		command = 0;
881 		break;
882 	}
883 
884 	return true;
885 }
886 
887 //
888 // Activity Display
889 //
890 
ActivityDisplay()891 void CheatScreen::ActivityDisplay() {
892 	char    buf[512];
893 #ifdef __IPHONEOS__
894 	const int offsety1 = 99;
895 #else
896 	const int offsety1 = 0;
897 #endif
898 
899 	for (int i = 0; i < 11; i++) {
900 		snprintf(buf, 512, "%2i %s", i, schedules[i]);
901 		font->paint_text_fixedwidth(ibuf, buf, 0, i * 9 + offsety1, 8);
902 
903 		snprintf(buf, 512, "%2i %s", i + 11, schedules[i + 11]);
904 		font->paint_text_fixedwidth(ibuf, buf, 112, i * 9 + offsety1, 8);
905 
906 		if (i != 10) {
907 			snprintf(buf, 512, "%2i %s", i + 22, schedules[i + 22]);
908 			font->paint_text_fixedwidth(ibuf, buf, 224, i * 9 + offsety1, 8);
909 		}
910 	}
911 
912 }
913 
914 
915 //
916 // TimeSet
917 //
918 
TimeSetLoop()919 CheatScreen::Cheat_Prompt CheatScreen::TimeSetLoop() {
920 	// This is for the prompt message
921 	Cheat_Prompt mode = CP_Day;
922 
923 	// This is the command
924 	char input[5] = { 0, 0, 0, 0, 0 };
925 	int command;
926 	bool activate = false;
927 
928 	int day = 0;
929 	int hour = 0;
930 
931 	while (true) {
932 		gwin->clear_screen();
933 
934 		// First the display
935 		NormalDisplay();
936 
937 		// Now the Menu Column
938 		NormalMenu();
939 
940 		// Finally the Prompt...
941 		SharedPrompt(input, mode);
942 
943 		// Draw it!
944 		gwin->get_win()->show();
945 
946 		// Check to see if we need to change menus
947 		if (activate) {
948 			int val = std::atoi(input);
949 
950 			if (val == -1) {
951 				return CP_Canceled;
952 			} else if (val < -1) {
953 				return CP_InvalidTime;
954 			} else if (mode == CP_Day) {
955 				day = val;
956 				mode = CP_Hour;
957 			} else if (val > 59) {
958 				return CP_InvalidTime;
959 			} else if (mode == CP_Minute) {
960 				clock->reset();
961 				clock->set_day(day);
962 				clock->set_hour(hour);
963 				clock->set_minute(val);
964 				break;
965 			} else if (val > 23) {
966 				return CP_InvalidTime;
967 			} else if (mode == CP_Hour) {
968 				hour = val;
969 				mode = CP_Minute;
970 			}
971 
972 			activate = false;
973 			input[0] = 0;
974 			input[1] = 0;
975 			input[2] = 0;
976 			input[3] = 0;
977 			command = 0;
978 			continue;
979 		}
980 
981 		SharedInput(input, 5, command, mode, activate);
982 	}
983 
984 	return CP_ClockSet;
985 }
986 
987 
988 //
989 // Global Flags
990 //
991 
GlobalFlagLoop(int num)992 CheatScreen::Cheat_Prompt CheatScreen::GlobalFlagLoop(int num) {
993 	bool looping = true;
994 #ifdef __IPHONEOS__
995 	const int offsetx = 15;
996 	const int offsety1 = 83;
997 	const int offsety2 = 72;
998 #else
999 	const int offsetx = 0;
1000 	const int offsety1 = 0;
1001 	const int offsety2 = maxy - 36;
1002 #endif
1003 
1004 	// This is for the prompt message
1005 	Cheat_Prompt mode = CP_Command;
1006 
1007 	// This is the command
1008 	char input[17];
1009 	int i;
1010 	int command;
1011 	bool activate = false;
1012 	char    buf[512];
1013 
1014 	for (i = 0; i < 17; i++) input[i] = 0;
1015 
1016 	Usecode_machine *usecode = Game_window::get_instance()->get_usecode();
1017 
1018 	while (looping) {
1019 		gwin->clear_screen();
1020 
1021 #ifdef __IPHONEOS__
1022 		// on iOS we want lean and mean, so begone NormalDisplay
1023 		font->paint_text_fixedwidth(ibuf, "Global Flags", 15, 0, 8);
1024 #else
1025 		NormalDisplay();
1026 #endif
1027 
1028 		// First the info
1029 		snprintf(buf, 512, "Global Flag %i", num);
1030 		font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 99, 8);
1031 
1032 		snprintf(buf, 512, "Flag is %s", usecode->get_global_flag(num) ? "SET" : "UNSET");
1033 		font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 90, 8);
1034 
1035 		// Now the Menu Column
1036 		if (!usecode->get_global_flag(num)) font->paint_text_fixedwidth(ibuf, "[S]et Flag", offsetx + 160, maxy - offsety1 - 99, 8);
1037 		else font->paint_text_fixedwidth(ibuf, "[U]nset Flag", offsetx + 160, maxy - offsety1 - 99, 8);
1038 
1039 		// Change Flag
1040 
1041 		font->paint_text_fixedwidth(ibuf, "[*] Change Flag", offsetx, maxy - offsety1 - 72, 8);
1042 		if (num > 0 && num < c_last_gflag) font->paint_text_fixedwidth(ibuf, "[+-] Scroll Flags", offsetx, maxy - offsety1 - 63, 8);
1043 		else if (num == 0) font->paint_text_fixedwidth(ibuf, "[+] Scroll Flags", offsetx, maxy - offsety1 - 63, 8);
1044 		else font->paint_text_fixedwidth(ibuf, "[-] Scroll Flags", offsetx, maxy - offsety1 - 63, 8);
1045 		font->paint_text_fixedwidth(ibuf, "[X]it", offsetx, offsety2, 8);
1046 
1047 		// Finally the Prompt...
1048 		SharedPrompt(input, mode);
1049 
1050 		// Draw it!
1051 		gwin->get_win()->show();
1052 
1053 		// Check to see if we need to change menus
1054 		if (activate) {
1055 			mode = CP_Command;
1056 			if (command == '-') {   // Decrement
1057 				num--;
1058 				if (num < 0) {
1059 					num = 0;
1060 				}
1061 			} else if (command == '+') { // Increment
1062 				num++;
1063 				if (num > c_last_gflag) {
1064 					num = c_last_gflag;
1065 				}
1066 			} else if (command == '*') { // Change Flag
1067 				i = std::atoi(input);
1068 				if (i < -1 || i > c_last_gflag) {
1069 					mode = CP_InvalidValue;
1070 				} else if (i == -1) {
1071 					mode = CP_Canceled;
1072 				} else if (input[0]) {
1073 					num = i;
1074 				}
1075 			} else if (command == 's') { // Set
1076 				usecode->set_global_flag(num, 1);
1077 			} else if (command == 'u') { // Unset
1078 				usecode->set_global_flag(num, 0);
1079 			}
1080 
1081 			for (i = 0; i < 17; i++) {
1082 				input[i] = 0;
1083 			}
1084 			command = 0;
1085 			activate = false;
1086 			continue;
1087 		}
1088 
1089 		if (SharedInput(input, 17, command, mode, activate)) {
1090 			switch (command) {
1091 				// Simple commands
1092 			case 's':   // Set Flag
1093 			case 'u':   // Unset flag
1094 				input[0] = command;
1095 				activate = true;
1096 				break;
1097 
1098 				// Decrement
1099 			case SDLK_KP_MINUS:
1100 			case '-':
1101 				command = '-';
1102 				input[0] = command;
1103 				activate = true;
1104 				break;
1105 
1106 				// Increment
1107 			case SDLK_KP_PLUS:
1108 			case '=':
1109 				command = '+';
1110 				input[0] = command;
1111 				activate = true;
1112 				break;
1113 
1114 				// * Change Flag
1115 			case SDLK_KP_MULTIPLY:
1116 			case '8':
1117 				command = '*';
1118 				input[0] = 0;
1119 				mode = CP_GFlagNum;
1120 				break;
1121 
1122 				// X and Escape leave
1123 			case SDLK_ESCAPE:
1124 			case 'x':
1125 				input[0] = command;
1126 				looping = false;
1127 				break;
1128 
1129 			default:
1130 				mode = CP_InvalidCom;
1131 				input[0] = command;
1132 				command = 0;
1133 				break;
1134 			}
1135 		}
1136 	}
1137 	return CP_Command;
1138 }
1139 
1140 //
1141 // NPCs
1142 //
1143 
NPCLoop(int num)1144 CheatScreen::Cheat_Prompt CheatScreen::NPCLoop(int num) {
1145 	Actor *actor;
1146 
1147 	bool looping = true;
1148 
1149 	// This is for the prompt message
1150 	Cheat_Prompt mode = CP_Command;
1151 
1152 	// This is the command
1153 	char input[17];
1154 	int i;
1155 	int command;
1156 	bool activate = false;
1157 
1158 	for (i = 0; i < 17; i++) input[i] = 0;
1159 
1160 	while (looping) {
1161 		if (num == -1) actor = grabbed;
1162 		else actor = gwin->get_npc(num);
1163 		grabbed = actor;
1164 		if (actor) num = actor->get_npc_num();
1165 
1166 		gwin->clear_screen();
1167 
1168 		// First the display
1169 		NPCDisplay(actor, num);
1170 
1171 		// Now the Menu Column
1172 		NPCMenu(actor, num);
1173 
1174 		// Finally the Prompt...
1175 		SharedPrompt(input, mode);
1176 
1177 		// Draw it!
1178 		gwin->get_win()->show();
1179 
1180 		// Check to see if we need to change menus
1181 		if (activate) {
1182 			NPCActivate(input, command, mode, actor, num);
1183 			activate = false;
1184 			continue;
1185 		}
1186 
1187 		if (SharedInput(input, 17, command, mode, activate))
1188 			looping = NPCCheck(input, command, mode, activate, actor, num);
1189 	}
1190 	return CP_Command;
1191 }
1192 
NPCDisplay(Actor * actor,int & num)1193 void CheatScreen::NPCDisplay(Actor *actor, int &num) {
1194 	char    buf[512];
1195 #ifdef __IPHONEOS__
1196 	const int offsetx = 15;
1197 	const int offsety1 = 73;
1198 #else
1199 	const int offsetx = 0;
1200 	const int offsety1 = 0;
1201 #endif
1202 	if (actor) {
1203 		Tile_coord t = actor->get_tile();
1204 
1205 		// Paint the actors shape
1206 		Shape_frame *shape = actor->get_shape();
1207 		if (shape) actor->paint_shape(shape->get_xright() + 240, shape->get_yabove());
1208 
1209 		// Now the info
1210 		std::string namestr = actor->get_npc_name();
1211 		snprintf(buf, 512, "NPC %i - %s", num, namestr.c_str());
1212 		font->paint_text_fixedwidth(ibuf, buf, offsetx, 0, 8);
1213 
1214 		snprintf(buf, 512, "Loc (%04i, %04i, %02i)",
1215 		         t.tx, t.ty, t.tz);
1216 		font->paint_text_fixedwidth(ibuf, buf, offsetx, 9, 8);
1217 
1218 		snprintf(buf, 512, "Shape %04i:%02i  %s", actor->get_shapenum(), actor->get_framenum(), actor->get_flag(Obj_flags::met) ? "Met" : "Not Met");
1219 		font->paint_text_fixedwidth(ibuf, buf, offsetx, 18, 8);
1220 
1221 		snprintf(buf, 512, "Current Activity: %2i - %s", actor->get_schedule_type(), schedules[actor->get_schedule_type()]);
1222 		font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety1 + 36, 8);
1223 
1224 		snprintf(buf, 512, "Experience: %i", actor->get_property(Actor::exp));
1225 		font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety1 + 45, 8);
1226 
1227 		snprintf(buf, 512, "Level: %i", actor->get_level());
1228 		font->paint_text_fixedwidth(ibuf, buf, offsetx + 144, offsety1 + 45, 8);
1229 
1230 		snprintf(buf, 512, "Training: %2i  Health: %2i", actor->get_property(Actor::training), actor->get_property(Actor::health));
1231 		font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety1 + 54, 8);
1232 
1233 		if (num != -1) {
1234 			int ucitemnum = 0x10000 - num;
1235 			if (!num) ucitemnum = 0xfe9c;
1236 			snprintf(buf, 512, "Usecode item %4x function %x", ucitemnum, actor->get_usecode());
1237 			font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety1 + 63, 8);
1238 		} else {
1239 			snprintf(buf, 512, "Usecode function %x", actor->get_usecode());
1240 			font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety1 + 63, 8);
1241 		}
1242 
1243 		if (actor->get_flag(Obj_flags::charmed))
1244 			snprintf(buf, 512, "Alignment: %s (orig: %s)", alignments[actor->get_effective_alignment()], alignments[actor->get_alignment()]);
1245 		else
1246 			snprintf(buf, 512, "Alignment: %s", alignments[actor->get_alignment()]);
1247 		font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety1 + 72, 8);
1248 
1249 		if (actor->get_polymorph() != -1) {
1250 			snprintf(buf, 512, "Polymorphed from %04i", actor->get_polymorph());
1251 			font->paint_text_fixedwidth(ibuf, buf, offsetx, offsety1 + 81, 8);
1252 		}
1253 	} else {
1254 		snprintf(buf, 512, "NPC %i - Invalid NPC!", num);
1255 		font->paint_text_fixedwidth(ibuf, buf, offsetx, 0, 8);
1256 	}
1257 }
1258 
NPCMenu(Actor * actor,int & num)1259 void CheatScreen::NPCMenu(Actor *actor, int &num) {
1260 	ignore_unused_variable_warning(num);
1261 #ifdef __IPHONEOS__
1262 	const int offsetx = 15;
1263 	const int offsety1 = 74;
1264 	const int offsetx2 = 15;
1265 	const int offsety2 = 72;
1266 	const int offsetx3 = 175;
1267 	const int offsety3 = 63;
1268 	const int offsety4 = 72;
1269 #else
1270 	const int offsetx = 0;
1271 	const int offsety1 = 0;
1272 	const int offsetx2 = 0;
1273 	const int offsety2 = maxy - 36;
1274 	const int offsetx3 = offsetx + 160;
1275 	const int offsety3 = maxy - 45;
1276 	const int offsety4 = maxy - 36;
1277 #endif
1278 	// Left Column
1279 
1280 	if (actor) {
1281 		// Business Activity
1282 		font->paint_text_fixedwidth(ibuf, "[B]usiness Activity", offsetx, maxy - offsety1 - 99, 8);
1283 
1284 		// Change Shape
1285 		font->paint_text_fixedwidth(ibuf, "[C]hange Shape", offsetx, maxy - offsety1 - 90, 8);
1286 
1287 		// XP
1288 		font->paint_text_fixedwidth(ibuf, "[E]xperience", offsetx, maxy - offsety1 - 81, 8);
1289 
1290 		// NPC Flags
1291 		font->paint_text_fixedwidth(ibuf, "[N]pc Flags", offsetx, maxy - offsety1 - 72, 8);
1292 
1293 		// Name
1294 		font->paint_text_fixedwidth(ibuf, "[1] Name", offsetx, maxy - offsety1 - 63, 8);
1295 	}
1296 
1297 	// eXit
1298 	font->paint_text_fixedwidth(ibuf, "[X]it", offsetx2, offsety2, 8);
1299 
1300 	// Right Column
1301 
1302 	if (actor) {
1303 		// Stats
1304 		font->paint_text_fixedwidth(ibuf, "[S]tats", offsetx + 160, maxy - offsety1 - 99, 8);
1305 
1306 		// Training Points
1307 		font->paint_text_fixedwidth(ibuf, "[2] Training Points", offsetx + 160, maxy - offsety1 - 90, 8);
1308 
1309 		// Teleport
1310 		font->paint_text_fixedwidth(ibuf, "[T]eleport", offsetx + 160, maxy - offsety1 - 81, 8);
1311 
1312 		// Change NPC
1313 		font->paint_text_fixedwidth(ibuf, "[*] Change NPC", offsetx3, offsety3, 8);
1314 	}
1315 
1316 	// Change NPC
1317 	font->paint_text_fixedwidth(ibuf, "[+-] Scroll NPCs", offsetx3, offsety4, 8);
1318 }
1319 
NPCActivate(char * input,int & command,Cheat_Prompt & mode,Actor * actor,int & num)1320 void CheatScreen::NPCActivate(char *input, int &command, Cheat_Prompt &mode, Actor *actor, int &num) {
1321 	int i = std::atoi(input);
1322 	int nshapes =
1323 	    Shape_manager::get_instance()->get_shapes().get_num_shapes();
1324 
1325 	mode = CP_Command;
1326 
1327 	if (command == '-') {
1328 		num--;
1329 		if (num < 0)
1330 			num = 0;
1331 		else if (num >= 356 && num <= 359)
1332 			num = 355;
1333 	} else if (command == '+') {
1334 		num++;
1335 		if (num >= 356 && num <= 359)
1336 			num = 360;
1337 	} else if (command == '*') { // Change NPC
1338 		if (i < -1 || (i >= 356 && i <= 359)) mode = CP_InvalidNPC;
1339 		else if (i == -1) mode = CP_Canceled;
1340 		else if (input[0]) num = i;
1341 	} else if (actor) switch (command) {
1342 		case 'b':   // Business
1343 			BusinessLoop(actor);
1344 			break;
1345 
1346 		case 'n':   // Npc flags
1347 			FlagLoop(actor);
1348 			break;
1349 
1350 		case 's':   // stats
1351 			StatLoop(actor);
1352 			break;
1353 
1354 		case 't':   // Teleport
1355 			Game_window::get_instance()->teleport_party(actor->get_tile(),
1356 			        false, actor->get_map_num());
1357 			break;
1358 
1359 		case 'e':   // Experience
1360 			if (i < 0) mode = CP_Canceled;
1361 			else actor->set_property(Actor::exp, i);
1362 			break;
1363 
1364 		case '2':   // Training Points
1365 			if (i < 0) mode = CP_Canceled;
1366 			else actor->set_property(Actor::training, i);
1367 			break;
1368 
1369 		case 'c':   // Change shape
1370 			if (input[0] == 'b') {  // Browser
1371 				int n;
1372 				if (!cheat.get_browser_shape(i, n)) {
1373 					mode = CP_WrongShapeFile;
1374 					break;
1375 				}
1376 			}
1377 
1378 			if (i == -1) mode = CP_Canceled;
1379 			else if (i < 0) mode = CP_InvalidShape;
1380 			else if (i >= nshapes) mode = CP_InvalidShape;
1381 			else if (input[0] && (input[0] != '-' || input[1])) {
1382 				if (actor->get_npc_num() != 0)
1383 					actor->set_shape(i);
1384 				else
1385 					actor->set_polymorph(i);
1386 				mode = CP_ShapeSet;
1387 			}
1388 			break;
1389 
1390 		case '1':   // Name
1391 			if (!std::strlen(input)) mode = CP_Canceled;
1392 			else {
1393 				actor->set_npc_name(input);
1394 				mode = CP_NameSet;
1395 			}
1396 			break;
1397 
1398 		default:
1399 			break;
1400 		}
1401 	for (i = 0; i < 17; i++) input[i] = 0;
1402 	command = 0;
1403 }
1404 
1405 // Checks the input
NPCCheck(char * input,int & command,Cheat_Prompt & mode,bool & activate,Actor * actor,int & num)1406 bool CheatScreen::NPCCheck(char *input, int &command, Cheat_Prompt &mode, bool &activate, Actor *actor, int &num) {
1407 	ignore_unused_variable_warning(num);
1408 	switch (command) {
1409 		// Simple commands
1410 	case 'a':   // Attack mode
1411 	case 'b':   // BUsiness
1412 	case 'n':   // Npc flags
1413 	case 'd':   // pop weapon
1414 	case 's':   // stats
1415 	case 'z':   // Target
1416 	case 't':   // Teleport
1417 		input[0] = command;
1418 		if (!actor) mode = CP_InvalidCom;
1419 		else activate = true;
1420 		break;
1421 
1422 		// Value entries
1423 	case 'e':   // Experience
1424 	case '2':   // Training Points
1425 		if (!actor) mode = CP_InvalidCom;
1426 		else mode = CP_EnterValue;
1427 		break;
1428 
1429 		// Change shape
1430 	case 'c':
1431 		if (!actor) mode = CP_InvalidCom;
1432 		else mode = CP_Shape;
1433 		break;
1434 
1435 		// Name
1436 	case '1':
1437 		if (!actor) mode = CP_InvalidCom;
1438 		else mode = CP_Name;
1439 		break;
1440 
1441 		// - NPC
1442 	case SDLK_KP_MINUS:
1443 	case '-':
1444 		command = '-';
1445 		input[0] = command;
1446 		activate = true;
1447 		break;
1448 
1449 		// + NPC
1450 	case SDLK_KP_PLUS:
1451 	case '=':
1452 		command = '+';
1453 		input[0] = command;
1454 		activate = true;
1455 		break;
1456 
1457 		// * Change NPC
1458 	case SDLK_KP_MULTIPLY:
1459 	case '8':
1460 		command = '*';
1461 		input[0] = 0;
1462 		mode = CP_ChooseNPC;
1463 		break;
1464 
1465 		// X and Escape leave
1466 	case SDLK_ESCAPE:
1467 	case 'x':
1468 		input[0] = command;
1469 		return false;
1470 
1471 	default:
1472 		mode = CP_InvalidCom;
1473 		input[0] = command;
1474 		command = 0;
1475 		break;
1476 	}
1477 
1478 	return true;
1479 }
1480 
1481 //
1482 // NPC Flags
1483 //
1484 
FlagLoop(Actor * actor)1485 void CheatScreen::FlagLoop(Actor *actor) {
1486 #ifndef __IPHONEOS__
1487 	int num = actor->get_npc_num();
1488 #endif
1489 	bool looping = true;
1490 
1491 	// This is for the prompt message
1492 	Cheat_Prompt mode = CP_Command;
1493 
1494 	// This is the command
1495 	char input[17];
1496 	int i;
1497 	int command;
1498 	bool activate = false;
1499 
1500 	for (i = 0; i < 17; i++) input[i] = 0;
1501 
1502 	while (looping) {
1503 		gwin->clear_screen();
1504 
1505 #ifndef __IPHONEOS__
1506 		// First the display
1507 		NPCDisplay(actor, num);
1508 #endif
1509 
1510 		// Now the Menu Column
1511 		FlagMenu(actor);
1512 
1513 		// Finally the Prompt...
1514 		SharedPrompt(input, mode);
1515 
1516 		// Draw it!
1517 		gwin->get_win()->show();
1518 
1519 		// Check to see if we need to change menus
1520 		if (activate) {
1521 			FlagActivate(input, command, mode, actor);
1522 			activate = false;
1523 			continue;
1524 		}
1525 
1526 		if (SharedInput(input, 17, command, mode, activate))
1527 			looping = FlagCheck(input, command, mode, activate, actor);
1528 	}
1529 }
1530 
FlagMenu(Actor * actor)1531 void CheatScreen::FlagMenu(Actor *actor) {
1532 	char    buf[512];
1533 #ifdef __IPHONEOS__
1534 	const int offsetx = 10;
1535 	const int offsetx1 = 6;
1536 	const int offsety1 = 92;
1537 #else
1538 	const int offsetx = 0;
1539 	const int offsetx1 = 0;
1540 	const int offsety1 = 0;
1541 #endif
1542 
1543 	// Left Column
1544 
1545 	// Asleep
1546 	snprintf(buf, 512, "[A] Asleep.%c", actor->get_flag(Obj_flags::asleep) ? 'Y' : 'N');
1547 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 108, 8);
1548 
1549 	// Charmed
1550 	snprintf(buf, 512, "[B] Charmd.%c", actor->get_flag(Obj_flags::charmed) ? 'Y' : 'N');
1551 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 99, 8);
1552 
1553 	// Cursed
1554 	snprintf(buf, 512, "[C] Cursed.%c", actor->get_flag(Obj_flags::cursed) ? 'Y' : 'N');
1555 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 90, 8);
1556 
1557 	// Paralyzed
1558 	snprintf(buf, 512, "[D] Prlyzd.%c", actor->get_flag(Obj_flags::paralyzed) ? 'Y' : 'N');
1559 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 81, 8);
1560 
1561 	// Poisoned
1562 	snprintf(buf, 512, "[E] Poisnd.%c", actor->get_flag(Obj_flags::poisoned) ? 'Y' : 'N');
1563 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 72, 8);
1564 
1565 	// Protected
1566 	snprintf(buf, 512, "[F] Prtctd.%c", actor->get_flag(Obj_flags::protection) ? 'Y' : 'N');
1567 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 63, 8);
1568 
1569 	// Advanced Editor
1570 	font->paint_text_fixedwidth(ibuf, "[*] Advanced", offsetx, maxy - offsety1 - 45, 8);
1571 
1572 	// Exit
1573 	font->paint_text_fixedwidth(ibuf, "[X]it", offsetx, maxy - offsety1 - 36, 8);
1574 
1575 
1576 	// Center Column
1577 
1578 	// Party
1579 	snprintf(buf, 512, "[I] Party..%c", actor->get_flag(Obj_flags::in_party) ? 'Y' : 'N');
1580 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 108, 8);
1581 
1582 	// Invisible
1583 	snprintf(buf, 512, "[J] Invsbl.%c", actor->get_flag(Obj_flags::invisible) ? 'Y' : 'N');
1584 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 99, 8);
1585 
1586 	// Fly
1587 	snprintf(buf, 512, "[K] Fly....%c", actor->get_type_flag(Actor::tf_fly) ? 'Y' : 'N');
1588 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 90, 8);
1589 
1590 	// Walk
1591 	snprintf(buf, 512, "[L] Walk...%c", actor->get_type_flag(Actor::tf_walk) ? 'Y' : 'N');
1592 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 81, 8);
1593 
1594 	// Swim
1595 	snprintf(buf, 512, "[M] Swim...%c", actor->get_type_flag(Actor::tf_swim) ? 'Y' : 'N');
1596 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 72, 8);
1597 
1598 	// Ethereal
1599 	snprintf(buf, 512, "[N] Ethrel.%c", actor->get_type_flag(Actor::tf_ethereal) ? 'Y' : 'N');
1600 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 63, 8);
1601 
1602 	// Protectee
1603 	snprintf(buf, 512, "[O] Prtcee.%c", '?');
1604 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 54, 8);
1605 
1606 	// Conjured
1607 	snprintf(buf, 512, "[P] Conjrd.%c", actor->get_type_flag(Actor::tf_conjured) ? 'Y' : 'N');
1608 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 45, 8);
1609 
1610 	// Tournament (Original is SI only -- allowing for BG in Exult)
1611 	snprintf(buf, 512, "[3] Tourna.%c", actor->get_flag(
1612 	             Obj_flags::tournament) ? 'Y' : 'N');
1613 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 36, 8);
1614 
1615 	// Naked (AV ONLY)
1616 	if (!actor->get_npc_num()) {
1617 		snprintf(buf, 512, "[7] Naked..%c", actor->get_flag(Obj_flags::naked) ? 'Y' : 'N');
1618 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 104, maxy - offsety1 - 27, 8);
1619 	}
1620 
1621 
1622 	// Right Column
1623 
1624 	// Summoned
1625 	snprintf(buf, 512, "[Q] Summnd.%c", actor->get_type_flag(Actor::tf_summonned) ? 'Y' : 'N');
1626 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 108, 8);
1627 
1628 	// Bleeding
1629 	snprintf(buf, 512, "[R] Bleedn.%c", actor->get_type_flag(Actor::tf_bleeding) ? 'Y' : 'N');
1630 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 99, 8);
1631 
1632 	if (!actor->get_npc_num()) { // Avatar
1633 		// Sex
1634 		snprintf(buf, 512, "[S] Sex....%c", actor->get_type_flag(Actor::tf_sex) ? 'F' : 'M');
1635 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 90, 8);
1636 
1637 		// Skin
1638 		snprintf(buf, 512, "[1] Skin...%d", actor->get_skin_color());
1639 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 81, 8);
1640 
1641 		// Read
1642 		snprintf(buf, 512, "[4] Read...%c", actor->get_flag(Obj_flags::read) ? 'Y' : 'N');
1643 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 72, 8);
1644 	} else { // Not Avatar
1645 		// Met
1646 		snprintf(buf, 512, "[T] Met....%c", actor->get_flag(Obj_flags::met) ? 'Y' : 'N');
1647 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 90, 8);
1648 
1649 		// NoCast
1650 		snprintf(buf, 512, "[U] NoCast.%c", actor->get_flag(
1651 		             Obj_flags::no_spell_casting) ? 'Y' : 'N');
1652 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 81, 8);
1653 
1654 		// ID
1655 		snprintf(buf, 512, "[V] ID#:%02i", actor->get_ident());
1656 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 72, 8);
1657 	}
1658 
1659 	// Freeze
1660 	snprintf(buf, 512, "[W] Freeze.%c", actor->get_flag(
1661 	             Obj_flags::freeze) ? 'Y' : 'N');
1662 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 63, 8);
1663 
1664 	// Party
1665 	if (actor->is_in_party()) {
1666 		// Temp
1667 		snprintf(buf, 512, "[Y] Temp: %02i",
1668 		         actor->get_temperature());
1669 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 54, 8);
1670 
1671 		// Conjured
1672 		snprintf(buf, 512, "Warmth: %04i",
1673 		         actor->figure_warmth());
1674 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 45, 8);
1675 	}
1676 
1677 	// Polymorph
1678 	snprintf(buf, 512, "[2] Polymo.%c", actor->get_flag(Obj_flags::polymorph) ? 'Y' : 'N');
1679 	font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 36, 8);
1680 
1681 	// Patra (AV SI ONLY)
1682 	if (!actor->get_npc_num()) {
1683 		snprintf(buf, 512, "[5] Petra..%c", actor->get_flag(Obj_flags::petra) ? 'Y' : 'N');
1684 		font->paint_text_fixedwidth(ibuf, buf, offsetx1 + 208, maxy - offsety1 - 27, 8);
1685 	}
1686 
1687 }
1688 
FlagActivate(char * input,int & command,Cheat_Prompt & mode,Actor * actor)1689 void CheatScreen::FlagActivate(char *input, int &command, Cheat_Prompt &mode, Actor *actor) {
1690 	int i = std::atoi(input);
1691 	int nshapes =
1692 	    Shape_manager::get_instance()->get_shapes().get_num_shapes();
1693 
1694 	mode = CP_Command;
1695 	switch (command) {
1696 		// Everyone
1697 
1698 		// Toggles
1699 	case 'a':   // Asleep
1700 		if (actor->get_flag(Obj_flags::asleep))
1701 			actor->clear_flag(Obj_flags::asleep);
1702 		else
1703 			actor->set_flag(Obj_flags::asleep);
1704 		break;
1705 
1706 	case 'b':   // Charmed
1707 		if (actor->get_flag(Obj_flags::charmed))
1708 			actor->clear_flag(Obj_flags::charmed);
1709 		else
1710 			actor->set_flag(Obj_flags::charmed);
1711 		break;
1712 
1713 	case 'c':   // Cursed
1714 		if (actor->get_flag(Obj_flags::cursed))
1715 			actor->clear_flag(Obj_flags::cursed);
1716 		else
1717 			actor->set_flag(Obj_flags::cursed);
1718 		break;
1719 
1720 	case 'd':   // Paralyzed
1721 		if (actor->get_flag(Obj_flags::paralyzed))
1722 			actor->clear_flag(Obj_flags::paralyzed);
1723 		else
1724 			actor->set_flag(Obj_flags::paralyzed);
1725 		break;
1726 
1727 	case 'e':   // Poisoned
1728 		if (actor->get_flag(Obj_flags::poisoned))
1729 			actor->clear_flag(Obj_flags::poisoned);
1730 		else
1731 			actor->set_flag(Obj_flags::poisoned);
1732 		break;
1733 
1734 	case 'f':   // Protected
1735 		if (actor->get_flag(Obj_flags::protection))
1736 			actor->clear_flag(Obj_flags::protection);
1737 		else
1738 			actor->set_flag(Obj_flags::protection);
1739 		break;
1740 
1741 	case 'j':   // Invisible
1742 		if (actor->get_flag(Obj_flags::invisible))
1743 			actor->clear_flag(Obj_flags::invisible);
1744 		else
1745 			actor->set_flag(Obj_flags::invisible);
1746 		pal.apply();
1747 		break;
1748 
1749 	case 'k':   // Fly
1750 		if (actor->get_type_flag(Actor::tf_fly))
1751 			actor->clear_type_flag(Actor::tf_fly);
1752 		else
1753 			actor->set_type_flag(Actor::tf_fly);
1754 		break;
1755 
1756 	case 'l':   // Walk
1757 		if (actor->get_type_flag(Actor::tf_walk))
1758 			actor->clear_type_flag(Actor::tf_walk);
1759 		else
1760 			actor->set_type_flag(Actor::tf_walk);
1761 		break;
1762 
1763 	case 'm':   // Swim
1764 		if (actor->get_type_flag(Actor::tf_swim))
1765 			actor->clear_type_flag(Actor::tf_swim);
1766 		else
1767 			actor->set_type_flag(Actor::tf_swim);
1768 		break;
1769 
1770 	case 'n':   // Ethrel
1771 		if (actor->get_type_flag(Actor::tf_ethereal))
1772 			actor->clear_type_flag(Actor::tf_ethereal);
1773 		else
1774 			actor->set_type_flag(Actor::tf_ethereal);
1775 		break;
1776 
1777 	case 'p':   // Conjured
1778 		if (actor->get_type_flag(Actor::tf_conjured))
1779 			actor->clear_type_flag(Actor::tf_conjured);
1780 		else
1781 			actor->set_type_flag(Actor::tf_conjured);
1782 		break;
1783 
1784 	case 'q':   // Summoned
1785 		if (actor->get_type_flag(Actor::tf_summonned))
1786 			actor->clear_type_flag(Actor::tf_summonned);
1787 		else
1788 			actor->set_type_flag(Actor::tf_summonned);
1789 		break;
1790 
1791 	case 'r':   // Bleeding
1792 		if (actor->get_type_flag(Actor::tf_bleeding))
1793 			actor->clear_type_flag(Actor::tf_bleeding);
1794 		else
1795 			actor->set_type_flag(Actor::tf_bleeding);
1796 		break;
1797 
1798 	case 's':   // Sex
1799 		if (actor->get_type_flag(Actor::tf_sex))
1800 			actor->clear_type_flag(Actor::tf_sex);
1801 		else
1802 			actor->set_type_flag(Actor::tf_sex);
1803 		break;
1804 
1805 	case '4':   // Read
1806 		if (actor->get_flag(Obj_flags::read))
1807 			actor->clear_flag(Obj_flags::read);
1808 		else
1809 			actor->set_flag(Obj_flags::read);
1810 		break;
1811 
1812 	case '5':   // Petra
1813 		if (actor->get_flag(Obj_flags::petra))
1814 			actor->clear_flag(Obj_flags::petra);
1815 		else
1816 			actor->set_flag(Obj_flags::petra);
1817 		break;
1818 
1819 	case '7':   // Naked
1820 		if (actor->get_flag(Obj_flags::naked))
1821 			actor->clear_flag(Obj_flags::naked);
1822 		else
1823 			actor->set_flag(Obj_flags::naked);
1824 		break;
1825 
1826 	case 't':   // Met
1827 		if (actor->get_flag(Obj_flags::met))
1828 			actor->clear_flag(Obj_flags::met);
1829 		else
1830 			actor->set_flag(Obj_flags::met);
1831 		break;
1832 
1833 	case 'u':   // No Cast
1834 		if (actor->get_flag(Obj_flags::no_spell_casting))
1835 			actor->clear_flag(Obj_flags::no_spell_casting);
1836 		else
1837 			actor->set_flag(Obj_flags::no_spell_casting);
1838 		break;
1839 
1840 	case 'z':   // Zombie
1841 		if (actor->get_flag(Obj_flags::si_zombie))
1842 			actor->clear_flag(Obj_flags::si_zombie);
1843 		else
1844 			actor->set_flag(Obj_flags::si_zombie);
1845 		break;
1846 
1847 	case 'w':   // Freeze
1848 		if (actor->get_flag(Obj_flags::freeze))
1849 			actor->clear_flag(Obj_flags::freeze);
1850 		else
1851 			actor->set_flag(Obj_flags::freeze);
1852 		break;
1853 
1854 	case 'i':   // Party
1855 		if (actor->get_flag(Obj_flags::in_party)) {
1856 			gwin->get_party_man()->remove_from_party(actor);
1857 			gwin->revert_schedules(actor);
1858 			// Just to be sure.
1859 			actor->clear_flag(Obj_flags::in_party);
1860 		} else if (gwin->get_party_man()->add_to_party(actor))
1861 			actor->set_schedule_type(Schedule::follow_avatar);
1862 		break;
1863 
1864 	case 'o':   // Protectee
1865 		break;
1866 
1867 		// Value
1868 	case 'v':   // ID
1869 		if (i < -1) mode = CP_InvalidValue;
1870 		else if (i > 63) mode = CP_InvalidValue;
1871 		else if (i == -1 || !input[0]) mode = CP_Canceled;
1872 		else actor->set_ident(i);
1873 		break;
1874 
1875 	case '1':   // Skin color
1876 		actor->set_skin_color(
1877 		    Shapeinfo_lookup::GetNextSkin(
1878 		        actor->get_skin_color(), actor->get_type_flag(Actor::tf_sex),
1879 		        Shape_manager::get_instance()->have_si_shapes()));
1880 		break;
1881 
1882 	case '3':   // Tournament
1883 		if (actor->get_flag(Obj_flags::tournament))
1884 			actor->clear_flag(Obj_flags::tournament);
1885 		else
1886 			actor->set_flag(Obj_flags::tournament);
1887 		break;
1888 
1889 	case 'y':   // Warmth
1890 		if (i < -1) mode = CP_InvalidValue;
1891 		else if (i > 63) mode = CP_InvalidValue;
1892 		else if (i == -1 || !input[0]) mode = CP_Canceled;
1893 		else actor->set_temperature(i);
1894 		break;
1895 
1896 	case '2':   // Polymorph
1897 
1898 		// Clear polymorph
1899 		if (actor->get_polymorph() != -1) {
1900 			actor->set_polymorph(actor->get_polymorph());
1901 			break;
1902 		}
1903 
1904 		if (input[0] == 'b') {  // Browser
1905 			int n;
1906 			if (!cheat.get_browser_shape(i, n)) {
1907 				mode = CP_WrongShapeFile;
1908 				break;
1909 			}
1910 		}
1911 
1912 		if (i == -1) mode = CP_Canceled;
1913 		else if (i < 0) mode = CP_InvalidShape;
1914 		else if (i >= nshapes) mode = CP_InvalidShape;
1915 		else if (input[0] && (input[0] != '-' || input[1])) {
1916 			actor->set_polymorph(i);
1917 			mode = CP_ShapeSet;
1918 		}
1919 
1920 		break;
1921 
1922 		// Advanced Numeric Flag Editor
1923 	case '*':
1924 		if (i < -1) mode = CP_InvalidValue;
1925 		else if (i > 63) mode = CP_InvalidValue;
1926 		else if (i == -1 || !input[0]) mode = CP_Canceled;
1927 		else mode = AdvancedFlagLoop(i, actor);
1928 		break;
1929 
1930 	default:
1931 		break;
1932 	}
1933 	for (i = 0; i < 17; i++) input[i] = 0;
1934 	command = 0;
1935 }
1936 
1937 // Checks the input
FlagCheck(char * input,int & command,Cheat_Prompt & mode,bool & activate,Actor * actor)1938 bool CheatScreen::FlagCheck(char *input, int &command, Cheat_Prompt &mode, bool &activate, Actor *actor) {
1939 	switch (command) {
1940 		// Everyone
1941 
1942 		// Toggles
1943 	case 'a':   // Asleep
1944 	case 'b':   // Charmed
1945 	case 'c':   // Cursed
1946 	case 'd':   // Paralyzed
1947 	case 'e':   // Poisoned
1948 	case 'f':   // Protected
1949 	case 'i':   // Party
1950 	case 'j':   // Invisible
1951 	case 'k':   // Fly
1952 	case 'l':   // Walk
1953 	case 'm':   // Swim
1954 	case 'n':   // Ethrel
1955 	case 'o':   // Protectee
1956 	case 'p':   // Conjured
1957 	case 'q':   // Summoned
1958 	case 'r':   // Bleedin
1959 	case 'w':   // Freeze
1960 	case '3':   // Tournament
1961 		activate = true;
1962 		input[0] = command;
1963 		break;
1964 
1965 		// Value
1966 	case '2':   // Polymorph
1967 		if (actor->get_polymorph() == -1) {
1968 			mode = CP_Shape;
1969 			input[0] = 0;
1970 		} else {
1971 			activate = true;
1972 			input[0] = command;
1973 		}
1974 		break;
1975 
1976 
1977 		// Party Only
1978 
1979 		// Value
1980 	case 'y':   // Temp
1981 		if (!actor->is_in_party()) command = 0;
1982 		else  mode = CP_TempNum;
1983 		input[0] = 0;
1984 		break;
1985 
1986 
1987 		// Avatar Only
1988 
1989 		// Toggles
1990 	case 's':   // Sex
1991 	case '4':   // Read
1992 		if (actor->get_npc_num()) command = 0;
1993 		else activate = true;
1994 		input[0] = command;
1995 		break;
1996 
1997 		// Toggles SI
1998 	case '5':   // Petra
1999 	case '7':   // Naked
2000 		if (actor->get_npc_num()) command = 0;
2001 		else activate = true;
2002 		input[0] = command;
2003 		break;
2004 
2005 		// Value SI
2006 	case '1':   // Skin
2007 		if (actor->get_npc_num()) command = 0;
2008 		else activate = true;
2009 		input[0] = command;
2010 		break;
2011 
2012 
2013 		// Everyone but avatar
2014 
2015 		// Toggles
2016 	case 't':   // Met
2017 	case 'u':   // No Cast
2018 	case 'z':   // Zombie
2019 		if (!actor->get_npc_num()) command = 0;
2020 		else activate = true;
2021 		input[0] = command;
2022 		break;
2023 
2024 		// Value
2025 	case 'v':   // ID
2026 		if (!actor->get_npc_num()) command = 0;
2027 		else mode = CP_EnterValue;
2028 		input[0] = 0;
2029 		break;
2030 
2031 		// NPC Flag Editor
2032 
2033 	case SDLK_KP_MULTIPLY:
2034 	case '8':
2035 		command = '*';
2036 		input[0] = 0;
2037 		mode = CP_NFlagNum;
2038 		break;
2039 
2040 
2041 		// X and Escape leave
2042 	case SDLK_ESCAPE:
2043 	case 'x':
2044 		input[0] = command;
2045 		return false;
2046 
2047 		// Unknown
2048 	default:
2049 		command = 0;
2050 		break;
2051 	}
2052 
2053 	return true;
2054 }
2055 
2056 //
2057 // Business Schedules
2058 //
2059 
BusinessLoop(Actor * actor)2060 void CheatScreen::BusinessLoop(Actor *actor) {
2061 	bool looping = true;
2062 
2063 	// This is for the prompt message
2064 	Cheat_Prompt mode = CP_Command;
2065 
2066 	// This is the command
2067 	char input[17];
2068 	int i;
2069 	int command;
2070 	bool activate = false;
2071 	int time = 0;
2072 	int prev = 0;
2073 
2074 	for (i = 0; i < 17; i++) input[i] = 0;
2075 
2076 	while (looping) {
2077 		gwin->clear_screen();
2078 
2079 		// First the display
2080 		if (mode == CP_Activity)
2081 			ActivityDisplay();
2082 		else
2083 			BusinessDisplay(actor);
2084 
2085 		// Now the Menu Column
2086 		BusinessMenu(actor);
2087 
2088 		// Finally the Prompt...
2089 		SharedPrompt(input, mode);
2090 
2091 		// Draw it!
2092 		gwin->get_win()->show();
2093 
2094 		// Check to see if we need to change menus
2095 		if (activate) {
2096 			BusinessActivate(input, command, mode, actor, time, prev);
2097 			activate = false;
2098 			continue;
2099 		}
2100 
2101 		if (SharedInput(input, 17, command, mode, activate))
2102 			looping = BusinessCheck(input, command, mode, activate, actor, time);
2103 	}
2104 }
2105 
BusinessDisplay(Actor * actor)2106 void CheatScreen::BusinessDisplay(Actor *actor) {
2107 	char    buf[512];
2108 	Tile_coord t = actor->get_tile();
2109 #ifdef __IPHONEOS__
2110 	const int offsetx = 10;
2111 	const int offsety1 = 20;
2112 	const int offsetx2 = 161;
2113 	const int offsety2 = 8;
2114 #else
2115 	const int offsetx = 0;
2116 	const int offsety1 = 0;
2117 	const int offsetx2 = offsetx;
2118 	const int offsety2 = 16;
2119 #endif
2120 
2121 	// Now the info
2122 	std::string namestr = actor->get_npc_name();
2123 	snprintf(buf, 512, "NPC %i - %s - Schedules:", actor->get_npc_num(), namestr.c_str());
2124 	font->paint_text_fixedwidth(ibuf, buf, offsetx, 0, 8);
2125 
2126 	snprintf(buf, 512, "Loc (%04i, %04i, %02i)", t.tx, t.ty, t.tz);
2127 	font->paint_text_fixedwidth(ibuf, buf, 0, 8, 8);
2128 
2129 #ifdef __IPHONEOS__
2130 	const char activity_msg[] = "-Act: %2i %s";
2131 #else
2132 	const char activity_msg[] = "Current Activity:  %2i - %s";
2133 #endif
2134 	snprintf(buf, 512, activity_msg, actor->get_schedule_type(), schedules[actor->get_schedule_type()]);
2135 	font->paint_text_fixedwidth(ibuf, buf, offsetx2, offsety2, 8);
2136 
2137 
2138 	// Avatar can't have schedules
2139 	if (actor->get_npc_num() > 0) {
2140 #ifndef __IPHONEOS__
2141 		font->paint_text_fixedwidth(ibuf, "Schedules:", offsetx, 16, 8);
2142 #endif
2143 
2144 		Schedule_change *scheds;
2145 		int num;
2146 		int types[8] = { -1, -1, -1, -1, -1, -1, -1, -1};
2147 		int x[8];
2148 		int y[8];
2149 
2150 		actor->get_schedules(scheds, num);
2151 
2152 		for (int i = 0; i < num; i++) {
2153 			int time = scheds[i].get_time();
2154 			types[time] = scheds[i].get_type();
2155 			Tile_coord tile = scheds[i].get_pos();
2156 			x[time] = tile.tx;
2157 			y[time] = tile.ty;
2158 		}
2159 
2160 		font->paint_text_fixedwidth(ibuf, "12 AM:", offsetx, 36 - offsety1, 8);
2161 		font->paint_text_fixedwidth(ibuf, " 3 AM:", offsetx, 44 - offsety1, 8);
2162 		font->paint_text_fixedwidth(ibuf, " 6 AM:", offsetx, 52 - offsety1, 8);
2163 		font->paint_text_fixedwidth(ibuf, " 9 AM:", offsetx, 60 - offsety1, 8);
2164 		font->paint_text_fixedwidth(ibuf, "12 PM:", offsetx, 68 - offsety1, 8);
2165 		font->paint_text_fixedwidth(ibuf, " 3 PM:", offsetx, 76 - offsety1, 8);
2166 		font->paint_text_fixedwidth(ibuf, " 6 PM:", offsetx, 84 - offsety1, 8);
2167 		font->paint_text_fixedwidth(ibuf, " 9 PM:", offsetx, 92 - offsety1, 8);
2168 
2169 		for (int i = 0; i < 8; i++) if (types[i] != -1) {
2170 				snprintf(buf, 512, "%2i (%4i,%4i) - %s", types[i], x[i], y[i], schedules[types[i]]);
2171 				font->paint_text_fixedwidth(ibuf, buf, offsetx + 56, (36  - offsety1) + i * 8, 8);
2172 			}
2173 	}
2174 }
2175 
BusinessMenu(Actor * actor)2176 void CheatScreen::BusinessMenu(Actor *actor) {
2177 	// Left Column
2178 #ifdef __IPHONEOS__
2179 	const int offsetx = 10;
2180 #else
2181 	const int offsetx = 0;
2182 #endif
2183 	// Might break on monster npcs?
2184 	if (actor->get_npc_num() > 0) {
2185 		font->paint_text_fixedwidth(ibuf, "12 AM: [A] Set [I] Location [1] Clear", offsetx, maxy - 96, 8);
2186 		font->paint_text_fixedwidth(ibuf, " 3 AM: [B] Set [J] Location [2] Clear", offsetx, maxy - 88, 8);
2187 		font->paint_text_fixedwidth(ibuf, " 6 AM: [C] Set [K] Location [3] Clear", offsetx, maxy - 80, 8);
2188 		font->paint_text_fixedwidth(ibuf, " 9 AM: [D] Set [L] Location [4] Clear", offsetx, maxy - 72, 8);
2189 		font->paint_text_fixedwidth(ibuf, "12 PM: [E] Set [M] Location [5] Clear", offsetx, maxy - 64, 8);
2190 		font->paint_text_fixedwidth(ibuf, " 3 PM: [F] Set [N] Location [6] Clear", offsetx, maxy - 56, 8);
2191 		font->paint_text_fixedwidth(ibuf, " 6 PM: [G] Set [O] Location [7] Clear", offsetx, maxy - 48, 8);
2192 		font->paint_text_fixedwidth(ibuf, " 9 PM: [H] Set [P] Location [8] Clear", offsetx, maxy - 40, 8);
2193 
2194 		font->paint_text_fixedwidth(ibuf, "[S]et Current Activity [X]it [R]evert", offsetx, maxy - 30, 8);
2195 	} else
2196 		font->paint_text_fixedwidth(ibuf, "[S]et Current Activity [X]it", offsetx, maxy - 30, 8);
2197 }
2198 
BusinessActivate(char * input,int & command,Cheat_Prompt & mode,Actor * actor,int & time,int & prev)2199 void CheatScreen::BusinessActivate(char *input, int &command, Cheat_Prompt &mode, Actor *actor, int &time, int &prev) {
2200 	int i = std::atoi(input);
2201 
2202 	mode = CP_Command;
2203 	int old = command;
2204 	command = 0;
2205 	switch (old) {
2206 	case 'a':   // Set Activity
2207 		if (i < -1 || i > 31) mode = CP_InvalidValue;
2208 		else if (i == -1) mode = CP_Canceled;
2209 		else if (!input[0]) {
2210 			mode = CP_Activity;
2211 			command = 'a';
2212 		} else {
2213 			actor->set_schedule_time_type(time, i);
2214 		}
2215 		break;
2216 
2217 	case 'i':   // X Coord
2218 		if (i < -1 || i > c_num_tiles) mode = CP_InvalidValue;
2219 		else if (i == -1) mode = CP_Canceled;
2220 		else if (!input[0]) {
2221 			mode = CP_XCoord;
2222 			command = 'i';
2223 		} else {
2224 			prev = i;
2225 			mode = CP_YCoord;
2226 			command = 'j';
2227 		}
2228 		break;
2229 
2230 	case 'j':   // Y Coord
2231 		if (i < -1 || i > c_num_tiles) mode = CP_InvalidValue;
2232 		else if (i == -1) mode = CP_Canceled;
2233 		else if (!input[0]) {
2234 			mode = CP_YCoord;
2235 			command = 'j';
2236 		} else {
2237 			actor->set_schedule_time_location(time, prev, i);
2238 		}
2239 		break;
2240 
2241 
2242 	case '1':   // Clear
2243 		actor->remove_schedule(time);
2244 		break;
2245 
2246 
2247 	case 's':   // Set Current
2248 		if (i < -1 || i > 31) mode = CP_InvalidValue;
2249 		else if (i == -1) mode = CP_Canceled;
2250 		else if (!input[0]) {
2251 			mode = CP_Activity;
2252 			command = 's';
2253 		} else {
2254 			actor->set_schedule_type(i);
2255 		}
2256 		break;
2257 
2258 
2259 	case 'r':   // Revert
2260 		Game_window::get_instance()->revert_schedules(actor);
2261 		break;
2262 
2263 
2264 	default:
2265 		break;
2266 	}
2267 	for (i = 0; i < 17; i++) input[i] = 0;
2268 }
2269 
2270 // Checks the input
BusinessCheck(char * input,int & command,Cheat_Prompt & mode,bool & activate,Actor * actor,int & time)2271 bool CheatScreen::BusinessCheck(char *input, int &command, Cheat_Prompt &mode, bool &activate, Actor *actor, int &time) {
2272 	// Might break on monster npcs?
2273 	if (actor->get_npc_num() > 0) switch (command) {
2274 		case 'a':
2275 		case 'b':
2276 		case 'c':
2277 		case 'd':
2278 		case 'e':
2279 		case 'f':
2280 		case 'g':
2281 		case 'h':
2282 			time = command - 'a';
2283 			command = 'a';
2284 			mode = CP_Activity;
2285 			return true;
2286 
2287 		case 'i':
2288 		case 'j':
2289 		case 'k':
2290 		case 'l':
2291 		case 'm':
2292 		case 'n':
2293 		case 'o':
2294 		case 'p':
2295 			time = command - 'i';
2296 			command = 'i';
2297 			mode = CP_XCoord;
2298 			return true;
2299 
2300 		case '1':
2301 		case '2':
2302 		case '3':
2303 		case '4':
2304 		case '5':
2305 		case '6':
2306 		case '7':
2307 		case '8':
2308 			time = command - '1';
2309 			command = '1';
2310 			activate = true;
2311 			return true;
2312 
2313 		case 'r':
2314 			command = 'r';
2315 			activate = true;
2316 			return true;
2317 
2318 		default:
2319 			break;
2320 		}
2321 
2322 	switch (command) {
2323 		// Set Current
2324 	case 's':
2325 		command = 's';
2326 		input[0] = 0;
2327 		mode = CP_Activity;
2328 		break;
2329 
2330 		// X and Escape leave
2331 	case SDLK_ESCAPE:
2332 	case 'x':
2333 		input[0] = command;
2334 		return false;
2335 
2336 		// Unknown
2337 	default:
2338 		command = 0;
2339 		mode = CP_InvalidCom;
2340 		break;
2341 	}
2342 
2343 	return true;
2344 }
2345 
2346 //
2347 // NPC Stats
2348 //
2349 
StatLoop(Actor * actor)2350 void CheatScreen::StatLoop(Actor *actor) {
2351 #ifndef __IPHONEOS__
2352     int num = actor->get_npc_num();
2353 #endif
2354 	bool looping = true;
2355 
2356 	// This is for the prompt message
2357 	Cheat_Prompt mode = CP_Command;
2358 
2359 	// This is the command
2360 	char input[17];
2361 	int i;
2362 	int command;
2363 	bool activate = false;
2364 
2365 	for (i = 0; i < 17; i++) input[i] = 0;
2366 
2367 	while (looping) {
2368 		gwin->clear_screen();
2369 
2370 #ifndef __IPHONEOS__
2371 		// First the display
2372 		NPCDisplay(actor, num);
2373 #endif
2374 
2375 		// Now the Menu Column
2376 		StatMenu(actor);
2377 
2378 		// Finally the Prompt...
2379 		SharedPrompt(input, mode);
2380 
2381 		// Draw it!
2382 		gwin->get_win()->show();
2383 
2384 		// Check to see if we need to change menus
2385 		if (activate) {
2386 			StatActivate(input, command, mode, actor);
2387 			activate = false;
2388 			continue;
2389 		}
2390 
2391 		if (SharedInput(input, 17, command, mode, activate))
2392 			looping = StatCheck(input, command, mode, activate, actor);
2393 	}
2394 }
2395 
StatMenu(Actor * actor)2396 void CheatScreen::StatMenu(Actor *actor) {
2397 	char    buf[512];
2398 #ifdef __IPHONEOS__
2399 	const int offsetx = 15;
2400 	const int offsety1 = 92;
2401 #else
2402 	const int offsetx = 0;
2403 	const int offsety1 = 0;
2404 #endif
2405 
2406 	// Left Column
2407 
2408 	// Dexterity
2409 	snprintf(buf, 512, "[D]exterity....%3i", actor->get_property(Actor::dexterity));
2410 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 108 , 8);
2411 
2412 	// Food Level
2413 	snprintf(buf, 512, "[F]ood Level...%3i", actor->get_property(Actor::food_level));
2414 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 99, 8);
2415 
2416 	// Intelligence
2417 	snprintf(buf, 512, "[I]ntellicence.%3i", actor->get_property(Actor::intelligence));
2418 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 90, 8);
2419 
2420 	// Strength
2421 	snprintf(buf, 512, "[S]trength.....%3i", actor->get_property(Actor::strength));
2422 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 81, 8);
2423 
2424 	// Combat Skill
2425 	snprintf(buf, 512, "[C]ombat Skill.%3i", actor->get_property(Actor::combat));
2426 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 72, 8);
2427 
2428 	// Hit Points
2429 	snprintf(buf, 512, "[H]it Points...%3i", actor->get_property(Actor::health));
2430 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 63, 8);
2431 
2432 	// Magic
2433 	// Magic Points
2434 	snprintf(buf, 512, "[M]agic Points.%3i", actor->get_property(Actor::magic));
2435 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 54, 8);
2436 
2437 	// Mana
2438 	snprintf(buf, 512, "[V]ana Level...%3i", actor->get_property(Actor::mana));
2439 	font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 45, 8);
2440 
2441 	// Exit
2442 	font->paint_text_fixedwidth(ibuf, "[X]it", offsetx, maxy - offsety1 - 36, 8);
2443 
2444 }
2445 
StatActivate(char * input,int & command,Cheat_Prompt & mode,Actor * actor)2446 void CheatScreen::StatActivate(char *input, int &command, Cheat_Prompt &mode, Actor *actor) {
2447 	int i = std::atoi(input);
2448 	mode = CP_Command;
2449 	// Enforce sane bounds.
2450 	if (i > 60) {
2451 		i = 60;
2452 	} else if (i < 0 && command != 'h') {
2453 		if (i == -1) {   // canceled
2454 			for (i = 0; i < 17; i++)
2455 				input[i] = 0;
2456 			command = 0;
2457 			return;
2458 		}
2459 		i = 0;
2460 	} else if (i < -50) {
2461 		i = -50;
2462 	}
2463 
2464 	switch (command) {
2465 	case 'd':   // Dexterity
2466 		actor->set_property(Actor::dexterity, i);
2467 		break;
2468 
2469 	case 'f':   // Food Level
2470 		actor->set_property(Actor::food_level, i);
2471 		break;
2472 
2473 	case 'i':   // Intelligence
2474 		actor->set_property(Actor::intelligence, i);
2475 		break;
2476 
2477 	case 's':   // Strength
2478 		actor->set_property(Actor::strength, i);
2479 		break;
2480 
2481 	case 'c':   // Combat Points
2482 		actor->set_property(Actor::combat, i);
2483 		break;
2484 
2485 	case 'h':   // Hit Points
2486 		actor->set_property(Actor::health, i);
2487 		break;
2488 
2489 	case 'm':   // Magic
2490 		actor->set_property(Actor::magic, i);
2491 		break;
2492 
2493 	case 'v':   // [V]ana
2494 		actor->set_property(Actor::mana, i);
2495 		break;
2496 
2497 
2498 	default:
2499 		break;
2500 	}
2501 	for (i = 0; i < 17; i++) input[i] = 0;
2502 	command = 0;
2503 }
2504 
2505 // Checks the input
StatCheck(char * input,int & command,Cheat_Prompt & mode,bool & activate,Actor * actor)2506 bool CheatScreen::StatCheck(char *input, int &command, Cheat_Prompt &mode, bool &activate, Actor *actor) {
2507 	ignore_unused_variable_warning(activate, actor);
2508 	switch (command) {
2509 		// Everyone
2510 	case 'h':   // Hit Points
2511 		input[0] = 0;
2512 		mode = CP_EnterValueNoCancel;
2513 		break;
2514 	case 'd':   // Dexterity
2515 	case 'f':   // Food Level
2516 	case 'i':   // Intelligence
2517 	case 's':   // Strength
2518 	case 'c':   // Combat Points
2519 	case 'm':   // Magic
2520 	case 'v':   // [V]ana
2521 		input[0] = 0;
2522 		mode = CP_EnterValue;
2523 		break;
2524 
2525 		// X and Escape leave
2526 	case SDLK_ESCAPE:
2527 	case 'x':
2528 		input[0] = command;
2529 		return false;
2530 
2531 		// Unknown
2532 	default:
2533 		command = 0;
2534 		break;
2535 	}
2536 
2537 	return true;
2538 }
2539 
2540 
2541 //
2542 // Advanced Flag Edition
2543 //
2544 
AdvancedFlagLoop(int num,Actor * actor)2545 CheatScreen::Cheat_Prompt CheatScreen::AdvancedFlagLoop(int num, Actor *actor) {
2546 #ifdef __IPHONEOS__
2547 	const int offsetx = 15;
2548 	const int offsety1 = 83;
2549 	const int offsety2 = 72;
2550 #else
2551 	int npc_num = actor->get_npc_num();
2552 	const int offsetx = 0;
2553 	const int offsety1 = 0;
2554 	const int offsety2 = maxy - 36;
2555 #endif
2556 	bool looping = true;
2557 	// This is for the prompt message
2558 	Cheat_Prompt mode = CP_Command;
2559 
2560 	// This is the command
2561 	char input[17];
2562 	int i;
2563 	int command;
2564 	bool activate = false;
2565 	char    buf[512];
2566 
2567 	for (i = 0; i < 17; i++) input[i] = 0;
2568 
2569 	while (looping) {
2570 		gwin->clear_screen();
2571 
2572 #ifndef __IPHONEOS__
2573 		NPCDisplay(actor, npc_num);
2574 #endif
2575 
2576 		if (num < 0) num = 0;
2577 		else if (num > 63) num = 63;
2578 
2579 		// First the info
2580 		if (flag_names[num])
2581 			snprintf(buf, 512, "NPC Flag %i: %s", num, flag_names[num]);
2582 		else
2583 			snprintf(buf, 512, "NPC Flag %i", num);
2584 		font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 108, 8);
2585 
2586 		snprintf(buf, 512, "Flag is %s", actor->get_flag(num) ? "SET" : "UNSET");
2587 		font->paint_text_fixedwidth(ibuf, buf, offsetx, maxy - offsety1 - 90, 8);
2588 
2589 
2590 		// Now the Menu Column
2591 		if (!actor->get_flag(num)) font->paint_text_fixedwidth(ibuf, "[S]et Flag", offsetx + 160, maxy - offsety1 - 90, 8);
2592 		else font->paint_text_fixedwidth(ibuf, "[U]nset Flag", offsetx + 160, maxy - offsety1 - 90, 8);
2593 
2594 		// Change Flag
2595 		font->paint_text_fixedwidth(ibuf, "[*] Change Flag", offsetx, maxy - offsety1 - 72, 8);
2596 		if (num > 0 && num < 63) font->paint_text_fixedwidth(ibuf, "[+-] Scroll Flags", offsetx, maxy - offsety1 - 63, 8);
2597 		else if (num == 0) font->paint_text_fixedwidth(ibuf, "[+] Scroll Flags", offsetx, maxy - offsety1 - 63, 8);
2598 		else font->paint_text_fixedwidth(ibuf, "[-] Scroll Flags", offsetx, maxy - offsety1 - 63, 8);
2599 
2600 		font->paint_text_fixedwidth(ibuf, "[X]it", offsetx, offsety2, 8);
2601 
2602 		// Finally the Prompt...
2603 		SharedPrompt(input, mode);
2604 
2605 		// Draw it!
2606 		gwin->get_win()->show();
2607 
2608 		// Check to see if we need to change menus
2609 		if (activate) {
2610 			mode = CP_Command;
2611 			if (command == '-') {   // Decrement
2612 				num--;
2613 				if (num < 0) {
2614 					num = 0;
2615 				}
2616 			} else if (command == '+') { // Increment
2617 				num++;
2618 				if (num > 63) {
2619 					num = 63;
2620 				}
2621 			} else if (command == '*') { // Change Flag
2622 				i = std::atoi(input);
2623 				if (i < -1 || i > 63) {
2624 					mode = CP_InvalidValue;
2625 				} else if (i == -1) {
2626 					mode = CP_Canceled;
2627 				} else if (input[0]) {
2628 					num = i;
2629 				}
2630 			} else if (command == 's') { // Set
2631 				actor->set_flag(num);
2632 				if (num == Obj_flags::in_party) {
2633 					gwin->get_party_man()->add_to_party(actor);
2634 					actor->set_schedule_type(Schedule::follow_avatar);
2635 				}
2636 			} else if (command == 'u') { // Unset
2637 				if (num == Obj_flags::in_party) {
2638 					gwin->get_party_man()->remove_from_party(actor);
2639 					gwin->revert_schedules(actor);
2640 				}
2641 				actor->clear_flag(num);
2642 			}
2643 
2644 			for (i = 0; i < 17; i++) {
2645 				input[i] = 0;
2646 			}
2647 			command = 0;
2648 			activate = false;
2649 			continue;
2650 		}
2651 
2652 		if (SharedInput(input, 17, command, mode, activate)) {
2653 			switch (command) {
2654 				// Simple commands
2655 			case 's':   // Set Flag
2656 			case 'u':   // Unset flag
2657 				input[0] = command;
2658 				activate = true;
2659 				break;
2660 
2661 				// Decrement
2662 			case SDLK_KP_MINUS:
2663 			case '-':
2664 				command = '-';
2665 				input[0] = command;
2666 				activate = true;
2667 				break;
2668 
2669 				// Increment
2670 			case SDLK_KP_PLUS:
2671 			case '=':
2672 				command = '+';
2673 				input[0] = command;
2674 				activate = true;
2675 				break;
2676 
2677 				// * Change Flag
2678 			case SDLK_KP_MULTIPLY:
2679 			case '8':
2680 				command = '*';
2681 				input[0] = 0;
2682 				mode = CP_NFlagNum;
2683 				break;
2684 
2685 				// X and Escape leave
2686 			case SDLK_ESCAPE:
2687 			case 'x':
2688 				input[0] = command;
2689 				looping = false;
2690 				break;
2691 
2692 			default:
2693 				mode = CP_InvalidCom;
2694 				input[0] = command;
2695 				command = 0;
2696 				break;
2697 			}
2698 		}
2699 	}
2700 	return CP_Command;
2701 }
2702 
2703 
2704 //
2705 // Teleport screen
2706 //
2707 
TeleportLoop()2708 void CheatScreen::TeleportLoop() {
2709 	bool looping = true;
2710 
2711 	// This is for the prompt message
2712 	Cheat_Prompt mode = CP_Command;
2713 
2714 	// This is the command
2715 	char input[5];
2716 	int i;
2717 	int command;
2718 	bool activate = false;
2719 	int prev = 0;
2720 
2721 	for (i = 0; i < 5; i++) input[i] = 0;
2722 
2723 	while (looping) {
2724 		gwin->clear_screen();
2725 
2726 		// First the display
2727 		TeleportDisplay();
2728 
2729 		// Now the Menu Column
2730 		TeleportMenu();
2731 
2732 		// Finally the Prompt...
2733 		SharedPrompt(input, mode);
2734 
2735 		// Draw it!
2736 		gwin->get_win()->show();
2737 
2738 		// Check to see if we need to change menus
2739 		if (activate) {
2740 			TeleportActivate(input, command, mode, prev);
2741 			activate = false;
2742 			continue;
2743 		}
2744 
2745 		if (SharedInput(input, 5, command, mode, activate))
2746 			looping = TeleportCheck(input, command, mode, activate);
2747 	}
2748 }
2749 
TeleportDisplay()2750 void CheatScreen::TeleportDisplay() {
2751 	char    buf[512];
2752 	Tile_coord t = gwin->get_main_actor()->get_tile();
2753 	int curmap = gwin->get_map()->get_num();
2754 	int highest = Find_highest_map();
2755 #ifdef __IPHONEOS__
2756 	const int offsetx = 15;
2757 	const int offsety1 = 54;
2758 #else
2759 	const int offsetx = 0;
2760 	const int offsety1 = 0;
2761 #endif
2762 
2763 #ifdef __IPHONEOS__
2764 	font->paint_text_fixedwidth(ibuf, "Teleport Menu - Dangerous!", offsetx, 0, 8);
2765 #else
2766 	font->paint_text_fixedwidth(ibuf, "Teleport Menu", offsetx, 0, 8);
2767 	font->paint_text_fixedwidth(ibuf, "Dangerous - use with care!", offsetx, 18, 8);
2768 #endif
2769 
2770 	int longi = ((t.tx - 0x3A5) / 10);
2771 	int lati = ((t.ty - 0x46E) / 10);
2772 #ifdef __IPHONEOS__
2773 	snprintf(buf, 512, "Coords %d %s %d %s, Map #%d of %d",
2774 		abs(lati), (lati < 0 ? "North" : "South"),
2775 		abs(longi), (longi < 0 ? "West" : "East"), curmap, highest);
2776 	font->paint_text_fixedwidth(ibuf, buf, offsetx, 9, 8);
2777 #else
2778 	snprintf(buf, 512, "Coordinates   %d %s %d %s",
2779 		abs(lati), (lati < 0 ? "North" : "South"),
2780 		abs(longi), (longi < 0 ? "West" : "East"));
2781 	font->paint_text_fixedwidth(ibuf, buf, offsetx, 63, 8);
2782 #endif
2783 
2784 	snprintf(buf, 512, "Coords in hex (%04x, %04x, %02x)",
2785 	         t.tx, t.ty, t.tz);
2786 	font->paint_text_fixedwidth(ibuf, buf, offsetx, 72 - offsety1, 8);
2787 
2788 	snprintf(buf, 512, "Coords in dec (%04i, %04i, %02i)",
2789 	         t.tx, t.ty, t.tz);
2790 	font->paint_text_fixedwidth(ibuf, buf, offsetx, 81 - offsety1, 8);
2791 
2792 #ifndef __IPHONEOS__
2793 	snprintf(buf, 512, "On Map #%d of %d",
2794 	         curmap, highest);
2795 	font->paint_text_fixedwidth(ibuf, buf, offsetx, 90, 8);
2796 #endif
2797 }
2798 
2799 
TeleportMenu()2800 void CheatScreen::TeleportMenu() {
2801 
2802 #ifdef __IPHONEOS__
2803 	const int offsetx = 15;
2804 	const int offsety1 = 64;
2805 	const int offsetx2 = 175;
2806 	const int offsety2 = 63;
2807 	const int offsety3 = 72;
2808 #else
2809 	const int offsetx = 0;
2810 	const int offsety1 = 0;
2811 	const int offsetx2 = offsetx;
2812 	const int offsety2 = maxy - 63;
2813 	const int offsety3 = maxy - 36;
2814 #endif
2815 
2816 	// Left Column
2817 	// Geo
2818 	font->paint_text_fixedwidth(ibuf, "[G]eographic Coordinates", offsetx, maxy - offsety1 - 99, 8);
2819 
2820 
2821 	// Hex
2822 	font->paint_text_fixedwidth(ibuf, "[H]exadecimal Coordinates", offsetx, maxy - offsety1 - 90, 8);
2823 
2824 	// Dec
2825 	font->paint_text_fixedwidth(ibuf, "[D]ecimal Coordinates", offsetx, maxy - offsety1 - 81, 8);
2826 
2827 	// NPC
2828 	font->paint_text_fixedwidth(ibuf, "[N]PC Number", offsetx, maxy - offsety1 - 72, 8);
2829 
2830 	// Map
2831 	font->paint_text_fixedwidth(ibuf, "[M]ap Number", offsetx2, offsety2, 8);
2832 
2833 	// eXit
2834 	font->paint_text_fixedwidth(ibuf, "[X]it", offsetx, offsety3, 8);
2835 }
2836 
TeleportActivate(char * input,int & command,Cheat_Prompt & mode,int & prev)2837 void CheatScreen::TeleportActivate(char *input, int &command, Cheat_Prompt &mode, int &prev) {
2838 	int i = std::atoi(input);
2839 	static int lat;
2840 	Tile_coord t = gwin->get_main_actor()->get_tile();
2841 	int highest = Find_highest_map();
2842 
2843 	mode = CP_Command;
2844 	switch (command) {
2845 
2846 	case 'g':   // North or South
2847 		if (!input[0]) {
2848 			mode = CP_NorthSouth;
2849 			command = 'g';
2850 		} else if (input[0] == 'n' || input[0] == 's') {
2851 			prev = input[0];
2852 			if (prev == 'n') mode = CP_NLatitude;
2853 			else mode = CP_SLatitude;
2854 			command = 'a';
2855 		}else
2856 			mode = CP_InvalidValue;
2857 		break;
2858 
2859 	case 'a':   // latitude
2860 		if (i < -1 || (prev == 'n' && i > 113) || (prev == 's' && i > 193)) mode = CP_InvalidValue;
2861 		else if (i == -1) mode = CP_Canceled;
2862 		else if (!input[0]) {
2863 			if (prev == 'n') mode = CP_NLatitude;
2864 			else mode = CP_SLatitude;
2865 			command = 'a';
2866 		} else {
2867 			if (prev == 'n')
2868 				lat = ((i * -10) + 0x46E);
2869 			else
2870 				lat = ((i * 10) + 0x46E);
2871 			mode = CP_WestEast;
2872 			command = 'b';
2873 		}
2874 		break;
2875 
2876 	case 'b':   // West or East
2877 		if (!input[0]) {
2878 			mode = CP_WestEast;
2879 			command = 'b';
2880 		} else if (input[0] == 'w' || input[0] == 'e') {
2881 			prev = input[0];
2882 			if (prev == 'w') mode = CP_WLongitude;
2883 			else mode = CP_ELongitude;
2884 			command = 'c';
2885 		}
2886 		else
2887 			mode = CP_InvalidValue;
2888 		break;
2889 
2890 	case 'c':   // longitude
2891 		if (i < -1 || (prev == 'w' && i > 93) || (prev == 'e' && i > 213)) mode = CP_InvalidValue;
2892 		else if (i == -1) mode = CP_Canceled;
2893 		else if (!input[0]) {
2894 			if (prev == 'w') mode = CP_WLongitude;
2895 			else mode = CP_ELongitude;
2896 			command = 'c';
2897 		} else {
2898 			if (prev == 'w')
2899 				t.tx = ((i * -10) + 0x3A5);
2900 			else
2901 				t.tx = ((i * 10) + 0x3A5);
2902 			t.ty = lat;
2903 			t.tz = 0;
2904 			gwin->teleport_party(t);
2905 		}
2906 		break;
2907 
2908 	case 'h':   // hex X coord
2909 		i = strtol(input, nullptr, 16);
2910 		if (i < -1 || i > c_num_tiles) mode = CP_InvalidValue;
2911 		else if (i == -1) mode = CP_Canceled;
2912 		else if (!input[0]) {
2913 			mode = CP_HexXCoord;
2914 			command = 'h';
2915 		} else {
2916 			prev = i;
2917 			mode = CP_HexYCoord;
2918 			command = 'i';
2919 		}
2920 		break;
2921 
2922 	case 'i':   // hex Y coord
2923 		i = strtol(input, nullptr, 16);
2924 		if (i < -1 || i > c_num_tiles) mode = CP_InvalidValue;
2925 		else if (i == -1) mode = CP_Canceled;
2926 		else if (!input[0]) {
2927 			mode = CP_HexYCoord;
2928 			command = 'i';
2929 		} else {
2930 			t.tx = prev;
2931 			t.ty = i;
2932 			t.tz = 0;
2933 			gwin->teleport_party(t);
2934 		}
2935 		break;
2936 
2937 	case 'd':   // dec X coord
2938 		if (i < -1 || i > c_num_tiles) mode = CP_InvalidValue;
2939 		else if (i == -1) mode = CP_Canceled;
2940 		else if (!input[0]) {
2941 			mode = CP_XCoord;
2942 			command = 'd';
2943 		} else {
2944 			prev = i;
2945 			mode = CP_YCoord;
2946 			command = 'e';
2947 		}
2948 		break;
2949 
2950 	case 'e':   // dec Y coord
2951 		if (i < -1 || i > c_num_tiles) mode = CP_InvalidValue;
2952 		else if (i == -1) mode = CP_Canceled;
2953 		else if (!input[0]) {
2954 			mode = CP_YCoord;
2955 			command = 'e';
2956 		} else {
2957 			t.tx = prev;
2958 			t.ty = i;
2959 			t.tz = 0;
2960 			gwin->teleport_party(t);
2961 		}
2962 		break;
2963 
2964 	case 'n':   // NPC
2965 		if (i < -1 || (i >= 356 && i <= 359)) mode = CP_InvalidNPC;
2966 		else if (i == -1) mode = CP_Canceled;
2967 		else {
2968 			Actor *actor = gwin->get_npc(i);
2969 			Game_window::get_instance()->teleport_party(actor->get_tile(),
2970 			false, actor->get_map_num());
2971 		}
2972 		break;
2973 
2974 	case 'm':   // map
2975 		if (i == -1) mode = CP_Canceled;
2976 		else if ((i < 0 || i > 255) || i > highest) mode = CP_InvalidValue;
2977 		else
2978 			gwin->teleport_party(gwin->get_main_actor()->get_tile(), true, i);
2979 		break;
2980 
2981 	default:
2982 		break;
2983 	}
2984 	for (i = 0; i < 5; i++) input[i] = 0;
2985 }
2986 
2987 // Checks the input
TeleportCheck(char * input,int & command,Cheat_Prompt & mode,bool & activate)2988 bool CheatScreen::TeleportCheck(char *input, int &command, Cheat_Prompt &mode, bool &activate) {
2989 	ignore_unused_variable_warning(activate);
2990 	switch (command) {
2991 		// Simple commands
2992 	case 'g':   // geographic
2993 		mode = CP_NorthSouth;
2994 		return true;
2995 
2996 	case 'h':   // hex
2997 		mode = CP_HexXCoord;
2998 		return true;
2999 
3000 	case 'd':   // dec teleport
3001 		mode = CP_XCoord;
3002 		return true;
3003 
3004 	case 'n':   // NPC teleport
3005 		mode = CP_ChooseNPC;
3006 		break;
3007 
3008 	case 'm':   // NPC teleport
3009 		mode = CP_EnterValue;
3010 		break;
3011 
3012 		// X and Escape leave
3013 	case SDLK_ESCAPE:
3014 	case 'x':
3015 		input[0] = command;
3016 		return false;
3017 
3018 	default:
3019 		command = 0;
3020 		mode = CP_InvalidCom;
3021 		break;
3022 	}
3023 
3024 	return true;
3025 }
3026