files
kolibrios/programs/games/flood-it/flood-it.c
leency fcb9f49785 flood-it: Fixed buttons position (#193)
Reviewed-on: #193
Reviewed-by: Max Logaev <maxlogaev@proton.me>
Co-authored-by: leency <lipatov.kiril@gmail.com>
Co-committed-by: leency <lipatov.kiril@gmail.com>
2025-04-03 12:32:18 +02:00

425 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: GPL-2.0-only
// Flood-it! - Strategy game: Flood the board with one color, within a step limit.
// Copyright (C) 2011-2025 Leency <lipatov.kiril@gmail.com>
#include "lib\kolibri.h"
#include "lib\random.h"
system_colors sc;
proc_info Form;
dword help_window_stak[100];
#define DEFAULT_BLOCK_COUNT 14
#define DEFAULT_MAX_CLICKS 25
#define MAX_BLOCK_SIZE 28
char board_size = -1;
int BLOCK_SIZE; //cell size
int BLOCKS_NUM; //number of cells by X and Y
int MAX_CLICKS; //max clicks for win
int CLICKS; //how many clicks user already did
int game_end;
#define USER_PANEL_WIDTH 144
//six colors are used in a game for a cells
//and seventh color is used to mark a cell during filling process
dword FIELD_COLORS[] = {0xf18db6, 0x605ca8, 0xfddc80, 0xdc4a20, 0x46b1e2, 0x7e9d1e, 0x232323};
char BOARD_SIZES[] = "S\0L";
#ifdef LANG_RUS
char *BUTTON_CAPTIONS[]={ " ‡ ­®¢® [F2]", " <20>®¬®éì [F1]", " ‚ë室 [Esc]", 0};
char CLICKS_TEXT[]="Š«¨ª®¢: /";
char LEVELS_TEXT[]=" <20>®«¥:";
char HELP_WINDOW_CAPTION[]="<EFBFBD>®¬®éì";
char *HELP_TEXT[]={ "Š ª ¨£à âì ¢® Flood-it?",
"",
"‚ë¡¥à¨â¥ 梥â, ­ ¦ ¢ ­  ®¤¨­ ¨§ ª¢ ¤à â¨ª®¢. Š«¥âª¨ ®ªà áïâáï",
"í⨬ 梥⮬ <20>€—ˆ<E28094>€Ÿ <E2809A><EFBFBD>…‰ ‹…‚މ - â ª ¢ë ¯à¨á®¥¤¨­¨â¥",
"á®á¥¤­¨¥ ª«¥âª¨ ⮩ ¦¥ ®ªà áª¨. ‡ å¢ â¨âì ¯®«¥ ­ã¦­® § ",
"®£à ­¨ç¥­­®¥ ç¨á«® 室®¢. „®áâ㯭® ¤¢  à §¬¥à  ¤®áª¨.",
"",
"ˆ£à âì â ª¦¥ ¬®¦­® ª« ¢¨è ¬¨:",
"[Q] [W] [E]",
"[A] [S] [D]",
0};
#elif LANG_EST
char *BUTTON_CAPTIONS[]={ "Uus mäng [F2]", "Abi [F1]", "Välju [Esc]", 0};
char CLICKS_TEXT[]="Klikki: /";
char LEVELS_TEXT[]="Väli:";
char HELP_WINDOW_CAPTION[]="Help";
char *HELP_TEXT[]={ "Kuidas mängida mängu Flood-it?",
"",
"Ujuta kogu mänguväli üle ühe värviga lubatud käikude arvuga.",
"Mängu alustad ülemisest vasakust nurgast ja edened valides ühe värvi",
"vajutades nuppudele vasakul. Kui sa muudad värvi pragusel alal,",
"siis iga kokkupuutuv sama värv muutub samaks. Nii saad ujutada",
"teised alad mänguväljal üle. Valida saad 2 mänguvälja suuruse",
"vahel.",
"",
"Mängida saab ka klaviatuuriga:",
"[Q] [W] [E]",
"[A] [S] [D]",
0};
#else
char *BUTTON_CAPTIONS[]={ "Restart [F2]", " Help [F1]", " Exit [Esc]", 0};
char CLICKS_TEXT[]="Clicks: /";
char LEVELS_TEXT[]="Board:";
char HELP_WINDOW_CAPTION[]="Help";
char *HELP_TEXT[]={ "How to play Flood-it?",
"",
"You start from the TOP LEFT corner and progress by selecting one",
"of the colored buttons on the left. When you change your current area",
"color, every adjacent square with the same color also changes, that",
"way you can flood other areas of the board. Select from 2 sizes of",
"the board and try to flood-it in the least amount of steps!",
"",
"You can also play with keyboard:",
"[Q] [W] [E]",
"[A] [S] [D]",
0};
#endif
unsigned char color_matrix[28*28]; //our field
unsigned char loss_matrix[14*14]={
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 3, 2, 2, 2, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2,
2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2,
2, 3, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
};
unsigned char win_matrix[14*14]={
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 4, 1, 4,
4, 1, 4, 1, 4, 1, 4, 4, 4, 1, 4, 4, 1, 4,
4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 1, 4, 1, 4,
4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 1, 4,
4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 4, 1, 4,
4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 4, 1, 4,
4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 4, 1, 4,
4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 4, 1, 4,
4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 4, 1, 4,
4, 4, 1, 4, 1, 4, 4, 1, 4, 1, 4, 4, 1, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
};
void main()
{
int key, id;
set_board_size(0); //small board by default
new_game();
loop() switch(WaitEvent())
{
case evButton:
id = GetButtonID();
IF (id==1) || (id==4) ExitProcess();
IF (id==2) goto _NEW_GAME_MARK;
IF (id==3) goto _HELP_MARK;
IF (id>=100) {
make_turn(id-100);
}
if (id==10) set_board_size(0);
if (id==11) set_board_size(1);
break;
case evKey:
key = GetKeyScancode();
IF (key==01) //Escape
ExitProcess();
IF (key==59) //F1
{
_HELP_MARK:
CreateThread(#help_thread,#help_window_stak);
break;
}
IF (key==60) //F2
{
_NEW_GAME_MARK:
new_game();
draw_clicks_num();
draw_field();
break;
}
IF (key==16) make_turn(0); //Q
IF (key==17) make_turn(1); //W
IF (key==18) make_turn(2); //E
IF (key==30) make_turn(3); //A
IF (key==31) make_turn(4); //S
IF (key==32) make_turn(5); //D
break;
case evReDraw:
draw_window();
}
}
void set_board_size(char s)
{
if (board_size != s) {
board_size = s;
BLOCKS_NUM = board_size + 1 * DEFAULT_BLOCK_COUNT;
MAX_CLICKS = board_size + 1 * DEFAULT_MAX_CLICKS;
BLOCK_SIZE = GetScreenHeight() - 70 / BLOCKS_NUM;
if (BLOCK_SIZE > MAX_BLOCK_SIZE) BLOCK_SIZE = MAX_BLOCK_SIZE;
new_game();
MoveSize(-1, -1, BLOCK_SIZE*BLOCKS_NUM +14+USER_PANEL_WIDTH,
BLOCK_SIZE*BLOCKS_NUM +GetSkinHeight()+14);
}
}
void make_turn(int turn_id)
{
IF (color_matrix[0]==turn_id) return; //ignore no-sence click: first item color is equal to a new color
IF (!game_is_ended()) {
CLICKS++;
draw_clicks_num();
fill_field(turn_id);
if (!game_is_ended()) draw_field();
}
}
void draw_window()
{
int i;
#define BUTTON_SIZE 28
sc.get();
DefineAndDrawWindow(300,176, BLOCK_SIZE*BLOCKS_NUM +14+USER_PANEL_WIDTH,
BLOCK_SIZE*BLOCKS_NUM +GetSkinHeight()+14, 0x74,0,"Flood-it!");
// Fix rolled-up bug
GetProcessInfo(#Form, SelfInfo);
IF (Form.status_window==4) return;
// Fill background to reduce window redraw
for (i=0;i<=4;i++)
{
ESI = sc.work;
IF (i==4) ESI = sc.work_graph;
DrawRegion(USER_PANEL_WIDTH+i-5,i, BLOCK_SIZE*BLOCKS_NUM +9-i-i, ESI);
}
DrawBar(0,0, USER_PANEL_WIDTH-5, BLOCK_SIZE*BLOCKS_NUM+10, sc.work);
// Main buttons to fill the board
#define FILL_BUTTON_SIZE BUTTON_SIZE+8
for (i=0;i<6;i++) {
DefineButton(i%3*FILL_BUTTON_SIZE+17,calc(i/3)*FILL_BUTTON_SIZE+15,
FILL_BUTTON_SIZE,FILL_BUTTON_SIZE, i+100,FIELD_COLORS[i]);
}
// Menu buttons
for (i=0;i<3;i++)
{
DefineButton(17,i*31+140, 13*8+6, 25, i+2,sc.work_button);
WriteText(17+4,i*31+146,0x90,sc.work_button_text,BUTTON_CAPTIONS[i],0);
}
// Board size
WriteText(17,BLOCKS_NUM*BLOCK_SIZE-25+7,0x90,sc.work_text,#LEVELS_TEXT,0);
for (i=0;i<2;i++)
{
IF (board_size == i) {
ESI=sc.work_button;
EDI=sc.work_button_text;
} ELSE {
ESI = sc.work;
EDI = sc.work_text;
}
DefineButton(i*32+69,BLOCKS_NUM*BLOCK_SIZE-24, 26,25, i+10,ESI);
WriteText(i*32+69+9,BLOCKS_NUM*BLOCK_SIZE-24+6,0x90,EDI,#BOARD_SIZES+i+i,0);
$add ebx, 1<<16 //bold
$int 0x40
}
draw_clicks_num();
draw_field();
}
void randomly_fill_the_board()
{
int i;
for (i=0;i<BLOCKS_NUM*BLOCKS_NUM;i++) {
color_matrix[i] = random(6);
}
}
void new_game()
{
CLICKS = 0;
game_end = false;
randomly_fill_the_board();
}
void fill_field(int new_color_id)
{
int i, j,
old_color_id=color_matrix[0],
restart;
int cur_cell;
#define MARKED 6
color_matrix[0]=MARKED;
_RESTART_MARK:
restart=0;
for (i=0;i<BLOCKS_NUM;i++)
for (j=0;j<BLOCKS_NUM;j++)
{
cur_cell = i*BLOCKS_NUM+j;
IF (color_matrix[cur_cell]<>old_color_id) continue; //if not a needed color then continue
IF (color_matrix[cur_cell]==MARKED) continue; //if already marked then continue
IF (j>0) && (color_matrix[i*BLOCKS_NUM+j-1]==MARKED) color_matrix[cur_cell]=MARKED; //left
IF (i>0) && (color_matrix[i-1*BLOCKS_NUM+j]==MARKED) color_matrix[cur_cell]=MARKED; //top
IF (j<BLOCKS_NUM-1) && (color_matrix[i*BLOCKS_NUM+j+1]==MARKED) color_matrix[cur_cell]=MARKED; //right
IF (i<BLOCKS_NUM-1) && (color_matrix[i+1*BLOCKS_NUM+j]==MARKED) color_matrix[cur_cell]=MARKED; //bottom
IF (color_matrix[cur_cell]==MARKED) restart=1;
}
IF (restart) goto _RESTART_MARK;
for (i=0;i<BLOCKS_NUM*BLOCKS_NUM;i++)
IF (color_matrix[i]==MARKED) color_matrix[i]=new_color_id;
}
void draw_win_or_loose_animation(dword matrix)
{
int i, j, ii, jj;
for (i=0;i<14;i++) {
for (j=0;j<14;j++)
{
ii = board_size * 2 + i;
jj = board_size * 2 + j;
color_matrix[ii*BLOCKS_NUM+jj]=
color_matrix[ii+1*BLOCKS_NUM+jj]=
color_matrix[ii*BLOCKS_NUM+jj+1]=
color_matrix[ii+1*BLOCKS_NUM+jj+1]=ESBYTE[i*14+j+matrix];
draw_field();
}
}
}
int field_is_solid()
{
int i;
if (game_end) return 1;
game_end = 1;
for (i=0;i<BLOCKS_NUM*BLOCKS_NUM;i++) {
IF (color_matrix[i]<>color_matrix[0]) game_end = 0;
}
return game_end;
}
int game_is_ended()
{
int i;
if (game_end) return 1;
if (CLICKS>=MAX_CLICKS) //check for game end via max_clicks
{
IF (CLICKS==MAX_CLICKS) //probably user won on the last step
{
if (field_is_solid()) goto _WIN_MARK;
}
draw_win_or_loose_animation(#loss_matrix);
return 1;
} else {
if (!field_is_solid()) return 0;
//field is solid and CLICKS<MAX_CLICKS -> win
_WIN_MARK:
for (i=0;i<25;i++)
{
randomly_fill_the_board();
draw_field();
Pause(7);
}
draw_win_or_loose_animation(#win_matrix);
return 1;
}
}
void draw_clicks_num()
{
#define TEXT_X 19
#define TEXT_Y 100
DrawBar(TEXT_X, TEXT_Y, USER_PANEL_WIDTH-TEXT_X-5,16, sc.work);
WriteText(TEXT_X,TEXT_Y,0x90,sc.work_text,#CLICKS_TEXT,0);
IF (CLICKS<10) EBX=9*8+TEXT_X;
else EBX=8*8+TEXT_X;
WriteText(EBX,TEXT_Y,0x90,sc.work_text,itoa_nosign(CLICKS),0);
WriteText(11*8+TEXT_X,TEXT_Y,0x90,sc.work_text,itoa_nosign(MAX_CLICKS),0);
}
void draw_field()
{
int i, j;
int color_id;
for (i=0;i<BLOCKS_NUM;i++)
for (j=0;j<BLOCKS_NUM;j++)
{
color_id = color_matrix[i*BLOCKS_NUM+j];
DrawBar(j*BLOCK_SIZE+USER_PANEL_WIDTH, i*BLOCK_SIZE+5, BLOCK_SIZE,BLOCK_SIZE, FIELD_COLORS[color_id]);
}
}
void help_thread()
{
int i;
loop() switch (WaitEvent())
{
case evButton:
ExitProcess();
case evKey:
IF (GetKeyScancode()==001) ExitProcess(); //Esc
break;
case evReDraw:
//for (i=0; HELP_TEXT[i]<>0; i++;) {}; //calculate line numbers, predefined i=12 used to reduce size
DefineAndDrawWindow(400,200,612,12*19+25+GetSkinHeight(),0x34,sc.work,#HELP_WINDOW_CAPTION);
WriteText(6,12,0x90,sc.work_text,HELP_TEXT[0],0); //for a bold text
for (i=0; HELP_TEXT[i]<>0; i++;) WriteText(7,i*19+12,0x90,sc.work_text,HELP_TEXT[i],0);
}
}
stop: