From dd15125384d87cd8f224a95b11e8fc928e314985 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 2 Mar 2026 19:06:54 +0000 Subject: [PATCH] Upload files to "programs/games/solitare" V1.5 windows mode --- programs/games/solitare/solitare.asm | 1233 ++++++++++++++++++++++++++ 1 file changed, 1233 insertions(+) create mode 100644 programs/games/solitare/solitare.asm diff --git a/programs/games/solitare/solitare.asm b/programs/games/solitare/solitare.asm new file mode 100644 index 000000000..4f6d3e8c1 --- /dev/null +++ b/programs/games/solitare/solitare.asm @@ -0,0 +1,1233 @@ +; Solitaire V1.5 - Window Alignment Edition +; Platform: MenuetOS / KolibriOS +; Author: Max + +format binary as 'run' +use32 +org 0x0 + +; --- SYSTEM INCLUDES --- +include 'macros.inc' + +; --- CONSTANTS --- +SYS_REDRAW equ 12 +SYS_KEY equ 2 +SYS_BUTTON equ 17 +SYS_MOUSE_POS equ 37 +SYS_DRAW_WINDOW equ 0 +SYS_EXIT equ -1 +SYS_BLIT equ 7 +SYS_RANDOM equ 3 +SYS_DELAY equ 5 +SYS_GET_SKIN_H equ 48 + +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 +CARD_LOC equ 3 +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 + mcall SYS_GET_SKIN_H, 4 + 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 11 + cmp eax, 1 + je on_redraw + cmp eax, 2 + je on_key + cmp eax, 3 + je on_button + + call handle_mouse + + ; Redraw only if there's an active card movement or forced update + cmp dword [active_card_count], 0 + ja update_screen_only + cmp byte [force_redraw], 1 + je update_screen_only + + mcall SYS_DELAY, 1 + jmp event_loop + +on_key: + mcall SYS_KEY + jmp event_loop + +on_button: + mcall SYS_BUTTON + shr eax, 8 + cmp eax, 1 ; Close button (ID 1) + jne event_loop + mcall SYS_EXIT + +on_redraw: + mcall SYS_REDRAW, 1 + + ; EBX: [X start : Window Width] + mov ebx, 100 shl 16 + (WIN_W + 9) + + ; ECX: [Y start : Window Height + skin + border] + mov eax, [skin_h] + add eax, WIN_H + 5 + mov ecx, 100 shl 16 + mov cx, ax + + ; Draw window with skin flag (0x14) + mcall SYS_DRAW_WINDOW, , , 0x14000000 or COL_TABLE, , title + + mcall SYS_REDRAW, 2 + mov byte [force_redraw], 1 + jmp update_screen_only + +update_screen_only: + mov byte [force_redraw], 0 + call prepare_buffer + + ; EDX: [x_dest:16|y_dest:16] - Offset by border and skin height + mov edx, 4 shl 16 + add dx, word [skin_h] + + mcall SYS_BLIT, screen_buffer, WIN_W shl 16 + WIN_H, edx + jmp event_loop + +; --- MOUSE HANDLING --- + +handle_mouse: + pushad + mcall SYS_MOUSE_POS, 1 + mov ebp, eax + shr ebp, 16 + sub ebp, 5 ; Mouse X correction relative to frame + + and eax, 0xFFFF + sub eax, [skin_h] + mov edi, eax ; EDI = Mouse Y inside workspace + + mcall SYS_MOUSE_POS, 2 + test eax, 1 ; Check left button + 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 + + ; Check if clicking on the stock pile + 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 ; Check cards from top to bottom +.f_loop: + imul edx, ebx, CARD_STRUCT_SIZE + add edx, deck_data + movsx esi, word [edx+CARD_X] + movsx ecx, word [edx+CARD_Y] + + ; Bounds checking for the card + 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 + + ; Only pick up face-up cards + cmp byte [edx+CARD_STATE], 1 + jne .next_s + + mov dword [mouse_lock], 1 + mov [active_stack], ebx + mov dword [active_card_count], 1 + + ; Calculate mouse offset within card + 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 + + ; Move active card stack with the mouse + 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: + ; Clear buffer with table color + 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 + + ; Draw static cards + 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 + + ; Draw active (dragged) cards on top + 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] + + ; Shadow/Outline + mov edx, COL_BLACK + mov edi, CARD_W + mov ebp, CARD_H + call fill_rect_buf + + ; Face + inc ebx + inc ecx + mov edx, COL_WHITE + mov edi, CARD_W-2 + mov ebp, CARD_H-2 + call fill_rect_buf + + cmp byte [esi+CARD_STATE], 1 + je .face_up + + ; Back of the card + 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: + ; Suit color determination + mov edx, COL_RED + cmp byte [esi+CARD_SUIT], 2 + jb .is_red + mov edx, COL_BLACK +.is_red: + ; Top left symbol + 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 + + ; Bottom right symbol (inverted position) + 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 ; Print "SCORE" + 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 + + ; Handle score value display + mov eax, [score] + test eax, eax + jns .pos + neg eax + push eax + mov ecx, SCORE_Y + mov esi, 5 ; Minus sign + 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 ; Map digit to font index + 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 + ; Draw foundation slots + 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 + + ; Draw tableau slots + 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 + + ; Logic for single card foundation drop + 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 + + ; Check drop on another card + 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 + + ; Rules check: Opposite color and sequence (Value + 1) + 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: + ; Check drop on empty column (only Kings) + 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 + + ; No valid move found, snap back to original position + 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: + add dword [score], 10 + mov word [esi+CARD_X], bx + mov word [esi+CARD_Y], FOUND_Y + mov byte [esi+CARD_LOC], 8 ; Set location to foundation + 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 + + ; Empty foundation slot only accepts Aces (Value 1) + 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 + mov byte [esi+CARD_STATE], 1 ; Flip the bottom card of the stack face up +.next_col: + add ebx, 100 + cmp ebx, 740 + jl .col_loop + popad + ret + +move_single_to_top: + ; Moves a card to the end of the deck_data array so it's drawn last (on 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 + cmp byte [esi+CARD_STATE], 0 + je .o +.n: dec ecx + jns .f + call reset_stock + popad + ret +.o: + mov byte [esi+CARD_STATE], 1 + mov byte [esi+CARD_LOC], 9 ; Move to waste + 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 + +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 + mov byte [esi+CARD_STATE], 0 + 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 + 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 SYS_RANDOM + 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 + mov byte [edi+CARD_STATE], 1 + jmp .nx +.h: + mov byte [edi+CARD_STATE], 0 +.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 + mov byte [edi+CARD_STATE], 0 + add edi, CARD_STRUCT_SIZE + jmp .sf +.fin: ret + +; --- DATA & FONTS --- +title db 'Solitaire V1.5', 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: +; Definitions for S, C, O, R, E, -, and digits 0-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: +; Definitions for A, 2-10, J, Q, K, and Suits +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: