1 /***********************************************************************************
2   Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 
4   (c) Copyright 1996 - 2002  Gary Henderson (gary.henderson@ntlworld.com),
5                              Jerremy Koot (jkoot@snes9x.com)
6 
7   (c) Copyright 2002 - 2004  Matthew Kendora
8 
9   (c) Copyright 2002 - 2005  Peter Bortas (peter@bortas.org)
10 
11   (c) Copyright 2004 - 2005  Joel Yliluoma (http://iki.fi/bisqwit/)
12 
13   (c) Copyright 2001 - 2006  John Weidman (jweidman@slip.net)
14 
15   (c) Copyright 2002 - 2006  funkyass (funkyass@spam.shaw.ca),
16                              Kris Bleakley (codeviolation@hotmail.com)
17 
18   (c) Copyright 2002 - 2010  Brad Jorsch (anomie@users.sourceforge.net),
19                              Nach (n-a-c-h@users.sourceforge.net),
20 
21   (c) Copyright 2002 - 2011  zones (kasumitokoduck@yahoo.com)
22 
23   (c) Copyright 2006 - 2007  nitsuja
24 
25   (c) Copyright 2009 - 2016  BearOso,
26                              OV2
27 
28 
29   BS-X C emulator code
30   (c) Copyright 2005 - 2006  Dreamer Nom,
31                              zones
32 
33   C4 x86 assembler and some C emulation code
34   (c) Copyright 2000 - 2003  _Demo_ (_demo_@zsnes.com),
35                              Nach,
36                              zsKnight (zsknight@zsnes.com)
37 
38   C4 C++ code
39   (c) Copyright 2003 - 2006  Brad Jorsch,
40                              Nach
41 
42   DSP-1 emulator code
43   (c) Copyright 1998 - 2006  _Demo_,
44                              Andreas Naive (andreasnaive@gmail.com),
45                              Gary Henderson,
46                              Ivar (ivar@snes9x.com),
47                              John Weidman,
48                              Kris Bleakley,
49                              Matthew Kendora,
50                              Nach,
51                              neviksti (neviksti@hotmail.com)
52 
53   DSP-2 emulator code
54   (c) Copyright 2003         John Weidman,
55                              Kris Bleakley,
56                              Lord Nightmare (lord_nightmare@users.sourceforge.net),
57                              Matthew Kendora,
58                              neviksti
59 
60   DSP-3 emulator code
61   (c) Copyright 2003 - 2006  John Weidman,
62                              Kris Bleakley,
63                              Lancer,
64                              z80 gaiden
65 
66   DSP-4 emulator code
67   (c) Copyright 2004 - 2006  Dreamer Nom,
68                              John Weidman,
69                              Kris Bleakley,
70                              Nach,
71                              z80 gaiden
72 
73   OBC1 emulator code
74   (c) Copyright 2001 - 2004  zsKnight,
75                              pagefault (pagefault@zsnes.com),
76                              Kris Bleakley
77                              Ported from x86 assembler to C by sanmaiwashi
78 
79   SPC7110 and RTC C++ emulator code used in 1.39-1.51
80   (c) Copyright 2002         Matthew Kendora with research by
81                              zsKnight,
82                              John Weidman,
83                              Dark Force
84 
85   SPC7110 and RTC C++ emulator code used in 1.52+
86   (c) Copyright 2009         byuu,
87                              neviksti
88 
89   S-DD1 C emulator code
90   (c) Copyright 2003         Brad Jorsch with research by
91                              Andreas Naive,
92                              John Weidman
93 
94   S-RTC C emulator code
95   (c) Copyright 2001 - 2006  byuu,
96                              John Weidman
97 
98   ST010 C++ emulator code
99   (c) Copyright 2003         Feather,
100                              John Weidman,
101                              Kris Bleakley,
102                              Matthew Kendora
103 
104   Super FX x86 assembler emulator code
105   (c) Copyright 1998 - 2003  _Demo_,
106                              pagefault,
107                              zsKnight
108 
109   Super FX C emulator code
110   (c) Copyright 1997 - 1999  Ivar,
111                              Gary Henderson,
112                              John Weidman
113 
114   Sound emulator code used in 1.5-1.51
115   (c) Copyright 1998 - 2003  Brad Martin
116   (c) Copyright 1998 - 2006  Charles Bilyue'
117 
118   Sound emulator code used in 1.52+
119   (c) Copyright 2004 - 2007  Shay Green (gblargg@gmail.com)
120 
121   S-SMP emulator code used in 1.54+
122   (c) Copyright 2016         byuu
123 
124   SH assembler code partly based on x86 assembler code
125   (c) Copyright 2002 - 2004  Marcus Comstedt (marcus@mc.pp.se)
126 
127   2xSaI filter
128   (c) Copyright 1999 - 2001  Derek Liauw Kie Fa
129 
130   HQ2x, HQ3x, HQ4x filters
131   (c) Copyright 2003         Maxim Stepin (maxim@hiend3d.com)
132 
133   NTSC filter
134   (c) Copyright 2006 - 2007  Shay Green
135 
136   GTK+ GUI code
137   (c) Copyright 2004 - 2016  BearOso
138 
139   Win32 GUI code
140   (c) Copyright 2003 - 2006  blip,
141                              funkyass,
142                              Matthew Kendora,
143                              Nach,
144                              nitsuja
145   (c) Copyright 2009 - 2016  OV2
146 
147   Mac OS GUI code
148   (c) Copyright 1998 - 2001  John Stiles
149   (c) Copyright 2001 - 2011  zones
150 
151 
152   Specific ports contains the works of other authors. See headers in
153   individual files.
154 
155 
156   Snes9x homepage: http://www.snes9x.com/
157 
158   Permission to use, copy, modify and/or distribute Snes9x in both binary
159   and source form, for non-commercial purposes, is hereby granted without
160   fee, providing that this license information and copyright notice appear
161   with all copies and any derived work.
162 
163   This software is provided 'as-is', without any express or implied
164   warranty. In no event shall the authors be held liable for any damages
165   arising from the use of this software or it's derivatives.
166 
167   Snes9x is freeware for PERSONAL USE only. Commercial users should
168   seek permission of the copyright holders first. Commercial use includes,
169   but is not limited to, charging money for Snes9x or software derived from
170   Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
171   using Snes9x as a promotion for your commercial product.
172 
173   The copyright holders request that bug fixes and improvements to the code
174   should be forwarded to them so everyone can benefit from the modifications
175   in future versions.
176 
177   Super NES and Super Nintendo Entertainment System are trademarks of
178   Nintendo Co., Limited and its subsidiary companies.
179  ***********************************************************************************/
180 
181 /***********************************************************************************
182   SNES9X for Mac OS (c) Copyright John Stiles
183 
184   Snes9x for Mac OS X
185 
186   (c) Copyright 2001 - 2011  zones
187   (c) Copyright 2002 - 2005  107
188   (c) Copyright 2002         PB1400c
189   (c) Copyright 2004         Alexander and Sander
190   (c) Copyright 2004 - 2005  Steven Seeger
191   (c) Copyright 2005         Ryan Vogt
192  ***********************************************************************************/
193 
194 
195 #include "port.h"
196 #include "cheats.h"
197 
198 #define __STDC_FORMAT_MACROS
199 #include <inttypes.h>
200 
201 #include "mac-prefix.h"
202 #include "mac-dialog.h"
203 #include "mac-os.h"
204 #include "mac-stringtools.h"
205 #include "mac-cheat.h"
206 
207 #define	kDataBrowser	'BRSR'
208 #define	kCmCheckBox		'CHK_'
209 #define	kCmAddress		'ADDR'
210 #define	kCmValue		'VALU'
211 #define	kCmDescription	'DESC'
212 #define	kNewButton		'NEW_'
213 #define	kDelButton		'DEL_'
214 #define	kAllButton		'ALL_'
215 
216 extern SCheatData	Cheat;
217 
218 typedef struct
219 {
220 	uint32	id;
221 	uint32	address;
222 	uint8	value;
223 	bool8	valid;
224 	bool8	enabled;
225 	char	description[22];
226 }	CheatItem;
227 
228 static WindowRef	wRef;
229 static HIViewRef	dbRef;
230 static CheatItem	citem[MAX_CHEATS];
231 static uint32		numofcheats;
232 
233 static void InitCheatItems (void);
234 static void ImportCheatItems (void);
235 static void DetachCheatItems (void);
236 static void AddCheatItem (void);
237 static void DeleteCheatItem (void);
238 static void EnableAllCheatItems (void);
239 static pascal void DBItemNotificationCallBack (HIViewRef, DataBrowserItemID, DataBrowserItemNotification);
240 static pascal Boolean DBCompareCallBack (HIViewRef, DataBrowserItemID, DataBrowserItemID, DataBrowserPropertyID);
241 static pascal OSStatus DBClientDataCallback (HIViewRef, DataBrowserItemID, DataBrowserPropertyID, DataBrowserItemDataRef, Boolean);
242 static pascal OSStatus CheatEventHandler (EventHandlerCallRef, EventRef, void *);
243 
244 
InitCheatItems(void)245 static void InitCheatItems (void)
246 {
247 	for (unsigned int i = 0; i < MAX_CHEATS; i++)
248 	{
249 		citem[i].id      = i + 1;
250 		citem[i].valid   = false;
251 		citem[i].enabled = false;
252 		citem[i].address = 0;
253 		citem[i].value   = 0;
254 		sprintf(citem[i].description, "Cheat %03" PRIu32, citem[i].id);
255 	}
256 }
257 
ImportCheatItems(void)258 static void ImportCheatItems (void)
259 {
260 	for (unsigned int i = 0; i < Cheat.num_cheats; i++)
261 	{
262 		citem[i].valid   = true;
263 		citem[i].enabled = Cheat.c[i].enabled;
264 		citem[i].address = Cheat.c[i].address;
265 		citem[i].value   = Cheat.c[i].byte;
266 		strcpy(citem[i].description, Cheat.c[i].name);
267 	}
268 }
269 
DetachCheatItems(void)270 static void DetachCheatItems (void)
271 {
272 	S9xDeleteCheats(); // Cheat.num_cheats = 0
273 
274 	for (unsigned int i = 0; i < MAX_CHEATS; i++)
275 	{
276 		if (citem[i].valid)
277 		{
278 			strcpy(Cheat.c[Cheat.num_cheats].name, citem[i].description);
279 			S9xAddCheat(citem[i].enabled, false, citem[i].address, citem[i].value); // Cheat.num_cheats++
280 		}
281 	}
282 
283 	S9xApplyCheats();
284 }
285 
ConfigureCheat(void)286 void ConfigureCheat (void)
287 {
288 	if (!cartOpen)
289 		return;
290 
291 	OSStatus	err;
292 	IBNibRef	nibRef;
293 
294 	err = CreateNibReference(kMacS9XCFString, &nibRef);
295 	if (err == noErr)
296 	{
297 		err = CreateWindowFromNib(nibRef, CFSTR("CheatEntry"), &wRef);
298 		if (err == noErr)
299 		{
300 			DataBrowserCallbacks	callbacks;
301 			EventHandlerRef			eref;
302 			EventHandlerUPP			eUPP;
303 			EventTypeSpec			events[] = { { kEventClassCommand, kEventCommandProcess      },
304 												 { kEventClassCommand, kEventCommandUpdateStatus },
305 												 { kEventClassWindow,  kEventWindowClose         } };
306 			HIViewRef				ctl, root;
307 			HIViewID				cid;
308 
309 			root = HIViewGetRoot(wRef);
310 			cid.id = 0;
311 			cid.signature = kDataBrowser;
312 			HIViewFindByID(root, cid, &dbRef);
313 
314 		#ifdef MAC_PANTHER_SUPPORT
315 			if (systemVersion < 0x1040)
316 			{
317 				HISize	minSize;
318 				Rect	rct;
319 
320 				GetWindowBounds(wRef, kWindowContentRgn, &rct);
321 				minSize.width  = (float) (rct.right  - rct.left);
322 				minSize.height = (float) (rct.bottom - rct.top );
323 				err = SetWindowResizeLimits(wRef, &minSize, NULL);
324 			}
325 		#endif
326 
327 			callbacks.version = kDataBrowserLatestCallbacks;
328 			err = InitDataBrowserCallbacks(&callbacks);
329 			callbacks.u.v1.itemDataCallback = NewDataBrowserItemDataUPP(DBClientDataCallback);
330 			callbacks.u.v1.itemCompareCallback = NewDataBrowserItemCompareUPP(DBCompareCallBack);
331 			callbacks.u.v1.itemNotificationCallback = NewDataBrowserItemNotificationUPP(DBItemNotificationCallBack);
332 			err = SetDataBrowserCallbacks(dbRef, &callbacks);
333 
334 			if (systemVersion >= 0x1040)
335 				err = DataBrowserChangeAttributes(dbRef, kDataBrowserAttributeListViewAlternatingRowColors, kDataBrowserAttributeNone);
336 
337 			InitCheatItems();
338 			ImportCheatItems();
339 
340 			DataBrowserItemID	*id;
341 
342 			id = new DataBrowserItemID[MAX_CHEATS];
343 			if (!id)
344 				QuitWithFatalError(0, "cheat 01");
345 
346 			numofcheats = 0;
347 
348 			for (unsigned int i = 0; i < MAX_CHEATS; i++)
349 			{
350 				if (citem[i].valid)
351 				{
352 					id[numofcheats] = citem[i].id;
353 					numofcheats++;
354 				}
355 			}
356 
357 			if (numofcheats)
358 				err = AddDataBrowserItems(dbRef, kDataBrowserNoItem, numofcheats, id, kDataBrowserItemNoProperty);
359 
360 			delete [] id;
361 
362 			cid.signature = kNewButton;
363 			HIViewFindByID(root, cid, &ctl);
364 			if (numofcheats == MAX_CHEATS)
365 				err = DeactivateControl(ctl);
366 			else
367 				err = ActivateControl(ctl);
368 
369 			cid.signature = kAllButton;
370 			HIViewFindByID(root, cid, &ctl);
371 			if (numofcheats == 0)
372 				err = DeactivateControl(ctl);
373 			else
374 				err = ActivateControl(ctl);
375 
376 			cid.signature = kDelButton;
377 			HIViewFindByID(root, cid, &ctl);
378 			err = DeactivateControl(ctl);
379 
380 			eUPP = NewEventHandlerUPP(CheatEventHandler);
381 			err = InstallWindowEventHandler(wRef, eUPP, GetEventTypeCount(events), events, (void *) wRef, &eref);
382 
383 			err = SetKeyboardFocus(wRef, dbRef, kControlFocusNextPart);
384 
385 			MoveWindowPosition(wRef, kWindowCheatEntry, true);
386 			ShowWindow(wRef);
387 			err = RunAppModalLoopForWindow(wRef);
388 			HideWindow(wRef);
389 			SaveWindowPosition(wRef, kWindowCheatEntry);
390 
391 			err = RemoveEventHandler(eref);
392 			DisposeEventHandlerUPP(eUPP);
393 
394 			DisposeDataBrowserItemNotificationUPP(callbacks.u.v1.itemNotificationCallback);
395 			DisposeDataBrowserItemCompareUPP(callbacks.u.v1.itemCompareCallback);
396 			DisposeDataBrowserItemDataUPP(callbacks.u.v1.itemDataCallback);
397 
398 			CFRelease(wRef);
399 
400 			DetachCheatItems();
401 		}
402 
403 		DisposeNibReference(nibRef);
404 	}
405 }
406 
AddCheatItem(void)407 static void AddCheatItem (void)
408 {
409 	OSStatus			err;
410 	HIViewRef			ctl, root;
411 	HIViewID			cid;
412 	DataBrowserItemID	id[1];
413 	unsigned int		i;
414 
415 	if (numofcheats == MAX_CHEATS)
416 		return;
417 
418 	for (i = 0; i < MAX_CHEATS; i++)
419 		if (citem[i].valid == false)
420 			break;
421 
422 	if (i == MAX_CHEATS)
423 		return;
424 
425 	numofcheats++;
426 	citem[i].valid   = true;
427 	citem[i].enabled = false;
428 	citem[i].address = 0;
429 	citem[i].value   = 0;
430 	sprintf(citem[i].description, "Cheat %03" PRIu32, citem[i].id);
431 
432 	id[0] = citem[i].id;
433 	err = AddDataBrowserItems(dbRef, kDataBrowserNoItem, 1, id, kDataBrowserItemNoProperty);
434 	err = RevealDataBrowserItem(dbRef, id[0], kCmAddress, true);
435 
436 	root = HIViewGetRoot(wRef);
437 	cid.id = 0;
438 
439 	if (numofcheats == MAX_CHEATS)
440 	{
441 		cid.signature = kNewButton;
442 		HIViewFindByID(root, cid, &ctl);
443 		err = DeactivateControl(ctl);
444 	}
445 
446 	if (numofcheats)
447 	{
448 		cid.signature = kAllButton;
449 		HIViewFindByID(root, cid, &ctl);
450 		err = ActivateControl(ctl);
451 	}
452 }
453 
DeleteCheatItem(void)454 static void DeleteCheatItem (void)
455 {
456 	OSStatus	err;
457 	HIViewRef	ctl, root;
458 	HIViewID	cid;
459 	Handle		selectedItems;
460 	ItemCount	selectionCount;
461 
462 	selectedItems = NewHandle(0);
463 	if (!selectedItems)
464 		return;
465 
466 	err = GetDataBrowserItems(dbRef, kDataBrowserNoItem, true, kDataBrowserItemIsSelected, selectedItems);
467 	selectionCount = (GetHandleSize(selectedItems) / sizeof(DataBrowserItemID));
468 
469 	if (selectionCount == 0)
470 	{
471 		DisposeHandle(selectedItems);
472 		return;
473 	}
474 
475 	err = RemoveDataBrowserItems(dbRef, kDataBrowserNoItem, selectionCount, (DataBrowserItemID *) *selectedItems, kDataBrowserItemNoProperty);
476 
477 	for (unsigned int i = 0; i < selectionCount; i++)
478 	{
479 		citem[((DataBrowserItemID *) (*selectedItems))[i] - 1].valid   = false;
480 		citem[((DataBrowserItemID *) (*selectedItems))[i] - 1].enabled = false;
481 		numofcheats--;
482 	}
483 
484 	DisposeHandle(selectedItems);
485 
486 	root = HIViewGetRoot(wRef);
487 	cid.id = 0;
488 
489 	if (numofcheats < MAX_CHEATS)
490 	{
491 		cid.signature = kNewButton;
492 		HIViewFindByID(root, cid, &ctl);
493 		err = ActivateControl(ctl);
494 	}
495 
496 	if (numofcheats == 0)
497 	{
498 		cid.signature = kAllButton;
499 		HIViewFindByID(root, cid, &ctl);
500 		err = DeactivateControl(ctl);
501 	}
502 }
503 
EnableAllCheatItems(void)504 static void EnableAllCheatItems (void)
505 {
506 	OSStatus	err;
507 
508 	for (unsigned int i = 0; i < MAX_CHEATS; i++)
509 		if (citem[i].valid)
510 			citem[i].enabled = true;
511 
512 	err = UpdateDataBrowserItems(dbRef, kDataBrowserNoItem, kDataBrowserNoItem, NULL, kDataBrowserItemNoProperty, kCmCheckBox);
513 }
514 
DBClientDataCallback(HIViewRef browser,DataBrowserItemID itemID,DataBrowserPropertyID property,DataBrowserItemDataRef itemData,Boolean changeValue)515 static pascal OSStatus DBClientDataCallback (HIViewRef browser, DataBrowserItemID itemID, DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean changeValue)
516 {
517 	OSStatus 	err, result;
518 	CFStringRef	str;
519 	Boolean		r;
520 	uint32		address;
521 	uint8		value;
522 	char		code[256];
523 
524 	result = noErr;
525 
526 	switch (property)
527 	{
528 		case kCmCheckBox:
529 			ThemeButtonValue	buttonValue;
530 
531             if (changeValue)
532 			{
533 				err = GetDataBrowserItemDataButtonValue(itemData, &buttonValue);
534 				citem[itemID - 1].enabled = (buttonValue == kThemeButtonOn) ? true : false;
535  	        }
536 			else
537 				err = SetDataBrowserItemDataButtonValue(itemData, citem[itemID - 1].enabled ? kThemeButtonOn : kThemeButtonOff);
538 
539 			break;
540 
541 		case kCmAddress:
542 			if (changeValue)
543 			{
544 				err = GetDataBrowserItemDataText(itemData, &str);
545 				r = CFStringGetCString(str, code, 256, CFStringGetSystemEncoding());
546 				CFRelease(str);
547 				if (r)
548 				{
549 					Boolean	translated;
550 
551 					if (S9xProActionReplayToRaw(code, address, value) == NULL)
552 						translated = true;
553 					else
554 					if (S9xGameGenieToRaw(code, address, value) == NULL)
555 						translated = true;
556 					else
557 					{
558 						translated = false;
559 						if (sscanf(code, "%" SCNx32, &address) != 1)
560 							address = 0;
561 						else
562 							address &= 0xFFFFFF;
563 					}
564 
565 					citem[itemID - 1].address = address;
566 					sprintf(code, "%06" PRIX32, address);
567 					str = CFStringCreateWithCString(kCFAllocatorDefault, code, CFStringGetSystemEncoding());
568 					err = SetDataBrowserItemDataText(itemData, str);
569 					CFRelease(str);
570 
571 					if (translated)
572 					{
573 						DataBrowserItemID	id[1];
574 
575 						citem[itemID - 1].value = value;
576 						id[0] = itemID;
577 						err = UpdateDataBrowserItems(browser, kDataBrowserNoItem, 1, id, kDataBrowserItemNoProperty, kCmValue);
578 					}
579 				}
580 			}
581 			else
582 			{
583 				sprintf(code, "%06" PRIX32, citem[itemID - 1].address);
584 				str = CFStringCreateWithCString(kCFAllocatorDefault, code, CFStringGetSystemEncoding());
585 				err = SetDataBrowserItemDataText(itemData, str);
586 				CFRelease(str);
587 			}
588 
589 			break;
590 
591 		case kCmValue:
592 			if (changeValue)
593 			{
594 				err = GetDataBrowserItemDataText(itemData, &str);
595 				r = CFStringGetCString(str, code, 256, CFStringGetSystemEncoding());
596 				CFRelease(str);
597 				if (r)
598 				{
599 					uint32	byte;
600 
601 					if (sscanf(code, "%" SCNx32, &byte) == 1)
602 						citem[itemID - 1].value = (uint8) byte;
603 					else
604 					{
605 						citem[itemID - 1].value = 0;
606 						err = SetDataBrowserItemDataText(itemData, CFSTR("00"));
607 					}
608 				}
609 			}
610 			else
611 			{
612 				sprintf(code, "%02" PRIX8, citem[itemID - 1].value);
613 				str = CFStringCreateWithCString(kCFAllocatorDefault, code, CFStringGetSystemEncoding());
614 				err = SetDataBrowserItemDataText(itemData, str);
615 				CFRelease(str);
616 			}
617 
618 			break;
619 
620 		case kCmDescription:
621 			if (changeValue)
622 			{
623 				code[0] = 0;
624 				err = GetDataBrowserItemDataText(itemData, &str);
625 				strcpy(code, GetMultiByteCharacters(str, 19));
626 				CFRelease(str);
627 
628 				if (code[0] == 0)
629 				{
630 					code[0] = ' ';
631 					code[1] = 0;
632 				}
633 
634 				strcpy(citem[itemID - 1].description, code);
635 			}
636 			else
637 			{
638 				str = CFStringCreateWithCString(kCFAllocatorDefault, citem[itemID - 1].description, CFStringGetSystemEncoding());
639 				err = SetDataBrowserItemDataText(itemData, str);
640 				CFRelease(str);
641 			}
642 
643 			break;
644 
645 		case kDataBrowserItemIsActiveProperty:
646 			err = SetDataBrowserItemDataBooleanValue(itemData, true);
647 			break;
648 
649 		case kDataBrowserItemIsEditableProperty:
650 			err = SetDataBrowserItemDataBooleanValue(itemData, true);
651 			break;
652 
653 		default:
654 			result = errDataBrowserPropertyNotSupported;
655 	}
656 
657 	return (result);
658 }
659 
DBCompareCallBack(HIViewRef browser,DataBrowserItemID itemOne,DataBrowserItemID itemTwo,DataBrowserPropertyID sortProperty)660 static pascal Boolean DBCompareCallBack (HIViewRef browser, DataBrowserItemID itemOne, DataBrowserItemID itemTwo, DataBrowserPropertyID sortProperty)
661 {
662 	Boolean	result = false;
663 
664 	switch (sortProperty)
665 	{
666 		case kCmCheckBox:
667 			result = (citem[itemOne - 1].enabled && !(citem[itemTwo - 1].enabled)) ? true : false;
668 			break;
669 
670 		case kCmAddress:
671 			result = (citem[itemOne - 1].address <    citem[itemTwo - 1].address)  ? true : false;
672 			break;
673 
674 		case kCmValue:
675 			result = (citem[itemOne - 1].value   <    citem[itemTwo - 1].value)    ? true : false;
676 			break;
677 
678 		case kCmDescription:
679 			result = (strcmp(citem[itemOne - 1].description, citem[itemTwo - 1].description) < 0) ? true : false;
680 	}
681 
682 	return (result);
683 }
684 
DBItemNotificationCallBack(HIViewRef browser,DataBrowserItemID itemID,DataBrowserItemNotification message)685 static pascal void DBItemNotificationCallBack (HIViewRef browser, DataBrowserItemID itemID, DataBrowserItemNotification message)
686 {
687 	OSStatus	err;
688 	HIViewRef	ctl;
689 	HIViewID	cid = { kDelButton, 0 };
690 	ItemCount	selectionCount;
691 
692 	switch (message)
693 	{
694 		case kDataBrowserSelectionSetChanged:
695 			HIViewFindByID(HIViewGetRoot(wRef), cid, &ctl);
696 
697 			err = GetDataBrowserItemCount(browser, kDataBrowserNoItem, true, kDataBrowserItemIsSelected, &selectionCount);
698 			if (selectionCount == 0)
699 				err = DeactivateControl(ctl);
700 			else
701 				err = ActivateControl(ctl);
702 	}
703 }
704 
CheatEventHandler(EventHandlerCallRef inHandlerCallRef,EventRef inEvent,void * inUserData)705 static pascal OSStatus CheatEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
706 {
707 	OSStatus	err, result = eventNotHandledErr;
708 	WindowRef	tWindowRef;
709 
710 	tWindowRef = (WindowRef) inUserData;
711 
712 	switch (GetEventClass(inEvent))
713 	{
714 		case kEventClassWindow:
715 			switch (GetEventKind(inEvent))
716 			{
717 				case kEventWindowClose:
718 					QuitAppModalLoopForWindow(tWindowRef);
719 					result = noErr;
720 					break;
721 			}
722 
723 			break;
724 
725 		case kEventClassCommand:
726 			switch (GetEventKind(inEvent))
727 			{
728 				HICommand	tHICommand;
729 
730 				case kEventCommandUpdateStatus:
731 					err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
732 					if (err == noErr && tHICommand.commandID == 'clos')
733 					{
734 						UpdateMenuCommandStatus(true);
735 						result = noErr;
736 					}
737 
738 					break;
739 
740 				case kEventCommandProcess:
741 					err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
742 					if (err == noErr)
743 					{
744 						switch (tHICommand.commandID)
745 						{
746 							case kNewButton:
747 								AddCheatItem();
748 								result = noErr;
749 								break;
750 
751 							case kDelButton:
752 								DeleteCheatItem();
753 								result = noErr;
754 								break;
755 
756 							case kAllButton:
757 								EnableAllCheatItems();
758 								result = noErr;
759 						}
760 					}
761 			}
762 	}
763 
764 	return (result);
765 }
766