1179 lines
24 KiB
NASM
1179 lines
24 KiB
NASM
; Solitare V1.5.2
|
|
; Platform: KolibriOS / MenuetOS
|
|
; Author: Max (Refactored/Fixed)
|
|
; Scoring Fix: Cards only give points ONCE, even if moved back and forth.
|
|
|
|
format binary as 'run'
|
|
use32
|
|
org 0x0
|
|
|
|
; --- SYSTEM INCLUDES ---
|
|
include 'macros.inc'
|
|
include 'KOSfuncs.inc'
|
|
|
|
; --- GAME CONSTANTS ---
|
|
CARD_W equ 50
|
|
CARD_H equ 70
|
|
STACK_OFFSET equ 20
|
|
WIN_W equ 750
|
|
WIN_H equ 560
|
|
BPP equ 3
|
|
STRIDE equ WIN_W * BPP
|
|
|
|
COL_TABLE equ 0x207020
|
|
COL_REVERSE equ 0x0000AA
|
|
COL_WHITE equ 0xFFFFFF
|
|
COL_RED equ 0xCC0000
|
|
COL_BLACK equ 0x000000
|
|
COL_SLOT equ 0x185018
|
|
|
|
; Card structure offsets
|
|
CARD_STRUCT_SIZE equ 12
|
|
CARD_VALUE equ 0
|
|
CARD_SUIT equ 1
|
|
CARD_STATE equ 2 ; Bit 0: Face-up, Bit 7: Already Scored
|
|
CARD_LOC equ 3 ; 0-6: Tableau, 7: Stock, 8: Foundation, 9: Waste
|
|
CARD_X equ 4
|
|
CARD_Y equ 6
|
|
CARD_OLD_X equ 8
|
|
CARD_OLD_Y equ 10
|
|
|
|
STOCK_X equ 20
|
|
WASTE_X equ 80
|
|
FOUNDATION_X equ 350
|
|
FOUND_Y equ 20
|
|
SCORE_Y equ 535
|
|
|
|
; --- HEADER ---
|
|
db 'MENUET01'
|
|
dd 0x01
|
|
dd start
|
|
dd i_end
|
|
dd mem_end
|
|
dd stacktop
|
|
dd 0, 0
|
|
|
|
start:
|
|
mov esp, stacktop
|
|
|
|
; Get system skin height
|
|
mcall SF_STYLE_SETTINGS, SSF_GET_SKIN_HEIGHT
|
|
mov [skin_h], eax
|
|
|
|
call init_deck
|
|
call shuffle_deck
|
|
call layout_tableau
|
|
mov dword [score], 0
|
|
mov byte [game_won], 0
|
|
|
|
event_loop:
|
|
mcall SF_CHECK_EVENT
|
|
cmp eax, 1 ; Redraw event
|
|
je on_redraw
|
|
cmp eax, 2 ; Key event
|
|
je on_key
|
|
cmp eax, 3 ; Button event
|
|
je on_button
|
|
|
|
call handle_mouse
|
|
|
|
; Update display if dragging or forced
|
|
cmp dword [active_card_count], 0
|
|
ja update_screen_only
|
|
cmp byte [force_redraw], 1
|
|
je update_screen_only
|
|
|
|
mcall SF_SLEEP, 1
|
|
jmp event_loop
|
|
|
|
on_key:
|
|
mcall SF_GET_KEY
|
|
jmp event_loop
|
|
|
|
on_button:
|
|
mcall SF_GET_BUTTON
|
|
shr eax, 8
|
|
cmp eax, 1 ; Window close button
|
|
jne event_loop
|
|
mcall SF_TERMINATE_PROCESS
|
|
|
|
on_redraw:
|
|
mcall SF_REDRAW, SSF_BEGIN_DRAW
|
|
mov ebx, 100 shl 16 + (WIN_W + 9)
|
|
mov eax, [skin_h]
|
|
add eax, WIN_H + 5
|
|
mov ecx, 100 shl 16
|
|
mov cx, ax
|
|
mcall SF_CREATE_WINDOW, , , 0x14000000 or COL_TABLE, , title
|
|
mcall SF_REDRAW, SSF_END_DRAW
|
|
mov byte [force_redraw], 1
|
|
jmp update_screen_only
|
|
|
|
update_screen_only:
|
|
mov byte [force_redraw], 0
|
|
call prepare_buffer
|
|
mov edx, 4 shl 16
|
|
add dx, word [skin_h]
|
|
mcall SF_PUT_IMAGE, screen_buffer, WIN_W shl 16 + WIN_H, edx
|
|
jmp event_loop
|
|
|
|
; --- MOUSE HANDLING ---
|
|
|
|
handle_mouse:
|
|
pushad
|
|
mcall SF_MOUSE_GET, SSF_WINDOW_POSITION
|
|
mov ebp, eax
|
|
shr ebp, 16
|
|
sub ebp, 5 ; Mouse X correction
|
|
|
|
and eax, 0xFFFF
|
|
sub eax, [skin_h]
|
|
mov edi, eax ; Mouse Y in workspace
|
|
|
|
mcall SF_MOUSE_GET, SSF_BUTTON
|
|
test eax, 1 ; Left click?
|
|
jnz .dragging_state
|
|
|
|
cmp dword [mouse_lock], 1
|
|
jne .exit
|
|
|
|
mov dword [mouse_lock], 0
|
|
cmp dword [active_card_count], 0
|
|
je .exit
|
|
|
|
call check_stack_move
|
|
mov dword [active_card_count], 0
|
|
mov byte [force_redraw], 1
|
|
popad
|
|
ret
|
|
|
|
.dragging_state:
|
|
cmp dword [mouse_lock], 1
|
|
je .no_deal_click
|
|
|
|
; Stock pile interaction
|
|
cmp ebp, STOCK_X
|
|
jb .find_card
|
|
cmp ebp, STOCK_X+CARD_W
|
|
jae .find_card
|
|
cmp edi, FOUND_Y
|
|
jb .find_card
|
|
cmp edi, FOUND_Y+CARD_H
|
|
jae .find_card
|
|
|
|
mov dword [mouse_lock], 1
|
|
call deal_from_stock
|
|
mov byte [force_redraw], 1
|
|
popad
|
|
ret
|
|
|
|
.find_card:
|
|
mov ebx, 51
|
|
.f_loop:
|
|
imul edx, ebx, CARD_STRUCT_SIZE
|
|
add edx, deck_data
|
|
movsx esi, word [edx+CARD_X]
|
|
movsx ecx, word [edx+CARD_Y]
|
|
|
|
cmp ebp, esi
|
|
jb .next_s
|
|
add esi, CARD_W
|
|
cmp ebp, esi
|
|
jae .next_s
|
|
cmp edi, ecx
|
|
jb .next_s
|
|
add ecx, CARD_H
|
|
cmp edi, ecx
|
|
jae .next_s
|
|
|
|
test byte [edx+CARD_STATE], 1 ; Is card face up?
|
|
jz .next_s
|
|
|
|
mov dword [mouse_lock], 1
|
|
mov [active_stack], ebx
|
|
mov dword [active_card_count], 1
|
|
|
|
mov ax, word [edx+CARD_X]
|
|
sub ax, bp
|
|
mov [mouse_off_x], ax
|
|
mov ax, word [edx+CARD_Y]
|
|
sub ax, di
|
|
mov [mouse_off_y], ax
|
|
|
|
mov eax, ebx
|
|
call build_active_stack
|
|
popad
|
|
ret
|
|
.next_s:
|
|
dec ebx
|
|
jns .f_loop
|
|
popad
|
|
ret
|
|
|
|
.no_deal_click:
|
|
cmp dword [active_card_count], 0
|
|
je .exit_drag
|
|
.drag_active:
|
|
xor ecx, ecx
|
|
.d_lp:
|
|
cmp ecx, [active_card_count]
|
|
jae .exit_drag
|
|
mov eax, [active_stack + ecx*4]
|
|
imul eax, CARD_STRUCT_SIZE
|
|
add eax, deck_data
|
|
|
|
mov dx, [mouse_off_x]
|
|
add dx, bp
|
|
mov [eax+CARD_X], dx
|
|
mov dx, [mouse_off_y]
|
|
add dx, di
|
|
|
|
push eax
|
|
mov eax, ecx
|
|
imul eax, STACK_OFFSET
|
|
add dx, ax
|
|
pop eax
|
|
mov [eax+CARD_Y], dx
|
|
|
|
inc ecx
|
|
jmp .d_lp
|
|
.exit_drag:
|
|
popad
|
|
ret
|
|
.exit:
|
|
popad
|
|
ret
|
|
|
|
; --- RENDERING ---
|
|
|
|
prepare_buffer:
|
|
mov edi, screen_buffer
|
|
mov ecx, WIN_W * WIN_H
|
|
mov eax, COL_TABLE
|
|
.clear_loop:
|
|
mov [edi], al
|
|
mov [edi+1], ah
|
|
push eax
|
|
shr eax, 16
|
|
mov byte [edi+2], al
|
|
pop eax
|
|
add edi, 3
|
|
dec ecx
|
|
jnz .clear_loop
|
|
|
|
call draw_slots
|
|
call render_score_ui
|
|
|
|
xor ecx, ecx
|
|
.draw_loop:
|
|
call is_card_active
|
|
jc .skip
|
|
push ecx
|
|
imul esi, ecx, CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
call draw_card_to_buffer
|
|
pop ecx
|
|
.skip:
|
|
inc ecx
|
|
cmp ecx, 52
|
|
jl .draw_loop
|
|
|
|
xor ecx, ecx
|
|
.draw_active:
|
|
cmp ecx, [active_card_count]
|
|
jae .done_rendering
|
|
push ecx
|
|
mov eax, [active_stack + ecx*4]
|
|
imul esi, eax, CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
call draw_card_to_buffer
|
|
pop ecx
|
|
inc ecx
|
|
jmp .draw_active
|
|
|
|
.done_rendering:
|
|
ret
|
|
|
|
draw_card_to_buffer:
|
|
pushad
|
|
movsx ebx, word [esi+CARD_X]
|
|
movsx ecx, word [esi+CARD_Y]
|
|
mov edx, COL_BLACK
|
|
mov edi, CARD_W
|
|
mov ebp, CARD_H
|
|
call fill_rect_buf
|
|
inc ebx
|
|
inc ecx
|
|
mov edx, COL_WHITE
|
|
mov edi, CARD_W-2
|
|
mov ebp, CARD_H-2
|
|
call fill_rect_buf
|
|
test byte [esi+CARD_STATE], 1
|
|
jnz .face_up
|
|
add ebx, 4
|
|
add ecx, 4
|
|
mov edx, COL_REVERSE
|
|
mov edi, CARD_W-10
|
|
mov ebp, CARD_H-10
|
|
call fill_rect_buf
|
|
popad
|
|
ret
|
|
.face_up:
|
|
mov edx, COL_RED
|
|
cmp byte [esi+CARD_SUIT], 2
|
|
jb .is_red
|
|
mov edx, COL_BLACK
|
|
.is_red:
|
|
push edx
|
|
push esi
|
|
movzx eax, byte [esi+CARD_VALUE]
|
|
dec eax
|
|
mov esi, eax
|
|
add ebx, 3
|
|
add ecx, 3
|
|
call draw_char_to_buf
|
|
pop esi
|
|
push esi
|
|
movzx eax, byte [esi+CARD_SUIT]
|
|
add eax, 13
|
|
add ebx, 6
|
|
mov esi, eax
|
|
call draw_char_to_buf
|
|
pop esi
|
|
pop edx
|
|
push edx
|
|
push esi
|
|
movsx ebx, word [esi+CARD_X]
|
|
add ebx, CARD_W - 8
|
|
movsx ecx, word [esi+CARD_Y]
|
|
add ecx, CARD_H - 10
|
|
movzx eax, byte [esi+CARD_VALUE]
|
|
dec eax
|
|
mov esi, eax
|
|
call draw_char_to_buf
|
|
pop esi
|
|
push esi
|
|
movzx eax, byte [esi+CARD_SUIT]
|
|
add eax, 13
|
|
sub ebx, 6
|
|
mov esi, eax
|
|
call draw_char_to_buf
|
|
pop esi
|
|
pop edx
|
|
popad
|
|
ret
|
|
|
|
fill_rect_buf:
|
|
pushad
|
|
mov esi, ebp
|
|
.yl:
|
|
cmp ecx, 0
|
|
jl .skip_line
|
|
cmp ecx, WIN_H
|
|
jge .skip_line
|
|
push ecx
|
|
push ebx
|
|
mov eax, ecx
|
|
imul eax, STRIDE
|
|
add eax, screen_buffer
|
|
mov dword [temp_counter], edi
|
|
.xl:
|
|
cmp ebx, 0
|
|
jl .skip_pixel
|
|
cmp ebx, WIN_W
|
|
jge .skip_pixel
|
|
push eax
|
|
mov ecx, ebx
|
|
imul ecx, 3
|
|
add eax, ecx
|
|
mov [eax], dl
|
|
mov [eax+1], dh
|
|
push edx
|
|
shr edx, 16
|
|
mov [eax+2], dl
|
|
pop edx
|
|
pop eax
|
|
.skip_pixel:
|
|
inc ebx
|
|
dec dword [temp_counter]
|
|
jnz .xl
|
|
pop ebx
|
|
pop ecx
|
|
.skip_line:
|
|
inc ecx
|
|
dec esi
|
|
jnz .yl
|
|
popad
|
|
ret
|
|
|
|
draw_char_to_buf:
|
|
pushad
|
|
imul esi, 7
|
|
add esi, font_5x7
|
|
mov ebp, 7
|
|
.y_loop:
|
|
push ebx
|
|
push ecx
|
|
mov al, [esi]
|
|
mov ah, 10000000b
|
|
mov dword [temp_counter], 5
|
|
.x_loop:
|
|
test al, ah
|
|
jz .skip_pixel
|
|
cmp ebx, 0
|
|
jl .skip_pixel
|
|
cmp ebx, WIN_W
|
|
jge .skip_pixel
|
|
cmp ecx, 0
|
|
jl .skip_pixel
|
|
cmp ecx, WIN_H
|
|
jge .skip_pixel
|
|
push eax
|
|
mov eax, ecx
|
|
imul eax, STRIDE
|
|
push ebx
|
|
imul ebx, 3
|
|
add eax, ebx
|
|
pop ebx
|
|
add eax, screen_buffer
|
|
mov [eax], dl
|
|
mov [eax+1], dh
|
|
push edx
|
|
shr edx, 16
|
|
mov [eax+2], dl
|
|
pop edx
|
|
pop eax
|
|
.skip_pixel:
|
|
shr ah, 1
|
|
inc ebx
|
|
dec dword [temp_counter]
|
|
jnz .x_loop
|
|
pop ecx
|
|
pop ebx
|
|
inc esi
|
|
inc ecx
|
|
dec ebp
|
|
jnz .y_loop
|
|
popad
|
|
ret
|
|
|
|
draw_large_char_to_buf:
|
|
pushad
|
|
imul esi, 12
|
|
add esi, font_8x12
|
|
mov ebp, 12
|
|
.y_loop:
|
|
push ebx
|
|
push ecx
|
|
mov al, [esi]
|
|
mov ah, 10000000b
|
|
mov dword [temp_counter], 8
|
|
.x_loop:
|
|
test al, ah
|
|
jz .skip_pixel
|
|
cmp ebx, 0
|
|
jl .skip_pixel
|
|
cmp ebx, WIN_W
|
|
jge .skip_pixel
|
|
cmp ecx, 0
|
|
jl .skip_pixel
|
|
cmp ecx, WIN_H
|
|
jge .skip_pixel
|
|
push eax
|
|
mov eax, ecx
|
|
imul eax, STRIDE
|
|
push ebx
|
|
imul ebx, 3
|
|
add eax, ebx
|
|
pop ebx
|
|
add eax, screen_buffer
|
|
mov [eax], dl
|
|
mov [eax+1], dh
|
|
push edx
|
|
shr edx, 16
|
|
mov [eax+2], dl
|
|
pop edx
|
|
pop eax
|
|
.skip_pixel:
|
|
shr ah, 1
|
|
inc ebx
|
|
dec dword [temp_counter]
|
|
jnz .x_loop
|
|
pop ecx
|
|
pop ebx
|
|
inc esi
|
|
inc ecx
|
|
dec ebp
|
|
jnz .y_loop
|
|
popad
|
|
ret
|
|
|
|
render_score_ui:
|
|
mov edx, COL_BLACK
|
|
mov ebx, 530
|
|
mov ecx, SCORE_Y
|
|
xor esi, esi
|
|
call draw_large_char_to_buf
|
|
add ebx, 10
|
|
mov esi, 1
|
|
call draw_large_char_to_buf
|
|
add ebx, 10
|
|
mov esi, 2
|
|
call draw_large_char_to_buf
|
|
add ebx, 10
|
|
mov esi, 3
|
|
call draw_large_char_to_buf
|
|
add ebx, 10
|
|
mov esi, 4
|
|
call draw_large_char_to_buf
|
|
add ebx, 20
|
|
mov eax, [score]
|
|
test eax, eax
|
|
jns .pos
|
|
neg eax
|
|
push eax
|
|
mov ecx, SCORE_Y
|
|
mov esi, 5
|
|
call draw_large_char_to_buf
|
|
add ebx, 10
|
|
pop eax
|
|
.pos:
|
|
mov edi, 10
|
|
xor ecx, ecx
|
|
.dec_loop:
|
|
xor edx, edx
|
|
div edi
|
|
push edx
|
|
inc ecx
|
|
test eax, eax
|
|
jnz .dec_loop
|
|
.print_dec:
|
|
pop edx
|
|
add edx, 6
|
|
push ecx
|
|
mov ecx, SCORE_Y
|
|
mov esi, edx
|
|
mov edx, COL_BLACK
|
|
call draw_large_char_to_buf
|
|
add ebx, 10
|
|
pop ecx
|
|
loop .print_dec
|
|
ret
|
|
|
|
draw_slots:
|
|
pushad
|
|
mov ebx, FOUNDATION_X
|
|
mov ecx, FOUND_Y
|
|
mov dword [temp_counter2], 4
|
|
.f_loop:
|
|
mov edx, COL_SLOT
|
|
mov edi, CARD_W
|
|
mov ebp, CARD_H
|
|
call fill_rect_buf
|
|
add ebx, 60
|
|
dec dword [temp_counter2]
|
|
jnz .f_loop
|
|
mov ebx, 40
|
|
mov ecx, 110
|
|
mov dword [temp_counter2], 7
|
|
.t_loop:
|
|
mov edx, COL_SLOT
|
|
mov edi, CARD_W
|
|
mov ebp, CARD_H
|
|
call fill_rect_buf
|
|
add ebx, 100
|
|
dec dword [temp_counter2]
|
|
jnz .t_loop
|
|
popad
|
|
ret
|
|
|
|
is_card_active:
|
|
push eax
|
|
push ebx
|
|
xor ebx, ebx
|
|
.l:
|
|
cmp ebx, [active_card_count]
|
|
jae .no
|
|
mov eax, [active_stack + ebx*4]
|
|
cmp eax, ecx
|
|
je .yes
|
|
inc ebx
|
|
jmp .l
|
|
.yes:
|
|
pop ebx
|
|
pop eax
|
|
stc
|
|
ret
|
|
.no:
|
|
pop ebx
|
|
pop eax
|
|
clc
|
|
ret
|
|
|
|
build_active_stack:
|
|
pushad
|
|
imul esi, eax, CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
mov bx, [esi+CARD_X]
|
|
mov dx, [esi+CARD_Y]
|
|
movzx ebp, dx
|
|
add ebp, STACK_OFFSET
|
|
.y_search:
|
|
xor ecx, ecx
|
|
.l:
|
|
imul edi, ecx, CARD_STRUCT_SIZE
|
|
add edi, deck_data
|
|
cmp word [edi+CARD_X], bx
|
|
jne .nx
|
|
cmp word [edi+CARD_Y], bp
|
|
jne .nx
|
|
mov edx, [active_card_count]
|
|
mov [active_stack + edx*4], ecx
|
|
inc dword [active_card_count]
|
|
add ebp, STACK_OFFSET
|
|
jmp .y_search
|
|
.nx:
|
|
inc ecx
|
|
cmp ecx, 52
|
|
jl .l
|
|
.done:
|
|
xor ecx, ecx
|
|
.save:
|
|
cmp ecx, [active_card_count]
|
|
jae .fin
|
|
mov eax, [active_stack + ecx*4]
|
|
imul eax, CARD_STRUCT_SIZE
|
|
add eax, deck_data
|
|
mov dx, [eax+CARD_X]
|
|
mov [eax+CARD_OLD_X], dx
|
|
mov dx, [eax+CARD_Y]
|
|
mov [eax+CARD_OLD_Y], dx
|
|
inc ecx
|
|
jmp .save
|
|
.fin:
|
|
popad
|
|
ret
|
|
|
|
check_stack_move:
|
|
pushad
|
|
mov esi, [active_stack]
|
|
imul esi, CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
cmp dword [active_card_count], 1
|
|
jne .tableau_check
|
|
mov ebx, FOUNDATION_X
|
|
xor ecx, ecx
|
|
.f_lp:
|
|
movsx eax, word [esi+CARD_X]
|
|
sub eax, ebx
|
|
add eax, 25
|
|
cmp eax, 50
|
|
ja .next_f
|
|
movsx eax, word [esi+CARD_Y]
|
|
sub eax, FOUND_Y
|
|
add eax, 30
|
|
cmp eax, 60
|
|
ja .next_f
|
|
call check_foundation_logic
|
|
jc .found_match
|
|
.next_f:
|
|
add ebx, 60
|
|
inc ecx
|
|
cmp ecx, 4
|
|
jl .f_lp
|
|
.tableau_check:
|
|
mov ebx, 40
|
|
.col_lp:
|
|
xor ecx, ecx
|
|
mov dword [temp_val], -1
|
|
mov dword [temp_counter], 0
|
|
.find_l:
|
|
imul edi, ecx, CARD_STRUCT_SIZE
|
|
add edi, deck_data
|
|
push ecx
|
|
call is_card_active
|
|
pop ecx
|
|
jc .sk_l
|
|
cmp word [edi+CARD_X], bx
|
|
jne .sk_l
|
|
movzx eax, word [edi+CARD_Y]
|
|
cmp eax, [temp_counter]
|
|
jl .sk_l
|
|
mov [temp_counter], eax
|
|
mov [temp_val], ecx
|
|
.sk_l:
|
|
inc ecx
|
|
cmp ecx, 52
|
|
jl .find_l
|
|
cmp dword [temp_val], -1
|
|
je .empty_col
|
|
mov ecx, [temp_val]
|
|
imul edi, ecx, CARD_STRUCT_SIZE
|
|
add edi, deck_data
|
|
movsx eax, word [esi+CARD_X]
|
|
movsx edx, word [edi+CARD_X]
|
|
sub eax, edx
|
|
add eax, 25
|
|
cmp eax, 50
|
|
ja .nx_col
|
|
movsx eax, word [esi+CARD_Y]
|
|
movsx edx, word [edi+CARD_Y]
|
|
sub eax, edx
|
|
add eax, 30
|
|
cmp eax, 60
|
|
ja .nx_col
|
|
mov al, [esi+CARD_SUIT]
|
|
mov dl, [edi+CARD_SUIT]
|
|
shr al, 1
|
|
shr dl, 1
|
|
cmp al, dl
|
|
je .nx_col
|
|
mov al, [esi+CARD_VALUE]
|
|
mov dl, [edi+CARD_VALUE]
|
|
inc al
|
|
cmp al, dl
|
|
jne .nx_col
|
|
mov dx, word [edi+CARD_Y]
|
|
add dx, STACK_OFFSET
|
|
jmp .apply_move
|
|
.empty_col:
|
|
movsx eax, word [esi+CARD_X]
|
|
sub eax, ebx
|
|
add eax, 25
|
|
cmp eax, 50
|
|
ja .nx_col
|
|
movsx eax, word [esi+CARD_Y]
|
|
sub eax, 110
|
|
add eax, 30
|
|
cmp eax, 60
|
|
ja .nx_col
|
|
cmp byte [esi+CARD_VALUE], 13
|
|
jne .nx_col
|
|
mov dx, 110
|
|
jmp .apply_move
|
|
.nx_col:
|
|
add ebx, 100
|
|
cmp ebx, 740
|
|
jl .col_lp
|
|
xor ecx, ecx
|
|
.back:
|
|
cmp ecx, [active_card_count]
|
|
jae .out
|
|
mov eax, [active_stack + ecx*4]
|
|
imul eax, CARD_STRUCT_SIZE
|
|
add eax, deck_data
|
|
mov dx, [eax+CARD_OLD_X]
|
|
mov [eax+CARD_X], dx
|
|
mov dx, [eax+CARD_OLD_Y]
|
|
mov [eax+CARD_Y], dx
|
|
inc ecx
|
|
jmp .back
|
|
.out:
|
|
popad
|
|
ret
|
|
.found_match:
|
|
; FIXED SCORING: Check Bit 7 of STATE (Scored flag)
|
|
test byte [esi+CARD_STATE], 0x80
|
|
jnz .already_scored
|
|
add dword [score], 10
|
|
or byte [esi+CARD_STATE], 0x80 ; Set Scored Flag
|
|
.already_scored:
|
|
mov word [esi+CARD_X], bx
|
|
mov word [esi+CARD_Y], FOUND_Y
|
|
mov byte [esi+CARD_LOC], 8
|
|
pushad
|
|
mov eax, [active_stack]
|
|
mov [temp_active], eax
|
|
call move_single_to_top
|
|
popad
|
|
call auto_reveal_all
|
|
call check_win
|
|
popad
|
|
ret
|
|
.apply_move:
|
|
xor ecx, ecx
|
|
push eax
|
|
push edx
|
|
mov eax, ebx
|
|
sub eax, 40
|
|
xor edx, edx
|
|
mov edi, 100
|
|
div edi
|
|
mov [temp_val], eax
|
|
pop edx
|
|
pop eax
|
|
mov [temp_counter2], edx
|
|
.sticky_loop:
|
|
cmp ecx, [active_card_count]
|
|
jae .sticky_done
|
|
mov eax, [active_stack + ecx*4]
|
|
imul eax, CARD_STRUCT_SIZE
|
|
add eax, deck_data
|
|
mov word [eax+CARD_X], bx
|
|
mov dx, word [temp_counter2]
|
|
mov word [eax+CARD_Y], dx
|
|
mov dl, byte [temp_val]
|
|
mov byte [eax+CARD_LOC], dl
|
|
add word [temp_counter2], STACK_OFFSET
|
|
inc ecx
|
|
jmp .sticky_loop
|
|
.sticky_done:
|
|
xor ecx, ecx
|
|
.top_loop:
|
|
cmp ecx, [active_card_count]
|
|
jae .ok
|
|
push ecx
|
|
mov eax, [active_stack + ecx*4]
|
|
mov [temp_active], eax
|
|
call move_single_to_top
|
|
call update_active_stack_after_move
|
|
pop ecx
|
|
inc ecx
|
|
jmp .top_loop
|
|
.ok:
|
|
call auto_reveal_all
|
|
popad
|
|
ret
|
|
|
|
update_active_stack_after_move:
|
|
pushad
|
|
mov edx, [temp_active]
|
|
xor ecx, ecx
|
|
.up_lp:
|
|
cmp ecx, [active_card_count]
|
|
jae .up_dn
|
|
mov eax, [active_stack + ecx*4]
|
|
cmp eax, edx
|
|
jbe .no_chg
|
|
dec eax
|
|
mov [active_stack + ecx*4], eax
|
|
.no_chg:
|
|
inc ecx
|
|
jmp .up_lp
|
|
.up_dn:
|
|
popad
|
|
ret
|
|
|
|
check_foundation_logic:
|
|
pushad
|
|
xor eax, eax
|
|
mov dword [temp_val], 0
|
|
mov dword [temp_counter], -1
|
|
xor ebp, ebp
|
|
.find_top:
|
|
imul edi, ebp, CARD_STRUCT_SIZE
|
|
add edi, deck_data
|
|
cmp word [edi+CARD_X], bx
|
|
jne .nx_c
|
|
cmp word [edi+CARD_Y], FOUND_Y
|
|
jne .nx_c
|
|
movzx edx, byte [edi+CARD_VALUE]
|
|
cmp edx, [temp_val]
|
|
jle .nx_c
|
|
mov [temp_val], edx
|
|
mov [temp_counter], ebp
|
|
.nx_c:
|
|
inc ebp
|
|
cmp ebp, 52
|
|
jl .find_top
|
|
mov al, [esi+CARD_VALUE]
|
|
mov dl, [esi+CARD_SUIT]
|
|
cmp dword [temp_counter], -1
|
|
jne .not_empty
|
|
cmp al, 1
|
|
je .valid
|
|
jmp .invalid
|
|
.not_empty:
|
|
mov edi, [temp_counter]
|
|
imul edi, 12
|
|
add edi, deck_data
|
|
cmp dl, [edi+CARD_SUIT]
|
|
jne .invalid
|
|
mov dl, [edi+CARD_VALUE]
|
|
inc dl
|
|
cmp al, dl
|
|
je .valid
|
|
.invalid:
|
|
popad
|
|
clc
|
|
ret
|
|
.valid:
|
|
popad
|
|
stc
|
|
ret
|
|
|
|
check_win:
|
|
pushad
|
|
xor ecx, ecx
|
|
xor eax, eax
|
|
.l:
|
|
imul esi, ecx, CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
cmp byte [esi+CARD_LOC], 8
|
|
jne .no
|
|
inc eax
|
|
.no:
|
|
inc ecx
|
|
cmp ecx, 52
|
|
jl .l
|
|
cmp eax, 52
|
|
jne .out
|
|
cmp byte [game_won], 0
|
|
jne .out
|
|
add dword [score], 100
|
|
mov byte [game_won], 1
|
|
.out:
|
|
popad
|
|
ret
|
|
|
|
auto_reveal_all:
|
|
pushad
|
|
mov ebx, 40
|
|
.col_loop:
|
|
xor esi, esi
|
|
mov dword [temp_val], -1
|
|
xor ecx, ecx
|
|
.find_lowest:
|
|
imul edi, ecx, CARD_STRUCT_SIZE
|
|
add edi, deck_data
|
|
cmp word [edi+CARD_X], bx
|
|
jne .next_card
|
|
movzx eax, word [edi+CARD_Y]
|
|
cmp eax, [temp_val]
|
|
jle .next_card
|
|
mov [temp_val], eax
|
|
mov esi, edi
|
|
.next_card:
|
|
inc ecx
|
|
cmp ecx, 52
|
|
jl .find_lowest
|
|
cmp dword [temp_val], -1
|
|
je .next_col
|
|
or byte [esi+CARD_STATE], 1 ; Reveal face up
|
|
.next_col:
|
|
add ebx, 100
|
|
cmp ebx, 740
|
|
jl .col_loop
|
|
popad
|
|
ret
|
|
|
|
move_single_to_top:
|
|
mov eax, [temp_active]
|
|
cmp eax, 51
|
|
je .done
|
|
imul esi, eax, CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
mov edi, temp_card_buf
|
|
mov ecx, 3
|
|
cld
|
|
rep movsd
|
|
mov eax, [temp_active]
|
|
inc eax
|
|
imul esi, eax, CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
imul edi, [temp_active], CARD_STRUCT_SIZE
|
|
add edi, deck_data
|
|
mov ecx, 51
|
|
sub ecx, [temp_active]
|
|
imul ecx, 3
|
|
rep movsd
|
|
mov esi, temp_card_buf
|
|
mov edi, deck_data + (51 * CARD_STRUCT_SIZE)
|
|
mov ecx, 3
|
|
rep movsd
|
|
.done: ret
|
|
|
|
deal_from_stock:
|
|
pushad
|
|
mov ecx, 51
|
|
.f:
|
|
imul esi, ecx, CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
cmp byte [esi+CARD_LOC], 7
|
|
jne .n
|
|
test byte [esi+CARD_STATE], 1 ; Already visible?
|
|
jnz .n
|
|
.o:
|
|
or byte [esi+CARD_STATE], 1
|
|
mov byte [esi+CARD_LOC], 9
|
|
mov word [esi+CARD_X], WASTE_X
|
|
mov word [esi+CARD_Y], FOUND_Y
|
|
mov [temp_active], ecx
|
|
call move_single_to_top
|
|
popad
|
|
ret
|
|
.n: dec ecx
|
|
jns .f
|
|
call reset_stock
|
|
popad
|
|
ret
|
|
|
|
reset_stock:
|
|
sub dword [score], 20
|
|
xor ecx, ecx
|
|
.l:
|
|
imul esi, ecx, CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
cmp byte [esi+CARD_LOC], 9
|
|
jne .s
|
|
and byte [esi+CARD_STATE], 0xFE ; Set face down
|
|
mov byte [esi+CARD_LOC], 7
|
|
mov word [esi+CARD_X], STOCK_X
|
|
mov word [esi+CARD_Y], FOUND_Y
|
|
.s: inc ecx
|
|
cmp ecx, 52
|
|
jl .l
|
|
ret
|
|
|
|
init_deck:
|
|
mov edi, deck_data
|
|
xor eax, eax
|
|
.s: xor ebx, ebx
|
|
.r: inc ebx
|
|
mov byte [edi+CARD_VALUE], bl
|
|
mov byte [edi+CARD_SUIT], al
|
|
mov byte [edi+CARD_STATE], 0 ; Face down, Not Scored
|
|
mov byte [edi+CARD_LOC], 7
|
|
add edi, CARD_STRUCT_SIZE
|
|
cmp ebx, 13
|
|
jne .r
|
|
inc eax
|
|
cmp eax, 4
|
|
jne .s
|
|
ret
|
|
|
|
shuffle_deck:
|
|
mov dword [temp_counter2], 51
|
|
.sh:
|
|
mcall SF_GET_SYS_TIME
|
|
and eax, 0xFFFF
|
|
xor edx, edx
|
|
mov ebx, [temp_counter2]
|
|
inc ebx
|
|
div ebx
|
|
imul esi, [temp_counter2], CARD_STRUCT_SIZE
|
|
add esi, deck_data
|
|
imul edi, edx, CARD_STRUCT_SIZE
|
|
add edi, deck_data
|
|
mov ecx, 3
|
|
.sw:
|
|
mov eax, [esi]
|
|
mov edx, [edi]
|
|
mov [esi], edx
|
|
mov [edi], eax
|
|
add esi, 4
|
|
add edi, 4
|
|
loop .sw
|
|
dec dword [temp_counter2]
|
|
jnz .sh
|
|
ret
|
|
|
|
layout_tableau:
|
|
mov edi, deck_data
|
|
mov ebx, 40
|
|
xor edx, edx
|
|
.cols:
|
|
mov ecx, 110
|
|
mov eax, edx
|
|
inc eax
|
|
mov ebp, eax
|
|
.cards:
|
|
mov word [edi+CARD_X], bx
|
|
mov word [edi+CARD_Y], cx
|
|
mov byte [edi+CARD_LOC], dl
|
|
dec ebp
|
|
jnz .h
|
|
or byte [edi+CARD_STATE], 1 ; Top card face up
|
|
jmp .nx
|
|
.h:
|
|
and byte [edi+CARD_STATE], 0xFE ; Other cards face down
|
|
.nx:
|
|
add edi, CARD_STRUCT_SIZE
|
|
add ecx, STACK_OFFSET
|
|
cmp edx, 6
|
|
je .cl
|
|
cmp ebp, 0
|
|
jne .cards
|
|
add ebx, 100
|
|
inc edx
|
|
jmp .cols
|
|
.cl:
|
|
cmp ebp, 0
|
|
jne .cards
|
|
.sf:
|
|
cmp edi, deck_data + (52 * CARD_STRUCT_SIZE)
|
|
jae .fin
|
|
mov word [edi+CARD_X], STOCK_X
|
|
mov word [edi+CARD_Y], FOUND_Y
|
|
mov byte [edi+CARD_LOC], 7
|
|
and byte [edi+CARD_STATE], 0xFE
|
|
add edi, CARD_STRUCT_SIZE
|
|
jmp .sf
|
|
.fin: ret
|
|
|
|
; --- DATA & FONTS ---
|
|
title db 'Solitare V1.5.2', 0
|
|
score dd 0
|
|
game_won db 0
|
|
mouse_lock dd 0
|
|
force_redraw db 0
|
|
temp_counter dd 0
|
|
temp_counter2 dd 0
|
|
temp_val dd 0
|
|
mouse_off_x dw 0
|
|
mouse_off_y dw 0
|
|
temp_active dd 0
|
|
temp_card_buf rd 3
|
|
active_card_count dd 0
|
|
active_stack rd 13
|
|
skin_h dd 0
|
|
|
|
font_8x12:
|
|
; S, C, O, R, E, -, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
db 01111100b,10000010b,10000000b,10000000b,01111100b,00000010b,00000010b,10000010b,01111100b,00000000b,00000000b,00000000b ; S
|
|
db 01111100b,10000010b,10000000b,10000000b,10000000b,10000000b,10000000b,10000010b,01111100b,00000000b,00000000b,00000000b ; C
|
|
db 01111100b,10000010b,10000010b,10000010b,10000010b,10000010b,10000010b,10000010b,01111100b,00000000b,00000000b,00000000b ; O
|
|
db 11111100b,10000010b,10000010b,10000010b,11111100b,10010000b,10001000b,10000100b,10000010b,00000000b,00000000b,00000000b ; R
|
|
db 11111110b,10000000b,10000000b,10000000b,11111100b,10000000b,10000000b,10000000b,11111110b,00000000b,00000000b,00000000b ; E
|
|
db 00000000b,00000000b,00000000b,00000000b,11111111b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b ; -
|
|
db 00111100b,01000010b,10000001b,10000001b,10000001b,10000001b,10000001b,01000010b,00111100b,00000000b,00000000b,00000000b ; 0
|
|
db 00011000b,00111000b,00001000b,00001000b,00001000b,00001000b,00001000b,00001000b,00111100b,00000000b,00000000b,00000000b ; 1
|
|
db 01111100b,10000010b,00000010b,00000010b,01111100b,10000000b,10000000b,10000000b,11111110b,00000000b,00000000b,00000000b ; 2
|
|
db 01111100b,10000010b,00000010b,00000010b,00111100b,00000010b,00000010b,10000010b,01111100b,00000000b,00000000b,00000000b ; 3
|
|
db 00001000b,00011000b,00101000b,01001000b,10001000b,11111111b,00001000b,00001000b,00001000b,00000000b,00000000b,00000000b ; 4
|
|
db 11111110b,10000000b,10000000b,11111100b,00000010b,00000010b,00000010b,10000010b,01111100b,00000000b,00000000b,00000000b ; 5
|
|
db 01111100b,10000010b,10000000b,11111100b,10000010b,10000010b,10000010b,10000010b,01111100b,00000000b,00000000b,00000000b ; 6
|
|
db 11111110b,00000010b,00000100b,00001000b,00010000b,00100000b,00100000b,00100000b,00100000b,00000000b,00000000b,00000000b ; 7
|
|
db 01111100b,10000010b,10000010b,10000010b,01111100b,10000010b,10000010b,10000010b,01111100b,00000000b,00000000b,00000000b ; 8
|
|
db 01111100b,10000010b,10000010b,10000010b,10000010b,01111110b,00000010b,10000010b,01111100b,00000000b,00000000b,00000000b ; 9
|
|
|
|
font_5x7:
|
|
; A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, Hearts, Diamonds, Clubs, Spades
|
|
db 01110000b,10001000b,10001000b,11111000b,10001000b,10001000b,10001000b ; A
|
|
db 11110000b,00001000b,00010000b,00100000b,01000000b,10000000b,11111000b ; 2
|
|
db 11110000b,00001000b,00001000b,01110000b,00001000b,00001000b,11110000b ; 3
|
|
db 10001000b,10001000b,10001000b,11111000b,00001000b,00001000b,00001000b ; 4
|
|
db 11111000b,10000000b,10000000b,11110000b,00001000b,00001000b,11111000b ; 5
|
|
db 01110000b,10000000b,10000000b,11110000b,10001000b,10001000b,01110000b ; 6
|
|
db 11111000b,00001000b,00010000b,00100000b,01000000b,01000000b,01000000b ; 7
|
|
db 01110000b,10001000b,10001000b,01110000b,10001000b,10001000b,01110000b ; 8
|
|
db 01110000b,10001000b,10001000b,01111000b,00001000b,00001000b,01110000b ; 9
|
|
db 10111000b,10101000b,10101000b,10101000b,10101000b,10101000b,10111000b ; 10
|
|
db 00011000b,00001000b,00001000b,00001000b,00001000b,10001000b,01110000b ; J
|
|
db 01110000b,10001000b,10001000b,10001000b,10101000b,10010000b,01101000b ; Q
|
|
db 10001000b,10010000b,10100000b,11000000b,10100000b,10010000b,10001000b ; K
|
|
db 01010000b,11111000b,11111000b,01110000b,00100000b,00000000b,00000000b ; Hearts
|
|
db 00100000b,01110000b,11111000b,11111000b,01110000b,00100000b,00000000b ; Diamonds
|
|
db 00100000b,00100000b,11111000b,11111000b,00100000b,00100000b,01110000b ; Clubs
|
|
db 00100000b,01110000b,11111000b,11111000b,01110000b,00100000b,01110000b ; Spades
|
|
|
|
align 4
|
|
deck_data: rb 52 * CARD_STRUCT_SIZE
|
|
i_end:
|
|
|
|
align 4096
|
|
screen_buffer: rb WIN_W * WIN_H * 3 + 32768
|
|
stack_bottom: rb 8192
|
|
stacktop:
|
|
mem_end:
|