diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b59d06..9f999b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,14 +13,17 @@ set(SOURCES src/main.c src/core.c src/display.c + src/menus.c ) set(ASSETS) set(ASSETS_fx + assets-fx/calccity.png assets-fx/large_tileset.png assets-fx/large_water.png assets-fx/title.png + assets-fx/fn_keys.png ) set(ASSETS_cg) diff --git a/assets-fx/calccity.png b/assets-fx/calccity.png new file mode 100644 index 0000000..a069279 Binary files /dev/null and b/assets-fx/calccity.png differ diff --git a/assets-fx/fn_keys.png b/assets-fx/fn_keys.png new file mode 100644 index 0000000..912a57f Binary files /dev/null and b/assets-fx/fn_keys.png differ diff --git a/assets-fx/fxconv-metadata.txt b/assets-fx/fxconv-metadata.txt index 74707b1..fc09555 100644 --- a/assets-fx/fxconv-metadata.txt +++ b/assets-fx/fxconv-metadata.txt @@ -1,3 +1,11 @@ *.png: type: bopti-image - name_regex: (.*)\.png img_\1 \ No newline at end of file + name_regex: (.*)\.png img_\1 + +calccity.png: + type: font + name: font_calccity + charset: print + grid.size: 5x6 + grid.padding: 1 + proportional: True \ No newline at end of file diff --git a/src/calccity.c b/src/calccity.c index 510dfd5..0ce9e8c 100644 --- a/src/calccity.c +++ b/src/calccity.c @@ -1,2 +1,3 @@ #include "calccity.h" +static const char tiles_names = {}; \ No newline at end of file diff --git a/src/calccity.h b/src/calccity.h index 7666150..d44884e 100644 --- a/src/calccity.h +++ b/src/calccity.h @@ -3,41 +3,42 @@ #include - struct calccity { // human's statistics = {happyness, health, education, housing, work, food} - signed long humans[6]; + unsigned long humans[6]; // population evolution = {population, birth_rate, death_rate, immigration, emigration} - signed long population[5]; + unsigned long population[5]; // trade statistics = {import, export, production, commercial, industrial, annual_cost} - signed long trade[6]; + unsigned long trade[6]; // production = {water, power} - signed long production[2]; + unsigned long production[2]; // consumption = {water, power} - signed long consumption[2]; + unsigned long consumption[2]; // some others statistics = {treasure, crime, safety, fire_hazard, nuclear_hazard, pollution, transport, grabage, graves} - signed long misc[9]; + unsigned long misc[9]; // taxes in percents on {housing, trade, industry, export} - int taxes[4]; + unsigned int taxes[4]; // fund in percents on {police, fireman, education, heathcare} - int funds[4]; + unsigned int funds[4]; // in-game time int month, year; int blinker; + int tick; // in-game options uint8_t disaster; uint8_t animation; int time_speed; + int menu; }; @@ -57,6 +58,6 @@ struct map }; -#define ENGINE_TICK 1000 +#define ENGINE_TICK 100 #endif /* _CALCCITY_H */ \ No newline at end of file diff --git a/src/core.c b/src/core.c index 81cb056..ad1796d 100644 --- a/src/core.c +++ b/src/core.c @@ -17,14 +17,19 @@ int callback_tick(volatile int *tick) void default_values(struct calccity *calccity, struct camera *camera, struct map *map) { + srand(20211104); + // Initialisation of struct calccity memset(calccity, 0, sizeof *calccity); // Treasure - calccity->misc[0] = 500000; + calccity->misc[0] = 5000; for (int i = 0; i < 4; i++) + { calccity->taxes[i] = 10; + calccity->funds[i] = 100; + } calccity->month = 1; calccity->year = 1900; @@ -32,13 +37,13 @@ void default_values(struct calccity *calccity, struct camera *camera, struct map calccity->disaster = 1; calccity->animation = 1; - calccity->time_speed = 30; + calccity->time_speed = 5100; // Initialisation of struct camera memset(camera, 0, sizeof *camera); - camera->cursor_x = 64; - camera->cursor_y = 32; + camera->cursor_x = 2; + camera->cursor_y = 2; // Initialisation of struct map @@ -49,15 +54,55 @@ void default_values(struct calccity *calccity, struct camera *camera, struct map // Water if ((x * y == 0) || (x == 49 || y == 49)) map->data[y][x] = 139; - - // Shorelines - - // Ground else map->data[y][x] = 48 + rand() % 2; + + // Shorelines + switch (y) + { + case 1: + switch (x) + { + case 1: + map->data[y][x] = 110; + break; + case 48: + map->data[y][x] = 112; + break; + + default: + if (x != 0 && x != 49) map->data[y][x] = 111; + break; + } + break; + + case 48: + switch (x) + { + case 1: + map->data[y][x] = 130; + break; + + case 48: + map->data[y][x] = 132; + break; + + default: + if (x != 0 && x != 49) map->data[y][x] = 131; + break; + } + break; + + default: + if (y != 0 && y != 49) + { + if (x == 1) map->data[y][x] = 120; + if (x == 48) map->data[y][x] = 122; + } + } } } @@ -76,6 +121,27 @@ int rtc_key(void) } +void next_step(struct calccity *calccity) +{ + calccity->tick += ENGINE_TICK; + + // In-game animation + if (calccity->animation && !(calccity->tick % 1000)) + calccity->blinker = (calccity->blinker + 1 ) % 2; + + // In-game time + if (!(calccity->tick % calccity->time_speed)) + { + calccity->month ++; + if (calccity->month > 12) + { + calccity->month = 1; + calccity->year ++; + } + } +} + + void main_loop(struct calccity *calccity, struct camera *camera, struct map *map) { // Timer initialisation @@ -89,12 +155,92 @@ void main_loop(struct calccity *calccity, struct camera *camera, struct map *map while (!end) { - display_map(calccity, camera, map); + // Real-time clock system + while (!tick) sleep(); + tick = 0; + next_step(calccity); + + // Display map + display_large_map(calccity, camera, map); + display_around(calccity, camera); + + // Get and manage input key = rtc_key(); + keyboard_managment(calccity, camera, key); + // Open the menu + switch (calccity->menu) + { + // Tax and funds + case 4: + menu_4(calccity); + break; + + case 5: + menu_5(calccity); + break; + + // Options + case 6: + end = menu_6(calccity); + break; + } + calccity->menu = 0; } // Free timer if (t >= 0) timer_stop(t); +} + + +void keyboard_managment(struct calccity *calccity, struct camera *camera, const int key) +{ + switch (key) + { + case KEY_UP: + if (camera->cursor_y > 0) camera->cursor_y --; + else if (camera->y > 0) camera->y --; + break; + + case KEY_RIGHT: + if (camera->cursor_x < 14) camera->cursor_x ++; + else if (camera->x < 42) camera->x ++; + break; + + case KEY_DOWN: + if (camera->cursor_y < 6) camera->cursor_y ++; + else if (camera->y < 46) camera->y ++; + break; + + case KEY_LEFT: + if (camera->cursor_x > 0) camera->cursor_x --; + else if (camera->x > 0) camera->x --; + break; + + + case KEY_F1: + calccity->menu = 1; + break; + + case KEY_F2: + calccity->menu = 2; + break; + + case KEY_F3: + calccity->menu = 3; + break; + + case KEY_F4: + calccity->menu = 4; + break; + + case KEY_F5: + calccity->menu = 5; + break; + + case KEY_F6: + calccity->menu = 6; + break; + } } \ No newline at end of file diff --git a/src/core.h b/src/core.h index 3289348..408ea95 100644 --- a/src/core.h +++ b/src/core.h @@ -3,6 +3,7 @@ #include "calccity.h" #include "display.h" +#include "menus.h" // callback_tick : time function int callback_tick(volatile int *tick); @@ -13,7 +14,13 @@ void default_values(struct calccity *current_game, struct camera *camera, struct // rtc_key : get a key with RTC system int rtc_key(void); +// next_step : compute in-game time +void next_step(struct calccity *calccity); + // main_loop : game main loop void main_loop(struct calccity *calccity, struct camera *camera, struct map *map); +// keyboard_managment : get the key and manage input +void keyboard_managment(struct calccity *calccity, struct camera *camera, const int key); + #endif /* _CORE_H */ \ No newline at end of file diff --git a/src/display.c b/src/display.c index 260bcdd..a6ef94b 100644 --- a/src/display.c +++ b/src/display.c @@ -15,33 +15,57 @@ void title_screen(void) } -void display_map(struct calccity *calccity, struct camera *camera, struct map *map) +void display_large_map(struct calccity *calccity, struct camera *camera, struct map *map) { extern const bopti_image_t img_large_tileset; extern const bopti_image_t img_large_water; - if (calccity->animation) - calccity->blinker = (calccity->blinker + 1 ) % 2; - else - calccity->blinker = 0; - dclear(C_WHITE); - for (int y = camera->y; y <= camera->y + 3; y++) + + for (int y = 0; y < 4; y++) { - for (int x = camera->x; x <= camera->x + 7; x ++) + for (int x = 0; x < 8; x ++) { + int cam_x = x + camera->x, cam_y = y + camera->y; // Water - if (map->data[y][x] == 139) - dsubimage(x * 15, y * 15, &img_large_water, 15 * calccity->blinker, 0, 15 * (calccity->blinker + 1), 15, DIMAGE_NONE); + if (cam_y > 49 || cam_x > 49 || map->data[cam_y][cam_x] == 139) + dsubimage(3 + x * 15, y * 15, &img_large_water, 15 * calccity->blinker, 0, 15 * (calccity->blinker + 1), 15, DIMAGE_NONE); else { - unsigned tile_id = map->data[y][x]; - unsigned int tile_x = 16 * (tile_id % 10); - unsigned int tile_y = 16 * (tile_id / 10); + unsigned tile_id = map->data[cam_y][cam_x]; + unsigned int tile_x = 15 * (tile_id % 10); + unsigned int tile_y = 15 * (tile_id / 10); - dsubimage(x * 15, y * 15, &img_large_tileset, tile_x, tile_y, 15, 15, DIMAGE_NONE); + dsubimage(3 + x * 15, y * 15, &img_large_tileset, tile_x, tile_y, 15, 15, DIMAGE_NONE); } } } + +} + + +void display_around(struct calccity *calccity, struct camera *camera) +{ + extern const bopti_image_t img_fn_keys; + + // Functions keys + dimage(3, 57, &img_fn_keys); + + // Frame around screen + dline(3, 0, 123, 0, C_BLACK); + dline(3, 56, 123, 56, C_BLACK); + dline(3, 0, 3, 56, C_BLACK); + dline(123, 0, 123, 56, C_BLACK); + + // Date in the top-left corner + dprint_opt(4, 1, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, "%d-%d", calccity->month, calccity->year); + + // Cursor + drect_border(8 * camera->cursor_x + 3, 8 * camera->cursor_y, 8 * camera->cursor_x + 11, 8 * camera->cursor_y + 8, C_WHITE, 1, C_BLACK); + dline(8 * camera->cursor_x + 6, 8 * camera->cursor_y + 4, 8 * camera->cursor_x + 8, 8 * camera->cursor_y + 4, C_BLACK); + dline(8 * camera->cursor_x + 7, 8 * camera->cursor_y + 3, 8 * camera->cursor_x + 7, 8 * camera->cursor_y + 5, C_BLACK); + + dupdate(); } + diff --git a/src/display.h b/src/display.h index 78fa18a..9e4f937 100644 --- a/src/display.h +++ b/src/display.h @@ -6,7 +6,10 @@ // title_screen : display title screen void title_screen(void); -// display_map : display the current state of the map -void display_map(struct calccity *calccity, struct camera *camera, struct map *map); +// display_large_map : display the current state of the large map +void display_large_map(struct calccity *calccity, struct camera *camera, struct map *map); + +// display_around : display the screen frame and cursor +void display_around(struct calccity *calccity, struct camera *camera); #endif /* _DISPLAY_H */ \ No newline at end of file diff --git a/src/main.c b/src/main.c index 9b49904..d2d7a95 100644 --- a/src/main.c +++ b/src/main.c @@ -1,8 +1,12 @@ +#include #include "core.h" int main(void) { + extern font_t font_calccity; + dfont(&font_calccity); + title_screen(); // Game initialisation diff --git a/src/menus.c b/src/menus.c new file mode 100644 index 0000000..425c888 --- /dev/null +++ b/src/menus.c @@ -0,0 +1,263 @@ +#include +#include +#include + +#include "menus.h" + + +void menu_5(struct calccity *calccity) +{ + int scroll = 0, key = 0; + int opt = GETKEY_DEFAULT & GETKEY_REP_ARROWS; + int timeout = 0; + + static const char *names[23] = { + "GENERAL", + "ARGENT", + "POPULATION", + "BONHEUR", + "SANTE", + "EDUCATION", + "LOGEMENT", + "TRAVAIL", + "NOURRITURE", + "EAU", + "ENERGIE", + "TRANSPORT", + "DECHETS", + "TOMBES", + "RISQUES", + "CRIME", + "RISQUE INCENDIE", + "RISQUE NUCLEAIRE", + "POLLUTION", + "COMMERCE", + "PRODUCTION", + "IMPORT", + "EXPORT" + }; + + long int values[23] = { + -1, + calccity->misc[0], + calccity->population[0], + calccity->humans[0], + calccity->humans[1], + calccity->humans[2], + calccity->humans[3], + calccity->humans[4], + calccity->humans[5], + calccity->production[0], + calccity->production[1], + calccity->misc[6], + calccity->misc[7], + calccity->misc[8], + -1, + calccity->misc[1], + calccity->misc[3], + calccity->misc[4], + calccity->misc[5], + -1, + calccity->trade[2], + calccity->trade[0], + calccity->trade[1] + }; + + while (key != KEY_ALPHA) + { + dclear(C_WHITE); + + // Title + drect(0, 0, 127, 6, C_BLACK); + dtext(27, 1, C_WHITE, "STATISTIQUES"); + + // Frame + dhline(0, C_BLACK); + dhline(63, C_BLACK); + dvline(0, C_BLACK); + dvline(127, C_BLACK); + + // Scroll bar + dline(5, 6, 5, 63, C_BLACK); + drect(2, scroll + 8, 3, 8 + scroll + 38, C_BLACK); + + for (int i = 0; i < 8; i ++) + { + if (values[i + scroll] < 0) + { + drect(5, 7 + i * 7, 127, 13 + i * 7, C_BLACK); + dtext(12, 8 + i * 7, C_WHITE, names[i + scroll]); + } + else + dprint(7, 8 + i * 7, C_BLACK, "%s %lu", names[i + scroll], values[i + scroll]); + } + + dupdate(); + + key = getkey_opt(opt, &timeout).key; + + switch (key) + { + case KEY_UP: + if (scroll > 0) scroll --; + break; + + case KEY_DOWN: + if (scroll < 15) scroll ++; + break; + } + + } +} + + +void menu_4(struct calccity *calccity) +{ + int choice = 0, key = 0; + int opt = GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA & GETKEY_REP_ARROWS; + int timeout = 0; + + while (key != KEY_ALPHA) + { + dclear(C_WHITE); + drect(0, 0, 127, 6, C_BLACK); + dtext(24, 1, C_WHITE, "TAXES & FONDS"); + + dhline(0, C_BLACK); + dhline(63, C_BLACK); + dvline(0, C_BLACK); + dvline(127, C_BLACK); + + dtext(7, 8, C_BLACK, "TAXE HABITATION"); + dtext(7, 15, C_BLACK, "TAXE COMMERCE"); + dtext(7, 22, C_BLACK, "TAXE INDUSTRIE"); + dtext(7, 29, C_BLACK, "TAXE EXPORT"); + dtext(7, 36, C_BLACK, "FOND POLICE"); + dtext(7, 43, C_BLACK, "FOND POMPIER"); + dtext(7, 50, C_BLACK, "FOND ECOLE"); + dtext(7, 57, C_BLACK, "FOND S.SOCIALE"); + + for (int i = 0; i < 4; i ++) + { + dprint(97, 8 + i * 7, C_BLACK, "%d%%", calccity->taxes[i]); + dprint(97, 36 + i * 7, C_BLACK, "%d%%", calccity->funds[i]); + } + + + dtext(2, 8 + choice * 7, C_BLACK, ">"); + dtext(121, 8 + choice * 7, C_BLACK, "<"); + dupdate(); + + key = getkey_opt(opt, &timeout).key; + switch (key) + { + case KEY_UP: + if (choice > 0) choice --; + break; + + case KEY_DOWN: + if (choice < 7) choice ++; + break; + + case KEY_LEFT: + if (choice < 5 && calccity->taxes[choice] > 0) calccity->taxes[choice] --; + if (choice >= 5 && calccity->funds[choice - 5] > 0) calccity->funds[choice - 5] --; + break; + + case KEY_RIGHT: + if (choice < 5 && calccity->taxes[choice] < 100) calccity->taxes[choice] ++; + if (choice >= 5 && calccity->funds[choice - 5] < 100) calccity->funds[choice - 5] ++; + break; + } + + } +} + + +int menu_6(struct calccity *calccity) +{ + int choice = 0, key = 0; + int opt = GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA & GETKEY_REP_ARROWS; + int timeout = 0; + + while (key != KEY_ALPHA) + { + int prcnt = 100 - (calccity->time_speed * 100 / 10000); + + dclear(C_WHITE); + + drect(0, 0, 127, 6, C_BLACK); + dtext(39, 1, C_WHITE, "OPTIONS"); + + dhline(0, C_BLACK); + dhline(63, C_BLACK); + dvline(0, C_BLACK); + dvline(127, C_BLACK); + + dtext(7, 9, C_BLACK, "ANIMATIONS "); + dtext(7, 16, C_BLACK, "CATASTROPHES"); + dtext(7, 23, C_BLACK, "VITESSE DU JEU"); + dtext(7, 30, C_BLACK, "QUITTER LE JEU"); + dtext(7, 37, C_BLACK, "REPRENDRE"); + + if (calccity->animation) + dtext(85, 9, C_BLACK, "on"); + else + dtext(85, 9, C_BLACK, "off"); + + if (calccity->disaster) + dtext(85, 16, C_BLACK, "on"); + else + dtext(85, 16, C_BLACK, "off"); + + dprint(97, 23, C_BLACK, "%d%%", prcnt + 1); + + + dtext(2, 9 + choice * 7, C_BLACK, ">"); + dtext(121, 9 + choice * 7, C_BLACK, "<"); + dupdate(); + + key = getkey_opt(opt, &timeout).key; + + switch (key) + { + case KEY_UP: + if (choice > 0) choice --; + break; + + case KEY_DOWN: + if (choice < 4) choice ++; + break; + + case KEY_SHIFT: + switch (choice) + { + case 0: + calccity->animation = (calccity->animation + 1) % 2; + break; + + case 1: + calccity->disaster = (calccity->disaster + 1) % 2; + break; + + case 3: + return 1; + break; + + case 4: + return 0; + + } + break; + + case KEY_LEFT: + if (choice == 2 && calccity->time_speed < 10000) calccity->time_speed += 100; + break; + + case KEY_RIGHT: + if (choice == 2 && calccity->time_speed > 100) calccity->time_speed -= 100; + break; + } + } + return 0; +} diff --git a/src/menus.h b/src/menus.h new file mode 100644 index 0000000..d1d3caa --- /dev/null +++ b/src/menus.h @@ -0,0 +1,16 @@ +#ifndef _MENUS_H +#define _MENUS_H + +#include "calccity.h" + + +// menu_4 : tax and funds +void menu_4(struct calccity *calccity); + +// menu_5 : informations +void menu_5(struct calccity *calccity); + +// menu_6 : options +int menu_6(struct calccity *calccity); + +#endif /* _MENUS_H */ \ No newline at end of file