Version non regressive pour CG50 et à tester pour FX9860G ...

This commit is contained in:
Jérôme Henry-Barnaudière 2023-12-01 16:23:39 +01:00
parent 010f0fb66b
commit b981d1375d
17 changed files with 191 additions and 52 deletions

View File

@ -3,7 +3,8 @@
* Ajouts
* Génération pour la FX9860G
* Corrections
* CMakeLists.txt définit la constantes DEST_CASIO_CALC
* CMakeLists.txt définit (enfin) la constante DEST_CASIO_CALC
#### v0.4
* 29 nov. 2023
* Ajouts

View File

@ -29,7 +29,7 @@ La majorité des comportements est régi par des constantes que l'on peut trouve
* `src/consts.h` - Contantes et définitions générales de l'application
* `src/shared/casioCalcs.h` - Constantes spécifiques aux calculatrices.
A défaut, les constantes, toujours en majusucules dans les sources, sont définies avec les objets qui les concernent spécifiquement. Par exemple `src/shared/tabs.h` propose les définitions liées aux onglets.
A défaut, les constantes, toujours en majusucules dans les sources, sont définies avec les objets qui les concernent spécifiquement. Par exemple `src/shared/tabs.h` et `src/shared/tabs.cpp` proposent les définitions liées aux onglets.
Faute d'émulateur, tous les sources sont 100% fonctionnels en C/CPP ANSI. Ils peuvent donc être compilés dans un projet Windows (testé avec Visual Studio) ou sous Linux. Dans ce cas seuls les affichages ne seront pas effectués :).
@ -57,6 +57,7 @@ L'application se présente sous la forme d'onglets associés aux touches de cont
| ![F4](assets/key_F4.png) | Affichage de **l'ombre de la pièce**. En l'absence d'ombre les lignes complètes raporteront plus de points. Les ombres sont affichées par défaut.|
| ![F5](assets/key_F5.png) | **Lancement** d'une partie avec les paramètres sélectionnés.|
| ![F6](assets/key_F6.png) | **Sortie** de l'application.|
| ![left](assets/key_left.png) ![right](assets/key_right.png)| Modification de la valeur du paramètre dans les onglets *Level* et *Lines*.|
| ![shift](assets/key_shift.png) ![7](assets/key_7.png)| Activation / désactivation de la **capture** (communication avec `fxlink`). Il faut le programme soit compilé en mode *TRACE*.|
| ![shift](assets/key_alpha.png) ![7](assets/key_mult.png)| Affichage du tableau des scores. |
@ -118,4 +119,9 @@ Jeu en mode normal :
... la même partie continue en affichage vertical :
![Vertical](assets/vert.png)
![Vertical](assets/vert.png)
Affichage des meilleurs scores à partir de la page principale :
![high](assets/best.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1010 B

After

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1010 B

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 820 B

BIN
assets/best.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -37,7 +37,7 @@ extern "C" {
// App. infos
#define APP_NAME "geeTetris"
#define APP_VERSION "0.5-1"
#define APP_VERSION "0.5-2"
#define APP_AUTHOR "GeeHB"
// Playfield's dimensions (in box units)
@ -60,18 +60,24 @@ enum VALUE_ID{
COMPLETED_LINES_ID = 2,
VAL_COUNT = COMPLETED_LINES_ID + 1
};
#ifdef FX9860G
#define SCORE_STR "Sc: "
#define LEVEL_STR "Le: "
#define COMPLETED_LINES_STR "Li: "
#define MAX_VALUE_NAME_LEN 13
#else
#define SCORE_STR "Score : "
#define LEVEL_STR "Level : "
#define COMPLETED_LINES_STR "Lines : "
#define MAX_VALUE_NAME_LEN 30
#define MAX_VALUE_NAME_LEN 30
#endif // #ifdef FX9860G
//
// Colour IDs
//
enum COLOUR_ID{
COLOUR_ID_BOARD = 0x00,
COLOUR_ID_BOARD = 0,
// 1 -> 7 : Pieces colours (nCurses ID)
COLOUR_ID_SHADOW = 8,
COLOUR_ID_TEXT = 9,
@ -79,7 +85,7 @@ enum COLOUR_ID{
COLOUR_ID_BKGRND = 11,
//#define COLOUR_ID_ANIMATE 12 // animation When line if full
COLOUR_ID_NONE = 12,
LAST_COLOUR_ID = COLOUR_ID_NONE
LAST_COLOUR_ID = COLOUR_ID_BKGRND
};
// Key codes

View File

@ -110,6 +110,12 @@ int main(){
else{
if (KEY_CODE_SHOW_SCORES == car && keys.isPressed(MOD_ALPHA)){
tetrisGame::showScores();
/*
// "window" mode is not compatible with capture ????
gCapture.install();
drect(0, 0, 1, 1, C_WHITE);
dupdate();
*/
currentTab->select();
}
#ifdef TRACE_MODE

View File

@ -32,6 +32,26 @@ extern "C" {
// Box dimensions in pixels
//
#ifdef FX9860G
#define CASIO_BOX_WIDTH 3
#define CASIO_BOX_WIDTH_ROTATED 5
#define CASIO_BOX_WIDTH_NP CASIO_BOX_WIDTH // next piece preview
#define CASIO_BOX_WIDTH_NP_ROTATED 3
// Playfield pos & dims
//
#define CASIO_PLAYFIELD_LEFT 0
#define CASIO_PLAYFIELD_BORDER 0
#define CASIO_BORDER_GAP 1
// Texts pos & dims
//
#define CASIO_INFO_LEFT 45
#define CASIO_INFO_TOP 1
#define CASIO_INFO_GAP 1 // between border and text
#else
#define CASIO_BOX_WIDTH 9
#define CASIO_BOX_WIDTH_ROTATED 14
@ -49,6 +69,7 @@ extern "C" {
#define CASIO_INFO_LEFT 250
#define CASIO_INFO_TOP 10
#define CASIO_INFO_GAP 4 // between border and text
#endif // #ifdef FX9860G
// During games draings appends in 2 zones :
// game zone and next-piece (ie. preview) zone

View File

@ -21,17 +21,21 @@
// Construction
//
sList::_node::_node(uint32_t escore, uint16_t elines, uint16_t elevel){
sList::_node::_node(uint32_t escore, uint16_t elines, [[maybe_unused]] uint16_t elevel){
record.score = escore;
record.lines = elines;
#ifndef FX9860G
record.level = elevel;
#endif // #ifndef FX9860G
next = nullptr;
}
sList::_node::_node(RECORD& score){
record.score = score.score;
record.lines = score.lines;
#ifndef FX9860G
record.level = score.level;
#endif // #ifndef FX9860G
next = nullptr;
}
@ -46,15 +50,21 @@ int8_t sList::_node::compare(_node* other){
return -2;
}
if (other->record.score < record.score ||
(other->record.score == record.score && other->record.lines < record.lines) ||
(other->record.score == record.score && other->record.lines == record.lines && other->record.level < record.level )){
if (other->record.score < record.score
|| (other->record.score == record.score && other->record.lines < record.lines)
#ifndef FX9860G
|| (other->record.score == record.score && other->record.lines == record.lines && other->record.level < record.level )
#endif // #ifndef FX9860G
){
return -1;
}
if (other->record.score > record.score ||
(other->record.score == record.score && other->record.lines > record.lines) ||
(other->record.score == record.score && other->record.lines == record.lines && other->record.level > record.level )){
if (other->record.score > record.score
|| (other->record.score == record.score && other->record.lines > record.lines)
#ifndef FX9860G
|| (other->record.score == record.score && other->record.lines == record.lines && other->record.level > record.level )
#endif // #ifndef FX9860G
){
return 1;
}

View File

@ -37,18 +37,32 @@ extern "C" {
#endif // #ifdef DEST_CASIO_CALC
// # of scores in file
#ifdef FX9860G
#define MAX_SCORES 5
#else
#define MAX_SCORES 10
#endif // #ifdef FX9860G
// Size in bytes of a score
#ifdef FX9860G
#define SIZE_SCORE 6 // (sizeof(int32_t) + sizeof(int16_t))
#else
#define SIZE_SCORE 8 // (sizeof(int32_t) + 2*sizeof(int16_t))
#endif // #ifdef FX9860G
// Size of the file
#define SIZE_SCORES_FILE (SIZE_SCORE*MAX_SCORES)
// Size of the Window
#ifdef FX9860G
#define WIN_X 9
#define WIN_WIDTH 110
#define WIN_HEIGHT 60
#else
#define WIN_X 20
#define WIN_WIDTH 190
#define WIN_HEIGHT 140
#endif // #ifdef FX9860G
//---------------------------------------------------------------------------
//--
@ -66,7 +80,9 @@ class sList{
// Score and other informations
uint32_t score;
uint16_t lines;
uint16_t level;
#ifndef FX9860G
uint16_t level; // Level aren't stored on FX9860G
#endif // #ifndef FX9860G
}RECORD;
// Internal node

View File

@ -46,12 +46,12 @@ enum DEF_COLOUR{
COLOUR_BLACK = C_BLACK,
COLOUR_WHITE = C_WHITE,
COLOUR_RED = C_DARK,
COLOUR_GREEN = C_LIGHT,
COLOUR_YELLOW = C_LIGHT,
COLOUR_GREEN = C_BLACK,
COLOUR_YELLOW = C_BLACK,
COLOUR_BLUE = C_DARK,
COLOUR_LT_BLUE = C_LIGHT,
COLOUR_LT_BLUE = C_BLACK,
COLOUR_PURPLE = C_DARK,
COLOUR_CYAN = C_LIGHT,
COLOUR_CYAN = C_BLACK,
COLOUR_ORANGE = C_DARK,
COLOUR_LT_GREY = C_LIGHT,
COLOUR_GREY = C_WHITE,

View File

@ -39,9 +39,27 @@ extern font_t font_horz;
//--
//---------------------------------------------------------------------------
#ifdef FX9860G
// tabs colors
#define COLOUR_SELECTED C_BLACK
#define COLOUR_UNSELECTED C_LIGHT
// Ranged values colors - selected
#define COLOUR_VAL_TXT_SEL COLOUR_WHITE
#define COLOUR_VAL_BK_SEL COLOUR_BLACK
#else
// tabs colors
#define COLOUR_SELECTED COLOUR_BLUE
#define COLOUR_UNSELECTED COLOUR_GREY
#define COLOUR_BK_HILITE COLOUR_LT_BLUE
// Ranged values colors - selected
#define COLOUR_VAL_TXT_SEL COLOUR_WHITE
#define COLOUR_VAL_BK_SEL COLOUR_LT_BLUE
#endif // #ifdef FX9860G
// Ranged values colors - unselected
#define COLOUR_VAL_TXT_UNSEL COLOUR_BLACK
#define COLOUR_VAL_BK_UNSEL COLOUR_WHITE
//---------------------------------------------------------------------------
//--
@ -338,8 +356,9 @@ void tabRangedValue::_selectValue(int8_t value, bool select){
uint16_t x(xPos_ + (value - minVal_) * TAB_RANGE_BOX_WIDTH);
#ifdef DEST_CASIO_CALC
drect(x + 1, yPos_ + 1 , x + TAB_RANGE_BOX_WIDTH - 1, yPos_ + TAB_RANGE_BOX_WIDTH - 1 , select?COLOUR_BK_HILITE:COLOUR_WHITE);
dprint(x + 5, yPos_ + 3, select?COLOUR_WHITE:COLOUR_BLACK, "%d", value);
drect(x + 1, yPos_ + 1 , x + TAB_RANGE_BOX_WIDTH - 1, yPos_ + TAB_RANGE_BOX_WIDTH - 1 ,
select?COLOUR_VAL_BK_SEL:COLOUR_VAL_BK_UNSEL);
dprint(x + 5, yPos_ + 3, select?COLOUR_VAL_TXT_SEL:COLOUR_VAL_TXT_UNSEL, "%d", value);
#else
x++; // for compiler
#endif // #ifdef DEST_CASIO_CALC

View File

@ -20,7 +20,7 @@
#ifdef DEST_CASIO_CALC
#include "scrCapture.h" // capture only on TRACE mode
// #define TRACE_MODE 1 // Only for tests
//#define TRACE_MODE 1 // Only for tests
#else
#ifdef TRACE_MODE // ???
#undef TRACE_MODE

View File

@ -293,31 +293,46 @@ void tetrisGame::showScores(int32_t score, uint32_t lines, uint32_t level){
wInf.position.y = WIN_X;
wInf.position.w = WIN_WIDTH;
wInf.position.h = WIN_HEIGHT;
wInf.bkColour = COLOUR_LT_GREY;
#ifndef FX9860G
wInf.bkColour = COLOUR_LT_GREY;
#endif // #ifdef FX9860G
scWin.create(wInf);
sList::PNODE current(scores.head());
if (nullptr == current){
scWin.drawText("La liste est vide", -1, -1, COLOUR_RED);
scWin.drawText("La liste est vide", -1, -1
#ifndef FX9860G
, COLOUR_RED
#endif // #ifndef FX9860G
);
}
else{
uint8_t count(0);
int px(15), py(8);
char line[25];
char line[26];
while (current && count < MAX_SCORES){
line[0] = 0;
__valtoa(++count, NULL, line, 3);
__valtoa(current->record.score, NULL, line + 3, 8); // score
__valtoa(current->record.lines, NULL, line + 11, 5); // lines
__valtoa(current->record.level, NULL, line + 16, 5); // level
__valtoa(current->record.score, NULL, line + 3, 9); // score
__valtoa(current->record.lines, NULL, line + 12, 5); // lines
#ifndef FX9860G
// No "levels" for FX9860G
__valtoa(current->record.level, NULL, line + 17, 5); // level
#endif // FX9860G
#ifndef DEST_CASIO_CALC
if (score == (int32_t)current->record.score){
line[0] = '>';
}
#endif // #ifndef DEST_CASIO_CALC
scWin.drawText(line, px, py, (score == (int32_t)current->record.score)?COLOUR_RED:COLOUR_BLUE);
//scWin.update();
scWin.drawText(line, px, py, (score == (int32_t)current->record.score)?
#ifndef FX9860G
COLOUR_RED:COLOUR_BLUE
#else
C_BLACK:C_LIGHT
#endif // FX9860G
);
// next ...
py+=11;
@ -1084,7 +1099,11 @@ void tetrisGame::_scores2List(char* data, sList& scores){
// append to list (no need to add, values are already ordered)
if (record.score){
scores.append(record.score, record.lines, record.level);
scores.append(record.score, record.lines
#ifndef FX9860G
, record.level
#endif // #ifndef FX9860G
);
}
pos+=SIZE_SCORE; // next record
}

View File

@ -29,15 +29,17 @@ extern bopti_image_t img_geeTetris;
// The current tab is selected => show splash screen
//
uint8_t aboutTab::select(){
// Draw the image and text
// Draw the image and copyright
#ifdef DEST_CASIO_CALC
clearScreen();
dimage(0, 0, &img_geeTetris);
char copyright[255]; // Should be enough !
strcpy(copyright, APP_NAME);
#ifdef FXCG50
strcat(copyright, " par ");
strcat(copyright, APP_AUTHOR);
#endif // #ifdef FX9860G
strcat(copyright, " v");
strcat(copyright, APP_VERSION);

View File

@ -5,7 +5,7 @@
#
# Auteur : JHB
#
# Date : 09/11/2023
# Date : 01/12/2023
#
from PIL import Image
@ -17,23 +17,40 @@ SRC_FILE = "base.png"
SRC_W = 166 # Dimensions réelles de l'image
SRC_H = 45
# Ficier destinatation
DEST_FILE = "../assets-cg/coloured.png"
DEST_W = 396
DEST_H = 202 # Hauteur casio - barre de menu
# Ficier destinatation CG
#
DEST_CG_FILE = "../assets-cg/coloured.png"
DEST_CG_W = 396
DEST_CG_H = 202 # Hauteur casio - barre de menu
# Largeur d'un cube
CUBE_W = 6
SQUARE_CG_W = 6
# Offset sur la source
SRC_STEP = int(CUBE_W * SRC_W / DEST_W) + 1
SRC_CG_STEP = int(SQUARE_CG_W * SRC_W / DEST_CG_W) + 1
DEST_OFFSET_X = 0
DEST_OFFSET_Y = 30
DEST_CG_OFFSET_X = 30
DEST_CG_OFFSET_Y = 30
# Ficier destinatation FX
#
DEST_FX_FILE = "../assets-fx/bw.png"
DEST_FX_W = 128
DEST_FX_H = 42
# Largeur d'un cube
SQUARE_FX_W = 3
# Offset sur la source
SRC_FX_STEP = int(SQUARE_FX_W * SRC_W / DEST_FX_W) + 1
DEST_FX_OFFSET_X = 0
DEST_FX_OFFSET_Y = 0
# Couleurs utilisées
#
COLOUR_WHITE = (255, 255, 255)
COLOUR_BLACK = (0, 0, 0)
COLOUR_BKGROUND = (245, 245, 245)
# Couleurs des pieces
@ -50,8 +67,8 @@ COLOUR_ORANGE = (255, 128, 0)
# dst : image destination
# x,y : coin superieur gauche
# largeur, hauteur : dimensions
# couleur_bord : Couleur de la bordure au format RGB (ou None si pas de bordure)
# couleur_fond : Couleur de remplissage au format RGB (ou None si vide)
# couleur_bord : Couleur de la bordure au format RGB (ou None si pas de bordure)
#
def draw_rectangle(dest, x, y, largeur, hauteur, couleur_fond = None, couleur_bord = None):
# Le contour ?
@ -84,21 +101,37 @@ if __name__ == "__main__":
colours.append(COLOUR_ORANGE)
src = Image.open(SRC_FILE)
dst = Image.new('RGB', (DEST_W, DEST_H), COLOUR_BKGROUND)
width = int(SRC_W / SRC_STEP)
height = int(SRC_H / SRC_STEP)
# For CG calc.
#
dstCG = Image.new('RGB', (DEST_CG_W, DEST_CG_H), COLOUR_BKGROUND)
width = int(SRC_W / SRC_CG_STEP)
height = int(SRC_H / SRC_CG_STEP)
for x in range(width):
for y in range(height):
r,g,b,_ = src.getpixel((x*SRC_STEP, y*SRC_STEP))
r,g,b,_ = src.getpixel((x*SRC_CG_STEP, y*SRC_CG_STEP))
colourID = int(x / 9) % 7 # for the pixel
if COLOUR_WHITE != (r,g,b):
draw_rectangle(dst, x * CUBE_W + DEST_OFFSET_X, y * CUBE_W + DEST_OFFSET_Y, CUBE_W, CUBE_W, colours[colourID])
draw_rectangle(dstCG, x * SQUARE_CG_W + DEST_CG_OFFSET_X, y * SQUARE_CG_W + DEST_CG_OFFSET_Y, SQUARE_CG_W, SQUARE_CG_W, colours[colourID])
# FX9660G calc.
#
dstFX = Image.new('RGB', (DEST_FX_W, DEST_FX_H), COLOUR_WHITE)
width = int(SRC_W / SRC_FX_STEP)
height = int(SRC_H / SRC_FX_STEP)
for x in range(width):
for y in range(height):
r,g,b,_ = src.getpixel((x*SRC_FX_STEP, y*SRC_FX_STEP))
if COLOUR_WHITE != (r,g,b):
draw_rectangle(dstFX, x * SQUARE_FX_W + DEST_FX_OFFSET_X, y * SQUARE_FX_W + DEST_FX_OFFSET_Y, SQUARE_FX_W, SQUARE_FX_W, None, COLOUR_BLACK)
# Enregistrement
dst.save(DEST_FILE, 'png')
# Enregistrements
dstCG.save(DEST_CG_FILE, 'png')
dstFX.save(DEST_FX_FILE, 'png')
# EOF