cheating

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
User avatar
never-obsolete
Posts: 403
Joined: Wed Sep 07, 2005 9:55 am
Location: Phoenix, AZ
Contact:

cheating

Post by never-obsolete »

i had a friend of mine beta testing my Pitfall! clone and his skills are terrible. i decided to put a cheat code in to help him out and this i what i came up with:

Code: Select all

	ldx cheatIndex			; if button_index >= cheat_length
	cpx #08
	bcs _cheat_Activate		;     branch to set cheat == ACTIVE
	lda P1Joypad			; if cur_pressed == cur_button
	cmp cheatCodeData, X
	beq _cheat_gotoNextButton	;     branch to check next button on next loop

_cheat_checkPrevButton:	dex		; else button didn't match
	cpx #$FF
	beq _cheat_resetIndex
	cmp cheatCodeData, X		;     so check if cur_pressed == prev_button
	beq _cheat_HangOnPrevButton	;         branch to wait for another frame

_cheat_resetIndex:	ldx #00		;     else reset button index
	stx cheatIndex
	jmp _cheat_ExitCheck

_cheat_gotoNextButton:	inx		; button matched so move on to next
	stx cheatIndex
	jmp _cheat_ExitCheck

_cheat_Activate:	lda #01		; all 8 buttons matched so set cheat==true
	sta cheatActive

_cheat_HangOnPrevButton:
_cheat_ExitCheck:
i think it works nicely. has anyone else ever implemented a cheat system in their projects? i'd like to know how mine stacks up.

edit: should proabably describe it

so each frame of the title screen it checks the currently pressed buttons against a sequence of button presses.

1. if the sequence index(cheatIndex) is greater then the sequence size (8), the cheat is enabled.
2. else if the current pressed button matches the next button in sequence, the sequence index is incremented and then wait for another loop
3. if #2 fails, then the current pressed button is compared to the previous button in sequence. if it matches the, the code hangs for another loop.
4. else it resets the sequence index and we repeat.

if the whole process takes too long, then the cheat is no longer available
. That's just like, your opinion, man .
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

I really liked your idea, but I feel that the implementation could be better. Here's my shot at it:

Code: Select all

	lda ButtonsJustPressed
	beq NoChange	;If nothing was pressed, there is nothing to do

	;Compare against the first cheat sequence
	ldx Cheat1Index	;Index of the value to match
	cmp Cheat1, x	;Compare with the current buttons
	bne Cheat1Reset	;If they are different, go reset the sequence
	dec Cheat1Index ;Move closer to the end of the sequence
	bpl Cheat1End	;Skip if we're not at the end of the sequence
	;->ENABLE CHEAT HERE<-
Cheat1Reset:
	ldx #Cheat1StartIndex	;Go back to the start of the sequence
	stx Cheat1Index
Cheat1End:

	;Compare against the second cheat sequence
	ldx Cheat2Index
	cmp Cheat2, x
	bne Cheat2Reset
	dec Cheat2Index
	bpl Cheat2End
	;->ENABLE CHEAT HERE<-
Chaet2Reset:
	ldx #Cheat2StartIndex
	stx Cheat2Index
Cheat2End:

NoChange:
First of all, the byte that holds the state of the buttons must only indicate buttons that were just pressed (the NewButtons XOR OldButtons AND NewButtons trick), and not the current snapshot of the controller. This saves you from having to compare against the previous index. Most games keep track of both types of keypresses, for things such as pausing (you only need to know if "start" was just pressed in order to pause, and you are not interested if was kept down for a few frames - in fact, that would unpause the game in the very next frame, and that'd be nasty).

Second, I'm scanning the cheat sequence backwards, because it's easier to detect if the index wrapped from 0 to 255, and that is the condition that indicates that the sequence was completed.

Also, in the code above, I'm supporting 2 different cheats, each with it's own button sequence, but more could be added without problems. I just commented the first one, because the second uses the exact same logic.

Note that I haven't tested this, this is just an idea, so there are probably bugs. One that I just thought of, which may not be a bug, is that it is possible to perform the whole button sequence while keeping pressed a button that does not belong to the sequence. To fix that you could probably load A with the current snapshot of the controller right after the "beq NoChange" command. That would make the code only run when something was pressed, but the whole controller must be as specified in the cheat sequence table.
User avatar
never-obsolete
Posts: 403
Joined: Wed Sep 07, 2005 9:55 am
Location: Phoenix, AZ
Contact:

Post by never-obsolete »

your implementation is much more elegant. :)
tokumaru wrote: First of all, the byte that holds the state of the buttons must only indicate buttons that were just pressed (the NewButtons XOR OldButtons AND NewButtons trick), and not the current snapshot of the controller. This saves you from having to compare against the previous index. Most games keep track of both types of keypresses, for things such as pausing (you only need to know if "start" was just pressed in order to pause, and you are not interested if was kept down for a few frames - in fact, that would unpause the game in the very next frame, and that'd be nasty).
the P1Joypad is a hangover from checking for START to skip the scrolling title screen (a la smb3's curtain intro) irregardless if it was newly pressed or held. though i did have that "start" problem earlier on in development with the menu system.

this game has some nasty code. most of it was from the early stages of development when i had little experience in a project this large. then i just got too lazy to fix what wasn't broke. i was able to salvage and clean up a lot of code for use in 2 other projects i started.
. That's just like, your opinion, man .
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

never-obsolete wrote:your implementation is much more elegant. :)
I had never thought of implementing cheats the way you described. I liked the idea so much that I had to try! =)
the P1Joypad is a hangover from checking for START to skip the scrolling title screen (a la smb3's curtain intro) irregardless if it was newly pressed or held. though i did have that "start" problem earlier on in development with the menu system.
Yeah, there are many places in a game, mostly ouside of the main game engine, where all you are interested in are the buttons that were just pressed, or else cursors would fly through the options because a person usually keeps the buttons pressed for longer than a frame. This is the trick I talked about:

Code: Select all

	lda NewButtons
	eor OldButtons
	and NewButtons
This will result in a byte with 1's indicating buttons that were just pressed, and whatever was already pressed in the previous frame is ignored. It is very useful to keep track of both types of keypresses.
this game has some nasty code. most of it was from the early stages of development when i had little experience in a project this large.
I know how it works! =) In fact, I always find myself rewriting code, and that must be one of the reasons I never finish anything!
then i just got too lazy to fix what wasn't broke.
Probably a very wise decision!
User avatar
never-obsolete
Posts: 403
Joined: Wed Sep 07, 2005 9:55 am
Location: Phoenix, AZ
Contact:

Post by never-obsolete »

I had never thought of implementing cheats the way you described.
what ways have you tought of? this was the only way i could come up with for a Konomi code type cheat.

Code: Select all

 lda NewButtons 
 eor OldButtons 
 and NewButtons
i do something similar:

Code: Select all

 lda JoypadOld
 eor #$FF
 and JoypadCurrent
. That's just like, your opinion, man .
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

never-obsolete wrote:what ways have you tought of? this was the only way i could come up with for a Konomi code type cheat.
You don't want to know. =) The only time I ever implemented cheats like these was back when I made QBasic games, and wasn't able to program anything else. I used to keep the codes of the last N pressed keys in a string (N being the largest a cheat code could be), then I'd check the end of that string against strings containing the cheats. This worked fine in QBasic, but in assembly your idea has to be the best.
Post Reply