;Copyright (C) 1997-2006 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
;
;http://www.zsnes.com
;http://sourceforge.net/projects/zsnes
;
;This program is free software; you can redistribute it and/or
;modify it under the terms of the GNU General Public License
;version 2 as published by the Free Software Foundation.
;
;This program is distributed in the hope that it will be useful,
;but WITHOUT ANY WARRANTY; without even the implied warranty of
;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;GNU General Public License for more details.
;
;You should have received a copy of the GNU General Public License
;along with this program; if not, write to the Free Software
;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.





SECTION .text

; GUI Cheat Code Routines

AddCSCheatCode:
    cmp byte[CSInputDisplay],'_'
    je .nodisplay
    jmp .okay
.nodisplay
    ret
.okay
    mov eax,[curentryval]
    mov [curaddrvalcs],eax
    mov eax,[CSCurValue]
    mov [curvaluecs],eax
    xor ecx,ecx
    mov cl,[CheatSrcByteSize]
    inc cl
    cmp byte[CheatUpperByteOnly],0
    je .cspardisploop
    mov cl,1
.cspardispagain
    cmp dword[curvaluecs],0FFh
    jbe .cspardisploop
    shr dword[curvaluecs],8
    inc dword[curaddrvalcs]
    jmp .cspardispagain
.cspardisploop
    push ecx
    mov esi,GUICSrcTextG1
    mov ecx,3
    mov eax,[curaddrvalcs]
    add eax,7E0000h
    mov bl,[curvaluecs]
    ; write bl at address eax
    call AddCheatCode

    shr dword[curvaluecs],8
    mov byte[GUItextcolor],223

    add dword[CheatSearchYPos],10
    inc dword[curaddrvalcs]
    pop ecx
    dec ecx
    jnz near .cspardisploop
    mov byte[CheatWinMode],2
    ret

%macro SearchCMPByte 0
    mov bl,[edi]
    cmp bl,[esi]
%endmacro

%macro SearchCMP2Bytes 0
    mov bx,[edi]
    cmp bx,[esi]
%endmacro

%macro SearchCMP3Bytes 0
    push ecx
    mov ebx,[edi]
    mov ecx,[esi]
    and ebx,0FFFFFFh
    and ecx,0FFFFFFh
    cmp ebx,ecx
    pop ecx
%endmacro

%macro SearchCMP4Bytes 0
    mov ebx,[edi]
    cmp ebx,[esi]
%endmacro

%macro SearchMacro 2
    mov dl,0FEh
%%searchloop
    %2
    %1 %%nofail
    and [eax],dl
%%nofail
    inc edi
    inc esi
    cmp dl,7Fh
    jne %%noinceax
    inc eax
%%noinceax
    rol dl,1
;    loop %%searchloop
    dec ecx
    jnz %%searchloop
%endmacro

%macro SearchMacroB 1
    cmp byte[CheatCompareValue],0
    je near %%greater
    cmp byte[CheatCompareValue],1
    je near %%lessthan
    cmp byte[CheatCompareValue],3
    je near %%notequalthan
    SearchMacro je, %1
    jmp .end
%%greater
    SearchMacro ja, %1
    jmp .end
%%lessthan
    SearchMacro jb, %1
    jmp .end
%%notequalthan
    SearchMacro jne, %1
    jmp .end
%endmacro

CheatCodeSearchProcess:
    cmp byte[CheatSrcSearchType],1
    je near .comparative
    cmp byte[CSInputDisplay],0
    je near .nodisplay
    cmp byte[CSInputDisplay],'_'
    je near .nodisplay
    cmp byte[CSOverValue],1
    je near .nodisplay
    mov byte[CSInputDisplay],'_'
    mov byte[CSInputDisplay+1],0
    ; Process Cheat Search
    mov ecx,65536*2
    xor ebx,ebx
    mov bl,[CheatSrcByteSize]
    sub ecx,ebx
    mov edx,[SrcMask+ebx*4]
    mov edi,[vidbuffer]
    add edi,129600+65536*2
    mov esi,[wramdata]
    mov bl,0FEh
    mov bh,01h
.exactloop
    mov eax,[esi]
    and eax,edx
    cmp eax,[CSCurValue]
    je .found
    inc eax
    and eax,edx
    cmp eax,[CSCurValue]
    je .foundb
.failedfind
    and [edi],bl
    jmp .foundc
.found
    test byte[edi+16384],bh
    jz .failedfind
    jmp .foundc
.foundb
    cmp byte[FirstSearch],1
    je .clear
    test byte[edi+16384],bh
    jnz .failedfind
    jmp .foundc
.clear
    and byte[edi+16384],bl
.foundc
    cmp bl,7Fh
    jne .noincedi
    inc edi
.noincedi
    rol bl,1
    rol bh,1
    inc esi
    dec ecx
    jnz .exactloop
    mov byte[CopyRamToggle],1
    mov byte[CheatSearchStatus],1
.nodisplay
    ret
.comparative
    mov byte[CSInputDisplay],'_'
    mov byte[CSInputDisplay+1],0
    mov byte[CheatSearchStatus],1
    mov eax,[vidbuffer]
    add eax,129600+65536*2
    mov esi,[vidbuffer]
    add esi,129600
    mov edi,[wramdata]
    mov ecx,65536*2
    cmp byte[CheatSrcByteSize],1
    je near .bytesize2
    cmp byte[CheatSrcByteSize],2
    je near .bytesize3
    cmp byte[CheatSrcByteSize],3
    je near .bytesize4
    SearchMacroB SearchCMPByte
.bytesize2
    dec ecx
    SearchMacroB SearchCMP2Bytes
.bytesize3
    sub ecx,2
    SearchMacroB SearchCMP3Bytes
.bytesize4
    sub ecx,3
    SearchMacroB SearchCMP4Bytes
.end
    mov byte[CopyRamToggle],1
    ret

SECTION .bss
CopyRamToggle resb 1
FirstSearch   resb 1
SECTION .text

CheatCodeSearchInit:
    mov byte[CSInputDisplay],'_'
    mov byte[CSInputDisplay+1],0
    mov byte[CheatWinMode],1
    mov byte[CheatSearchStatus],0
    cmp byte[CopyRamToggle],0
    mov byte[FirstSearch],1
    mov eax,[vidbuffer]
    add eax,129600
    ; copy 128k ram
    mov ebx,[wramdata]
    mov ecx,32768
.loop
    mov edx,[ebx]
    mov [eax],edx
    add ebx,4
    add eax,4
    dec ecx
    jnz .loop
    ; fill searched buffer with 0xFF
    mov eax,[vidbuffer]
    add eax,129600+65536*2
    mov ecx,8192
.loop2
    mov dword[eax],0FFFFFFFFh
    add eax,4
    dec ecx
    jnz .loop2
    cmp byte[CheatSrcSearchType],1
    jne .nottype1
    mov byte[CheatSearchStatus],1
.nottype1
    mov dword[CheatCompareValue],0
    mov eax,[vidbuffer]
    add eax,129600+65536*2
    cmp byte[CheatSrcByteSize],1
    je near .bytesize2
    cmp byte[CheatSrcByteSize],2
    je near .bytesize3
    cmp byte[CheatSrcByteSize],3
    je near .bytesize4
    ret
.bytesize2
    and byte[eax+16383],07Fh
    ret
.bytesize3
    and byte[eax+16383],03Fh
    ret
.bytesize4
    and byte[eax+16383],01Fh
    ret

CheatCodeSave:
    cmp byte[NumCheats],0
    jne .okay
    mov byte[GUICBHold],0
    ret
.okay
    mov byte[cheatdata+6],254
    mov byte[cheatdata+7],252

    call SRAMDirc
    mov byte[GUICBHold],0
    mov ebx,[statefileloc]
    sub ebx,2
    mov eax,[fnamest+ebx]
    mov dword[fnamest+ebx],'cht'
    push eax
    push ebx
    mov edx,fnamest+1
    call Create_File
    jc .cheatsavefail
    mov bx,ax
    mov ecx,[NumCheats]
    mov edx,ecx
    shl ecx,4
    shl edx,2
    add ecx,edx
    add ecx,edx
    add ecx,edx
    mov edx,cheatdata
    call Write_File
    call Close_File
.cheatsavefail
    pop ebx
    pop eax
    mov [fnamest+ebx],eax
    call LOADDir
    ret

CheatCodeLoad:
    call SRAMDirc
    mov byte[GUICBHold],0
    mov ebx,[statefileloc]
    sub ebx,2
    mov eax,[fnamest+ebx]
    mov dword[fnamest+ebx],'cht'
    push eax
    push ebx
    mov edx,fnamest+1
    call Open_File
    jc near .fail
    mov bx,ax
    ; Disable all codes
    push ebx
    mov esi,cheatdata
    mov ecx,[NumCheats]
    cmp ecx,0
    je .skip
.loop2
    test byte[esi],4
    jnz .disabled2
    push esi
    push ecx
    call DisableCheatCode
    pop ecx
    pop esi
.disabled2
    add esi,28
    dec ecx
    jnz .loop2
.skip
    pop ebx
    mov ecx,255*28
    mov edx,cheatdata
    call Read_File
    push eax
    call Close_File
    pop eax
    cmp byte[cheatdata+6],254
    jne .notnewformat
    cmp byte[cheatdata+7],252
    jne .notnewformat
    jmp .newformat
.notnewformat
    ; Convert format
    mov esi,cheatdata
    mov ebx,18
    push eax
    xor edx,edx
    div ebx
    push edx
    mov [NumCheats],eax
    mov ebx,28
    mul ebx
    mov ecx,eax
    pop edx
    pop eax
    sub eax,edx
.convloop
    sub ecx,28
    sub eax,18
    mov ebx,6
.convloopb
    mov dl,[cheatdata+eax+ebx-1]
    mov [cheatdata+ecx+ebx-1],dl
    dec ebx
    jnz .convloopb
    mov ebx,12
.convloopd
    mov dl,[cheatdata+eax+ebx+5]
    mov [cheatdata+ecx+ebx+7],dl
    dec ebx
    jnz .convloopd
    mov ebx,8
.convloopc
    mov byte[cheatdata+ecx+ebx+19],0
    dec ebx
    jnz .convloopc
    or ecx,ecx
    jnz .convloop
    jmp .fin
.newformat
    mov ebx,28
    xor edx,edx
    div ebx
    mov [NumCheats],eax
.fin
    pop ebx
    pop eax
    mov [fnamest+ebx],eax
    ; Enable all ON toggled cheat codes
    mov esi,cheatdata
    mov ecx,[NumCheats]
    cmp ecx,0
    je .skip2
.loop
    test byte[esi],4
    jnz .disabled
    push esi
    push ecx
    call EnableCheatCode
    pop ecx
    pop esi
.disabled
    add esi,28
    dec ecx
    jnz .loop
.skip2
    mov eax,[NumCheats]
    cmp eax,[GUIcurrentcheatcursloc]
    ja .noconf
    dec eax
    mov [GUIcurrentcheatcursloc],eax
.noconf
    cmp dword[NumCheats],0
    jne .nozero
    mov dword[GUIcurrentcheatcursloc],0
    mov byte[CheatOn],0
    call LOADDir
    ret
.nozero
    mov byte[CheatOn],1
    call LOADDir
    ret
.fail
    pop ebx
    pop eax
    mov [fnamest+ebx],eax
    call LOADDir
    ret

CheatCodeRemove:
    cmp dword[NumCheats],0
    jne .nonone
    mov byte[GUICBHold],0
    ret
.nonone
    mov byte[GUICBHold],0
    mov esi,[GUIcurrentcheatcursloc]
    shl esi,5
    sub esi,[GUIcurrentcheatcursloc]
    sub esi,[GUIcurrentcheatcursloc]
    sub esi,[GUIcurrentcheatcursloc]
    sub esi,[GUIcurrentcheatcursloc]
    add esi,cheatdata
    push esi
    call DisableCheatCode
    pop esi
    mov eax,255
    sub eax,[GUIcurrentcheatcursloc]
    mov ebx,eax
    shl eax,4
    add eax,ebx
    add eax,ebx
.loop
    mov bl,[esi+28]
    mov [esi],bl
    inc esi
    dec eax
    jnz .loop
    dec dword[NumCheats]
    mov eax,[GUIcurrentcheatcursloc]
    cmp dword[NumCheats],0
    je .okay
    cmp eax,[NumCheats]
    jne .okay
    dec eax
    mov [GUIcurrentcheatcursloc],eax
    sub eax,11
    mov [GUIcurrentcheatviewloc],eax
    test dword[GUIcurrentcheatviewloc],80000000h
    jz .noview
    mov dword[GUIcurrentcheatviewloc],0
.noview
.okay
    cmp byte[NumCheats],0
    jne .cheatexists
    mov byte[CheatOn],0
.cheatexists
    ret

CheatCodeFix:
    cmp dword[NumCheats],0
    jne .nonone
    mov byte[GUICBHold],0
    ret
.nonone
    mov byte[GUICBHold],0
    call DisableCheatCode
    mov esi,[GUIcurrentcheatcursloc]
    shl esi,5
    sub esi,[GUIcurrentcheatcursloc]
    sub esi,[GUIcurrentcheatcursloc]
    sub esi,[GUIcurrentcheatcursloc]
    sub esi,[GUIcurrentcheatcursloc]
    add esi,cheatdata
    xor byte[esi+3],80h
    call EnableCheatCodeNoPrevMod
    ret

CheatCodeToggle:
    cmp dword[NumCheats],0
    jne .nonone
    mov byte[GUICBHold],0
    ret
.nonone
    mov byte[GUICBHold],0
    mov esi,[GUIcurrentcheatcursloc]
    shl esi,5
    sub esi,[GUIcurrentcheatcursloc]
    sub esi,[GUIcurrentcheatcursloc]
    sub esi,[GUIcurrentcheatcursloc]
    sub esi,[GUIcurrentcheatcursloc]
    add esi,cheatdata
    test byte[esi],4
    jz DisableCheatCode
    jmp EnableCheatCodeNoPrevMod

DisableCheatCode:
    ; code is at esi
    xor ecx,ecx
    xor ebx,ebx
    or byte[esi],4
    test byte[esi],1
    jnz .gfrom
    mov al,[esi+5]
    mov cx,[esi+2]
    mov bl,[esi+4]
    mov byte[writeon],1
    test byte[esi],80h
    jnz .nowrite
    test byte[esi-28],80h
    jnz .nowrite
    call dword near [memtablew8+ebx*4]
.nowrite
    mov byte[writeon],0
    ret
.gfrom
    mov al,[esi+5]
    mov ecx,[esi+2]
    and ecx,0FFFFFFh
    mov esi,[romdata]
    mov [esi+ecx],al
    ret
.gfram
    mov al,[esi+5]
    mov ecx,[esi+2]
    and ecx,0FFFFFFh
    mov esi,[sram]
    mov [esi+ecx],al
    ret

EnableCheatCode:
    ; code is at esi
    xor ecx,ecx
    xor ebx,ebx
    and byte[esi],0FBh
    test byte[esi],1
    jnz .gfrom
    mov al,[esi+1]
    mov cx,[esi+2]
    mov bl,[esi+4]
    push ecx
    push eax
    push ebx
    push edx
    call dword near [memtabler8+ebx*4]
    pop edx
    mov [esi+5],al
    pop ebx
    pop eax
    pop ecx
    mov byte[writeon],1
    test byte[esi],80h
    jnz .nowrite
    test byte[esi-28],80h
    jnz .nowrite
    call dword near [memtablew8+ebx*4]
.nowrite
    mov byte[writeon],0
    ret
.gfrom
    mov al,[esi+1]
    mov ecx,[esi+2]
    and ecx,0FFFFFFh
    mov esi,[romdata]
    mov bl,[esi+ecx]
    mov [esi+ecx],al
    mov [esi+5],bl
    ret
.gfram
    mov al,[esi+1]
    mov ecx,[esi+2]
    and ecx,0FFFFFFh
    mov esi,[sram]
    mov bl,[esi+ecx]
    mov [esi+ecx],al
    mov [esi+5],bl
    ret

EnableCheatCodeNoPrevMod:
    ; code is at esi
    xor ecx,ecx
    xor ebx,ebx
    and byte[esi],0FBh
    test byte[esi],1
    jnz .gfrom
    mov al,[esi+1]
    mov cx,[esi+2]
    mov bl,[esi+4]
    mov byte[writeon],1
    test byte[esi],80h
    jnz .nowrite
    test byte[esi-28],80h
    jnz .nowrite
    call dword near [memtablew8+ebx*4]
.nowrite
    mov byte[writeon],0
    ret
.gfrom
    mov al,[esi+1]
    mov ecx,[esi+2]
    and ecx,0FFFFFFh
    mov esi,[romdata]
    mov bl,[esi+ecx]
    mov [esi+ecx],al
    mov [esi+5],bl
    ret
.gfram
    mov al,[esi+1]
    mov ecx,[esi+2]
    and ecx,0FFFFFFh
    mov esi,[sram]
    mov bl,[esi+ecx]
    mov [esi+ecx],al
    mov [esi+5],bl
    ret

AddCheatCode:
    mov byte[GUICBHold],0
    cmp dword[NumCheats],255
    jne .okay
    ret
.okay
    push eax
    push ebx
    ; transfer description
    mov eax,[NumCheats]
    shl eax,5
    sub eax,[NumCheats]
    sub eax,[NumCheats]
    sub eax,[NumCheats]
    sub eax,[NumCheats]
    add eax,cheatdata
    mov edx,eax
    push edx
    add eax,6
    mov ebx,CSDescDisplay
    mov ecx,20
.dloop
    mov dl,[ebx]
    mov [eax+2],dl
    mov [eax+18+2],dl
    mov [eax+18*2+2],dl
    inc ebx
    inc eax
    dec ecx
    jnz .dloop
    pop edx
    pop ebx
    pop eax
    ; toggle, value, address, pvalue, name(12)
    mov byte[edx],0
    mov [edx+1],bl
    push eax
    sub eax,7E0000h
    add eax,[wramdata]
    mov bh,[eax]
    mov [eax],bl
    pop eax
    mov [edx+2],eax
    mov [edx+5],bh
    inc dword[NumCheats]
    mov edx,7
    mov al,[GUIpmenupos]
    push eax
    call CheckMenuItemHelp
    pop eax
    mov [GUIpmenupos],al
    mov byte[CheatOn],1
    ret

ProcessCheatCode:
    mov byte[GUICBHold],0
    cmp dword[NumCheats],255
    je .fail
    cmp byte[GUICheatPosA],0
    je .fail
    jmp .okay
.fail
    ret
.okay
    ; make sure flashing cursor doesn't exist
    xor ebx,ebx
    mov bl,[GUICheatPosB]
    mov byte[GUICheatTextZ2+ebx],0
    ; transfer description
    mov eax,[NumCheats]
    shl eax,5
    sub eax,[NumCheats]
    sub eax,[NumCheats]
    sub eax,[NumCheats]
    sub eax,[NumCheats]
    add eax,cheatdata
    add eax,6
    mov ebx,GUICheatTextZ2
    mov ecx,20
.dloop
    mov dl,[ebx]
    mov [eax+2],dl
    mov [eax+18+2],dl
    mov [eax+18*2+2],dl
    inc ebx
    inc eax
    dec ecx
    jnz .dloop
    ; determine whether it is gamegenie, par, or GF
    ; uppercase all codes if necessary
    mov eax,GUICheatTextZ1
    mov ecx,14
.loop
    mov bl,[eax]
    cmp bl,'a'
    jb .nolower
    cmp bl,'z'
    ja .nolower
    sub bl,'a'-'A'
    mov [eax],bl
.nolower
    inc eax
    dec ecx
    jnz .loop
    mov byte[guicheatvalrep],0
    xor eax,eax
    mov al,[GUICheatPosA]
    dec al
    cmp byte[GUICheatTextZ1+eax],'R'
    jne .notrep
    mov byte[guicheatvalrep],80h
    dec byte[GUICheatPosA]
.notrep
    cmp byte[GUICheatPosA],8
    je near .par
    cmp byte[GUICheatPosA],9
    je near .gg
    cmp byte[GUICheatPosA],14
    je near .gf
.invalidpar
    jmp guicheaterror
.par
    ; check if code is valid
    mov eax,GUICheatTextZ1
    mov ecx,8
.looppar
    mov bl,[eax]
    cmp bl,'0'
    jb .invalidpar
    cmp bl,'9'
    jbe .okaypar
    cmp bl,'A'
    jb .invalidpar
    cmp bl,'F'
    ja .invalidpar
.okaypar
    inc eax
    dec ecx
    jnz .looppar
    jmp decodepar
.invalidgg
    jmp guicheaterror
.gg
    ; check if code is valid
    mov eax,GUICheatTextZ1
    mov ecx,9
.loopgg
    cmp ecx,5
    jne .nomid
    cmp byte[eax],'-'
    jne .invalidgg
    inc eax
    dec ecx
.nomid
    mov bl,[eax]
    cmp bl,'0'
    jb .invalidgg
    cmp bl,'9'
    jbe .okaygg
    cmp bl,'A'
    jb .invalidgg
    cmp bl,'F'
    ja .invalidgg
.okaygg
    inc eax
    dec ecx
    jnz .loopgg
    jmp decodegg
    ret
.invalidgf
    jmp guicheaterror
.gf
    ; check if code is valid
    mov eax,GUICheatTextZ1
    mov ecx,5
.loopgf
    mov bl,[eax]
    cmp bl,'0'
    jb .invalidgf
    cmp bl,'9'
    jbe .okaygf
    cmp bl,'A'
    jb .invalidgf
    cmp bl,'F'
    ja .invalidgf
.okaygf
    inc eax
    dec ecx
    jnz .loopgf
    mov eax,GUICheatTextZ1+5
    mov ecx,6
.loopgf2
    mov bl,[eax]
    cmp bl,'X'
    je .okaygf2
    cmp bl,'0'
    jb .invalidgf
    cmp bl,'9'
    jbe .okaygf2
    cmp bl,'A'
    jb near .invalidgf
    cmp bl,'F'
    ja near .invalidgf
.okaygf2
    inc eax
    dec ecx
    jnz .loopgf2
    mov bl,[GUICheatTextZ1+13]
    cmp bl,'0'
    je .okaygf3
    cmp bl,'1'
    jne near .invalidgf
.okaygf3
    jmp decodegf

decodegf:
    ; convert code to number format
    mov ecx,14
    mov esi,GUICheatTextZ1
.loopb2
    mov al,[esi]
    cmp al,'X'
    je .let2
    cmp al,'A'
    jb .num2
    sub al,'A'
    add al,10
    jmp .let2
.num2
    sub al,'0'
.let2
    mov [esi],al
    inc esi
    dec ecx
    jnz .loopb2

    ; get address
    xor ebx,ebx
    xor ecx,ecx
    mov cl,[GUICheatTextZ1]
    shl ecx,4
    add cl,[GUICheatTextZ1+1]
    shl ecx,4
    add cl,[GUICheatTextZ1+2]
    shl ecx,4
    add cl,[GUICheatTextZ1+3]
    shl ecx,4
    add cl,[GUICheatTextZ1+4]

    mov edx,[NumCheats]
    shl edx,5
    sub edx,[NumCheats]
    sub edx,[NumCheats]
    sub edx,[NumCheats]
    sub edx,[NumCheats]

    ; Write data to memory
    cmp byte[GUICheatTextZ1+13],1
    je near .modifysram

    ; get data
    cmp byte[GUICheatTextZ1+5],'X'
    je near .nocode
    cmp byte[GUICheatTextZ1+6],'X'
    je near .nocode
    mov bl,[GUICheatTextZ1+5]
    shl bl,4
    add bl,[GUICheatTextZ1+6]
    mov esi,[romdata]
    mov al,[esi+ecx]
    mov [esi+ecx],bl
    mov byte[cheatdata+edx],1
    mov [cheatdata+edx+2],ecx
    mov [cheatdata+edx+1],bl
    mov [cheatdata+edx+5],al
    push eax
    mov al,[guicheatvalrep]
    or [cheatdata+edx],al
    pop eax
    inc byte[NumCheats]
    add edx,28
.nocode
    inc ecx
    cmp byte[GUICheatTextZ1+7],'X'
    je near .nocode1
    cmp byte[GUICheatTextZ1+8],'X'
    je near .nocode1
    cmp byte[NumCheats],255
    je near .nocode1
    mov bl,[GUICheatTextZ1+7]
    shl bl,4
    add bl,[GUICheatTextZ1+8]
    mov esi,[romdata]
    mov al,[esi+ecx]
    mov [esi+ecx],bl
    mov byte[cheatdata+edx],1
    mov [cheatdata+edx+2],ecx
    mov [cheatdata+edx+1],bl
    mov [cheatdata+edx+5],al
    inc byte[NumCheats]
    add edx,28
.nocode1
    inc ecx
    cmp byte[GUICheatTextZ1+9],'X'
    je near .nocode2
    cmp byte[GUICheatTextZ1+10],'X'
    je near .nocode2
    cmp byte[NumCheats],255
    je near .nocode2
    mov bl,[GUICheatTextZ1+9]
    shl bl,4
    add bl,[GUICheatTextZ1+10]
    mov esi,[romdata]
    mov al,[esi+ecx]
    mov [esi+ecx],bl
    mov byte[cheatdata+edx],1
    mov [cheatdata+edx+2],ecx
    mov [cheatdata+edx+1],bl
    mov [cheatdata+edx+5],al
    inc byte[NumCheats]
.nocode2
    jmp .quit

.modifysram
    cmp ecx,65535
    ja near .quit
    mov esi,[sram]
    ; get data
    cmp byte[GUICheatTextZ1+5],'X'
    je .nocodeb
    cmp byte[GUICheatTextZ1+6],'X'
    je .nocodeb
    mov bl,[GUICheatTextZ1+5]
    shl bl,4
    add bl,[GUICheatTextZ1+6]
    mov al,[esi+ecx]
    mov [esi+ecx],bl
    mov byte[cheatdata+edx],2
    mov [cheatdata+edx+2],ecx
    mov [cheatdata+edx+1],bl
    mov [cheatdata+edx+5],al
    inc byte[NumCheats]
    add edx,28
.nocodeb
    inc ecx
    cmp byte[GUICheatTextZ1+7],'X'
    je .nocode1b
    cmp byte[GUICheatTextZ1+8],'X'
    je .nocode1b
    cmp byte[NumCheats],255
    je .nocode1b
    cmp ecx,65535
    ja .nocode1b
    mov bl,[GUICheatTextZ1+7]
    shl bl,4
    add bl,[GUICheatTextZ1+8]
    mov al,[esi+ecx+1]
    mov [esi+ecx+1],bl
    mov byte[cheatdata+edx],2
    mov [cheatdata+edx+2],ecx
    mov [cheatdata+edx+1],bl
    mov [cheatdata+edx+5],al
    inc byte[NumCheats]
    add edx,28
.nocode1b
    inc ecx
    cmp byte[GUICheatTextZ1+9],'X'
    je .nocode2c
    cmp byte[GUICheatTextZ1+10],'X'
    je .nocode2c
    cmp byte[NumCheats],255
    je .nocode2c
    cmp ecx,65535
    ja .nocode2c
    mov bl,[GUICheatTextZ1+9]
    shl bl,4
    add bl,[GUICheatTextZ1+10]
    mov al,[esi+ecx+2]
    mov [esi+ecx+2],bl
    mov byte[cheatdata+edx],2
    mov [cheatdata+edx+2],ecx
    mov [cheatdata+edx+1],bl
    mov [cheatdata+edx+5],al
    inc byte[NumCheats]
.nocode2c

.quit
    cmp byte[NumCheats],0
    je .nocheat
    mov byte[CheatOn],1
    mov dword[GUIcurrentcheatwin],1
    mov eax,[NumCheats]
    dec eax
    mov [GUIcurrentcheatcursloc],eax
    sub eax,11
    mov [GUIcurrentcheatviewloc],eax
    test dword[GUIcurrentcheatviewloc],80000000h
    jz .noview
    mov dword[GUIcurrentcheatviewloc],0
.noview
.nocheat
    mov dword[GUICheatTextZ1],0
    mov dword[GUICheatTextZ2],0
    mov byte[GUICheatPosA],0
    mov byte[GUICheatPosB],0
    ret

decodegg:
;Genie Hex:    D  F  4  7  0  9  1  5  6  B  C  8  A  2  3  E
;Normal  Hex:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
;              4  6  D  E  2  7  8  3  B  5  C  9  A  0  F  1
    ; Convert code
    mov esi,GUICheatTextZ1
    mov eax,[esi+5]
    mov [esi+4],eax
    ; convert code to number format
    mov ecx,8
    xor eax,eax
.loopb3
    mov al,[esi]
    cmp al,'A'
    jb .num3
    sub al,'A'
    add al,10
    jmp .let3
.num3
    sub al,'0'
.let3
    mov al,[.GG2Norm+eax]
    mov [esi],al
    inc esi
    dec ecx
    jnz .loopb3

    mov esi,GUICheatTextZ1
    xor ecx,ecx
    mov cl,[esi+2]
    shl ecx,4
    add cl,[esi+3]
    shl ecx,4
    add cl,[esi+4]
    shl ecx,4
    add cl,[esi+5]
    shl ecx,4
    add cl,[esi+6]
    shl ecx,4
    add cl,[esi+7]
;                        0123456789ABCDEF01234567
; 24bit encoded address: ijklqrstopabcduvwxefghmn
;                        abcdefghijklmnopqrstuvwx
;                        >8  >12 >6<10 >6  <14 <10
    mov ebx,ecx
    and ebx,000000000011110000000000b   ;abcd
    shl ebx,10
    mov eax,ecx
    and eax,000000000000000000111100b   ;efgh
    shl eax,14
    add ebx,eax
    mov eax,ecx
    and eax,111100000000000000000000b   ;ijkl
    shr eax,8
    add ebx,eax
    mov eax,ecx
    and eax,000000000000000000000011b   ;mn
    shl eax,10
    add ebx,eax
    mov eax,ecx
    and eax,000000001100000000000000b   ;op
    shr eax,6
    add ebx,eax
    mov eax,ecx
    and eax,000011110000000000000000b   ;qrst
    shr eax,12
    add ebx,eax
    mov eax,ecx
    and eax,000000000000001111000000b   ;uvwx
    shr eax,6
    add ebx,eax
    xor ecx,ecx
    mov cx,bx
    shr ebx,16
    test bl,40h
    jz .noover
;    xor cx,8000h
.noover
    mov al,[esi]
    shl al,4
    add al,[esi+1]

    ; store into cheatdata
    mov edx,[NumCheats]
    shl edx,5
    sub edx,[NumCheats]
    sub edx,[NumCheats]
    sub edx,[NumCheats]
    sub edx,[NumCheats]
    mov byte[cheatdata+edx],0
    mov [cheatdata+edx+1],al
    mov [cheatdata+edx+2],cx
    mov [cheatdata+edx+4],bl
    push eax
    mov al,[guicheatvalrep]
    or [cheatdata+edx],al
    pop eax
    push ecx
    push eax
    push ebx
    push edx
    call dword near [memtabler8+ebx*4]
    pop edx
    mov [cheatdata+edx+5],al
    pop ebx
    pop eax
    pop ecx

    mov byte[writeon],1

    test byte[cheatdata+edx],80h
    jnz .nowrite
    test byte[cheatdata+edx-28],80h
    jnz .nowrite
    call dword near [memtablew8+ebx*4]
.nowrite

    mov byte[writeon],0
    mov byte[CheatOn],1
    inc byte[NumCheats]
    mov dword[GUICheatTextZ1],0
    mov dword[GUICheatTextZ2],0
    mov byte[GUICheatPosA],0
    mov byte[GUICheatPosB],0
    mov dword[GUIcurrentcheatwin],1
    mov eax,[NumCheats]
    dec eax
    mov [GUIcurrentcheatcursloc],eax
    sub eax,11
    mov [GUIcurrentcheatviewloc],eax
    test dword[GUIcurrentcheatviewloc],80000000h
    jz .noview
    mov dword[GUIcurrentcheatviewloc],0
.noview
    ret
SECTION .data
.GG2Norm db 04h,06h,0Dh,0Eh,02h,07h,08h,03h,0Bh,05h,0Ch,09h,0Ah,00h,0Fh,01h
SECTION .text

decodepar:
    ; convert code to number format
    mov ecx,8
    mov esi,GUICheatTextZ1
.loopb
    mov al,[esi]
    cmp al,'A'
    jb .num
    sub al,'A'
    add al,10
    jmp .let
.num
    sub al,'0'
.let
    mov [esi],al
    inc esi
    dec ecx
    jnz .loopb
    ; get address
    xor ebx,ebx
    xor ecx,ecx
    mov bl,[GUICheatTextZ1]
    shl bl,4
    add bl,[GUICheatTextZ1+1]
    mov cl,[GUICheatTextZ1+2]
    shl cx,4
    add cl,[GUICheatTextZ1+3]
    shl cx,4
    add cl,[GUICheatTextZ1+4]
    shl cx,4
    add cl,[GUICheatTextZ1+5]
    mov al,[GUICheatTextZ1+6]
    shl al,4
    add al,[GUICheatTextZ1+7]

    ; store into cheatdata
    xor edx,edx
    mov dl,[NumCheats]
    push ebx
    mov ebx,edx
    shl edx,5
    sub edx,ebx
    sub edx,ebx
    sub edx,ebx
    sub edx,ebx
    pop ebx
    mov byte[cheatdata+edx],0
    mov [cheatdata+edx+1],al
    mov [cheatdata+edx+2],cx
    mov [cheatdata+edx+4],bl
    push eax
    mov al,[guicheatvalrep]
    or [cheatdata+edx],al
    pop eax
    push ecx
    push eax
    push ebx
    push edx
    call dword near [memtabler8+ebx*4]
    pop edx
    mov [cheatdata+edx+5],al
    pop ebx
    pop eax
    pop ecx

    mov byte[writeon],1
    test byte[cheatdata+edx],80h
    jnz .nowrite
    test byte[cheatdata+edx-28],80h
    jnz .nowrite
    call dword near [memtablew8+ebx*4]
.nowrite
    mov byte[writeon],0
    mov byte[CheatOn],1
    inc dword[NumCheats]
    mov dword[GUICheatTextZ1],0
    mov dword[GUICheatTextZ2],0
    mov byte[GUICheatPosA],0
    mov byte[GUICheatPosB],0
    mov dword[GUIcurrentcheatwin],1
    mov eax,[NumCheats]
    dec eax
    mov [GUIcurrentcheatcursloc],eax
    sub eax,11
    mov [GUIcurrentcheatviewloc],eax
    test dword[GUIcurrentcheatviewloc],80000000h
    jz .noview
    mov dword[GUIcurrentcheatviewloc],0
.noview
    ret

guicheaterror:
    xor ebx,ebx
    mov ecx,256+128+64
.a
    mov byte[pressed+ebx],0
    inc ebx
    dec ecx
    jnz .a
.again
    call GUIUnBuffer
    call DisplayBoxes
    call DisplayMenu
    GUIBox 75,95,192,143,160
    GUIBox 75,95,192,95,162
    GUIBox 75,95,75,143,161
    GUIBox 192,95,192,143,159
    GUIBox 75,143,192,143,158
    GUIOuttext 81,101,guicheaterror1,220-15
    GUIOuttext 80,100,guicheaterror1,220
    GUIOuttext 81,109,guicheaterror2,220-15
    GUIOuttext 80,108,guicheaterror2,220
    GUIOuttext 81,117,guicheaterror3,220-15
    GUIOuttext 80,116,guicheaterror3,220
    GUIOuttext 81,125,guicheaterror4,220-15
    GUIOuttext 80,124,guicheaterror4,220
    GUIOuttext 81,135,guicheaterror5,220-15
    GUIOuttext 80,134,guicheaterror5,220
    call vidpastecopyscr
    call JoyRead
    xor ebx,ebx
    mov ecx,256+128+64
.b
    cmp byte[pressed+ebx],0
    jne .pressedokay
    inc ebx
    dec ecx
    jnz .b
    cmp byte[MouseDis],1
    je .mousedis
    call Get_MouseData
    test bx,01h
    jnz .pressedokay
.mousedis
    jmp .again
.pressedokay
.again2
    call Check_Key
    or al,al
    jz .nokey
    call Get_Key
    jmp .again2
.nokey
    cmp byte[MouseDis],1
    je .mousedis2
    push ebx
;    mov eax,0Bh
;    int 33h
    pop ebx
.mousedis2
    mov dword[GUIcurrentcheatwin],1
    mov byte[GUIpclicked],1
    ret
SECTION .data
guicheaterror1 db 'INVALID CODE!  YOU',0
guicheaterror2 db 'MUST ENTER A VALID',0
guicheaterror3 db 'GAME GENIE,PAR, OR',0
guicheaterror4 db 'GOLD FINGER CODE.',0
guicheaterror5 db 'PRESS ANY KEY.',0
SECTION .bss
guicheatvalrep resb 1
SECTION .text


