5 // Created by Chaz McGarvey on 12/26/04.
6 // Copyright 2004 Chaz McGarvey. All rights reserved.
9 #import "CheatDocument.h"
12 @interface CheatDocument (DocumentActionsPrivateAPI
)
14 - (void)_confirmTargetChange
:(NSWindow
*)sheet returnCode
:(int)returnCode context
:(void *)contextInfo
;
19 @implementation CheatDocument ( DocumentActions
)
22 - (IBAction
)ibSetLocalCheater
:(id)sender
24 ChazLog( @
"Selected %@", sender
);
26 // if this is the current server, don't reconnect
27 if ( ![self shouldConnectWithServer
:sender
] ) {
31 // disconnect and prepare to reconnect
32 [self disconnectFromCheater
];
33 [self connectWithServer
:sender
];
35 // create new local cheater
36 _cheater
= [[LocalCheater alloc
] initWithDelegate
:self];
37 [(LocalCheater
*)_cheater setShouldCopy
:YES
];
39 // send initial messages
41 [_cheater getProcessList
];
43 // send preferences to the cheater
44 [_cheater limitReturnedResults
:[[NSUserDefaults standardUserDefaults
] integerForKey
:TCHitsDisplayedPref
]];
46 [ibStatusText setDefaultStatus
:[self defaultStatusString
]];
49 - (IBAction
)ibSetRemoteCheater
:(id)sender
51 ChazLog( @
"Selected %@", sender
);
53 if ( ![self shouldConnectWithServer
:sender
] ) {
57 ChazLog( @
"resolving rendezvous service..." );
59 _resolvingService
= [[sender representedObject
] retain
];
60 [_resolvingService setDelegate
:self];
61 [_resolvingService resolve
];
64 - (void)netServiceDidResolveAddress
:(NSNetService
*)sender
68 ChazLog( @
"service resolved!" );
73 if ( sender
!= _resolvingService
) {
77 [self disconnectFromCheater
];
78 [self connectWithServer
:(NSMenuItem
*)[ibServerPopup itemAtIndex
:[ibServerPopup indexOfItemWithRepresentedObject
:_resolvingService
]]];
80 addresses
= [_resolvingService addresses
];
82 _resolvingService
= nil;
84 // create new remote cheater
85 ChazLog( @
"found %i addresses", [addresses count
] );
86 _cheater
= [[RemoteCheater alloc
] initWithDelegate
:self];
87 [(RemoteCheater
*)_cheater connectToHostWithData
:[addresses objectAtIndex
:0]];
89 // send initial messages
91 [_cheater getProcessList
];
93 // send preferences to the cheater
94 [_cheater limitReturnedResults
:[[NSUserDefaults standardUserDefaults
] integerForKey
:TCHitsDisplayedPref
]];
96 [ibStatusText setDefaultStatus
:[self defaultStatusString
]];
97 [self updateInterface
];
100 - (void)netService
:(NSNetService
*)sender didNotResolve
:(NSDictionary
*)errorDict
104 if ( sender
!= _resolvingService
) {
108 _resolvingService
= nil;
110 NSBeginInformationalAlertSheet( @
"The Cheat can't find the server.", @
"OK", nil, nil, ibWindow
, self, NULL
, NULL
, NULL
,
111 @
"The Cheat can't connect to the server \"%@\" because it can't be found.", [sender name
] );
114 - (void)netServiceDidStop
:(NSNetService
*)sender
119 - (IBAction
)ibSetCustomCheater
:(id)sender
121 RemoteCheater
*cheater
;
122 ChazLog( @
"Selected %@", [sender description
] );
124 if ( ![self shouldConnectWithServer
:sender
] ) {
128 cheater
= [[RemoteCheater alloc
] initWithDelegate
:self];
129 if ( ![(RemoteCheater
*)cheater connectToHostWithData
:[sender representedObject
]] ) {
130 NSBeginInformationalAlertSheet( @
"The Cheat can't find the server.", @
"OK", nil, nil, ibWindow
, self, NULL
, NULL
, NULL
,
131 @
"The Cheat can't connect to \"%@\" because there is no server at that address.", [sender title
] );
133 [self selectConnectedCheater
];
137 [self disconnectFromCheater
];
138 [self connectWithServer
:sender
];
142 // send initial messages
144 [_cheater getProcessList
];
146 // send preferences to the cheater
147 [_cheater limitReturnedResults
:[[NSUserDefaults standardUserDefaults
] integerForKey
:TCHitsDisplayedPref
]];
149 [ibStatusText setDefaultStatus
:[self defaultStatusString
]];
150 [self updateInterface
];
153 - (IBAction
)ibSetNoCheater
:(id)sender
155 [self disconnectFromCheater
];
158 [_serverObject release
];
161 [ibStatusText setDefaultStatus
:[self defaultStatusString
]];
162 [self updateInterface
];
165 - (IBAction
)ibSetProcess
:(id)sender
167 if ( [_process isEqual
:(Process
*)[sender representedObject
]] ) {
168 // this process is already selected, do nothing
172 if ( [_searchData hasSearchedOnce
] ) {
173 NSBeginInformationalAlertSheet( @
"Confirm target change.", @
"OK", @
"Cancel", nil, ibWindow
, self, NULL
,
174 @selector(_confirmTargetChange
:returnCode
:context
:), [[sender representedObject
] retain
],
175 @
"If you change the target now, your search will be cleared. This cannot be undone. Continue?" );
178 // request the change
179 [_cheater setTarget
:(Process
*)[sender representedObject
]];
183 - (void)_confirmTargetChange
:(NSWindow
*)sheet returnCode
:(int)returnCode context
:(void *)contextInfo
185 NSMenu
*processMenu
= [ibProcessPopup menu
];
186 Process
*process
= (Process
*)contextInfo
;
188 if ( returnCode
== NSAlertDefaultReturn
) {
190 [self ibClearSearch
:nil];
191 // request the change
192 [_cheater setTarget
:process
];
195 // select the correct server menuitem
196 [ibProcessPopup selectItemAtIndex
:[processMenu indexOfItemWithRepresentedObject
:_process
]];
203 - (IBAction
)ibSetVariableType
:(id)sender
205 [_searchData setVariableType
:[sender tag
]];
206 [self updateInterface
];
209 - (IBAction
)ibSetIntegerSign
:(id)sender
211 [_searchData setIntegerSign
:[[sender selectedCell
] tag
]];
214 - (IBAction
)ibSetOperator
:(id)sender
216 [_searchData setSearchOperator
:[sender tag
]];
219 - (IBAction
)ibSetValueUsed
:(id)sender
221 [_searchData setValueUsed
:[[sender selectedCell
] tag
]];
222 [self updateInterface
];
225 - (IBAction
)ibClearSearch
:(id)sender
227 [_cheater clearSearch
];
230 - (IBAction
)ibSearch
:(id)sender
235 if ( [_searchData valueUsed
] == TCGivenValue
) {
236 variable
= [[Variable alloc
] initWithType
:[_searchData variableType
] integerSign
:[_searchData integerSign
]];
237 [variable setStringValue
:[ibSearchValueField stringValue
]];
238 if ( [variable isValueValid
] && [variable valueSize
] > 0 ) {
239 _status
= TCSearchingStatus
;
240 [ibStatusText setDefaultStatus
:[NSString stringWithFormat
:@
"Searching %@'s memory%C", [_process name
], 0x2026]];
241 [ibStatusBar setIndeterminate
:NO
];
243 [_searchData setSearchValue
:variable
];
245 [_cheater searchForVariable
:[_searchData searchValue
] comparison
:[_searchData searchOperator
]];
248 NSBeginAlertSheet( @
"Invalid Input", @
"OK", nil, nil, ibWindow
, nil, NULL
, NULL
, NULL
,
249 @
"The search value \"%@\" cannot be used with this type of search.", [ibSearchValueField stringValue
] );
253 _status
= TCSearchingStatus
;
254 [ibStatusText setDefaultStatus
:[NSString stringWithFormat
:@
"Searching %@'s memory%C", [_process name
], 0x2026]];
255 [ibStatusBar setIndeterminate
:NO
];
257 [_cheater searchLastValuesComparison
:[_searchData searchOperator
]];
260 [self updateInterface
];
263 - (IBAction
)ibAddSearchVariable
:(id)sender
268 // don't do anything if there is nothing selected
269 if ( [ibSearchVariableTable selectedRow
] == -1 ) {
273 rows
= [ibSearchVariableTable selectedRows
];
275 for ( i
= 0; i
< top
; i
++ ) {
276 int rowIndex
= [[rows objectAtIndex
:i
] unsignedIntValue
];
277 // transfer the search variable to the cheat data
278 [_cheatData addVariable
:[_searchData variableAtIndex
:rowIndex
]];
281 // update the variable table
282 [ibCheatVariableTable reloadData
];
284 if ( [[NSUserDefaults standardUserDefaults
] boolForKey
:TCSwitchVariablesPref
] ) {
285 [self switchToCheatMode
];
287 int rowIndex
= [_cheatData variableCount
]-1;
288 if ( MacOSXVersion() >= 0x1030 ) {
289 [ibCheatVariableTable selectRowIndexes
:[NSIndexSet indexSetWithIndex
:rowIndex
] byExtendingSelection
:NO
];
292 [ibCheatVariableTable selectRow
:rowIndex byExtendingSelection
:NO
];
294 // start editing the last added variable
295 if ( [[NSUserDefaults standardUserDefaults
] boolForKey
:TCAutoStartEditingVarsPref
] ) {
298 if ( MacOSXVersion() >= 0x1030 ) {
299 [ibCheatVariableTable selectRowIndexes
:[NSIndexSet indexSetWithIndexesInRange
:NSMakeRange(rowIndex
-top
+1,top
-1)]
300 byExtendingSelection
:YES
];
303 for ( i
= 1; i
< top
; i
++ ) {
304 [ibCheatVariableTable selectRow
:rowIndex
-i byExtendingSelection
:YES
];
307 [ibCheatVariableTable scrollRowToVisible
:rowIndex
];
308 [self ibRunEditVariablesSheet
:nil];
312 [ibCheatVariableTable editColumn
:[ibCheatVariableTable columnWithIdentifier
:@
"value"]
313 row
:rowIndex withEvent
:nil select
:YES
];
319 [self setDocumentChanged
];
320 [self updateInterface
];
324 - (IBAction
)ibSetCheatRepeats
:(id)sender
326 [_cheatData setRepeats
:[sender state
]];
329 [self setDocumentChanged
];
330 [self updateInterface
];
333 - (IBAction
)ibSetRepeatInterval
:(id)sender
335 [_cheatData setRepeatInterval
:[sender doubleValue
]];
338 [self setDocumentChanged
];
339 [self updateInterface
];
342 - (IBAction
)ibCheat
:(id)sender
344 _status
= TCCheatingStatus
;
345 [_cheater makeVariableChanges
:[_cheatData enabledVariables
] repeat
:[_cheatData repeats
] interval
:[_cheatData repeatInterval
]];
347 // update status description
348 if ( [_cheatData repeats
] ) {
349 [ibStatusText setDefaultStatus
:[NSString stringWithFormat
:@
"Applying cheats to %@%C", [_process name
], 0x2026]];
350 [ibStatusBar setIndeterminate
:YES
];
351 [ibStatusBar startAnimation
:self];
353 [self updateInterface
];
358 - (IBAction
)ibRunPropertiesSheet
:(id)sender
361 [ibWindowTitleField setStringValue
:[_cheatData windowTitle
]];
362 [ibCheatInfoField setStringValue
:[_cheatData cheatInfo
]];
365 [NSApp beginSheet
:ibPropertiesSheet modalForWindow
:ibWindow modalDelegate
:nil didEndSelector
:NULL contextInfo
:nil];
368 - (IBAction
)ibEndPropertiesSheet
:(id)sender
370 [ibPropertiesSheet orderOut
:sender
];
371 [NSApp endSheet
:ibPropertiesSheet returnCode
:0];
373 if ( [sender tag
] == 1 ) {
374 // do not update anything if nothing has changed
375 if ( [[ibWindowTitleField stringValue
] isEqualToString
:[_cheatData windowTitle
]] &&
376 [[ibCheatInfoField stringValue
] isEqualToString
:[_cheatData cheatInfo
]] ) {
380 [_cheatData setWindowTitle
:[ibWindowTitleField stringValue
]];
381 [_cheatData setCheatInfo
:[ibCheatInfoField stringValue
]];
383 [self setDocumentChanged
];
384 [self updateInterface
];
389 - (IBAction
)ibRunPasswordSheet
:(id)sender
394 - (IBAction
)ibEndPasswordSheet
:(id)sender
400 - (IBAction
)ibRunCustomServerSheet
:(id)sender
403 [ibServerField setStringValue
:@
""];
404 [ibPortField setStringValue
:[NSString stringWithFormat
:@
"%i", TCDefaultListenPort
]];
407 [NSApp beginSheet
:ibCustomServerSheet modalForWindow
:ibWindow modalDelegate
:nil didEndSelector
:NULL contextInfo
:nil];
410 - (IBAction
)ibEndCustomServerSheet
:(id)sender
412 NSString
*server
= [ibServerField stringValue
];
413 int port
= [[ibPortField stringValue
] intValue
];
415 ChazLog( @
"ibEndCustomServerSheet: %@:%i", server
, port
);
417 [ibCustomServerSheet orderOut
:sender
];
418 [NSApp endSheet
:ibCustomServerSheet returnCode
:0];
420 if ( [sender tag
] == 1 ) {
421 [self connectWithURL
:[NSString stringWithFormat
:@
"cheat://%@:%i", server
, port
]];
426 - (IBAction
)ibRunEditVariablesSheet
:(id)sender
428 int row
= [ibCheatVariableTable selectedRow
];
431 // must have selected items
436 var
= [_cheatData variableAtIndex
:row
];
439 [ibNewValueField setStringValue
:[var stringValue
]];
440 [ibVariableEnableButton setState
:[var isEnabled
]];
443 [NSApp beginSheet
:ibEditVariablesSheet modalForWindow
:ibWindow modalDelegate
:nil didEndSelector
:NULL contextInfo
:nil];
446 - (IBAction
)ibEndEditVariablesSheet
:(id)sender
448 NSString
*newValue
= [ibNewValueField stringValue
];
449 BOOL enabled
= [ibVariableEnableButton state
];
453 [ibEditVariablesSheet orderOut
:sender
];
454 [NSApp endSheet
:ibEditVariablesSheet returnCode
:0];
456 if ( [sender tag
] == 0 ) {
459 if ( [newValue isEqualToString
:@
""] ) {
463 rows
= [ibCheatVariableTable selectedRows
];
466 for ( i
= 0; i
< top
; i
++ ) {
467 Variable
*var
= [_cheatData variableAtIndex
:[[rows objectAtIndex
:i
] unsignedIntValue
]];
469 [var setStringValue
:newValue
];
471 [var setEnabled
:enabled
];
474 [ibCheatVariableTable reloadData
];
476 [self setDocumentChanged
];
477 [self updateInterface
];
481 - (IBAction
)ibPauseTarget
:(id)sender
483 [_cheater pauseTarget
];
486 - (IBAction
)ibResumeTarget
:(id)sender
488 [_cheater resumeTarget
];
492 - (IBAction
)ibCancelSearch
:(id)sender
494 _isCancelingTask
= YES
;
495 [_cheater cancelSearch
];
497 [self updateInterface
];
500 - (IBAction
)ibStopCheat
:(id)sender
502 _isCancelingTask
= YES
;
503 [_cheater stopChangingVariables
];
505 [self updateInterface
];
509 - (IBAction
)ibDumpMemory
:(id)sender
511 _status
= TCDumpingStatus
;
512 [_cheater getMemoryDump
];
515 [ibStatusText setDefaultStatus
:[NSString stringWithFormat
:@
"Dumping %@'s memory%C", [_process name
], 0x2026]];
516 [ibStatusBar setIndeterminate
:YES
];
517 [ibStatusBar startAnimation
:self];
519 [self updateInterface
];
522 - (IBAction
)ibCancelDump
:(id)sender
524 _isCancelingTask
= YES
;
525 [_cheater cancelMemoryDump
];
527 [self updateInterface
];
531 - (IBAction
)ibAddCheatVariable
:(id)sender
533 ChazLog( @
"ibAddCheatVariable:" );
535 Variable
*var
= [[Variable alloc
] initWithType
:[sender tag
]];
536 // add the new variable to the doc data
537 [_cheatData addVariable
:var
];
539 // update the variable table
540 [ibCheatVariableTable reloadData
];
542 if ( [[NSUserDefaults standardUserDefaults
] boolForKey
:TCSwitchVariablesPref
] ) {
543 [self switchToCheatMode
];
545 int row
= [_cheatData variableCount
]-1;
546 if ( MacOSXVersion() >= 0x1030 ) {
547 [ibCheatVariableTable selectRowIndexes
:[NSIndexSet indexSetWithIndex
:row
] byExtendingSelection
:NO
];
550 [ibCheatVariableTable selectRow
:row byExtendingSelection
:NO
];
552 // start editing new variable
553 if ( [[NSUserDefaults standardUserDefaults
] boolForKey
:TCAutoStartEditingVarsPref
] ) {
554 [ibCheatVariableTable editColumn
:[ibCheatVariableTable columnWithIdentifier
:@
"address"] row
:row withEvent
:nil select
:YES
];
559 [self setDocumentChanged
];
560 [self updateInterface
];
563 - (IBAction
)ibSetVariableEnabled
:(id)sender
570 ChazLog( @
"ibSetVariableEnabled: %i", [sender selectedRow
] );
572 flag
= [[_cheatData variableAtIndex
:[ibCheatVariableTable selectedRow
]] isEnabled
];
574 rows
= [ibCheatVariableTable selectedRows
];
577 for ( i
= 0; i
< top
; i
++ ) {
578 Variable
*var
= [_cheatData variableAtIndex
:[[rows objectAtIndex
:i
] unsignedIntValue
]];
579 [var setEnabled
:!flag
];
583 [ibCheatVariableTable reloadData
];
584 [self setDocumentChanged
];
585 [self updateInterface
];
589 - (IBAction
)ibToggleSearchCheat
:(id)sender
591 if ( _mode
== TCCheatMode
) {
592 [self switchToSearchMode
];
594 else if ( _mode
== TCSearchMode
) {
595 [self switchToCheatMode
];
600 - (IBAction
)ibUndo
:(id)sender
605 - (IBAction
)ibRedo
:(id)sender