commit 04d7285299f89da280e31ee07170097e653ae2c8 Author: Alexander Zhirov Date: Sun Apr 30 23:49:25 2023 +0300 v1.0.0-dev diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ef1f9a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode +build +spaceshooter diff --git a/README.md b/README.md new file mode 100644 index 0000000..122e497 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +![logo](images/logo.png) + +A space shooter based on the [lessons](https://www.youtube.com/watch?v=98hTrHen7IA&list=PL9333715188CD7669) of [Mike Geig](https://twitter.com/mikegeig). Main innovations: game menu, network game support. [Demonstration](https://www.youtube.com/watch?v=6D-t6TV8ITs) of the game. + +This game is under development. Currently, the repository has been suspended since 2020. + +![menu](images/menu.png) + +![game](images/game.png) + +## Build + +```sh +mkdir build +cd build +cmake -B . -S ../game +make +``` + +The basic data needed to run the game is located in the [data](data/) directory. diff --git a/data/bitmaps/comet.png b/data/bitmaps/comet.png new file mode 100644 index 0000000..492798c Binary files /dev/null and b/data/bitmaps/comet.png differ diff --git a/data/bitmaps/explosion.png b/data/bitmaps/explosion.png new file mode 100644 index 0000000..ba8d686 Binary files /dev/null and b/data/bitmaps/explosion.png differ diff --git a/data/bitmaps/ship_green.png b/data/bitmaps/ship_green.png new file mode 100644 index 0000000..53d6f6c Binary files /dev/null and b/data/bitmaps/ship_green.png differ diff --git a/data/bitmaps/ship_red.png b/data/bitmaps/ship_red.png new file mode 100644 index 0000000..4c50d6a Binary files /dev/null and b/data/bitmaps/ship_red.png differ diff --git a/data/bitmaps/ship_yellow.png b/data/bitmaps/ship_yellow.png new file mode 100644 index 0000000..4ebe6bd Binary files /dev/null and b/data/bitmaps/ship_yellow.png differ diff --git a/data/bitmaps/starBG.png b/data/bitmaps/starBG.png new file mode 100644 index 0000000..f17233d Binary files /dev/null and b/data/bitmaps/starBG.png differ diff --git a/data/bitmaps/starFG.png b/data/bitmaps/starFG.png new file mode 100644 index 0000000..43bc97a Binary files /dev/null and b/data/bitmaps/starFG.png differ diff --git a/data/bitmaps/starMG.png b/data/bitmaps/starMG.png new file mode 100644 index 0000000..134acd0 Binary files /dev/null and b/data/bitmaps/starMG.png differ diff --git a/data/fonts/Press_Start_2P.ttf b/data/fonts/Press_Start_2P.ttf new file mode 100644 index 0000000..e9b029c Binary files /dev/null and b/data/fonts/Press_Start_2P.ttf differ diff --git a/data/fonts/VT323.ttf b/data/fonts/VT323.ttf new file mode 100644 index 0000000..758d38e Binary files /dev/null and b/data/fonts/VT323.ttf differ diff --git a/data/fonts/space_age_cyrillic.ttf b/data/fonts/space_age_cyrillic.ttf new file mode 100644 index 0000000..1acf046 Binary files /dev/null and b/data/fonts/space_age_cyrillic.ttf differ diff --git a/data/samples/boom.ogg b/data/samples/boom.ogg new file mode 100644 index 0000000..65f9125 Binary files /dev/null and b/data/samples/boom.ogg differ diff --git a/data/samples/button.ogg b/data/samples/button.ogg new file mode 100644 index 0000000..2c2a4ef Binary files /dev/null and b/data/samples/button.ogg differ diff --git a/data/samples/enter.ogg b/data/samples/enter.ogg new file mode 100644 index 0000000..2d0a397 Binary files /dev/null and b/data/samples/enter.ogg differ diff --git a/data/samples/game.ogg b/data/samples/game.ogg new file mode 100644 index 0000000..507899e Binary files /dev/null and b/data/samples/game.ogg differ diff --git a/data/samples/menu.ogg b/data/samples/menu.ogg new file mode 100644 index 0000000..2d79f11 Binary files /dev/null and b/data/samples/menu.ogg differ diff --git a/data/samples/shot.ogg b/data/samples/shot.ogg new file mode 100644 index 0000000..d23b63c Binary files /dev/null and b/data/samples/shot.ogg differ diff --git a/deps b/deps new file mode 100644 index 0000000..018f438 --- /dev/null +++ b/deps @@ -0,0 +1,84 @@ +linux-vdso.so.1 (0x00007fffea1d0000) +liballegro.so.5.2 => /usr/lib/liballegro.so.5.2 (0x00007f55d8202000) +liballegro_primitives.so.5.2 => /usr/lib/liballegro_primitives.so.5.2 (0x00007f55d81ec000) +liballegro_dialog.so.5.2 => /usr/lib/liballegro_dialog.so.5.2 (0x00007f55d81de000) +liballegro_image.so.5.2 => /usr/lib/liballegro_image.so.5.2 (0x00007f55d81cd000) +liballegro_font.so.5.2 => /usr/lib/liballegro_font.so.5.2 (0x00007f55d81c0000) +liballegro_ttf.so.5.2 => /usr/lib/liballegro_ttf.so.5.2 (0x00007f55d81b8000) +liballegro_audio.so.5.2 => /usr/lib/liballegro_audio.so.5.2 (0x00007f55d8199000) +liballegro_acodec.so.5.2 => /usr/lib/liballegro_acodec.so.5.2 (0x00007f55d818f000) +libenet.so.7 => /usr/lib/libenet.so.7 (0x00007f55d8182000) +libc.so.6 => /usr/lib/libc.so.6 (0x00007f55d7e00000) +libm.so.6 => /usr/lib/libm.so.6 (0x00007f55d8099000) +libX11.so.6 => /usr/lib/libX11.so.6 (0x00007f55d7c7b000) +libXcursor.so.1 => /usr/lib/libXcursor.so.1 (0x00007f55d8089000) +libXpm.so.4 => /usr/lib/libXpm.so.4 (0x00007f55d8072000) +libXi.so.6 => /usr/lib/libXi.so.6 (0x00007f55d805e000) +libXinerama.so.1 => /usr/lib/libXinerama.so.1 (0x00007f55d8059000) +libXrandr.so.2 => /usr/lib/libXrandr.so.2 (0x00007f55d804c000) +libOpenGL.so.0 => /usr/lib/libOpenGL.so.0 (0x00007f55d801f000) +libGLX.so.0 => /usr/lib/libGLX.so.0 (0x00007f55d7c47000) +/usr/lib64/ld-linux-x86-64.so.2 (0x00007f55d8345000) +libgtk-x11-2.0.so.0 => /usr/lib/libgtk-x11-2.0.so.0 (0x00007f55d7600000) +libgdk-x11-2.0.so.0 => /usr/lib/libgdk-x11-2.0.so.0 (0x00007f55d7b81000) +libgdk_pixbuf-2.0.so.0 => /usr/lib/libgdk_pixbuf-2.0.so.0 (0x00007f55d7b4f000) +libpango-1.0.so.0 => /usr/lib/libpango-1.0.so.0 (0x00007f55d7ad0000) +libgobject-2.0.so.0 => /usr/lib/libgobject-2.0.so.0 (0x00007f55d7a70000) +libglib-2.0.so.0 => /usr/lib/libglib-2.0.so.0 (0x00007f55d74ba000) +libpng16.so.16 => /usr/lib/libpng16.so.16 (0x00007f55d747d000) +libjpeg.so.8 => /usr/lib/libjpeg.so.8 (0x00007f55d73fc000) +libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x00007f55d72ff000) +libpulse-simple.so.0 => /usr/lib/libpulse-simple.so.0 (0x00007f55d8015000) +libpulse.so.0 => /usr/lib/libpulse.so.0 (0x00007f55d72b4000) +libopenal.so.1 => /usr/lib/libopenal.so.1 (0x00007f55d716d000) +libFLAC.so.12 => /usr/lib/libFLAC.so.12 (0x00007f55d70f3000) +libvorbisfile.so.3 => /usr/lib/libvorbisfile.so.3 (0x00007f55d7a5f000) +libxcb.so.1 => /usr/lib/libxcb.so.1 (0x00007f55d70c5000) +libXrender.so.1 => /usr/lib/libXrender.so.1 (0x00007f55d8006000) +libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0x00007f55d70bd000) +libXext.so.6 => /usr/lib/libXext.so.6 (0x00007f55d70a4000) +libGLdispatch.so.0 => /usr/lib/libGLdispatch.so.0 (0x00007f55d6fea000) +libgmodule-2.0.so.0 => /usr/lib/libgmodule-2.0.so.0 (0x00007f55d6fe3000) +libpangocairo-1.0.so.0 => /usr/lib/libpangocairo-1.0.so.0 (0x00007f55d6fd2000) +libatk-1.0.so.0 => /usr/lib/libatk-1.0.so.0 (0x00007f55d6fa9000) +libcairo.so.2 => /usr/lib/libcairo.so.2 (0x00007f55d6e3c000) +libgio-2.0.so.0 => /usr/lib/libgio-2.0.so.0 (0x00007f55d6c53000) +libpangoft2-1.0.so.0 => /usr/lib/libpangoft2-1.0.so.0 (0x00007f55d6c39000) +libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0x00007f55d6bed000) +libXcomposite.so.1 => /usr/lib/libXcomposite.so.1 (0x00007f55d6be8000) +libXdamage.so.1 => /usr/lib/libXdamage.so.1 (0x00007f55d6be3000) +libfribidi.so.0 => /usr/lib/libfribidi.so.0 (0x00007f55d6bc3000) +libharfbuzz.so.0 => /usr/lib/libharfbuzz.so.0 (0x00007f55d6ac8000) +libffi.so.7 => /usr/lib/libffi.so.7 (0x00007f55d6abc000) +libpcre2-8.so.0 => /usr/lib/libpcre2-8.so.0 (0x00007f55d6a21000) +libz.so.1 => /usr/lib/libz.so.1 (0x00007f55d6a04000) +libbz2.so.1.0 => /usr/lib/libbz2.so.1.0 (0x00007f55d69e4000) +libbrotlidec.so.1 => /usr/lib/libbrotlidec.so.1 (0x00007f55d69d6000) +libpulsecommon-15.0.so => /usr/lib64/pulseaudio/libpulsecommon-15.0.so (0x00007f55d6960000) +libdbus-1.so.3 => /usr/lib/libdbus-1.so.3 (0x00007f55d691d000) +libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f55d6600000) +libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f55d68fa000) +libogg.so.0 => /usr/lib/libogg.so.0 (0x00007f55d68ec000) +libvorbis.so.0 => /usr/lib/libvorbis.so.0 (0x00007f55d68a9000) +libXau.so.6 => /usr/lib/libXau.so.6 (0x00007f55d68a4000) +libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0x00007f55d689c000) +libpixman-1.so.0 => /usr/lib/libpixman-1.so.0 (0x00007f55d6506000) +libEGL.so.1 => /usr/lib/libEGL.so.1 (0x00007f55d6883000) +libxcb-shm.so.0 => /usr/lib/libxcb-shm.so.0 (0x00007f55d687e000) +libxcb-render.so.0 => /usr/lib/libxcb-render.so.0 (0x00007f55d686d000) +libGL.so.1 => /usr/lib/libGL.so.1 (0x00007f55d647f000) +libmount.so.1 => /usr/lib/libmount.so.1 (0x00007f55d6420000) +libexpat.so.1 => /usr/lib/libexpat.so.1 (0x00007f55d63f5000) +libgraphite2.so.3 => /usr/lib/libgraphite2.so.3 (0x00007f55d63d1000) +libbrotlicommon.so.1 => /usr/lib/libbrotlicommon.so.1 (0x00007f55d63ae000) +libsndfile.so.1 => /usr/lib/libsndfile.so.1 (0x00007f55d631f000) +libsystemd.so.0 => /usr/lib/libsystemd.so.0 (0x00007f55d626c000) +libmvec.so.1 => /usr/lib/libmvec.so.1 (0x00007f55d6172000) +libblkid.so.1 => /usr/lib/libblkid.so.1 (0x00007f55d611c000) +libvorbisenc.so.2 => /usr/lib/libvorbisenc.so.2 (0x00007f55d6068000) +libopus.so.0 => /usr/lib/libopus.so.0 (0x00007f55d5ffa000) +libcap.so.2 => /usr/lib/libcap.so.2 (0x00007f55d685d000) +libgcrypt.so.20 => /usr/lib/libgcrypt.so.20 (0x00007f55d5ed6000) +liblzma.so.5 => /usr/lib/liblzma.so.5 (0x00007f55d5ea6000) +libzstd.so.1 => /usr/lib/libzstd.so.1 (0x00007f55d5dcf000) +libgpg-error.so.0 => /usr/lib/libgpg-error.so.0 (0x00007f55d5da8000) diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt new file mode 100644 index 0000000..2fe0c1c --- /dev/null +++ b/game/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.0) +project(spaceshooter) + +include_directories("lib/" "network/" "objects/") + +set(SRC_GAME + autors.c + common.c + data.c + gameover.c + main.c + menu.c + networkcreate.c + networkgame.c + networkjoin.c + networklist.c + networkmode.c + networkout.c + networkparty.c + pause.c + single.c) + +set(SRC_LIB + lib/common.c + lib/event.c + lib/instance.c + lib/interface.c + lib/media.c + lib/message.c + lib/screen.c + lib/timer.c) + +set(SRC_NETWORK network/network.c) + +set(SRC_OBJECTS objects/objects.c) + +find_library(ALLEGRO_LIB NAMES allegro) +find_library(ALLEGRO_PRIMITIVES_LIB NAMES allegro_primitives) +find_library(ALLEGRO_DIALOG_LIB NAMES allegro_dialog) +find_library(ALLEGRO_IMAGE_LIB allegro_image) +find_library(ALLEGRO_FONT_LIB allegro_font) +find_library(ALLEGRO_TTF_LIB allegro_ttf) +find_library(ALLEGRO_AUDIO_LIB allegro_audio) +find_library(ALLEGRO_ACODEC_LIB allegro_acodec) +find_library(ENET_LIB enet) + +add_executable(${PROJECT_NAME} ${SRC_OBJECTS} ${SRC_LIB} ${SRC_NETWORK} ${SRC_GAME}) + +target_link_libraries(${PROJECT_NAME} + ${ALLEGRO_LIB} + ${ALLEGRO_PRIMITIVES_LIB} + ${ALLEGRO_DIALOG_LIB} + ${ALLEGRO_IMAGE_LIB} + ${ALLEGRO_COLOR_LIB} + ${ALLEGRO_FONT_LIB} + ${ALLEGRO_TTF_LIB} + ${ALLEGRO_AUDIO_LIB} + ${ALLEGRO_ACODEC_LIB} + ${ENET_LIB}) diff --git a/game/autors.c b/game/autors.c new file mode 100644 index 0000000..6164d9b --- /dev/null +++ b/game/autors.c @@ -0,0 +1,142 @@ +#include "common.h" +#include "autors.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void autors_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + cl_change_state(data, MENU); + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + autors_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + autors_push_button(data); + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { + cl_update_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { + autors_push_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + cl_update_background(data, BG1); + cl_update_background(data, BG2); + } +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void autors_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG2); + cl_draw_header(data); + cl_draw_button(data); +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +void autors_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[AUTORS]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_button( + data->pairing.interface[AUTORS]->button[key_button], + font->al_font, text, data->screen.width / 2, + (block_size * (key_button + 6)) + (block_size / 4) + (block_size / 2) - font->size, + (data->screen.width / 2) - (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 6) + (block_size / 4), + (data->screen.width / 2) + (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 6) + block_size); + } +} + +static void autors_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->al_font && interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + switch(i) + { + case BUTTON_AUTORS_OUT: + interface->button[i]->selected = false; + cl_change_state(data, MENU); + break; + } + } +} diff --git a/game/autors.h b/game/autors.h new file mode 100644 index 0000000..ee64284 --- /dev/null +++ b/game/autors.h @@ -0,0 +1,28 @@ +/* + * File: autors.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.07 + */ + +#ifndef client_autors +#define client_autors + +enum autors_buttons +{ + BUTTON_AUTORS_OUT // output +}; + +void autors_handling(CLIENT_DATA* data); +void autors_draw(CLIENT_DATA* data); +/************************************************************ + * PROCESSING + ***********************************************************/ +void autors_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); +static void autors_push_button(CLIENT_DATA* data); + +#endif + + + diff --git a/game/common.c b/game/common.c new file mode 100644 index 0000000..527d0d6 --- /dev/null +++ b/game/common.c @@ -0,0 +1,834 @@ +#include "common.h" +#include "menu.h" +#include "single.h" +#include "networkmode.h" +#include "networkcreate.h" +#include "networkjoin.h" +#include "networklist.h" +#include "networkparty.h" +#include "networkgame.h" +#include "networkout.h" +#include "autors.h" +#include "pause.h" +#include "gameover.h" + +#include +#include + +void cl_init_interfaces(CLIENT_PAIRING* pairing) +{ + pairing->interface[MENU] = cl_create_interface(2, 5, 0); + pairing->interface[SINGLE] = cl_create_interface(3, 0, 0); + pairing->interface[NETWORKMODE] = cl_create_interface(0, 3, 0); + pairing->interface[NETWORKCREATE] = cl_create_interface(0, 2, 2); + pairing->interface[NETWORKJOIN] = cl_create_interface(0, 2, 1); + pairing->interface[NETWORKLIST] = cl_create_interface(0, 1, 0); + pairing->interface[NETWORKPARTY] = cl_create_interface(0, 4, 0); + pairing->interface[NETWORKGAME] = cl_create_interface(3, 0, 0); + pairing->interface[NETWORKOUT] = cl_create_interface(0, 2, 0); + pairing->interface[SETTINGS] = cl_create_interface(0, 0, 0); + pairing->interface[AUTORS] = cl_create_interface(0, 1, 0); // 0 background size (background copies) + pairing->interface[PAUSE] = cl_create_interface(0, 2, 0); // 0 background size (background copies) + pairing->interface[GAMEOVER] = cl_create_interface(0, 1, 0); // 0 background size (background copies) +} + +void cl_load_media(CLIENT_MEDIA* media) +{ + cl_load_bitmap(media, BG1, "data/bitmaps/starBG.png"); + cl_load_bitmap(media, BG2, "data/bitmaps/starFG.png"); + cl_load_bitmap(media, BG3, "data/bitmaps/starMG.png"); + cl_load_bitmap(media, SHIP_R, "data/bitmaps/ship_red.png"); + al_convert_mask_to_alpha(media->bitmaps[SHIP_R]->al_bitmap, al_map_rgb(255, 0, 255)); + cl_load_bitmap(media, SHIP_G, "data/bitmaps/ship_green.png"); + al_convert_mask_to_alpha(media->bitmaps[SHIP_G]->al_bitmap, al_map_rgb(255, 0, 255)); + cl_load_bitmap(media, SHIP_Y, "data/bitmaps/ship_yellow.png"); + al_convert_mask_to_alpha(media->bitmaps[SHIP_Y]->al_bitmap, al_map_rgb(255, 0, 255)); + cl_load_bitmap(media, COMET, "data/bitmaps/comet.png"); + cl_load_bitmap(media, EXPLOSION, "data/bitmaps/explosion.png"); + cl_load_font(media, FONT_SAC60, "data/fonts/space_age_cyrillic.ttf", 60); + cl_load_font(media, FONT_SAC80, "data/fonts/space_age_cyrillic.ttf", 80); + cl_load_font(media, FONT_PS2P30, "data/fonts/Press_Start_2P.ttf", 30); + cl_load_font(media, FONT_PS2P40, "data/fonts/Press_Start_2P.ttf", 40); + cl_load_sample(media, SAMPLE_BOOM, "data/samples/boom.ogg"); + cl_load_sample(media, SAMPLE_SHOT, "data/samples/shot.ogg"); + cl_load_sample(media, SAMPLE_MENU, "data/samples/menu.ogg"); + cl_load_sample(media, SAMPLE_GAME, "data/samples/game.ogg"); + cl_load_sample(media, SAMPLE_BUTTON, "data/samples/button.ogg"); + cl_load_sample(media, SAMPLE_ENTER, "data/samples/enter.ogg"); +} + +void cl_init_media(CLIENT_DATA* data) +{ + cl_init_sample_instance(data, INSTANCE_MENU, SAMPLE_MENU); + cl_init_sample_instance(data, INSTANCE_GAME, SAMPLE_GAME); + /************************************************************ + * MENU + ***********************************************************/ + cl_init_background(data, MENU, BG1, 0, 0, 1, 0, -1, 1); + cl_init_background(data, MENU, BG2, 0, 0, 5, 0, -1, 1); + cl_init_header(data, MENU, FONT_SAC80, "Космический шутер"); + menu_init_button(data, BUTTON_MENU_SINGLE, FONT_SAC60, "Одиночная игра"); + menu_init_button(data, BUTTON_MENU_NETWORK, FONT_SAC60, "Сетевая игра"); + menu_init_button(data, BUTTON_MENU_SETTINGS, FONT_SAC60, "Настройки"); + menu_init_button(data, BUTTON_MENU_AUTORS, FONT_SAC60, "Авторы"); + menu_init_button(data, BUTTON_MENU_OUT, FONT_SAC60, "Выход"); + /************************************************************ + * NETWORK + ***********************************************************/ + cl_copy_background(data, NETWORKMODE, MENU); + cl_init_header(data, NETWORKMODE, FONT_SAC80, "Сетевая игра"); + networkmode_init_button(data, BUTTON_NETWORKMODE_CREATE, FONT_SAC60, "Создать"); + networkmode_init_button(data, BUTTON_NETWORKMODE_JOIN, FONT_SAC60, "Присоединиться"); + networkmode_init_button(data, BUTTON_NETWORKMODE_OUT, FONT_SAC60, "Назад в меню"); + /************************************************************ + * NETWORK CREATE + ***********************************************************/ + cl_copy_background(data, NETWORKCREATE, MENU); + cl_init_header(data, NETWORKCREATE, FONT_SAC80, "Создание сетевой игры"); + networkcreate_init_field(data, FIELD_NETWORKCREATE_NICKNAME, FONT_PS2P40, "Никнейм:"); + networkcreate_init_field(data, FIELD_NETWORKCREATE_GAMENAME, FONT_PS2P40, "Название игры:"); + networkcreate_init_button(data, BUTTON_NETWORKCREATE_CREATE, FONT_SAC60, "Создать игру"); + networkcreate_init_button(data, BUTTON_NETWORKCREATE_OUT, FONT_SAC60, "Назад"); + /************************************************************ + * NETWORK JOIN + ***********************************************************/ + cl_copy_background(data, NETWORKJOIN, MENU); + cl_init_header(data, NETWORKJOIN, FONT_SAC80, "Присоединиться к игре"); + networkjoin_init_field(data, FIELD_NETWORKJOIN_NICKNAME, FONT_PS2P40, "Никнейм:"); + networkjoin_init_button(data, BUTTON_NETWORKJOIN_CREATE, FONT_SAC60, "Найти игру"); + networkjoin_init_button(data, BUTTON_NETWORKJOIN_OUT, FONT_SAC60, "Назад"); + /************************************************************ + * NETWORK LIST + ***********************************************************/ + cl_copy_background(data, NETWORKLIST, MENU); + cl_init_header(data, NETWORKLIST, FONT_SAC80, "Список серверов"); + networklist_init_button(data, BUTTON_NETWORKLIST_OUT, FONT_SAC60, "Назад"); + networklist_init_list(data, FONT_PS2P40); + /************************************************************ + * AUTORS + ***********************************************************/ + cl_copy_background(data, AUTORS, MENU); + cl_init_header(data, AUTORS, FONT_SAC80, "Авторы"); + autors_init_button(data, BUTTON_AUTORS_OUT, FONT_SAC60, "Назад в меню"); + /************************************************************ + * NETWORK PARTY + ***********************************************************/ + cl_copy_background(data, NETWORKPARTY, MENU); + cl_init_header(data, NETWORKPARTY, FONT_SAC80, "Новая игра"); + networkparty_init_button(data, BUTTON_NETWORKPARTY_START, FONT_SAC60, "Начать"); + networkparty_init_button(data, BUTTON_NETWORKPARTY_READY, FONT_SAC60, "Готов"); + networkparty_init_button(data, BUTTON_NETWORKPARTY_UNREADY, FONT_SAC60, "Не готов"); + networkparty_init_button(data, BUTTON_NETWORKPARTY_OUT, FONT_SAC60, "Назад"); + networkparty_init_list(data, FONT_PS2P40); + /************************************************************ + * NETWORK OUT + ***********************************************************/ + cl_copy_background(data, NETWORKOUT, NETWORKGAME); + cl_init_header(data, NETWORKOUT, FONT_SAC80, "Режим сетевой игры"); + networkout_init_button(data, BUTTON_NETWORKOUT_BACK, FONT_SAC60, "Продолжить"); + networkout_init_button(data, BUTTON_NETWORKOUT_MENU, FONT_SAC60, "Выйти в меню"); + /************************************************************ + * PAUSE + ***********************************************************/ + cl_copy_background(data, PAUSE, MENU); + cl_init_header(data, PAUSE, FONT_SAC80, "Пауза"); + pause_init_button(data, BUTTON_PAUSE_BACK, FONT_SAC60, "Продолжить"); + pause_init_button(data, BUTTON_PAUSE_MENU, FONT_SAC60, "Выйти в меню"); + /************************************************************ + * GAMEOVER + ***********************************************************/ + cl_copy_background(data, GAMEOVER, MENU); + cl_init_header(data, GAMEOVER, FONT_SAC80, "Конец игры"); + gameover_init_button(data, BUTTON_GAMEOVER_OUT, FONT_SAC60, "Выйти в меню"); +} + +void cl_change_state(CLIENT_DATA* data, int state) +{ + if(data->state == MENU && state == SINGLE) + { + /************************************************************ + * CREATE GAME OBJECTS + ***********************************************************/ + cl_init_background(data, SINGLE, BG1, 0, 0, 1, 0, -1, 1); + cl_init_background(data, SINGLE, BG2, 0, 0, 5, 0, -1, 1); + cl_init_background(data, SINGLE, BG3, 0, 0, 3, 0, -1, 1); + + cl_init_objects(data); + } + else if((data->state == PAUSE || data->state == GAMEOVER) && state == MENU) + /************************************************************ + * DESTROY GAME OBJECTS + ***********************************************************/ + cl_destroy_objects(&data->objects); + else if(data->state == NETWORKCREATE && state == NETWORKPARTY) + { + cl_create_enet(&data->enet); + if(data->enet.connect) + cl_send_message_create(data); + else + state = NETWORKCREATE; + } + else if(data->state == NETWORKJOIN && state == NETWORKLIST) + { + cl_create_enet(&data->enet); + if(data->enet.connect) + cl_send_message_join(data); + else + state = NETWORKJOIN; + } + else if((data->state == NETWORKPARTY && state == NETWORKMODE) || + (data->state == NETWORKLIST && state == NETWORKMODE)) + { + cl_disconnect_enet(&data->enet); + } + else if(data->state == NETWORKOUT && state == NETWORKMODE) + { + cl_disconnect_enet(&data->enet); + cl_destroy_objects(&data->objects); + } + else if(data->state == NETWORKPARTY && state == NETWORKGAME) + { + /************************************************************ + * CREATE GAME OBJECTS + ***********************************************************/ + cl_init_background(data, NETWORKGAME, BG1, 0, 0, 1, 0, -1, 1); + cl_init_background(data, NETWORKGAME, BG2, 0, 0, 5, 0, -1, 1); + cl_init_background(data, NETWORKGAME, BG3, 0, 0, 3, 0, -1, 1); + + networkgame_create_objects(data); + } + + + data->state = state; + + cl_change_sample_instance(data, state); +} + +/************************************************************ + * SAMPLE INSTANCE + ***********************************************************/ + +static void cl_init_sample_instance(CLIENT_DATA* data, int key_instance, int key_sample) +{ + cl_add_instance( + data->sound.instance[key_instance], + data->media.samples[key_sample]->al_sapmle, + ALLEGRO_PLAYMODE_LOOP, + data->settings.music_gain); +} + +static void cl_change_sample_instance(CLIENT_DATA* data, int state) +{ + switch(state) + { + case MENU: + case NETWORKMODE: + case NETWORKCREATE: + case NETWORKJOIN: + case NETWORKLIST: + case NETWORKPARTY: + case SETTINGS: + case AUTORS: + if(data->sound.current_instance != INSTANCE_MENU) + { + al_stop_sample_instance(data->sound.instance[INSTANCE_GAME]->al_instance); + al_play_sample_instance(data->sound.instance[INSTANCE_MENU]->al_instance); + } + break; + case SINGLE: + case NETWORKGAME: + case NETWORKOUT: + case PAUSE: + case GAMEOVER: + if(data->sound.current_instance != INSTANCE_GAME) + { + al_stop_sample_instance(data->sound.instance[INSTANCE_MENU]->al_instance); + al_play_sample_instance(data->sound.instance[INSTANCE_GAME]->al_instance); + } + break; + } +} + +void cl_play_sound(CLIENT_DATA* data, int key_sample) +{ + al_play_sample(data->media.samples[key_sample]->al_sapmle, data->settings.effects_gain, 0, 1, ALLEGRO_PLAYMODE_ONCE, 0); +} + +/************************************************************ + * BACKGROUND + ***********************************************************/ + +static void cl_init_background(CLIENT_DATA* data, int key_state, int key_bitmap, float x, float y, float vel_x, float vel_y, int dir_x, int dir_y) +{ + if(data->pairing.interface[key_state]->background_size > key_bitmap) + cl_add_interface_background( + data->pairing.interface[key_state]->background[key_bitmap], + data->media.bitmaps[key_bitmap], + dir_x, dir_y, vel_x, vel_y, x, y); +} + +static void cl_copy_background(CLIENT_DATA* data, int dir_key_state, int src_key_state) +{ + data->pairing.interface[dir_key_state]->background = data->pairing.interface[src_key_state]->background; +} + +void cl_draw_background(CLIENT_DATA* data, int key_bitmap) +{ + CLIENT_BACKGROUND_PAGE* bg = data->pairing.interface[data->state]->background[key_bitmap]; + + al_draw_bitmap(bg->bitmap->al_bitmap, bg->x, bg->y, 0); + al_draw_bitmap(bg->bitmap->al_bitmap, bg->x + bg->bitmap->width, bg->y, 0); + + if(bg->x + bg->bitmap->width + bg->bitmap->width < data->screen.width) + al_draw_bitmap(bg->bitmap->al_bitmap, bg->x + bg->bitmap->width + bg->bitmap->width, bg->y, 0); +} + +void cl_update_background(CLIENT_DATA* data, int key_bitmap) +{ + CLIENT_BACKGROUND_PAGE* bg = data->pairing.interface[data->state]->background[key_bitmap]; + + bg->x += bg->vel_x * bg->dir_x; + if(bg->x + bg->bitmap->width < 0) + bg->x = 0; +} + +/************************************************************ + * HEADER + ***********************************************************/ + +static void cl_init_header(CLIENT_DATA* data, int key_state, int key_font, const char* text) +{ + int block_size = data->screen.height / 8; + + cl_add_interface_header( + &data->pairing.interface[key_state]->header, + data->media.fonts[key_font]->al_font, + data->screen.width / 2, + block_size - data->media.fonts[key_font]->size / 2, + text); +} + +void cl_draw_header(CLIENT_DATA* data) +{ + CLIENT_HEADER header = data->pairing.interface[data->state]->header; + + al_draw_text(header.al_font, al_map_rgb(255, 255, 255), header.x, header.y, ALLEGRO_ALIGN_CENTRE, header.text); +} + +/************************************************************ + * BUTTON + ***********************************************************/ +// use with mouse event +void cl_update_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + int mx, my; + + if(data->screen.fullscreen) + { + mx = data->event.current.mouse.x / data->screen.scale_factor_x - data->screen.pos_x; + my = data->event.current.mouse.y / data->screen.scale_factor_y - data->screen.pos_y; + } + else + { + mx = data->event.current.mouse.x; + my = data->event.current.mouse.y; + } + + for(int i = 0; i < interface->button_size; i++) + { + CLIENT_BUTTON* btn = interface->button[i]; + + if(!btn->active) continue; + + if(btn->b_sx < mx && btn->b_dx > mx && btn->b_sy < my && btn->b_dy > my) + { + if(!btn->selected) + cl_play_sound(data, SAMPLE_BUTTON); + + btn->selected = true; + interface->selected = SELECTED_BUTTON; + } + else + btn->selected = false; + } +} +// use with key +void cl_select_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + bool is_selected = false; + + if(interface->selected == SELECTED_BUTTON) + { + int count_active_button = 0; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->active) + count_active_button++; + + if(count_active_button) + { + CLIENT_BUTTON* button[count_active_button]; + int iterator = 0; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->active) + button[iterator++] = interface->button[i]; + + for(int i = 0; i < count_active_button; i++) + if(button[i]->selected) + { + if(data->keys[UP] && !data->keys[DOWN]) + { + button[i]->selected = false; + + if(i != 0) + button[i - 1]->selected = true; + else + button[count_active_button - 1]->selected = true; + } + else if(data->keys[DOWN] && !data->keys[UP]) + { + button[i]->selected = false; + + if(i == count_active_button - 1) + button[0]->selected = true; + else + button[i + 1]->selected = true; + } + + is_selected = true; + break; + } + + if(!is_selected) + if(data->keys[UP] && !data->keys[DOWN]) + button[count_active_button - 1]->selected = true; + else if(data->keys[DOWN] && !data->keys[UP]) + button[0]->selected = true; + + cl_play_sound(data, SAMPLE_BUTTON); + } + } + else if(interface->selected == SELECTED_FIELD) + { + for(int i = 0; i < interface->field_size; i++) + if(interface->field[i]->selected) + { + interface->field[i]->enter = false; + + if(data->keys[UP] && !data->keys[DOWN]) + { + interface->field[i]->selected = false; + + if(i != 0) + interface->field[i - 1]->selected = true; + else + interface->field[interface->field_size - 1]->selected = true; + } + else if(data->keys[DOWN] && !data->keys[UP]) + { + interface->field[i]->selected = false; + + if(i == interface->field_size - 1) + interface->field[0]->selected = true; + else + interface->field[i + 1]->selected = true; + } + + is_selected = true; + break; + } + + if(!is_selected) + if(data->keys[UP] && !data->keys[DOWN]) + interface->field[interface->field_size - 1]->selected = true; + else if(data->keys[DOWN] && !data->keys[UP]) + interface->field[0]->selected = true; + + cl_play_sound(data, SAMPLE_BUTTON); + } + else if(interface->selected == SELECTED_LIST) + { + int count_active_item = 0; + + for(int i = 0; i < 3; i++) + if(interface->list.item[i].active) + count_active_item++; + + if(count_active_item) + { + CLIENT_LIST_ITEM* item[count_active_item]; + int iterator = 0; + + for(int i = 0; i < 3; i++) + if(interface->list.item[i].active) + item[iterator++] = &interface->list.item[i]; + + for(int i = 0; i < count_active_item; i++) + if(item[i]->selected) + { + if(data->keys[UP] && !data->keys[DOWN]) + { + item[i]->selected = false; + + if(i != 0) + item[i - 1]->selected = true; + else + item[count_active_item - 1]->selected = true; + } + else if(data->keys[DOWN] && !data->keys[UP]) + { + item[i]->selected = false; + + if(i == count_active_item - 1) + item[0]->selected = true; + else + item[i + 1]->selected = true; + } + + is_selected = true; + break; + } + + if(!is_selected) + if(data->keys[UP] && !data->keys[DOWN]) + item[count_active_item - 1]->selected = true; + else if(data->keys[DOWN] && !data->keys[UP]) + item[0]->selected = true; + + cl_play_sound(data, SAMPLE_BUTTON); + } + } +} + +void cl_draw_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->al_font) + { + CLIENT_BUTTON* btn = interface->button[i]; + ALLEGRO_COLOR clr; + + btn->active = true; + + if(btn->selected) + clr = al_map_rgba_f(0.4, 0.4, 0.0, 0.2); + else + clr = al_map_rgba_f(0.2, 0.2, 0.2, 0.2); + + al_draw_filled_rectangle(btn->b_sx, btn->b_sy, btn->b_dx, btn->b_dy, clr); + al_draw_text(btn->al_font, al_map_rgb(255, 255, 255), btn->t_x, btn->t_y, ALLEGRO_ALIGN_CENTRE, btn->text); + } +} + +/************************************************************ + * FIELD + ***********************************************************/ + +void cl_draw_field(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->field_size; i++) + { + CLIENT_FIELD* field = interface->field[i]; + ALLEGRO_COLOR clr; + + if(field->selected) + clr = al_map_rgba_f(0.4, 0.4, 0.0, 0.2); + else + clr = al_map_rgba_f(0.2, 0.2, 0.2, 0.2); + + al_draw_text(field->al_font, al_map_rgb(255, 255, 255), field->d_x, field->d_y, 0, field->description); + al_draw_rectangle(field->f_sx, field->f_sy, field->f_dx, field->f_dy, clr, 2); + al_draw_text(field->al_font, al_map_rgb(255, 255, 255), field->ft_x, field->ft_y, 0, field->field_text); + + if(field->enter) + al_draw_text(field->al_font, al_map_rgb(255, 255, 255), field->ft_x + field->char_number * field->char_size, field->ft_y, 0, "_"); + } +} + +void cl_update_field(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + int mx, my; + + if(data->screen.fullscreen) + { + mx = data->event.current.mouse.x / data->screen.scale_factor_x - data->screen.pos_x; + my = data->event.current.mouse.y / data->screen.scale_factor_y - data->screen.pos_y; + } + else + { + mx = data->event.current.mouse.x; + my = data->event.current.mouse.y; + } + + for(int i = 0; i < interface->field_size; i++) + { + CLIENT_FIELD* field = interface->field[i]; + + if(field->f_sx < mx && field->f_dx > mx && field->f_sy < my && field->f_dy > my) + { + if(!field->selected) + cl_play_sound(data, SAMPLE_BUTTON); + + field->selected = true; + interface->selected = SELECTED_FIELD; + } + else if(field->enter) + field->selected = true; + else + field->selected = false; + } +} + +void cl_enter_field(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + int mx, my; + + if(data->screen.fullscreen) + { + mx = data->event.current.mouse.x / data->screen.scale_factor_x - data->screen.pos_x; + my = data->event.current.mouse.y / data->screen.scale_factor_y - data->screen.pos_y; + } + else + { + mx = data->event.current.mouse.x; + my = data->event.current.mouse.y; + } + + for(int i = 0; i < interface->field_size; i++) + { + CLIENT_FIELD* field = interface->field[i]; + + if(field->f_sx < mx && field->f_dx > mx && field->f_sy < my && field->f_dy > my) + field->enter = true; + else + { + field->enter = false; + field->selected = false; + } + } +} + +void cl_print_field(CLIENT_DATA* data) +{ + bool backspace = false; + char symbol = '\0'; + + switch(data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_A: + symbol = 'A'; + break; + case ALLEGRO_KEY_B: + symbol = 'B'; + break; + case ALLEGRO_KEY_C: + symbol = 'C'; + break; + case ALLEGRO_KEY_D: + symbol = 'D'; + break; + case ALLEGRO_KEY_E: + symbol = 'E'; + break; + case ALLEGRO_KEY_F: + symbol = 'F'; + break; + case ALLEGRO_KEY_G: + symbol = 'G'; + break; + case ALLEGRO_KEY_H: + symbol = 'H'; + break; + case ALLEGRO_KEY_I: + symbol = 'I'; + break; + case ALLEGRO_KEY_J: + symbol = 'J'; + break; + case ALLEGRO_KEY_K: + symbol = 'K'; + break; + case ALLEGRO_KEY_L: + symbol = 'L'; + break; + case ALLEGRO_KEY_M: + symbol = 'M'; + break; + case ALLEGRO_KEY_N: + symbol = 'N'; + break; + case ALLEGRO_KEY_O: + symbol = 'O'; + break; + case ALLEGRO_KEY_P: + symbol = 'P'; + break; + case ALLEGRO_KEY_Q: + symbol = 'Q'; + break; + case ALLEGRO_KEY_R: + symbol = 'R'; + break; + case ALLEGRO_KEY_S: + symbol = 'S'; + break; + case ALLEGRO_KEY_T: + symbol = 'T'; + break; + case ALLEGRO_KEY_U: + symbol = 'U'; + break; + case ALLEGRO_KEY_V: + symbol = 'V'; + break; + case ALLEGRO_KEY_W: + symbol = 'W'; + break; + case ALLEGRO_KEY_X: + symbol = 'X'; + break; + case ALLEGRO_KEY_Y: + symbol = 'Y'; + break; + case ALLEGRO_KEY_Z: + symbol = 'Z'; + break; + case ALLEGRO_KEY_BACKSPACE: + backspace = true; + break; + } + + if(symbol != '\0') + { + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->field_size; i++) + { + CLIENT_FIELD* field = interface->field[i]; + + if(field->enter && field->char_number < 18) + { + field->field_text[field->char_number] = symbol; + ++field->char_number; + field->field_text[field->char_number] = '\0'; + break; + } + } + } + else if(backspace) + { + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->field_size; i++) + { + CLIENT_FIELD* field = interface->field[i]; + + if(field->enter && field->char_number > 0) + { + --field->char_number; + field->field_text[field->char_number] = symbol; + break; + } + } + } +} + +/************************************************************ + * LIST + ***********************************************************/ + +void cl_draw_list(CLIENT_DATA* data) +{ + CLIENT_LIST* list = &data->pairing.interface[data->state]->list; + +// if(btn->selected) +// clr = al_map_rgba_f(0.4, 0.4, 0.0, 0.2); +// else +// clr = al_map_rgba_f(0.2, 0.2, 0.2, 0.2); + + al_draw_rectangle(list->sx, list->sy, list->dx, list->dy, al_map_rgba_f(0.2, 0.2, 0.2, 0.2), 3); +} + +void cl_update_list(CLIENT_DATA* data) +{ + CLIENT_LIST* list = &data->pairing.interface[data->state]->list; + int mx, my; + + if(data->screen.fullscreen) + { + mx = data->event.current.mouse.x / data->screen.scale_factor_x - data->screen.pos_x; + my = data->event.current.mouse.y / data->screen.scale_factor_y - data->screen.pos_y; + } + else + { + mx = data->event.current.mouse.x; + my = data->event.current.mouse.y; + } + + for(int i = 0; i < 3; i++) + { + if(!list->item[i].active) continue; + + CLIENT_LIST_ITEM* item = &list->item[i]; + + if(item->sx_item < mx && item->dx_item > mx && item->sy_item < my && item->dy_item > my) + { + item->selected = true; + data->pairing.interface[data->state]->selected = SELECTED_LIST; + } + else + item->selected = false; + } +} + +/************************************************************ + * NETWORK + ***********************************************************/ + +void cl_send_message_create(CLIENT_DATA* data) +{ + CLIENT_MESSAGE_NONE message; + + CLIENT_FIELD** field = data->pairing.interface[data->state]->field; + + message.display_height = data->screen.display_height; + message.display_width = data->screen.display_width; + message.scale_factor = data->screen.scale_factor; + strncpy(message.game_name, field[FIELD_NETWORKCREATE_GAMENAME]->field_text, 40); + strncpy(message.nickname, field[FIELD_NETWORKCREATE_NICKNAME]->field_text, 40); + message.is_creator = true; + message.is_ready = true; + message.state = STATE_PARTY; + + ENetPacket *packet = enet_packet_create(&message, sizeof(message), ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(data->enet.server, 0, packet); +} + +void cl_send_message_join(CLIENT_DATA* data) +{ + CLIENT_MESSAGE_NONE message; + + CLIENT_FIELD** field = data->pairing.interface[data->state]->field; + + message.display_height = data->screen.display_height; + message.display_width = data->screen.display_width; + message.scale_factor = data->screen.scale_factor; + strncpy(message.nickname, field[FIELD_NETWORKJOIN_NICKNAME]->field_text, 40); + message.is_creator = false; + message.is_ready = false; + message.state = STATE_LIST; + + ENetPacket *packet = enet_packet_create(&message, sizeof(message), ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(data->enet.server, 0, packet); +} diff --git a/game/common.h b/game/common.h new file mode 100644 index 0000000..9f38d4a --- /dev/null +++ b/game/common.h @@ -0,0 +1,159 @@ +/* + * File: game.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.03 + */ + +#ifndef client_data +#define client_data + +#include "lib/common.h" +#include "objects.h" +#include "network.h" + +enum bitmaps +{ + BG1, + BG2, + BG3, + SHIP_R, + SHIP_G, + SHIP_Y, + EXPLOSION, + COMET +}; + +enum fonts +{ + FONT_SAC60, + FONT_SAC80, + FONT_PS2P30, + FONT_PS2P40 +}; + +enum samples +{ + SAMPLE_BOOM, + SAMPLE_SHOT, + SAMPLE_MENU, + SAMPLE_GAME, + SAMPLE_BUTTON, + SAMPLE_ENTER +}; + +enum instance +{ + INSTANCE_MENU, + INSTANCE_GAME +}; + +enum states +{ + MENU, + SINGLE, + NETWORKMODE, + NETWORKCREATE, + NETWORKJOIN, + NETWORKLIST, + NETWORKPARTY, + NETWORKGAME, + NETWORKOUT, + SETTINGS, + AUTORS, + PAUSE, + GAMEOVER +}; + +enum keys +{ + UP, + DOWN, + LEFT, + RIGHT, + ENTER, + ESCAPE, + SPACE +}; + +typedef struct cl_settings +{ + float effects_gain; + float music_gain; +} CLIENT_SETTINGS; + +typedef struct cl_data +{ + CLIENT_SCREEN screen; + CLIENT_TIMER timer; + CLIENT_EVENT event; + CLIENT_MEDIA media; + CLIENT_PAIRING pairing; + CLIENT_OBJECTS objects; + CLIENT_NETWORK network; + CLIENT_ENET enet; + CLIENT_SOUND sound; + CLIENT_SETTINGS settings; + bool keys[7]; + bool pause; + bool done; + bool render; + int state; +} CLIENT_DATA; + +/************************************************************ + * CREATE DATA PLAYER (MAIN OBJECT) + ***********************************************************/ +CLIENT_DATA* cl_create_data(CLIENT_DATA* data, CLIENT_PARAMETRS parametrs); +void cl_destroy_data(CLIENT_DATA* data); +/************************************************************ + * COMMON FUNCTION + ***********************************************************/ +void cl_init_interfaces(CLIENT_PAIRING* pairing); +void cl_load_media(CLIENT_MEDIA* media); +void cl_init_media(CLIENT_DATA* data); +void cl_change_state(CLIENT_DATA* data, int state); +/************************************************************ + * SAMPLE INSTANCE + ***********************************************************/ +static void cl_init_sample_instance(CLIENT_DATA* data, int key_instance, int key_sample); +static void cl_change_sample_instance(CLIENT_DATA* data, int state); +void cl_play_sound(CLIENT_DATA* data, int key_sample); +/************************************************************ + * BACKGROUND + ***********************************************************/ +static void cl_init_background(CLIENT_DATA* data, int key_state, int key_bitmap, float x, float y, float vel_x, float vel_y, int dir_x, int dir_y); +static void cl_copy_background(CLIENT_DATA* data, int dir_key_state, int src_key_state); +void cl_draw_background(CLIENT_DATA* data, int key_bitmap); +void cl_update_background(CLIENT_DATA* data, int key_bitmap); +/************************************************************ + * HEADER + ***********************************************************/ +static void cl_init_header(CLIENT_DATA* data, int key_state, int key_font, const char* text); +void cl_draw_header(CLIENT_DATA* data); +/************************************************************ + * BUTTON + ***********************************************************/ +void cl_update_button(CLIENT_DATA* data); +void cl_select_button(CLIENT_DATA* data); +void cl_draw_button(CLIENT_DATA* data); +/************************************************************ + * FIELD + ***********************************************************/ +void cl_draw_field(CLIENT_DATA* data); +void cl_update_field(CLIENT_DATA* data); +void cl_enter_field(CLIENT_DATA* data); +void cl_print_field(CLIENT_DATA* data); +/************************************************************ + * LIST + ***********************************************************/ +void cl_draw_list(CLIENT_DATA* data); +void cl_update_list(CLIENT_DATA* data); +/************************************************************ + * NETWORK + ***********************************************************/ +void cl_send_message_create(CLIENT_DATA* data); +void cl_send_message_join(CLIENT_DATA* data); + +#endif diff --git a/game/data.c b/game/data.c new file mode 100644 index 0000000..e5b22e2 --- /dev/null +++ b/game/data.c @@ -0,0 +1,45 @@ +#include "common.h" +#include "message.h" + +CLIENT_DATA* cl_create_data(CLIENT_DATA* data, CLIENT_PARAMETRS parametrs) +{ + if(!data) + { + data = (CLIENT_DATA*)malloc(sizeof(CLIENT_DATA)); + show_message_error(data, "Failed to allocate space for CLIENT_DATA"); + } + + cl_create_screen(&data->screen, parametrs.scale_factor, parametrs.fullscreen, parametrs.resolution, parametrs.width, parametrs.height, parametrs.FPS, parametrs.num_adapter); + cl_create_timer(&data->timer, parametrs.FPS); + cl_create_event(&data->event, &data->timer, &data->screen); + cl_create_media(&data->media, parametrs.bitmaps_size, parametrs.fonts_size, parametrs.samples_size); + cl_create_pairing(&data->pairing, parametrs.pairing_size); + cl_create_sound(&data->sound, parametrs.sound_size); + + for(int i = 0; i < 7; i++) + { + data->keys[i] = false; + } + + data->pause = false; + data->done = false; + data->render = false; + data->state = 0; + data->enet.port = parametrs.enet_port; + strncpy(data->enet.host, parametrs.enet_host, 20); + data->settings.effects_gain = parametrs.effects_gain; + data->settings.music_gain = parametrs.music_gain; + + return data; +} + +void cl_destroy_data(CLIENT_DATA* data) +{ + cl_destroy_media(&data->media); + cl_destroy_event(&data->event); + cl_destroy_timer(&data->timer); + cl_destroy_screen(&data->screen); + cl_destroy_pairing(&data->pairing); + cl_destroy_sound(&data->sound); + free(data); +} \ No newline at end of file diff --git a/game/game.h b/game/game.h new file mode 100644 index 0000000..111597b --- /dev/null +++ b/game/game.h @@ -0,0 +1,29 @@ +/* + * File: game.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.05 + */ + +#ifndef client_game +#define client_game + +#include "common.h" +#include "menu.h" +#include "single.h" +#include "networkmode.h" +#include "networkcreate.h" +#include "networkjoin.h" +#include "networklist.h" +#include "networkparty.h" +#include "networkgame.h" +#include "networkout.h" +#include "autors.h" +#include "pause.h" +#include "gameover.h" + +#endif + + + diff --git a/game/gameover.c b/game/gameover.c new file mode 100644 index 0000000..e14c078 --- /dev/null +++ b/game/gameover.c @@ -0,0 +1,140 @@ +#include "common.h" +#include "gameover.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void gameover_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + cl_change_state(data, MENU); + } + break; + } + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + gameover_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + gameover_push_button(data); + break; + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + cl_update_button(data); + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + gameover_push_button(data); + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + cl_update_background(data, BG1); + cl_update_background(data, BG2); + } +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void gameover_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG2); + cl_draw_header(data); + cl_draw_button(data); + gameover_draw_statistic(data); +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +void gameover_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[GAMEOVER]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_button( + data->pairing.interface[GAMEOVER]->button[key_button], + font->al_font, text, data->screen.width / 2, + (block_size * (key_button + 6)) + (block_size / 4) + (block_size / 2) - font->size, + (data->screen.width / 2) - (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 6) + (block_size / 4), + (data->screen.width / 2) + (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 6) + block_size); + } +} + +static void gameover_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->al_font && interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + switch(i) + { + case BUTTON_GAMEOVER_OUT: + interface->button[i]->selected = false; + cl_change_state(data, MENU); + break; + } + } +} + +static void gameover_draw_statistic(CLIENT_DATA* data) +{ + CLIENT_SHIP* ship = data->objects.ships[0]; + ALLEGRO_FONT* font = data->media.fonts[FONT_PS2P40]->al_font; + ALLEGRO_COLOR color = al_map_rgba_f(1.0, 0.0, 0.0, 0.2); + ALLEGRO_COLOR color_text = al_map_rgba_f(1.0, 1.0, 1.0, 0.2); + + al_draw_text( + font, color, + (data->screen.width / 2) - al_get_text_width(font, "УНИЧТОЖЕНО:") / 2, + data->screen.height / 2, 0, "УНИЧТОЖЕНО:"); + al_draw_textf( + font, color_text, + (data->screen.width / 2) + al_get_text_width(font, "УНИЧТОЖЕНО:") / 2, + data->screen.height / 2, 0, "%d", ship->score); +} diff --git a/game/gameover.h b/game/gameover.h new file mode 100644 index 0000000..3a0e72b --- /dev/null +++ b/game/gameover.h @@ -0,0 +1,29 @@ +/* + * File: gameover.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.11 + */ + +#ifndef client_gameover +#define client_gameover + +enum gameover_buttons +{ + BUTTON_GAMEOVER_OUT +}; + +void gameover_handling(CLIENT_DATA* data); +void gameover_draw(CLIENT_DATA* data); +/************************************************************ + * PROCESSING + ***********************************************************/ +void gameover_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); +static void gameover_push_button(CLIENT_DATA* data); +static void gameover_draw_statistic(CLIENT_DATA* data); + +#endif + + + diff --git a/game/lib/common.c b/game/lib/common.c new file mode 100644 index 0000000..02217a7 --- /dev/null +++ b/game/lib/common.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "message.h" + +void cl_load_allegro_resources() +{ + show_message_error(al_init(), "Failed to initialize Allegro"); + show_message_error(al_init_primitives_addon(), "Failed to initialize addon primitives"); + show_message_error(al_init_image_addon(), "Failed to initialize addon image"); + show_message_error(al_install_keyboard(), "Failed to install keyboard"); + show_message_error(al_install_mouse(), "Failed to install mouse"); + show_message_error(al_init_font_addon(), "Failed to initialize addon font"); + show_message_error(al_init_ttf_addon(), "Failed to initialize addon ttf"); + show_message_error(al_install_audio(), "Failed to install audio"); + show_message_error(al_init_acodec_addon(), "Failed to initialize addon acodec"); + al_reserve_samples(20); +} + +CLIENT_RESOURCE* cl_create_resource(CLIENT_RESOURCE* res, CLIENT_PARAMETRS parametrs) +{ + if(!res) + { + res = (CLIENT_RESOURCE*)malloc(sizeof(CLIENT_RESOURCE)); + show_message_error(res, "Failed to allocate space for CLIENT_RESOURCE"); + } + + cl_create_screen(&res->screen, parametrs.scale_factor, parametrs.fullscreen, parametrs.resolution, parametrs.width, parametrs.height, parametrs.FPS, parametrs.num_adapter); + cl_create_timer(&res->timer, parametrs.FPS); + cl_create_event(&res->event, &res->timer, &res->screen); + cl_create_media(&res->media, parametrs.bitmaps_size, parametrs.fonts_size, parametrs.samples_size); + cl_create_pairing(&res->pairing, parametrs.pairing_size); + cl_create_sound(&res->sound, parametrs.sound_size); + + return res; +} + +void cl_destroy_resource(CLIENT_RESOURCE* res) +{ + cl_destroy_media(&res->media); + cl_destroy_event(&res->event); + cl_destroy_timer(&res->timer); + cl_destroy_screen(&res->screen); + cl_destroy_pairing(&res->pairing); + cl_destroy_sound(&res->sound); + free(res); +} + diff --git a/game/lib/common.h b/game/lib/common.h new file mode 100644 index 0000000..89ea30c --- /dev/null +++ b/game/lib/common.h @@ -0,0 +1,53 @@ +/* + * File: common.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.02 + */ + +#ifndef client_common +#define client_common + +#include "screen.h" +#include "timer.h" +#include "event.h" +#include "media.h" +#include "interface.h" +#include "instance.h" + +typedef struct cl_resource +{ + CLIENT_SCREEN screen; + CLIENT_TIMER timer; + CLIENT_EVENT event; + CLIENT_MEDIA media; + CLIENT_PAIRING pairing; + CLIENT_SOUND sound; +} CLIENT_RESOURCE; + +typedef struct cl_parametrs +{ + float scale_factor; + bool fullscreen; + bool resolution; + int width; + int height; + int num_adapter; + int FPS; + int bitmaps_size; + int fonts_size; + int samples_size; + int pairing_size; + int sound_size; + char enet_host[20]; + int enet_port; + float effects_gain; + float music_gain; +} CLIENT_PARAMETRS; + +void cl_load_allegro_resources(); +CLIENT_RESOURCE* cl_create_resource(CLIENT_RESOURCE* res, CLIENT_PARAMETRS parametrs); +void cl_destroy_resource(CLIENT_RESOURCE* res); + +#endif diff --git a/game/lib/event.c b/game/lib/event.c new file mode 100644 index 0000000..3173810 --- /dev/null +++ b/game/lib/event.c @@ -0,0 +1,35 @@ +#include "event.h" +#include "message.h" +#include "screen.h" + +CLIENT_EVENT* cl_create_event(CLIENT_EVENT* event, CLIENT_TIMER* timer, CLIENT_SCREEN* screen) +{ + if(!event) + { + event = (CLIENT_EVENT*)malloc(sizeof(CLIENT_EVENT)); + show_message_error(event, "Failed to allocate space for CLIENT_EVENT"); + } + + event->queue = al_create_event_queue(); + show_message_error(event->queue, "Failed to create Allegro event"); + + al_register_event_source(event->queue, al_get_keyboard_event_source()); + al_register_event_source(event->queue, al_get_mouse_event_source()); + if(screen) + al_register_event_source(event->queue, al_get_display_event_source(screen->display)); + if(timer) + al_register_event_source(event->queue, al_get_timer_event_source(timer->al_timer)); + + return event; +} + +void cl_free_event(CLIENT_EVENT* event) +{ + cl_destroy_event(event); + free(event); +}; + +void cl_destroy_event(CLIENT_EVENT* event) +{ + al_destroy_event_queue(event->queue); +} diff --git a/game/lib/event.h b/game/lib/event.h new file mode 100644 index 0000000..a3f37be --- /dev/null +++ b/game/lib/event.h @@ -0,0 +1,26 @@ +/* + * File: event.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.02 + */ + +#ifndef client_event +#define client_event + +#include +#include "timer.h" +#include "screen.h" + +typedef struct cl_event +{ + ALLEGRO_EVENT_QUEUE* queue; + ALLEGRO_EVENT current; +} CLIENT_EVENT; + +CLIENT_EVENT* cl_create_event(CLIENT_EVENT* event, CLIENT_TIMER* timer, CLIENT_SCREEN* screen); +void cl_free_event(CLIENT_EVENT* event); +void cl_destroy_event(CLIENT_EVENT* event); + +#endif diff --git a/game/lib/instance.c b/game/lib/instance.c new file mode 100644 index 0000000..9d0466b --- /dev/null +++ b/game/lib/instance.c @@ -0,0 +1,56 @@ +#include "instance.h" +#include "message.h" + +CLIENT_SOUND* cl_create_sound(CLIENT_SOUND* sound, int instance_size) +{ + if(!sound) + { + sound = (CLIENT_SOUND*)malloc(sizeof(CLIENT_SOUND)); + show_message_error(sound, "Failed to allocate space for CLIENT_SOUND"); + } + + sound->instance_size = instance_size; + sound->current_instance = -1; + + sound->instance = (CLIENT_SAMPLE_INSTANCE**)malloc(sizeof(CLIENT_SAMPLE_INSTANCE*) * instance_size); + show_message_error(sound->instance, "Failed to allocate space for CLIENT_SAMPLE_INSTANCE collection"); + + for(int i = 0; i < instance_size; i++) + { + sound->instance[i] = (CLIENT_SAMPLE_INSTANCE*)malloc(sizeof(CLIENT_SAMPLE_INSTANCE)); + show_message_error(sound->instance[i], "Failed to allocate space for CLIENT_SAMPLE_INSTANCE"); + + sound->instance[i]->al_instance = NULL; + sound->instance[i]->al_sample = NULL; + } + + return sound; +} + +void cl_free_sound(CLIENT_SOUND* sound) +{ + cl_destroy_sound(sound); + free(sound); +} + +void cl_destroy_sound(CLIENT_SOUND* sound) +{ + for(int i = 0; i < sound->instance_size; i++) + { + if(sound->instance[i]->al_instance) + al_destroy_sample_instance(sound->instance[i]->al_instance); + free(sound->instance[i]); + } + free(sound->instance); +} + +void cl_add_instance(CLIENT_SAMPLE_INSTANCE* instance, ALLEGRO_SAMPLE* sample, ALLEGRO_PLAYMODE playmode, float gain) +{ + instance->playmode = playmode; + instance->gain = gain; + instance->al_sample = sample; + instance->al_instance = al_create_sample_instance(instance->al_sample); + al_set_sample_instance_playmode(instance->al_instance, instance->playmode); + al_set_sample_instance_gain(instance->al_instance, instance->gain); + al_attach_sample_instance_to_mixer(instance->al_instance, al_get_default_mixer()); +} \ No newline at end of file diff --git a/game/lib/instance.h b/game/lib/instance.h new file mode 100644 index 0000000..80f5a67 --- /dev/null +++ b/game/lib/instance.h @@ -0,0 +1,39 @@ +/* + * File: instance.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.28 + */ + +#ifndef client_instance +#define client_instance + +#include + + +typedef struct cl_sample_instance +{ + ALLEGRO_SAMPLE_INSTANCE* al_instance; + ALLEGRO_PLAYMODE playmode; + ALLEGRO_SAMPLE* al_sample; + float gain; +} CLIENT_SAMPLE_INSTANCE; + +typedef struct cl_sound +{ + CLIENT_SAMPLE_INSTANCE** instance; + int instance_size; + int current_instance; +} CLIENT_SOUND; + +CLIENT_SOUND* cl_create_sound(CLIENT_SOUND* sound, int instance_size); +void cl_free_sound(CLIENT_SOUND* sound); +void cl_destroy_sound(CLIENT_SOUND* sound); + +void cl_add_instance(CLIENT_SAMPLE_INSTANCE* instance, ALLEGRO_SAMPLE* sample, ALLEGRO_PLAYMODE playmode, float gain); + +#endif + + + diff --git a/game/lib/interface.c b/game/lib/interface.c new file mode 100644 index 0000000..915e26e --- /dev/null +++ b/game/lib/interface.c @@ -0,0 +1,235 @@ +#include "interface.h" +#include "message.h" + +CLIENT_PAIRING* cl_create_pairing(CLIENT_PAIRING* pairing, int interface_size) +{ + if(!pairing) + { + pairing = (CLIENT_PAIRING*)malloc(sizeof(CLIENT_PAIRING)); + show_message_error(pairing, "Failed to allocate space for CLIENT_PAIRING"); + } + + pairing->interface_size = interface_size; + + if(interface_size) + { + pairing->interface = (CLIENT_INTERFACE**)malloc(sizeof(CLIENT_INTERFACE*) * interface_size); + show_message_error(pairing->interface, "Failed to allocate space for CLIENT_INTERFACE collection"); + + for(int i = 0; i < interface_size; i++) + pairing->interface[i] = NULL; + } + else + pairing->interface = NULL; + + return pairing; +} + +CLIENT_INTERFACE* cl_create_interface(int background_size, int button_size, int field_size) +{ + CLIENT_INTERFACE* interface = (CLIENT_INTERFACE*)malloc(sizeof(CLIENT_INTERFACE)); + show_message_error(interface, "Failed to allocate space for CLIENT_INTERFACE"); + + interface->header.al_font = NULL; + interface->background_size = background_size; + interface->button_size = button_size; + interface->field_size = field_size; + interface->selected = SELECTED_BUTTON; + interface->list.al_font = NULL; + + if(background_size) + interface->background = cl_create_background_pages(background_size); + else + interface->background = NULL; + + if(button_size) + interface->button = cl_create_buttons(button_size); + else + interface->button = NULL; + + if(field_size) + interface->field = cl_create_fields(field_size); + else + interface->field = NULL; + + return interface; +} + +static CLIENT_BACKGROUND_PAGE** cl_create_background_pages(int size) +{ + CLIENT_BACKGROUND_PAGE** background = (CLIENT_BACKGROUND_PAGE**)malloc(sizeof(CLIENT_BACKGROUND_PAGE*) * size); + show_message_error(background, "Failed to allocate space for CLIENT_BACKGROUND_PAGE collection"); + + for(int i = 0; i < size; i++) + { + background[i] = (CLIENT_BACKGROUND_PAGE*)malloc(sizeof(CLIENT_BACKGROUND_PAGE)); + show_message_error(background[i], "Failed to allocate space for CLIENT_BACKGROUND_PAGE"); + } + + return background; +} + +static CLIENT_BUTTON** cl_create_buttons(int size) +{ + CLIENT_BUTTON** buttons = (CLIENT_BUTTON**)malloc(sizeof(CLIENT_BUTTON*) * size); + show_message_error(buttons, "Failed to allocate space for CLIENT_BUTTON collection"); + + for(int i = 0; i < size; i++) + { + buttons[i] = (CLIENT_BUTTON*)malloc(sizeof(CLIENT_BUTTON)); + show_message_error(buttons[i], "Failed to allocate space for CLIENT_BUTTON"); + buttons[i]->al_font = NULL; + } + + return buttons; +} + +static CLIENT_FIELD** cl_create_fields(int size) +{ + CLIENT_FIELD** fields = (CLIENT_FIELD**)malloc(sizeof(CLIENT_FIELD*) * size); + show_message_error(fields, "Failed to allocate space for CLIENT_FIELD collection"); + + for(int i = 0; i < size; i++) + { + fields[i] = (CLIENT_FIELD*)malloc(sizeof(CLIENT_FIELD)); + show_message_error(fields[i], "Failed to allocate space for CLIENT_FIELD"); + fields[i]->al_font = NULL; + } + + return fields; +} + +void cl_change_selected(CLIENT_INTERFACE* interface) +{ + if(interface->selected == SELECTED_BUTTON) + { + interface->selected = SELECTED_FIELD; + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->selected) + interface->button[i]->selected = false; + } + else if(interface->selected == SELECTED_FIELD) + { + interface->selected = SELECTED_BUTTON; + for(int i = 0; i < interface->field_size; i++) + if(interface->field[i]->selected) + { + interface->field[i]->selected = false; + interface->field[i]->enter = false; + } + } +} + +void cl_free_pairing(CLIENT_PAIRING* pairing) +{ + cl_destroy_pairing(pairing); + free(pairing); +} + +void cl_destroy_pairing(CLIENT_PAIRING* pairing) +{ + for(int i = 0; i < pairing->interface_size; i++) + { + if(pairing->interface[i]) + { + cl_destroy_interface(pairing->interface[i]); + } + } + + free(pairing->interface); +} + +static void cl_destroy_interface(CLIENT_INTERFACE* interface) +{ + if(interface->background_size > 0) + { + for(int i = 0; i < interface->background_size; i++) + free(interface->background[i]); + free(interface->background); + } + + if(interface->button_size) + { + for(int i = 0; i < interface->button_size; i++) + free(interface->button[i]); + free(interface->button); + } + + if(interface->field_size) + { + for(int i = 0; i < interface->field_size; i++) + free(interface->field[i]); + free(interface->field); + } + + free(interface); +} + + +void cl_add_interface_header(CLIENT_HEADER* header, ALLEGRO_FONT* font, int x, int y, const char* text) +{ + header->al_font = font; + header->size = al_get_text_width(font, text); + strncpy(header->text, text, 100); + header->x = x; + header->y = y; +} + +void cl_add_interface_background(CLIENT_BACKGROUND_PAGE* background, CLIENT_BITMAP* bitmap, int dir_x, int dir_y, int vel_x, int vel_y, int x, int y) +{ + background->bitmap = bitmap; + background->dir_x = dir_x; + background->dir_y = dir_y; + background->vel_x = vel_x; + background->vel_y = vel_y; + background->x = x; + background->y = y; +} + +void cl_add_interface_button(CLIENT_BUTTON* button, ALLEGRO_FONT* font, const char* text, int t_x, int t_y, int b_sx, int b_sy, int b_dx, int b_dy) +{ + button->al_font = font; + strncpy(button->text, text, 100); + button->t_size = al_get_text_width(font, text); + button->t_x = t_x; + button->t_y = t_y; + button->selected = false; + button->active = false; + button->b_sx = b_sx; + button->b_sy = b_sy; + button->b_dx = b_dx; + button->b_dy = b_dy; +} + +void cl_add_interface_field(CLIENT_FIELD* field, ALLEGRO_FONT* font, int font_height, const char* description, int d_x, int d_y, int f_sx, int f_sy, int f_dx, int f_dy) +{ + field->al_font = font; + strncpy(field->description, description, 100); + field->char_size = al_get_text_width(font, "_"); + field->char_number = 0; + field->d_x = d_x; + field->d_y = d_y; + field->f_sx = f_sx; + field->f_sy = f_sy - font_height * 0.4; + field->f_dx = f_dx + al_get_text_width(font, "_") * 20; + field->f_dy = f_dy + font_height * 0.4; + field->ft_x = f_sx + al_get_text_width(font, "_") * 0.4; + field->ft_y = f_sy; + field->selected = false; + field->enter = false; +} + +void cl_add_list_item(CLIENT_LIST_ITEM* item, int sx_item, int sy_item, int dx_item, int dy_item, int x_h, int y_h, int x_status, int y_status, int r_status) +{ + item->sx_item = sx_item; + item->sy_item = sy_item; + item->dx_item = dx_item; + item->dy_item = dy_item; + item->x_h = x_h; + item->y_h = y_h; + item->x_status = x_status; + item->y_status = y_status; + item->r_status = r_status; + item->selected = false; + item->active = false; +} diff --git a/game/lib/interface.h b/game/lib/interface.h new file mode 100644 index 0000000..c20176c --- /dev/null +++ b/game/lib/interface.h @@ -0,0 +1,141 @@ +/* + * File: interface.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.04 + */ + +#ifndef client_interface +#define client_interface + +#include +#include "media.h" + +enum cl_selceted +{ + SELECTED_NONE, + SELECTED_BUTTON, + SELECTED_FIELD, + SELECTED_LIST +}; + +typedef struct cl_background_page +{ + CLIENT_BITMAP* bitmap; + float x; + float y; + float vel_x; + float vel_y; + int dir_x; + int dir_y; +} CLIENT_BACKGROUND_PAGE; + +typedef struct cl_button +{ + int b_sx; + int b_sy; + int b_dx; + int b_dy; + char text[100]; + int t_size; + ALLEGRO_FONT* al_font; + int t_x; + int t_y; + bool selected; + bool active; +} CLIENT_BUTTON; + +typedef struct cl_field +{ + ALLEGRO_FONT* al_font; + char description[100]; + char field_text[40]; + int char_size; + int char_number; + int d_x; // description x position + int d_y; // description y position + int f_sx; // field sx position + int f_sy; // field sy position + int f_dx; // field dx position + int f_dy; // field dy position + int ft_x; // field text x position + int ft_y; // field text y position + bool selected; + bool enter; +} CLIENT_FIELD; + +typedef struct cl_header +{ + int x; + int y; + char text[100]; + int size; // text size + ALLEGRO_FONT* al_font; +} CLIENT_HEADER; + +typedef struct cl_list_item +{ + int sx_item; + int sy_item; + int dx_item; + int dy_item; + int x_h; + int y_h; + int x_status; + int y_status; + int r_status; + bool selected; + bool active; +} CLIENT_LIST_ITEM; + +typedef struct cl_list +{ + int sx; + int sy; + int dx; + int dy; + CLIENT_LIST_ITEM item[3]; + ALLEGRO_FONT* al_font; +} CLIENT_LIST; + +typedef struct cl_interface +{ + CLIENT_HEADER header; + CLIENT_BACKGROUND_PAGE** background; + CLIENT_BUTTON** button; + CLIENT_FIELD** field; + CLIENT_LIST list; + int background_size; + int button_size; + int field_size; + int selected; // selceted current control (none/button/field) +} CLIENT_INTERFACE; + +typedef struct cl_pairing +{ + CLIENT_INTERFACE** interface; + int interface_size; +} CLIENT_PAIRING; + +CLIENT_PAIRING* cl_create_pairing(CLIENT_PAIRING* pairing, int interface_size); +void cl_free_pairing(CLIENT_PAIRING* pairing); +void cl_destroy_pairing(CLIENT_PAIRING* pairing); +CLIENT_INTERFACE* cl_create_interface(int background_size, int button_size, int field_size); +static void cl_destroy_interface(CLIENT_INTERFACE* interface); + +static CLIENT_BACKGROUND_PAGE** cl_create_background_pages(int size); +static CLIENT_BUTTON** cl_create_buttons(int size); +static CLIENT_FIELD** cl_create_fields(int size); + +void cl_change_selected(CLIENT_INTERFACE* interface); + +void cl_add_interface_header(CLIENT_HEADER* header, ALLEGRO_FONT* font, int x, int y, const char* text); +void cl_add_interface_background(CLIENT_BACKGROUND_PAGE* background, CLIENT_BITMAP* bitmap, int dir_x, int dir_y, int vel_x, int vel_y, int x, int y); +void cl_add_interface_button(CLIENT_BUTTON* button, ALLEGRO_FONT* font, const char* text, int t_x, int t_y, int b_sx, int b_sy, int b_dx, int b_dy); +void cl_add_interface_field(CLIENT_FIELD* field, ALLEGRO_FONT* font, int font_height, const char* description, int d_x, int d_y, int f_sx, int f_sy, int f_dx, int f_dy); + +// ITEMS +void cl_add_list_item(CLIENT_LIST_ITEM* item, int sx_item, int sy_item, int dx_item, int dy_item, int x_h, int y_h, int x_status, int y_status, int r_status); + +#endif diff --git a/game/lib/media.c b/game/lib/media.c new file mode 100644 index 0000000..a1946e3 --- /dev/null +++ b/game/lib/media.c @@ -0,0 +1,141 @@ +#include "media.h" +#include "message.h" +#include "screen.h" + +CLIENT_MEDIA* cl_create_media(CLIENT_MEDIA* media, int size_bitmaps, int size_fonts, int size_samples) +{ + if(!media) + { + media = (CLIENT_MEDIA*)malloc(sizeof(CLIENT_MEDIA)); + show_message_error(media, "Failed to allocate space for CLIENT_MEDIA"); + } + + media->size_bitmaps = size_bitmaps; + media->size_fonts = size_fonts; + media->size_samples = size_samples; + + media->bitmaps = cl_create_bitmaps(media->size_bitmaps); + media->fonts = cl_create_fonts(media->size_fonts); + media->samples = cl_create_samples(media->size_samples); + + return media; +} + +static CLIENT_BITMAP** cl_create_bitmaps(int size) +{ + CLIENT_BITMAP** bitmaps = (CLIENT_BITMAP**)malloc(sizeof(CLIENT_BITMAP*) * size); + show_message_error(bitmaps, "Failed to allocate space for CLIENT_BITMAP collection"); + + for(int i = 0; i < size; i++) + { + bitmaps[i] = (CLIENT_BITMAP*)malloc(sizeof(CLIENT_BITMAP)); + show_message_error(bitmaps[i], "Failed to allocate space for CLIENT_BITMAP"); + bitmaps[i]->al_bitmap = NULL; + } + + return bitmaps; +} + +static CLIENT_FONT** cl_create_fonts(int size) +{ + CLIENT_FONT** fonts = (CLIENT_FONT**)malloc(sizeof(CLIENT_FONT*) * size); + show_message_error(fonts, "Failed to allocate space for CLIENT_FONT collection"); + + for(int i = 0; i < size; i++) + { + fonts[i] = (CLIENT_FONT*)malloc(sizeof(CLIENT_FONT)); + show_message_error(fonts[i], "Failed to allocate space for CLIENT_FONT"); + fonts[i]->al_font = NULL; + } + + return fonts; +} + +static CLIENT_SAMPLE** cl_create_samples(int size) +{ + CLIENT_SAMPLE** samples = (CLIENT_SAMPLE**)malloc(sizeof(CLIENT_SAMPLE*) * size); + show_message_error(samples, "Failed to allocate space for CLIENT_SAMPLE collection"); + + for(int i = 0; i < size; i++) + { + samples[i] = (CLIENT_SAMPLE*)malloc(sizeof(CLIENT_SAMPLE)); + show_message_error(samples[i], "Failed to allocate space for CLIENT_SAMPLE"); + samples[i]->al_sapmle = NULL; + } + + return samples; +} + +void cl_free_media(CLIENT_MEDIA* media) +{ + cl_destroy_media(media); + free(media); +} + +void cl_destroy_media(CLIENT_MEDIA* media) +{ + for(int i = 0; i < media->size_bitmaps; i++) + { + if(media->bitmaps[i]->al_bitmap) + al_destroy_bitmap(media->bitmaps[i]->al_bitmap); + free(media->bitmaps[i]); + } + free(media->bitmaps); + + for(int i = 0; i < media->size_fonts; i++) + { + if(media->fonts[i]->al_font) + al_destroy_font(media->fonts[i]->al_font); + free(media->fonts[i]); + } + free(media->fonts); + + for(int i = 0; i < media->size_samples; i++) + { + if(media->samples[i]->al_sapmle) + al_destroy_sample(media->samples[i]->al_sapmle); + free(media->samples[i]); + } + free(media->samples); +} + +void cl_load_bitmap(CLIENT_MEDIA* media, int key_bitmap, const char* path) +{ + if(media->size_bitmaps > key_bitmap && key_bitmap >= 0) + { + if(!media->bitmaps[key_bitmap]->al_bitmap) + { + media->bitmaps[key_bitmap]->al_bitmap = al_load_bitmap(path); + show_message_error(media->bitmaps[key_bitmap]->al_bitmap, "Failed to load bitmap to collection"); + media->bitmaps[key_bitmap]->width = al_get_bitmap_width(media->bitmaps[key_bitmap]->al_bitmap); + media->bitmaps[key_bitmap]->height = al_get_bitmap_height(media->bitmaps[key_bitmap]->al_bitmap); + } + } +} + +void cl_load_font(CLIENT_MEDIA* media, int key_font, const char* path, int size_font) +{ + if(media->size_fonts > key_font && key_font >= 0) + { + if(!media->fonts[key_font]->al_font) + { + CLIENT_SCREEN screen = cl_get_screen(NULL); + + media->fonts[key_font]->al_font = al_load_font(path, size_font * screen.scale_factor, 0); + show_message_error(media->fonts[key_font]->al_font, "Failed to load font to collection"); + media->fonts[key_font]->size = size_font * screen.scale_factor; + } + } +} + +void cl_load_sample(CLIENT_MEDIA* media, int key_sample, const char* path) +{ + if(media->size_samples > key_sample && key_sample >= 0) + { + if(!media->samples[key_sample]->al_sapmle) + { + media->samples[key_sample]->al_sapmle = al_load_sample(path); + show_message_error(media->samples[key_sample]->al_sapmle, "Failed to load sample to collection"); + } + } +} diff --git a/game/lib/media.h b/game/lib/media.h new file mode 100644 index 0000000..682518a --- /dev/null +++ b/game/lib/media.h @@ -0,0 +1,76 @@ +/* + * File: media.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.02 + */ + +#ifndef client_media +#define client_media + +#include +#include +#include + +typedef struct cl_bitmap +{ + ALLEGRO_BITMAP* al_bitmap; + int width; + int height; +} CLIENT_BITMAP; + +typedef struct cl_font +{ + ALLEGRO_FONT* al_font; + int size; +} CLIENT_FONT; + +typedef struct cl_sample +{ + ALLEGRO_SAMPLE* al_sapmle; +} CLIENT_SAMPLE; + +typedef struct cl_media +{ + CLIENT_BITMAP** bitmaps; + CLIENT_FONT** fonts; + CLIENT_SAMPLE** samples; + int size_bitmaps; + int size_fonts; + int size_samples; +} CLIENT_MEDIA; + +CLIENT_MEDIA* cl_create_media(CLIENT_MEDIA* media, int size_bitmaps, int size_fonts, int size_samples); +void cl_free_media(CLIENT_MEDIA* media); +void cl_destroy_media(CLIENT_MEDIA* media); + +/* + * Создание коллекции изображений + */ +static CLIENT_BITMAP** cl_create_bitmaps(int size); +/* + * Создание коллекции шрифтов + */ +static CLIENT_FONT** cl_create_fonts(int size); +/* + * Создание коллекции аудио + */ +static CLIENT_SAMPLE** cl_create_samples(int size); +/* + * Загрузка bitmap в коллекцию + * keyBitmap - the name of the item enumeration in the array + */ +void cl_load_bitmap(CLIENT_MEDIA* media, int key_bitmap, const char* path); +/* + * Загрузка font в коллекцию + * keyFont - the name of the item enumeration in the array + */ +void cl_load_font(CLIENT_MEDIA* media, int key_font, const char* path, int size_font); +/* + * Загрузка sample в коллекцию + * keySample - the name of the item enumeration in the array + */ +void cl_load_sample(CLIENT_MEDIA* media, int key_sample, const char* path); + +#endif diff --git a/game/lib/message.c b/game/lib/message.c new file mode 100644 index 0000000..4b1ecfc --- /dev/null +++ b/game/lib/message.c @@ -0,0 +1,12 @@ +#include +#include "message.h" + +void show_message_error(bool result, const char* message) +{ + if(!result) + { + al_show_native_message_box(NULL, "Сообщение об ошибке", "Произошла ошибка", + message, NULL, ALLEGRO_MESSAGEBOX_ERROR); + exit(EXIT_FAILURE); + } +} diff --git a/game/lib/message.h b/game/lib/message.h new file mode 100644 index 0000000..98dc3ec --- /dev/null +++ b/game/lib/message.h @@ -0,0 +1,18 @@ +/* + * File: message.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.05.27 + */ + +#ifndef client_message +#define client_message + +#include +/* + * error message + */ +void show_message_error(bool result, const char* message); + +#endif diff --git a/game/lib/screen.c b/game/lib/screen.c new file mode 100644 index 0000000..51e815d --- /dev/null +++ b/game/lib/screen.c @@ -0,0 +1,190 @@ +#include "screen.h" +#include "message.h" + +CLIENT_SCREEN* cl_create_screen(CLIENT_SCREEN* screen, float scale_factor, bool fullscreen, bool resolution, int w, int h, int FPS, int num_adapter) +{ + if(!screen) + { + screen = (CLIENT_SCREEN*)malloc(sizeof(CLIENT_SCREEN)); + show_message_error(screen, "Failed to allocate space for CLIENT_SCREEN"); + } + + CLIENT_ADAPTER adapter = cl_get_info_adapter(num_adapter); + + screen->FPS = FPS; + screen->monitor_width = adapter.width; + screen->monitor_height = adapter.height; + screen->display_diagonal = (float)adapter.width / adapter.height; + screen->fullscreen = fullscreen; + + if(resolution) + { + if(w < 640 || h < 400 || ((float)w / h) < 1.0) + { + screen->width = screen->buffer_width = 640; + screen->height = screen->buffer_height = 400; + } + else + { + screen->width = screen->buffer_width = w; + screen->height = screen->buffer_height = h; + } + + screen->buffer_diagonal = (float)screen->buffer_width / screen->buffer_height; + + if(screen->fullscreen) + { + if(screen->display_diagonal > screen->buffer_diagonal) + { + screen->own_diagonal = true; + screen->scale_factor = (float)screen->buffer_width / screen->monitor_width; + screen->display_width = screen->monitor_width * ((float)screen->buffer_height / screen->monitor_height); + screen->display_height = screen->buffer_height; + screen->pos_x = (screen->display_width / 2) - (screen->buffer_width / 2); + screen->pos_y = 0; + } + else if(screen->display_diagonal < screen->buffer_diagonal) + { + screen->own_diagonal = false; + screen->scale_factor = (float)screen->buffer_height / screen->monitor_height; + screen->display_width = screen->buffer_width; + screen->display_height = screen->monitor_height * ((float)screen->buffer_width / screen->monitor_width); + screen->pos_x = 0; + screen->pos_y = (screen->display_height / 2) - (screen->buffer_height / 2); + } + else + { + screen->own_diagonal = true; + screen->scale_factor = (float)screen->buffer_width / screen->monitor_width; + screen->display_width = screen->buffer_width; + screen->display_height = screen->buffer_height; + screen->pos_x = 0; + screen->pos_y = 0; + } + } + else + { + if(screen->display_diagonal >= screen->buffer_diagonal) + screen->scale_factor = (float)screen->buffer_width / screen->monitor_width; + else if(screen->display_diagonal < screen->buffer_diagonal) + screen->scale_factor = (float)screen->buffer_height / screen->monitor_height; + + screen->own_diagonal = true; + screen->pos_x = 0; + screen->pos_y = 0; + screen->display_width = screen->buffer_width; + screen->display_height = screen->buffer_height; + } + } + else + { + if((float)scale_factor >= 0.1 && (float)scale_factor < 1.0) + screen->scale_factor = scale_factor; + else if((float)scale_factor >= 1.0) + { + screen->fullscreen = true; + screen->scale_factor = 1.0; + } + else + screen->scale_factor = 0.5; + + screen->own_diagonal = true; + screen->width = screen->buffer_width = screen->display_width = screen->monitor_width * screen->scale_factor; + screen->height = screen->buffer_height = screen->display_height = screen->monitor_height * screen->scale_factor; + screen->pos_x = 0; + screen->pos_y = 0; + } + + if(screen->fullscreen) + { + screen->scale_factor_x = (float)screen->monitor_width / screen->display_width; + screen->scale_factor_y = (float)screen->monitor_height / screen->display_height; + } + + // Create allegro display + al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST); + al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST); + + if(screen->fullscreen) + al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW); + + screen->display = al_create_display(screen->display_width, screen->display_height); + show_message_error(screen->display, "Failed to create Allegro display"); + screen->buffer = al_create_bitmap(screen->buffer_width, screen->buffer_height); + show_message_error(screen->buffer, "Failed to create Allegro buffer"); + + if(screen->fullscreen) + { + ALLEGRO_TRANSFORM t; + al_identity_transform(&t); + al_scale_transform(&t, screen->scale_factor_x, screen->scale_factor_y); + al_use_transform(&t); + } + + cl_get_screen(screen); + + return screen; +} + +static CLIENT_ADAPTER cl_get_info_adapter(int num_adapter) +{ + CLIENT_ADAPTER adapter; + const int num_monitor = al_get_num_video_adapters(); + ALLEGRO_MONITOR_INFO m_i; + int cur_adapter; + + show_message_error(num_monitor, "Could not find connected monitors"); + + if(num_adapter != -1 && num_adapter <= num_monitor - 1) + cur_adapter = num_adapter; + else + cur_adapter = 0; + + al_get_monitor_info(cur_adapter, &m_i); + + adapter.width = m_i.x2 - m_i.x1; + adapter.height = m_i.y2 - m_i.y1; + + return adapter; +} + +void cl_free_screen(CLIENT_SCREEN* screen) +{ + cl_destroy_screen(screen); + free(screen); +} + +void cl_destroy_screen(CLIENT_SCREEN* screen) +{ + al_destroy_bitmap(screen->buffer); + al_destroy_display(screen->display); +} + +CLIENT_SCREEN cl_get_screen(CLIENT_SCREEN* screen) +{ + static CLIENT_SCREEN screen_info; + + if(screen) + { + screen_info = *screen; + } + + return screen_info; +} + +void cl_pre_draw() +{ + CLIENT_SCREEN screen = cl_get_screen(NULL); + + al_set_target_bitmap(screen.buffer); + al_clear_to_color(al_map_rgb(0, 0, 0)); +} + +void cl_post_draw() +{ + CLIENT_SCREEN screen = cl_get_screen(NULL); + + al_set_target_backbuffer(screen.display); + al_draw_scaled_bitmap(screen.buffer, 0, 0, screen.buffer_width, screen.buffer_height, screen.pos_x, screen.pos_y, screen.buffer_width, screen.buffer_height, 0); + al_flip_display(); +} diff --git a/game/lib/screen.h b/game/lib/screen.h new file mode 100644 index 0000000..fff5fe8 --- /dev/null +++ b/game/lib/screen.h @@ -0,0 +1,58 @@ +/* + * File: screen.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 27 мая 2020 г., 17:17 + */ + +#ifndef client_screen +#define client_screen + +#include +#include + +typedef struct cl_screen +{ + ALLEGRO_DISPLAY* display; + ALLEGRO_BITMAP* buffer; + int monitor_width; + int monitor_height; + int display_width; + int display_height; + int buffer_width; + int buffer_height; + int width; // main width (== buffer width) + int height; // main height (== buffer height) + float display_diagonal; + float buffer_diagonal; + bool own_diagonal; // use own diagonal (if own diagonal >) + float scale_factor; + float scale_factor_x; + float scale_factor_y; + int FPS; + bool fullscreen; + int pos_x; // display output buffer position x + int pos_y; // display output buffer position y +} CLIENT_SCREEN; + +typedef struct cl_adapter +{ + int width; + int height; +} CLIENT_ADAPTER; + +CLIENT_SCREEN* cl_create_screen(CLIENT_SCREEN* screen, float scale_factor, bool fullscreen, bool resolution, int w, int h, int FPS, int num_adapter); + +static CLIENT_ADAPTER cl_get_info_adapter(int num_adapter); + +void cl_free_screen(CLIENT_SCREEN* screen); +void cl_destroy_screen(CLIENT_SCREEN* screen); + +void cl_pre_draw(); + +void cl_post_draw(); + +CLIENT_SCREEN cl_get_screen(CLIENT_SCREEN* screen); + +#endif diff --git a/game/lib/timer.c b/game/lib/timer.c new file mode 100644 index 0000000..457a66f --- /dev/null +++ b/game/lib/timer.c @@ -0,0 +1,27 @@ +#include "timer.h" +#include "message.h" + +CLIENT_TIMER* cl_create_timer(CLIENT_TIMER* timer, int FPS) +{ + if(!timer) + { + timer = (CLIENT_TIMER*)malloc(sizeof(CLIENT_TIMER)); + show_message_error(timer, "Failed to allocate space for CLIENT_TIMER"); + } + + timer->al_timer = al_create_timer(1.0 / FPS); + show_message_error(timer->al_timer, "Failed to create Allegro timer"); + + return timer; +} + +void cl_free_timer(CLIENT_TIMER* timer) +{ + cl_destroy_timer(timer); + free(timer); +} + +void cl_destroy_timer(CLIENT_TIMER* timer) +{ + al_destroy_timer(timer->al_timer); +} diff --git a/game/lib/timer.h b/game/lib/timer.h new file mode 100644 index 0000000..4845cc2 --- /dev/null +++ b/game/lib/timer.h @@ -0,0 +1,25 @@ +/* + * File: timer.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.02 + */ + +#ifndef client_timer +#define client_timer + +#include + +typedef struct cl_timer +{ + ALLEGRO_TIMER* al_timer; + float time; +} CLIENT_TIMER; + +CLIENT_TIMER* cl_create_timer(CLIENT_TIMER* timer, int FPS); + +void cl_free_timer(CLIENT_TIMER* timer); +void cl_destroy_timer(CLIENT_TIMER* timer); + +#endif diff --git a/game/main.c b/game/main.c new file mode 100644 index 0000000..d386b1b --- /dev/null +++ b/game/main.c @@ -0,0 +1,112 @@ +#include +#include "game.h" + +int main(int argc, char** argv) +{ + cl_load_allegro_resources(); + + CLIENT_PARAMETRS parametrs = + { + // screen + .num_adapter = 0, + .scale_factor = 0.5, + .fullscreen = false, + .resolution = true, + .width = 1280, + .height = 540, + .FPS = 60, + // media + .bitmaps_size = 8, + .fonts_size = 4, + .samples_size = 6, + // interface + .pairing_size = 13, + .sound_size = 2, + // network + .enet_port = 9234, + .enet_host = "127.0.0.1", + // settings + .effects_gain = 0.1, + .music_gain = 0.1 + }; + + CLIENT_DATA* data = cl_create_data(NULL, parametrs); + + cl_init_interfaces(&data->pairing); + cl_load_media(&data->media); + cl_init_media(data); + + al_start_timer(data->timer.al_timer); + data->timer.time = al_current_time(); + + srand(time(NULL)); + + cl_change_state(data, MENU); + + while(!data->done) + { + al_wait_for_event(data->event.queue, &data->event.current); + + if(data->state == MENU) + menu_handling(data); + if(data->state == AUTORS) + autors_handling(data); + if(data->state == SINGLE) + single_handling(data); + if(data->state == NETWORKMODE) + networkmode_handling(data); + if(data->state == NETWORKCREATE) + networkcreate_handling(data); + if(data->state == NETWORKJOIN) + networkjoin_handling(data); + if(data->state == NETWORKPARTY) + networkparty_handling(data); + if(data->state == NETWORKLIST) + networklist_handling(data); + if(data->state == NETWORKGAME) + networkgame_handling(data); + if(data->state == NETWORKOUT) + networkout_handling(data); + if(data->state == PAUSE) + pause_handling(data); + if(data->state == GAMEOVER) + gameover_handling(data); + + if(data->render && al_is_event_queue_empty(data->event.queue)) + { + data->render = false; + cl_pre_draw(); + + if(data->state == MENU) + menu_draw(data); + if(data->state == AUTORS) + autors_draw(data); + if(data->state == SINGLE) + single_draw(data); + if(data->state == NETWORKMODE) + networkmode_draw(data); + if(data->state == NETWORKCREATE) + networkcreate_draw(data); + if(data->state == NETWORKJOIN) + networkjoin_draw(data); + if(data->state == NETWORKPARTY) + networkparty_draw(data); + if(data->state == NETWORKLIST) + networklist_draw(data); + if(data->state == NETWORKGAME) + networkgame_draw(data); + if(data->state == NETWORKOUT) + networkout_draw(data); + if(data->state == PAUSE) + pause_draw(data); + if(data->state == GAMEOVER) + gameover_draw(data); + + cl_post_draw(); + } + } + + cl_destroy_data(data); + + return EXIT_SUCCESS; +} diff --git a/game/menu.c b/game/menu.c new file mode 100644 index 0000000..c129f3a --- /dev/null +++ b/game/menu.c @@ -0,0 +1,162 @@ +#include "common.h" +#include "menu.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void menu_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + data->done = true; + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + menu_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + menu_push_button(data); + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { + cl_update_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { + menu_push_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + cl_update_background(data, BG1); + cl_update_background(data, BG2); + } +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void menu_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG2); + cl_draw_header(data); + cl_draw_button(data); +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +void menu_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[MENU]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_button( + data->pairing.interface[MENU]->button[key_button], + font->al_font, text, data->screen.width / 2, + (block_size * (key_button + 2)) + (block_size / 4) + (block_size / 2) - font->size, + (data->screen.width / 2) - (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 2) + (block_size / 4), + (data->screen.width / 2) + (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 2) + block_size); + } +} + +static void menu_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + switch(i) + { + case BUTTON_MENU_SINGLE: + { + interface->button[i]->selected = false; + al_hide_mouse_cursor(data->screen.display); + cl_change_state(data, SINGLE); + break; + } + case BUTTON_MENU_NETWORK: + { + interface->button[i]->selected = false; + cl_change_state(data, NETWORKMODE); + break; + } + case BUTTON_MENU_SETTINGS: + break; + case BUTTON_MENU_AUTORS: + { + interface->button[i]->selected = false; + cl_change_state(data, AUTORS); + break; + } + case BUTTON_MENU_OUT: + data->done = true; + break; + } + } +} diff --git a/game/menu.h b/game/menu.h new file mode 100644 index 0000000..68b2010 --- /dev/null +++ b/game/menu.h @@ -0,0 +1,32 @@ +/* + * File: menu.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.03 + */ + +#ifndef client_menu +#define client_menu + +enum menu_buttons +{ + BUTTON_MENU_SINGLE, // single play + BUTTON_MENU_NETWORK, // network play + BUTTON_MENU_SETTINGS, // settings + BUTTON_MENU_AUTORS, // autors + BUTTON_MENU_OUT // output +}; + +void menu_handling(CLIENT_DATA* data); +void menu_draw(CLIENT_DATA* data); +/************************************************************ + * PROCESSING + ***********************************************************/ +void menu_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); +static void menu_push_button(CLIENT_DATA* data); + +#endif + + + diff --git a/game/network/network.c b/game/network/network.c new file mode 100644 index 0000000..5cee5a0 --- /dev/null +++ b/game/network/network.c @@ -0,0 +1,82 @@ +#include + +#include "common.h" +#include "network.h" +#include "message.h" + +CLIENT_ENET* cl_create_enet(CLIENT_ENET* enet) +{ + if(!enet) + { + enet = (CLIENT_ENET*)malloc(sizeof(CLIENT_ENET)); + show_message_error(enet, "Failed to allocate space for CLIENT_ENET"); + } + + show_message_error(enet_initialize() == 0, "Failed to allocate space for CLIENT_ENET"); + + int port = enet->port; + char host[20]; + strncpy(host, enet->host, 20); + + enet->client = enet_host_create(NULL, 1, 2, 0, 0); + show_message_error(enet->client, "Failed to client host create"); + + enet_address_set_host(&enet->address, host); + enet->address.port = port; + + enet->server = enet_host_connect(enet->client, &enet->address, 2, 0); + show_message_error(enet->server, "Failed to server connect"); + + if (enet_host_service(enet->client, &enet->event, 5000) > 0 && enet->event.type == ENET_EVENT_TYPE_CONNECT) + { + enet->connect = true; + printf("Клиент: присоединён к серверу %x:%hu\n", enet->event.peer->address.host, enet->event.peer->address.port); + } + else + { + enet->connect = false; + puts("Клиент: не удалось присоединиться к серверу"); + enet_peer_reset(enet->server); + cl_destroy_enet(enet); + } + + return enet; +} + +void cl_free_enet(CLIENT_ENET* enet) +{ + cl_destroy_enet(enet); + free(enet); +} + +void cl_destroy_enet(CLIENT_ENET* enet) +{ + enet_host_destroy(enet->client); + enet_deinitialize(); +} + +void cl_disconnect_enet(CLIENT_ENET* enet) +{ + enet_peer_disconnect(enet->server, 0); + + ENetEvent event; + + while (enet_host_service (enet->client, &event, 3000) > 0) + switch (event.type) + { + case ENET_EVENT_TYPE_RECEIVE: + enet_packet_destroy(event.packet); + break; + case ENET_EVENT_TYPE_DISCONNECT: + puts("Клиент: успешное отсоединение"); + return; + case ENET_EVENT_TYPE_NONE: + case ENET_EVENT_TYPE_CONNECT: + break; + } + + enet_peer_reset(enet->server); + + enet->connect = false; + cl_destroy_enet(enet); +} diff --git a/game/network/network.h b/game/network/network.h new file mode 100644 index 0000000..f2cabeb --- /dev/null +++ b/game/network/network.h @@ -0,0 +1,190 @@ +/* + * File: network.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.12 + */ + +#ifndef client_network +#define client_network + +#include +#include + +typedef enum srv_state +{ + STATE_NONE, + STATE_LIST, + STATE_PARTY, + STATE_GAME, + STATE_DISCONNECT +} SERVER_STATE; + + +typedef struct cl_user_command +{ + int dx; + int dy; + bool fire; +} SERVER_USER_COMMAND; + +typedef struct cl_user +{ + int id; + char nickname[40]; + bool is_ready; + SERVER_USER_COMMAND command; +} CLIENT_USER; + +typedef struct cl_gamedata +{ + int id; + char game_name[40]; + int count_connected; +} CLIENT_GAME_DATA; + +typedef struct cl_game_command +{ + int dx; + int dy; + bool fire; + bool send; +} CLIENT_GAME_COMMAND; + +typedef struct cl_network +{ + int game_id; + int user_id; + char game_name[40]; + CLIENT_USER users[3]; + CLIENT_GAME_DATA games[3]; + int user_size; + int count_connected; + int count_game; + bool game_started; + bool active; + bool is_creator; + bool is_ready; + CLIENT_GAME_COMMAND command; +} CLIENT_NETWORK; + +typedef struct cl_message_none +{ + int display_width; + int display_height; + float scale_factor; + SERVER_STATE state; + char game_name[40]; + char nickname[40]; + bool is_creator; + bool is_ready; +} CLIENT_MESSAGE_NONE; + +typedef struct cl_message_party +{ + int game_id; + int user_id; + CLIENT_USER users[3]; + char game_name[40]; + int count_connected; + bool game_started; + bool active; + bool is_creator; + bool is_ready; + SERVER_STATE state; +} CLIENT_MESSAGE_PARTY; + +typedef struct cl_message_list +{ + CLIENT_GAME_DATA games[3]; + SERVER_STATE state; + int count_game; +} CLIENT_MESSAGE_LIST; + +typedef struct cl_message_joingame +{ + int id; + SERVER_STATE state; +} CLIENT_MESSAGE_JOINGAME; + +typedef struct cl_message_sendparty +{ + SERVER_STATE state; + bool is_creator; + bool is_ready; + bool kick_user; + int user_id; +} CLIENT_MESSAGE_SENDPARTY; + +typedef struct cl_message_game +{ + int dx; + int dy; + bool fire; + SERVER_STATE state; +} CLIENT_MESSAGE_GAME; + +// GAME + +typedef struct cl_update_ship +{ + int ID; + int x; + int y; + int dx; + int dy; + int lives; + int score; + bool active; +} CLIENT_UPDATE_SHIP; + +typedef struct cl_update_bullet +{ + int ID; + int x; + int y; + bool live; + bool active; +} CLIENT_UPDATE_BULLET; + +typedef struct cl_update_comet +{ + int x; + int y; + bool live; +} CLIENT_UPDATE_COMET; + +typedef struct cl_update_explosion +{ + int x; + int y; + bool live; +} CLIENT_UPDATE_EXPLOSION; + +typedef struct cl_message_update +{ + CLIENT_UPDATE_SHIP ship[3]; + CLIENT_UPDATE_BULLET bullet[15]; + CLIENT_UPDATE_COMET comet[15]; + CLIENT_UPDATE_EXPLOSION explosion[15]; +} CLIENT_MESSAGE_UPDATE; + +typedef struct cl_enet +{ + ENetHost* client; + ENetPeer* server; + ENetEvent event; + ENetAddress address; + bool connect; + int port; + char host[20]; +} CLIENT_ENET; + +CLIENT_ENET* cl_create_enet(CLIENT_ENET* enet); +void cl_free_enet(CLIENT_ENET* enet); +void cl_destroy_enet(CLIENT_ENET* enet); +void cl_disconnect_enet(CLIENT_ENET* enet); + +#endif + diff --git a/game/networkcreate.c b/game/networkcreate.c new file mode 100644 index 0000000..b230548 --- /dev/null +++ b/game/networkcreate.c @@ -0,0 +1,219 @@ +#include "common.h" +#include "networkcreate.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void networkcreate_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + cl_change_state(data, NETWORKMODE); + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + networkcreate_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + networkcreate_push_button(data); + break; + case ALLEGRO_KEY_TAB: + networkcreate_change_selected(data); + break; + default: + cl_print_field(data); + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { + cl_update_button(data); + cl_update_field(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { + networkcreate_push_button(data); + cl_enter_field(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + cl_update_background(data, BG1); + cl_update_background(data, BG2); + } +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void networkcreate_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG2); + cl_draw_header(data); + cl_draw_button(data); + + cl_draw_field(data); +} + +/************************************************************ + * PROCESSING + ***********************************************************/ +/************************************************************ + * FIELD + ***********************************************************/ + +void networkcreate_init_field(CLIENT_DATA* data, int key_field, int key_font, const char* description) +{ + if(data->pairing.interface[NETWORKCREATE]->field_size > key_field) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_field( + data->pairing.interface[NETWORKCREATE]->field[key_field], + font->al_font, font->size, description, + (data->screen.width / 2) - al_get_text_width(font->al_font, description), + (block_size * (key_field + 3) - font->size / 2), + (data->screen.width / 2), + (block_size * (key_field + 3) - font->size / 2), + (data->screen.width / 2), + (block_size * (key_field + 3) + font->size / 2) + ); + } +} + +/************************************************************ + * BUTTON + ***********************************************************/ + +void networkcreate_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[NETWORKCREATE]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_button( + data->pairing.interface[NETWORKCREATE]->button[key_button], + font->al_font, text, data->screen.width / 2, + (block_size * (key_button + 5)) + (block_size / 4) + (block_size / 2) - font->size, + (data->screen.width / 2) - (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 5) + (block_size / 4), + (data->screen.width / 2) + (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 5) + block_size); + } +} + +static void networkcreate_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + if(interface->selected == SELECTED_BUTTON) + { + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->al_font && interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + switch(i) + { + case BUTTON_NETWORKCREATE_CREATE: + interface->button[i]->selected = false; + if(networkcreate_check_field(data)) + cl_change_state(data, NETWORKPARTY); + break; + case BUTTON_NETWORKCREATE_OUT: + interface->button[i]->selected = false; + cl_change_state(data, NETWORKMODE); + break; + } + } + } + else if(interface->selected == SELECTED_FIELD) + { + for(int i = 0; i < interface->field_size; i++) + if(interface->field[i]->selected) + switch(i) + { + case FIELD_NETWORKCREATE_NICKNAME: + interface->field[i]->enter = true; + break; + case FIELD_NETWORKCREATE_GAMENAME: + interface->field[i]->enter = true; + break; + } + } +} + +static void networkcreate_change_selected(CLIENT_DATA* data) +{ + cl_change_selected(data->pairing.interface[data->state]); +} + +static bool networkcreate_check_field(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + int field_size = interface->field_size; + int field_filled_size = 0; + + for(int i = 0; i < field_size; i++) + if(interface->field[i]->char_number > 0) + field_filled_size++; + + return field_size == field_filled_size; +} + diff --git a/game/networkcreate.h b/game/networkcreate.h new file mode 100644 index 0000000..b6076bb --- /dev/null +++ b/game/networkcreate.h @@ -0,0 +1,36 @@ +/* + * File: network_create.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.12 + */ + +#ifndef client_networkcreate +#define client_networkcreate + +enum networkcreate_buttons +{ + BUTTON_NETWORKCREATE_CREATE, + BUTTON_NETWORKCREATE_OUT +}; + +enum networkcreate_field +{ + FIELD_NETWORKCREATE_NICKNAME, + FIELD_NETWORKCREATE_GAMENAME +}; + +void networkcreate_handling(CLIENT_DATA* data); +void networkcreate_draw(CLIENT_DATA* data); +/************************************************************ + * PROCESSING + ***********************************************************/ +void networkcreate_init_field(CLIENT_DATA* data, int key_field, int key_font, const char* description); +void networkcreate_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); +static void networkcreate_push_button(CLIENT_DATA* data); +static void networkcreate_change_selected(CLIENT_DATA* data); +static bool networkcreate_check_field(CLIENT_DATA* data); + +#endif + diff --git a/game/networkgame.c b/game/networkgame.c new file mode 100644 index 0000000..ef2ce92 --- /dev/null +++ b/game/networkgame.c @@ -0,0 +1,571 @@ +#include +#include + +#include "common.h" +#include "networkgame.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void networkgame_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + al_show_mouse_cursor(data->screen.display); + cl_change_state(data, NETWORKOUT); + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; +// cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; +// cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; +// networkparty_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + networkgame_fire_bullet(data); + break; + case ALLEGRO_KEY_TAB: +// networkparty_change_selected(data); + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { +// cl_update_list(data); +// cl_update_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { +// networkparty_push_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + if(data->keys[UP]) + networkgame_move_ship_up(data); + else if(data->keys[DOWN]) + networkgame_move_ship_down(data); + else + networkgame_reset_ship_animation(data, 1); + + if(data->keys[LEFT]) + networkgame_move_ship_left(data); + else if(data->keys[RIGHT]) + networkgame_move_ship_right(data); + else + networkgame_reset_ship_animation(data, 2); + + networkgame_update_explosions(data); + networkgame_update_comet(data); + + cl_update_background(data, BG1); + cl_update_background(data, BG3); + cl_update_background(data, BG2); + } + + networkgame_enet_receive(data); +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void networkgame_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG3); + cl_draw_background(data, BG2); + + networkgame_draw_ship(data); + networkgame_draw_bullet(data); + networkgame_draw_comet(data); + networkgame_draw_explosions(data); + networkgame_draw_statistic(data); + + networkgame_send_move_ship(data); +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +void networkgame_create_objects(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + int iterator = 0; + + cl_create_objects(objects, data->network.count_connected, 5 * data->network.count_connected, 15, 5 * data->network.count_connected); + + for(int i = 0; i < objects->ship_size; i++) + { + cl_init_ships(objects, iterator, data->network.users[i].id, 3, 1, 1, 10, 12, 0, 0, 50, 41, 46, data->media.bitmaps[SHIP_R + i]->al_bitmap, 3, 3, 0, 0, 0, 0); + + for(int j = iterator++ * 5; j < iterator * 5; j++) + cl_init_bullets(objects, j, data->network.users[i].id, 10, 0, 0); + } + + for(int i = 0; i < objects->comet_size; i++) + cl_init_comets(objects, i, 0, 21, rand() % 2 ? 1 : -1, 35, 35, 0, 0, 2, 96, 96, data->media.bitmaps[COMET]->al_bitmap, 143, 5, 0, 0); + + for(int i = 0; i < objects->explosion_size; i++) + cl_init_explosions(objects, i, 8, 1, 0, 0, 1, 128, 128, data->media.bitmaps[EXPLOSION]->al_bitmap, 31, 0, 0); +} + +void networkgame_enet_receive(CLIENT_DATA* data) +{ + ENetEvent event; + CLIENT_MESSAGE_UPDATE* message; + + while(enet_host_service(data->enet.client, &event, 0) > 0) + if(event.type == ENET_EVENT_TYPE_RECEIVE) + { + message = (CLIENT_MESSAGE_UPDATE*)event.packet->data; + + for(int i = 0; i < data->objects.ship_size; i++) + { + CLIENT_SHIP* ship = data->objects.ships[i]; + + for(int j = 0; j < 3; j++) + if(ship->ID == message->ship[j].ID) + { + ship->x = message->ship[j].x; + ship->y = message->ship[j].y; + ship->lives = message->ship[j].lives; + ship->score = message->ship[j].score; + ship->active = message->ship[j].active; + + for(int k = 0; k < 3; k++) + { + CLIENT_USER* user = &data->network.users[k]; + + if(user->id == ship->ID) + { + user->command.dx = message->ship[j].dx; + user->command.dy = message->ship[j].dy; + } + } + + break; + } + } + + for(int i = 0; i < data->objects.bullet_size; i++) + { + CLIENT_BULLET* bullet = data->objects.bullets[i]; + + if(message->bullet[i].live && !bullet->live) + cl_play_sound(data, SAMPLE_SHOT); + + bullet->ID = message->bullet[i].ID; + bullet->active = message->bullet[i].active; + bullet->live = message->bullet[i].live; + bullet->x = message->bullet[i].x; + bullet->y = message->bullet[i].y; + } + + for(int i = 0; i < data->objects.comet_size; i++) + { + CLIENT_COMET* comet = data->objects.comets[i]; + + comet->live = message->comet[i].live; + comet->x = message->comet[i].x; + comet->y = message->comet[i].y; + } + + for(int i = 0; i < data->objects.explosion_size; i++) + { + CLIENT_EXPLOSION* explosion = data->objects.explosions[i]; + + if(message->explosion[i].live) + { + if(message->explosion[i].live && !explosion->live) + cl_play_sound(data, SAMPLE_BOOM); + + explosion->live = message->explosion[i].live; + explosion->x = message->explosion[i].x; + explosion->y = message->explosion[i].y; + } + } + + enet_packet_destroy(event.packet); + } +} + +static void networkgame_send_move_ship(CLIENT_DATA* data) +{ + if(data->network.command.send) + { + CLIENT_GAME_COMMAND command = data->network.command; + + command.send = false; + + ENetPacket *packet; + CLIENT_MESSAGE_GAME message; + + message.dx = command.dx; + message.dy = command.dy; + message.fire = command.fire; + message.state = STATE_GAME; + + data->network.command.fire = false; + + packet = enet_packet_create(&message, sizeof(message), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(data->enet.server, 0, packet); + } +} + +/************************************************************ + * SHIP + ***********************************************************/ + +static void networkgame_draw_ship(CLIENT_DATA* data) +{ + for(int i = 0; i < data->objects.ship_size; i++) + { + CLIENT_SHIP* ship = data->objects.ships[i]; + + if(!ship->active) continue; + + for(int j = 0; j < data->objects.ship_size; j++) + { + CLIENT_USER* user = &data->network.users[j]; + + if(user->id == ship->ID) + { + if(user->command.dy == -1) + ship->animation_row = 0; + else if(user->command.dy == 1) + ship->animation_row = 2; + else + ship->animation_row = 1; + + if(user->command.dx == -1) + ship->cur_frame = 2; + else if(user->command.dx == 1) + ship->cur_frame = 1; + else + ship->cur_frame = 0; + } + } + + int fx = (ship->cur_frame % ship->animation_columns) * ship->frame_width; + int fy = ship->animation_row * ship->frame_height; + + al_draw_bitmap_region(ship->image, fx, fy, ship->frame_width, ship->frame_height, + ship->x - ship->frame_width / 2, ship->y - ship->frame_height / 2, 0); + } +} + +static void networkgame_move_ship_up(CLIENT_DATA* data) +{ + for(int i = 0; i < data->objects.ship_size; i++) + { + CLIENT_SHIP* ship = data->objects.ships[i]; + + if(ship->ID == data->network.user_id) + { + ship->animation_row = 0; + data->network.command.dy = -1; + data->network.command.send = true; + } + } +} + +static void networkgame_move_ship_down(CLIENT_DATA* data) +{ + for(int i = 0; i < data->objects.ship_size; i++) + { + CLIENT_SHIP* ship = data->objects.ships[i]; + + if(ship->ID == data->network.user_id) + { + ship->animation_row = 2; + data->network.command.dy = 1; + data->network.command.send = true; + } + } +} + +static void networkgame_move_ship_left(CLIENT_DATA* data) +{ + for(int i = 0; i < data->objects.ship_size; i++) + { + CLIENT_SHIP* ship = data->objects.ships[i]; + + if(ship->ID == data->network.user_id) + { + ship->cur_frame = 2; + data->network.command.dx = -1; + data->network.command.send = true; + } + } +} + +static void networkgame_move_ship_right(CLIENT_DATA* data) +{ + for(int i = 0; i < data->objects.ship_size; i++) + { + CLIENT_SHIP* ship = data->objects.ships[i]; + + if(ship->ID == data->network.user_id) + { + ship->cur_frame = 1; + data->network.command.dx = 1; + data->network.command.send = true; + } + } +} + +static void networkgame_reset_ship_animation(CLIENT_DATA* data, int position) +{ + for(int i = 0; i < data->objects.ship_size; i++) + { + CLIENT_SHIP* ship = data->objects.ships[i]; + + if(ship->ID == data->network.user_id) + { + if(position == 1) + { + ship->animation_row = 1; + data->network.command.dy = 0; + } + else + { + ship->cur_frame = 0; + data->network.command.dx = 0; + } + + data->network.command.send = true; + } + } +} + +static bool networkgame_dead_ship(CLIENT_DATA* data) +{ + return data->objects.ships[0]->lives <= 0; +} + +/************************************************************ + * BULLET + ***********************************************************/ + +static void networkgame_fire_bullet(CLIENT_DATA* data) +{ + for(int i = 0; i < data->objects.ship_size; i++) + { + CLIENT_SHIP* ship = data->objects.ships[i]; + + if(ship->ID == data->network.user_id && ship->active) + data->network.command.fire = true; + } +} + +static void networkgame_draw_bullet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + + for(int i = 0; i < objects->bullet_size; i++) + { + CLIENT_BULLET* bullet = objects->bullets[i]; + + if(bullet->live) + al_draw_filled_circle(bullet->x, bullet->y, 2, al_map_rgb(255, 255, 255)); + } +} + +/************************************************************ + * COMET + ***********************************************************/ + +static void networkgame_draw_comet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + + for(int i = 0; i < objects->comet_size; i++) + { + CLIENT_COMET* comet = objects->comets[i]; + + if(comet->live) + { + int fx = (comet->cur_frame % comet->animation_columns) * comet->frame_width; + int fy = (comet->cur_frame / comet->animation_columns) * comet->frame_height; + + al_draw_bitmap_region(comet->image, fx, fy, comet->frame_width, comet->frame_height, + comet->x - comet->frame_width / 2, comet->y - comet->frame_height / 2, 0); + } + } +} + +void networkgame_update_comet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + + for(int i = 0; i < objects->comet_size; i++) + { + CLIENT_COMET* comet = objects->comets[i]; + + if(comet->live) + { + if(++comet->frame_count >= comet->frame_delay) + { + comet->cur_frame += comet->animation_direction; + if(comet->cur_frame >= comet->max_frame) + comet->cur_frame = 0; + else if(comet->cur_frame <= 0) + comet->cur_frame = comet->max_frame - 1; + + comet->frame_count = 0; + } + } + } +} + +/************************************************************ + * EXPLOSION + ***********************************************************/ + +static void networkgame_draw_explosions(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + + for(int i = 0; i < objects->explosion_size; i++) + { + CLIENT_EXPLOSION* explosion = objects->explosions[i]; + + if(explosion->live) + { + int fx = (explosion->cur_frame % explosion->animation_columns) * explosion->frame_width; + int fy = (explosion->cur_frame / explosion->animation_columns) * explosion->frame_height; + + al_draw_bitmap_region(explosion->image, fx, fy, explosion->frame_width, explosion->frame_height, + explosion->x - explosion->frame_width / 2, explosion->y - explosion->frame_height / 2, 0); + } + } +} + +void networkgame_update_explosions(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + + for(int i = 0; i < objects->explosion_size; i++) + { + CLIENT_EXPLOSION* explosion = objects->explosions[i]; + + if(explosion->live) + if(++explosion->frame_count >= explosion->frame_delay) + { + explosion->cur_frame += explosion->animation_direction; + if(explosion->cur_frame >= explosion->max_frame) + { + explosion->cur_frame = 0; + explosion->live = false; + } + + explosion->frame_count = 0; + } + } +} + +/************************************************************ + * STATISTIC + ***********************************************************/ + +static void networkgame_draw_statistic(CLIENT_DATA* data) +{ + ALLEGRO_COLOR color; + ALLEGRO_COLOR color_text = al_map_rgba_f(0.5, 0.5, 0.5, 0.2); + ALLEGRO_FONT* font = data->media.fonts[FONT_PS2P30]->al_font; + + char text[200] = {' ', '\0'}; + char num[5] = {'\0'}; + + for(int i = 0; i < data->objects.ship_size; i++) + { + CLIENT_SHIP* ship = data->objects.ships[i]; + CLIENT_USER user; + + switch(i) + { + case 0: + color = al_map_rgba_f(0.5, 0.0, 0.0, 0.2); + break; + case 1: + color = al_map_rgba_f(0.0, 0.5, 0.0, 0.2); + break; + case 2: + color = al_map_rgba_f(0.5, 0.5, 0.0, 0.2); + break; + } + + for(int j = 0; j < 3; j++) + if(data->network.users[j].id == ship->ID) + { + user = data->network.users[j]; + break; + } + + al_draw_text(font, color, al_get_text_width(font, text), 5, 0, user.nickname); + strcat(text, user.nickname); + al_draw_text(font, color, al_get_text_width(font, text), 5, 0, " - Ж:"); + strcat(text, " - Ж:"); + al_draw_textf(font, color_text, al_get_text_width(font, text), 5, 0, "%d", ship->lives); + sprintf(num, "%d", ship->lives); + strcat(text, num); + al_draw_text(font, color, al_get_text_width(font, text), 5, 0, " К:"); + strcat(text, " К:"); + al_draw_textf(font, color_text, al_get_text_width(font, text), 5, 0, "%d", ship->score); + sprintf(num, "%d ", ship->score); + strcat(text, num); + } +} + diff --git a/game/networkgame.h b/game/networkgame.h new file mode 100644 index 0000000..5c747c0 --- /dev/null +++ b/game/networkgame.h @@ -0,0 +1,53 @@ +/* + * File: network_game.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.12 + */ + +#ifndef client_network_game +#define client_network_game + +void networkgame_handling(CLIENT_DATA* data); +void networkgame_draw(CLIENT_DATA* data); + +void networkgame_create_objects(CLIENT_DATA* data); +void networkgame_enet_receive(CLIENT_DATA* data); + +static void networkgame_send_move_ship(CLIENT_DATA* data); + +/************************************************************ + * SHIP + ***********************************************************/ +static void networkgame_draw_ship(CLIENT_DATA* data); +static void networkgame_move_ship_up(CLIENT_DATA* data); +static void networkgame_move_ship_down(CLIENT_DATA* data); +static void networkgame_move_ship_left(CLIENT_DATA* data); +static void networkgame_move_ship_right(CLIENT_DATA* data); +static void networkgame_reset_ship_animation(CLIENT_DATA* data, int position); +static bool networkgame_dead_ship(CLIENT_DATA* data); +/************************************************************ + * BULLET + ***********************************************************/ +static void networkgame_fire_bullet(CLIENT_DATA* data); +static void networkgame_draw_bullet(CLIENT_DATA* data); +/************************************************************ + * COMET + ***********************************************************/ +static void networkgame_draw_comet(CLIENT_DATA* data); +void networkgame_update_comet(CLIENT_DATA* data); +/************************************************************ + * EXPLOSION + ***********************************************************/ +static void networkgame_draw_explosions(CLIENT_DATA* data); +void networkgame_update_explosions(CLIENT_DATA* data); +/************************************************************ + * STATISTIC + ***********************************************************/ +static void networkgame_draw_statistic(CLIENT_DATA* data); + +#endif + + + diff --git a/game/networkjoin.c b/game/networkjoin.c new file mode 100644 index 0000000..18abe3b --- /dev/null +++ b/game/networkjoin.c @@ -0,0 +1,212 @@ +#include "common.h" +#include "networkjoin.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void networkjoin_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + cl_change_state(data, NETWORKMODE); + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + networkjoin_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + networkjoin_push_button(data); + break; + case ALLEGRO_KEY_TAB: + networkjoin_change_selected(data); + break; + default: + cl_print_field(data); + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { + cl_update_button(data); + cl_update_field(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { + networkjoin_push_button(data); + cl_enter_field(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + cl_update_background(data, BG1); + cl_update_background(data, BG2); + } +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void networkjoin_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG2); + cl_draw_header(data); + cl_draw_button(data); + + cl_draw_field(data); +} + +/************************************************************ + * FIELD + ***********************************************************/ + +void networkjoin_init_field(CLIENT_DATA* data, int key_field, int key_font, const char* description) +{ + if(data->pairing.interface[NETWORKJOIN]->field_size > key_field) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_field( + data->pairing.interface[NETWORKJOIN]->field[key_field], + font->al_font, font->size, description, + (data->screen.width / 2) - al_get_text_width(font->al_font, description), + (block_size * (key_field + 3) - font->size / 2), + (data->screen.width / 2), + (block_size * (key_field + 3) - font->size / 2), + (data->screen.width / 2), + (block_size * (key_field + 3) + font->size / 2) + ); + } +} + +/************************************************************ + * BUTTON + ***********************************************************/ + +void networkjoin_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[NETWORKJOIN]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_button( + data->pairing.interface[NETWORKJOIN]->button[key_button], + font->al_font, text, data->screen.width / 2, + (block_size * (key_button + 5)) + (block_size / 4) + (block_size / 2) - font->size, + (data->screen.width / 2) - (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 5) + (block_size / 4), + (data->screen.width / 2) + (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 5) + block_size); + } +} + +static void networkjoin_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + if(interface->selected == SELECTED_BUTTON) + { + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->al_font && interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + switch(i) + { + case BUTTON_NETWORKJOIN_CREATE: + interface->button[i]->selected = false; + if(networkjoin_check_field(data)) + cl_change_state(data, NETWORKLIST); + break; + case BUTTON_NETWORKJOIN_OUT: + interface->button[i]->selected = false; + cl_change_state(data, NETWORKMODE); + break; + } + } + } + else if(interface->selected == SELECTED_FIELD) + { + for(int i = 0; i < interface->field_size; i++) + if(interface->field[i]->selected) + switch(i) + { + case FIELD_NETWORKJOIN_NICKNAME: + interface->field[i]->enter = true; + break; + } + } +} + +static void networkjoin_change_selected(CLIENT_DATA* data) +{ + cl_change_selected(data->pairing.interface[data->state]); +} + +static bool networkjoin_check_field(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + int field_size = interface->field_size; + int field_filled_size = 0; + + for(int i = 0; i < field_size; i++) + if(interface->field[i]->char_number > 0) + field_filled_size++; + + return field_size == field_filled_size; +} diff --git a/game/networkjoin.h b/game/networkjoin.h new file mode 100644 index 0000000..11b1e14 --- /dev/null +++ b/game/networkjoin.h @@ -0,0 +1,36 @@ +/* + * File: network_join.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.12 + */ + +#ifndef client_network_join +#define client_network_join + +enum networkjoin_buttons +{ + BUTTON_NETWORKJOIN_CREATE, + BUTTON_NETWORKJOIN_OUT +}; + +enum networkjoin_field +{ + FIELD_NETWORKJOIN_NICKNAME +}; + +void networkjoin_handling(CLIENT_DATA* data); +void networkjoin_draw(CLIENT_DATA* data); + +void networkjoin_init_field(CLIENT_DATA* data, int key_field, int key_font, const char* description); +void networkjoin_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); + +static void networkjoin_push_button(CLIENT_DATA* data); +static void networkjoin_change_selected(CLIENT_DATA* data); +static bool networkjoin_check_field(CLIENT_DATA* data); + +#endif + + + diff --git a/game/networklist.c b/game/networklist.c new file mode 100644 index 0000000..6a1250e --- /dev/null +++ b/game/networklist.c @@ -0,0 +1,303 @@ +#include "common.h" +#include "networklist.h" + +#include +#include + +/************************************************************ + * HANDLING + ***********************************************************/ + +void networklist_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + cl_change_state(data, NETWORKMODE); + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + networklist_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + networklist_push_button(data); + break; + case ALLEGRO_KEY_TAB: + networklist_change_selected(data); + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { + cl_update_button(data); + cl_update_list(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { + networklist_push_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + cl_update_background(data, BG1); + cl_update_background(data, BG2); + } + + networklist_enet_receive(data); +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void networklist_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG2); + cl_draw_header(data); + cl_draw_button(data); + networklist_draw_list(data); +} + +/************************************************************ + * BUTTON + ***********************************************************/ + +void networklist_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[NETWORKLIST]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + int index = 0; + + cl_add_interface_button( + data->pairing.interface[NETWORKLIST]->button[key_button], + font->al_font, text, + data->screen.width - (750 * data->screen.scale_factor + 60) / 2, + block_size * (index + 6) + (block_size / 4) + (block_size / 2) - font->size, + data->screen.width - (750 * data->screen.scale_factor) - 30, + block_size * (index + 6) + (block_size / 4), + data->screen.width - 30, + block_size * (index + 6) + block_size); + } +} + +/************************************************************ + * LIST + ***********************************************************/ + +void networklist_init_list(CLIENT_DATA* data, int key_font) +{ + CLIENT_LIST* list = &data->pairing.interface[NETWORKLIST]->list; + + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + int item_height = ((data->screen.height - 15) - block_size * 2) / 3; + + list->sx = 15; + list->sy = block_size * 2; + list->dx = data->screen.width - (750 * data->screen.scale_factor) - 60; + list->dy = data->screen.height - 15; + list->al_font = font->al_font; + + for(int i = 0; i < 3; i++) + cl_add_list_item( + &list->item[i], + list->sx, + list->sy + (item_height * i), + list->dx, + list->sy + item_height + (item_height * i), + list->sx + 30, + (list->sy + (item_height * i)) + ((item_height / 2) - (font->size / 2)), + list->dx - font->size - 30, + list->sy + (item_height * i) + (item_height / 2), + font->size); +} + +static void networklist_draw_list(CLIENT_DATA* data) +{ + CLIENT_LIST* list = &data->pairing.interface[NETWORKLIST]->list; + ALLEGRO_COLOR clr; + + al_draw_rectangle(list->sx, list->sy, list->dx, list->dy, al_map_rgba_f(0.2, 0.2, 0.2, 0.2), 3); + + for(int i = 0; i < 3; i++) + { + if(i < data->network.count_game) + { + list->item[i].active = true; + + CLIENT_LIST_ITEM item = list->item[i]; + + if(item.selected) + clr = al_map_rgba_f(0.4, 0.4, 0.0, 0.2); + else + clr = al_map_rgba_f(0.2, 0.2, 0.2, 0.2); + + al_draw_filled_rectangle(item.sx_item, item.sy_item, item.dx_item, item.dy_item, clr); + al_draw_text(list->al_font, al_map_rgb(255, 255, 255), item.x_h, item.y_h, 0, data->network.games[i].game_name); + + if(data->network.games[i].count_connected == 3) + clr = al_map_rgba_f(0.5, 0.0, 0.0, 0.2); + else if(data->network.games[i].count_connected == 2) + clr = al_map_rgba_f(0.5, 0.5, 0.0, 0.2); + else + clr = al_map_rgba_f(0.0, 0.5, 0.0, 0.2); + + al_draw_filled_circle(item.x_status, item.y_status, item.r_status, clr); + } + else + list->item[i].active = false; + } +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +static void networklist_enet_receive(CLIENT_DATA* data) +{ + ENetEvent event; + CLIENT_MESSAGE_LIST* message; + CLIENT_MESSAGE_PARTY* messages; + + while(enet_host_service(data->enet.client, &event, 0) > 0) + if(event.type == ENET_EVENT_TYPE_RECEIVE) + { + message = (CLIENT_MESSAGE_LIST*)event.packet->data; + + if(message->state == STATE_PARTY) + { + cl_change_state(data, NETWORKPARTY); + break; + } + + CLIENT_NETWORK* network = &data->network; + + for(int i = 0; i < 3; i++) + { + network->games[i].id = message->games[i].id; + network->games[i].count_connected = message->games[i].count_connected; + strncpy(network->games[i].game_name, message->games[i].game_name, 40); + } + + network->count_game = message->count_game; + + enet_packet_destroy(event.packet); + } +} + +static void networklist_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[NETWORKLIST]; + + ENetPacket *packet; + CLIENT_MESSAGE_JOINGAME message; + + if(interface->selected == SELECTED_LIST) + { + CLIENT_LIST* list = &interface->list; + + for(int i = 0; i < 3; i++) + if(list->item[i].selected && data->network.games[i].count_connected < 3) + { + list->item[i].selected = false; + + message.id = data->network.games[i].id; + message.state = STATE_PARTY; + packet = enet_packet_create(&message, sizeof(message), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(data->enet.server, 0, packet); + + break; + } + } + else if(interface->selected == SELECTED_BUTTON) + { + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->al_font && interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + switch(i) + { + case BUTTON_NETWORKLIST_OUT: + interface->button[i]->selected = false; + cl_change_state(data, NETWORKMODE); + break; + } + } + } +} + +void networklist_change_selected(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[NETWORKLIST]; + + if(interface->selected == SELECTED_BUTTON) + { + interface->selected = SELECTED_LIST; + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->selected) + interface->button[i]->selected = false; + } + else if(interface->selected == SELECTED_LIST) + { + interface->selected = SELECTED_BUTTON; + for(int i = 0; i < 3; i++) + if(interface->list.item[i].selected) + interface->list.item[i].selected = false; + } +} + diff --git a/game/networklist.h b/game/networklist.h new file mode 100644 index 0000000..d043f66 --- /dev/null +++ b/game/networklist.h @@ -0,0 +1,33 @@ +/* + * File: networklist.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.21 + */ + +#ifndef client_network_list +#define client_network_list + +enum networkparty_buttons +{ + BUTTON_NETWORKLIST_OUT +}; + +void networklist_handling(CLIENT_DATA* data); +void networklist_draw(CLIENT_DATA* data); + +void networklist_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); + +void networklist_init_list(CLIENT_DATA* data, int key_font); +static void networklist_draw_list(CLIENT_DATA* data); + +static void networklist_enet_receive(CLIENT_DATA* data); +static void networklist_push_button(CLIENT_DATA* data); + +void networklist_change_selected(CLIENT_DATA* data); + +#endif + + + diff --git a/game/networkmode.c b/game/networkmode.c new file mode 100644 index 0000000..d7c8a6a --- /dev/null +++ b/game/networkmode.c @@ -0,0 +1,150 @@ +#include "common.h" +#include "networkmode.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void networkmode_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + cl_change_state(data, MENU); + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + networkmode_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + networkmode_push_button(data); + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { + cl_update_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { + networkmode_push_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + cl_update_background(data, BG1); + cl_update_background(data, BG2); + } +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void networkmode_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG2); + cl_draw_header(data); + cl_draw_button(data); +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +void networkmode_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[NETWORKMODE]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_button( + data->pairing.interface[NETWORKMODE]->button[key_button], + font->al_font, text, data->screen.width / 2, + (block_size * (key_button + 3)) + (block_size / 4) + (block_size / 2) - font->size, + (data->screen.width / 2) - (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 3) + (block_size / 4), + (data->screen.width / 2) + (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 3) + block_size); + } +} + +static void networkmode_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->al_font && interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + switch(i) + { + case BUTTON_NETWORKMODE_CREATE: + interface->button[i]->selected = false; + cl_change_state(data, NETWORKCREATE); + break; + case BUTTON_NETWORKMODE_JOIN: + interface->button[i]->selected = false; + cl_change_state(data, NETWORKJOIN); + break; + case BUTTON_NETWORKMODE_OUT: + interface->button[i]->selected = false; + cl_change_state(data, MENU); + break; + } + } +} diff --git a/game/networkmode.h b/game/networkmode.h new file mode 100644 index 0000000..760e100 --- /dev/null +++ b/game/networkmode.h @@ -0,0 +1,30 @@ +/* + * File: network.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.11 + */ + +#ifndef client_networkmode +#define client_networkmode + +enum networkmode_buttons +{ + BUTTON_NETWORKMODE_CREATE, + BUTTON_NETWORKMODE_JOIN, + BUTTON_NETWORKMODE_OUT +}; + +void networkmode_handling(CLIENT_DATA* data); +void networkmode_draw(CLIENT_DATA* data); +/************************************************************ + * PROCESSING + ***********************************************************/ +void networkmode_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); +static void networkmode_push_button(CLIENT_DATA* data); + +#endif + + + diff --git a/game/networkout.c b/game/networkout.c new file mode 100644 index 0000000..1cc5063 --- /dev/null +++ b/game/networkout.c @@ -0,0 +1,160 @@ +#include "common.h" +#include "networkout.h" +#include "networkgame.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void networkout_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + al_hide_mouse_cursor(data->screen.display); + cl_change_state(data, NETWORKGAME); + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + networkout_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + networkout_push_button(data); + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { + cl_update_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { + networkout_push_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + networkgame_update_explosions(data); + networkgame_update_comet(data); + + cl_update_background(data, BG1); + cl_update_background(data, BG3); + cl_update_background(data, BG2); + } + + networkgame_enet_receive(data); +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void networkout_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG3); + cl_draw_background(data, BG2); + cl_draw_header(data); + cl_draw_button(data); +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +void networkout_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[NETWORKOUT]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_button( + data->pairing.interface[NETWORKOUT]->button[key_button], + font->al_font, text, data->screen.width / 2, + (block_size * (key_button + 3)) + (block_size / 4) + (block_size / 2) - font->size, + (data->screen.width / 2) - (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 3) + (block_size / 4), + (data->screen.width / 2) + (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 3) + block_size); + } +} + +static void networkout_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + switch(i) + { + case BUTTON_NETWORKOUT_BACK: + { + interface->button[i]->selected = false; + al_hide_mouse_cursor(data->screen.display); + cl_change_state(data, NETWORKGAME); + break; + } + case BUTTON_NETWORKOUT_MENU: + { + interface->button[i]->selected = false; + cl_change_state(data, NETWORKMODE); + break; + } + } + } +} diff --git a/game/networkout.h b/game/networkout.h new file mode 100644 index 0000000..5ff5856 --- /dev/null +++ b/game/networkout.h @@ -0,0 +1,27 @@ +/* + * File: networkout.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.27 + */ + +#ifndef client_networkout +#define client_networkout + +enum networkout_buttons +{ + BUTTON_NETWORKOUT_BACK, + BUTTON_NETWORKOUT_MENU +}; + +void networkout_handling(CLIENT_DATA* data); +void networkout_draw(CLIENT_DATA* data); + +void networkout_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); +static void networkout_push_button(CLIENT_DATA* data); + +#endif + + + diff --git a/game/networkparty.c b/game/networkparty.c new file mode 100644 index 0000000..16785c9 --- /dev/null +++ b/game/networkparty.c @@ -0,0 +1,433 @@ +#include "common.h" +#include "networkparty.h" +#include "networkcreate.h" + +#include +#include + +/************************************************************ + * HANDLING + ***********************************************************/ + +void networkparty_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + if(data->network.is_creator) + cl_change_state(data, NETWORKMODE); + else + networkparty_send_exit(data); + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + networkparty_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + networkparty_push_button(data); + break; + case ALLEGRO_KEY_TAB: + networkparty_change_selected(data); + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { + cl_update_list(data); + cl_update_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { + networkparty_push_button(data); + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + cl_update_background(data, BG1); + cl_update_background(data, BG2); + } + + networkparty_enet_receive(data); +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void networkparty_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG2); + cl_draw_header(data); + networkparty_draw_button(data); + networkparty_draw_list(data); +} + +/************************************************************ + * BUTTON + ***********************************************************/ + +void networkparty_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[NETWORKPARTY]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + int index = 0; + + if(key_button == BUTTON_NETWORKPARTY_OUT) + index = 1; + + cl_add_interface_button( + data->pairing.interface[NETWORKPARTY]->button[key_button], + font->al_font, text, + data->screen.width - (750 * data->screen.scale_factor + 60) / 2, + block_size * (index + 5) + (block_size / 4) + (block_size / 2) - font->size, + data->screen.width - (750 * data->screen.scale_factor) - 30, + block_size * (index + 5) + (block_size / 4), + data->screen.width - 30, + block_size * (index + 5) + block_size); + } +} + +static void networkparty_draw_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[NETWORKPARTY]; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->al_font) + { + CLIENT_BUTTON* btn = interface->button[i]; + + if(data->network.is_creator) + { + if(i == BUTTON_NETWORKPARTY_READY || i == BUTTON_NETWORKPARTY_UNREADY) + { + btn->active = false; + continue; + } + } + else if(data->network.is_ready) + { + if(i == BUTTON_NETWORKPARTY_READY || i == BUTTON_NETWORKPARTY_START) + { + btn->active = false; + continue; + } + } + else + { + if(i == BUTTON_NETWORKPARTY_UNREADY || i == BUTTON_NETWORKPARTY_START) + { + btn->active = false; + continue; + } + } + + ALLEGRO_COLOR clr; + + btn->active = true; + + if(btn->selected) + clr = al_map_rgba_f(0.4, 0.4, 0.0, 0.2); + else + clr = al_map_rgba_f(0.2, 0.2, 0.2, 0.2); + + al_draw_filled_rectangle(btn->b_sx, btn->b_sy, btn->b_dx, btn->b_dy, clr); + al_draw_text(btn->al_font, al_map_rgb(255, 255, 255), btn->t_x, btn->t_y, ALLEGRO_ALIGN_CENTRE, btn->text); + } +} + +/************************************************************ + * LIST + ***********************************************************/ + +void networkparty_init_list(CLIENT_DATA* data, int key_font) +{ + CLIENT_LIST* list = &data->pairing.interface[NETWORKPARTY]->list; + + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + int item_height = ((data->screen.height - 15) - block_size * 2) / 3; + + list->sx = 15; + list->sy = block_size * 2; + list->dx = data->screen.width - (750 * data->screen.scale_factor) - 60; + list->dy = data->screen.height - 15; + list->al_font = font->al_font; + + for(int i = 0; i < 3; i++) + cl_add_list_item( + &list->item[i], + list->sx, + list->sy + (item_height * i), + list->dx, + list->sy + item_height + (item_height * i), + list->sx + 30, + (list->sy + (item_height * i)) + ((item_height / 2) - (font->size / 2)), + list->dx - font->size - 30, + list->sy + (item_height * i) + (item_height / 2), + font->size); +} + +static void networkparty_draw_list(CLIENT_DATA* data) +{ + CLIENT_LIST* list = &data->pairing.interface[NETWORKPARTY]->list; + ALLEGRO_COLOR clr; + + al_draw_rectangle(list->sx, list->sy, list->dx, list->dy, al_map_rgba_f(0.2, 0.2, 0.2, 0.2), 3); + + for(int i = 0; i < 3; i++) + { + if(i < data->network.count_connected) + { + list->item[i].active = true; + + CLIENT_LIST_ITEM item = list->item[i]; + + if(item.selected) + clr = al_map_rgba_f(0.4, 0.4, 0.0, 0.2); + else + clr = al_map_rgba_f(0.2, 0.2, 0.2, 0.2); + + al_draw_filled_rectangle(item.sx_item, item.sy_item, item.dx_item, item.dy_item, clr); + al_draw_text(list->al_font, al_map_rgb(255, 255, 255), item.x_h, item.y_h, 0, data->network.users[i].nickname); + + if(data->network.users[i].is_ready) + clr = al_map_rgba_f(0.0, 0.5, 0.0, 0.2); + else + clr = al_map_rgba_f(0.5, 0.0, 0.0, 0.2); + + al_draw_filled_circle(item.x_status, item.y_status, item.r_status, clr); + } + else + list->item[i].active = false; + } +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +static void networkparty_enet_receive(CLIENT_DATA* data) +{ + ENetEvent event; + CLIENT_MESSAGE_PARTY* message; + + while(enet_host_service(data->enet.client, &event, 0) > 0) + if(event.type == ENET_EVENT_TYPE_RECEIVE) + { + message = (CLIENT_MESSAGE_PARTY*)event.packet->data; + + if(message->state == STATE_LIST) + { + cl_change_state(data, NETWORKLIST); + break; + } + else if(message->state == STATE_GAME) + { + cl_change_state(data, NETWORKGAME); + break; + } + + CLIENT_NETWORK* network = &data->network; + + network->active = message->active; + network->count_connected = message->count_connected; + network->game_started = message->game_started; + strncpy(network->game_name, message->game_name, 40); + network->is_creator = message->is_creator; + network->is_ready = message->is_ready; + network->game_id = message->game_id; + network->user_id = message->user_id; + + for(int i = 0; i < network->count_connected; i++) + { + network->users[i].id = message->users[i].id; + network->users[i].is_ready = message->users[i].is_ready; + strncpy(network->users[i].nickname, message->users[i].nickname, 40); + } + + enet_packet_destroy(event.packet); + } +} + +static void networkparty_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[NETWORKPARTY]; + + if(interface->selected == SELECTED_BUTTON) + { + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + interface->button[i]->selected = false; + + switch(i) + { + case BUTTON_NETWORKPARTY_START: + if(networkparty_check_users(data)) + networkparty_send_start(data); + break; + case BUTTON_NETWORKPARTY_READY: + case BUTTON_NETWORKPARTY_UNREADY: + networkparty_send_ready(data); + break; + case BUTTON_NETWORKPARTY_OUT: + if(data->network.is_creator) + cl_change_state(data, NETWORKMODE); + else + networkparty_send_exit(data); + break; + } + } + } + else if(interface->selected == SELECTED_LIST) + { + if(data->network.is_creator) + { + CLIENT_LIST* list = &interface->list; + + for(int i = 0; i < 3; i++) + if(list->item[i].selected && data->network.users[i].id != data->network.user_id) + { + list->item[i].selected = false; + + networkparty_send_kick(data, data->network.users[i].id); + + break; + } + } + } +} + +static void networkparty_change_selected(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[NETWORKPARTY]; + + if(interface->selected == SELECTED_BUTTON) + { + interface->selected = SELECTED_LIST; + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->selected) + interface->button[i]->selected = false; + } + else if(interface->selected == SELECTED_LIST) + { + interface->selected = SELECTED_BUTTON; + for(int i = 0; i < 3; i++) + if(interface->list.item[i].selected) + interface->list.item[i].selected = false; + } +} + +static bool networkparty_check_users(CLIENT_DATA* data) +{ + bool ready = true; + + for(int i = 0; i < data->network.count_connected; i++) + if(!data->network.users[i].is_ready) + { + ready = false; + break; + } + + return ready; +} + +static void networkparty_send_exit(CLIENT_DATA* data) +{ + CLIENT_MESSAGE_SENDPARTY message; + + message.state = STATE_LIST; + message.kick_user = false; + + ENetPacket *packet = enet_packet_create(&message, sizeof(message), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(data->enet.server, 0, packet); +} + +static void networkparty_send_ready(CLIENT_DATA* data) +{ + CLIENT_MESSAGE_SENDPARTY message; + + message.state = STATE_PARTY; + message.is_ready = !data->network.is_ready; + + ENetPacket *packet = enet_packet_create(&message, sizeof(message), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(data->enet.server, 0, packet); +} + +static void networkparty_send_kick(CLIENT_DATA* data, int user_id) +{ + CLIENT_MESSAGE_SENDPARTY message; + + message.state = STATE_LIST; + message.kick_user = true; + message.user_id = user_id; + + ENetPacket *packet = enet_packet_create(&message, sizeof(message), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(data->enet.server, 0, packet); +} + +static void networkparty_send_start(CLIENT_DATA* data) +{ + CLIENT_MESSAGE_SENDPARTY message; + + message.state = STATE_GAME; + + ENetPacket *packet = enet_packet_create(&message, sizeof(message), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(data->enet.server, 0, packet); +} diff --git a/game/networkparty.h b/game/networkparty.h new file mode 100644 index 0000000..2930adc --- /dev/null +++ b/game/networkparty.h @@ -0,0 +1,42 @@ +/* + * File: network_party.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.12 + */ + +#ifndef client_network_party +#define client_network_party + +enum networklist_buttons +{ + BUTTON_NETWORKPARTY_START, + BUTTON_NETWORKPARTY_READY, + BUTTON_NETWORKPARTY_UNREADY, + BUTTON_NETWORKPARTY_OUT +}; + +void networkparty_handling(CLIENT_DATA* data); +void networkparty_draw(CLIENT_DATA* data); + +static void networkparty_enet_receive(CLIENT_DATA* data); +void networkparty_init_list(CLIENT_DATA* data, int key_font); + +static void networkparty_draw_list(CLIENT_DATA* data); +void networkparty_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); +static void networkparty_draw_button(CLIENT_DATA* data); +static void networkparty_push_button(CLIENT_DATA* data); +static void networkparty_change_selected(CLIENT_DATA* data); + +static bool networkparty_check_users(CLIENT_DATA* data); + +static void networkparty_send_exit(CLIENT_DATA* data); +static void networkparty_send_ready(CLIENT_DATA* data); +static void networkparty_send_kick(CLIENT_DATA* data, int user_id); +static void networkparty_send_start(CLIENT_DATA* data); + +#endif + + + diff --git a/game/objects/objects.c b/game/objects/objects.c new file mode 100644 index 0000000..29db198 --- /dev/null +++ b/game/objects/objects.c @@ -0,0 +1,199 @@ +#include "objects.h" +#include "message.h" + +CLIENT_OBJECTS* cl_create_objects(CLIENT_OBJECTS* objects, int ship_size, int bullet_size, int comet_size, int explosion_size) +{ + if(!objects) + { + CLIENT_OBJECTS* objects = (CLIENT_OBJECTS*)malloc(sizeof(CLIENT_OBJECTS)); + show_message_error(objects, "Failed to allocate space for CLIENT_OBJECTS"); + } + + objects->ship_size = ship_size; + objects->bullet_size = bullet_size; + objects->comet_size = comet_size; + objects->explosion_size = explosion_size; + + objects->ships = cl_create_ships(ship_size); + objects->bullets = cl_create_bullets(bullet_size); + objects->comets = cl_create_comets(comet_size); + objects->explosions = cl_create_explosions(explosion_size); + + return objects; +} + +void cl_free_objects(CLIENT_OBJECTS* objects) +{ + cl_destroy_objects(objects); + free(objects); +} + +void cl_destroy_objects(CLIENT_OBJECTS* objects) +{ + if(objects->ship_size > 0) + { + for(int i = 0; i < objects->ship_size; i++) + free(objects->ships[i]); + free(objects->ships); + } + + if(objects->bullet_size > 0) + { + for(int i = 0; i < objects->bullet_size; i++) + free(objects->bullets[i]); + free(objects->bullets); + } + + if(objects->comet_size > 0) + { + for(int i = 0; i < objects->comet_size; i++) + free(objects->comets[i]); + free(objects->comets); + } + + if(objects->explosion_size > 0) + { + for(int i = 0; i < objects->explosion_size; i++) + free(objects->explosions[i]); + free(objects->explosions); + } +} + +static CLIENT_SHIP** cl_create_ships(int size) +{ + CLIENT_SHIP** ships = (CLIENT_SHIP**)malloc(sizeof(CLIENT_SHIP*) * size); + show_message_error(ships, "Failed to allocate space for CLIENT_SHIP collection"); + + for(int i = 0; i < size; i++) + { + ships[i] = (CLIENT_SHIP*)malloc(sizeof(CLIENT_SHIP)); + show_message_error(ships[i], "Failed to allocate space for CLIENT_SHIP"); + ships[i]->image = NULL; + } + + return ships; +} + +static CLIENT_BULLET** cl_create_bullets(int size) +{ + CLIENT_BULLET** bullets = (CLIENT_BULLET**)malloc(sizeof(CLIENT_BULLET*) * size); + show_message_error(bullets, "Failed to allocate space for CLIENT_BULLET collection"); + + for(int i = 0; i < size; i++) + { + bullets[i] = (CLIENT_BULLET*)malloc(sizeof(CLIENT_BULLET)); + show_message_error(bullets[i], "Failed to allocate space for CLIENT_BULLET"); + } + + return bullets; +} + +static CLIENT_COMET** cl_create_comets(int size) +{ + CLIENT_COMET** comets = (CLIENT_COMET**)malloc(sizeof(CLIENT_COMET*) * size); + show_message_error(comets, "Failed to allocate space for CLIENT_COMET collection"); + + for(int i = 0; i < size; i++) + { + comets[i] = (CLIENT_COMET*)malloc(sizeof(CLIENT_COMET)); + show_message_error(comets[i], "Failed to allocate space for CLIENT_COMET"); + comets[i]->image = NULL; + } + + return comets; +} + +static CLIENT_EXPLOSION** cl_create_explosions(int size) +{ + CLIENT_EXPLOSION** explosions = (CLIENT_EXPLOSION**)malloc(sizeof(CLIENT_EXPLOSION*) * size); + show_message_error(explosions, "Failed to allocate space for CLIENT_EXPLOSION collection"); + + for(int i = 0; i < size; i++) + { + explosions[i] = (CLIENT_EXPLOSION*)malloc(sizeof(CLIENT_EXPLOSION)); + show_message_error(explosions[i], "Failed to allocate space for CLIENT_EXPLOSION"); + explosions[i]->image = NULL; + } + + return explosions; +} + +void cl_init_ships(CLIENT_OBJECTS* objects, int key_ship, int ID, int animation_columns, int animation_direction, int animation_row, int boundx, int boundy, int cur_frame, + int frame_count, int frame_delay, int frame_height, int frame_width, ALLEGRO_BITMAP* image, int lives, int max_frame, int score, int speed, int x, int y) +{ + CLIENT_SHIP* ship = objects->ships[key_ship]; + + ship->ID = ID; + ship->animation_columns = animation_columns; + ship->animation_direction = animation_direction; + ship->animation_row = animation_row; + ship->boundx = boundx; + ship->boundy = boundy; + ship->cur_frame = cur_frame; + ship->frame_count = frame_count; + ship->frame_delay = frame_delay; + ship->frame_height = frame_height; + ship->frame_width = frame_width; + ship->image = image; + ship->lives = lives; + ship->max_frame = max_frame; + ship->score = score; + ship->speed = speed; + ship->x = x; + ship->y = y; + ship->active = true; +} + +void cl_init_bullets(CLIENT_OBJECTS* objects, int key_bullet, int ID, int speed, int x, int y) +{ + CLIENT_BULLET* bullet = objects->bullets[key_bullet]; + + bullet->ID = ID; + bullet->live = false; + bullet->speed = speed; + bullet->x = x; + bullet->y = y; + bullet->active = true; +} + +void cl_init_comets(CLIENT_OBJECTS* objects, int key_comet, int ID, int animation_columns, int animation_direction, int boundx, int boundy, int cur_frame, + int frame_count, int frame_delay, int frame_height, int frame_width, ALLEGRO_BITMAP* image, int max_frame, int speed, int x, int y) +{ + CLIENT_COMET* comet = objects->comets[key_comet]; + + comet->ID = ID; + comet->animation_columns = animation_columns; + comet->animation_direction = animation_direction; + comet->boundx = boundx; + comet->boundy = boundy; + comet->cur_frame = cur_frame; + comet->frame_count = frame_count; + comet->frame_delay = frame_delay; + comet->frame_height = frame_height; + comet->frame_width = frame_width; + comet->image = image; + comet->max_frame = max_frame; + comet->speed = speed; + comet->live = false; + comet->x = x; + comet->y = y; +} + +void cl_init_explosions(CLIENT_OBJECTS* objects, int key_explosion, int animation_columns, int animation_direction, int cur_frame, + int frame_count, int frame_delay, int frame_height, int frame_width, ALLEGRO_BITMAP* image, int max_frame, int x, int y) +{ + CLIENT_EXPLOSION* explosion = objects->explosions[key_explosion]; + + explosion->animation_columns = animation_columns; + explosion->animation_direction = animation_direction; + explosion->cur_frame = cur_frame; + explosion->frame_count = frame_count; + explosion->frame_delay = frame_delay; + explosion->frame_height = frame_height; + explosion->frame_width = frame_width; + explosion->image = image; + explosion->live = false; + explosion->max_frame = max_frame; + explosion->x = x; + explosion->y = y; +} diff --git a/game/objects/objects.h b/game/objects/objects.h new file mode 100644 index 0000000..77cc1a7 --- /dev/null +++ b/game/objects/objects.h @@ -0,0 +1,120 @@ +/* + * File: objects.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.03 + */ + +#ifndef client_objects +#define client_objects + +#include +#include + +typedef struct cl_ship +{ + int ID; + int x; + int y; + int lives; + int speed; + int boundx; + int boundy; + int score; + bool active; + + int max_frame; + int cur_frame; + int frame_count; + int frame_delay; + int frame_width; + int frame_height; + int animation_columns; + int animation_direction; + + int animation_row; + + ALLEGRO_BITMAP *image; +} CLIENT_SHIP; + +typedef struct cl_bullet +{ + int ID; + int x; + int y; + bool live; + int speed; + bool active; +} CLIENT_BULLET; + +typedef struct cl_comet +{ + int ID; + int x; + int y; + bool live; + int speed; + int boundx; + int boundy; + + int max_frame; + int cur_frame; + int frame_count; + int frame_delay; + int frame_width; + int frame_height; + int animation_columns; + int animation_direction; + + ALLEGRO_BITMAP *image; +} CLIENT_COMET; + +typedef struct cl_explosion +{ + int x; + int y; + bool live; + + int max_frame; + int cur_frame; + int frame_count; + int frame_delay; + int frame_width; + int frame_height; + int animation_columns; + int animation_direction; + + ALLEGRO_BITMAP *image; +} CLIENT_EXPLOSION; + +typedef struct cl_objects +{ + CLIENT_SHIP** ships; + int ship_size; + CLIENT_BULLET** bullets; + int bullet_size; + CLIENT_COMET** comets; + int comet_size; + CLIENT_EXPLOSION** explosions; + int explosion_size; +} CLIENT_OBJECTS; + +CLIENT_OBJECTS* cl_create_objects(CLIENT_OBJECTS* data, int ship_size, int bullet_size, int comet_size, int explosion_size); +void cl_free_objects(CLIENT_OBJECTS* objects); +void cl_destroy_objects(CLIENT_OBJECTS* objects); + +static CLIENT_SHIP** cl_create_ships(int size); +static CLIENT_BULLET** cl_create_bullets(int size); +static CLIENT_COMET** cl_create_comets(int size); +static CLIENT_EXPLOSION** cl_create_explosions(int size); + +void cl_init_ships(CLIENT_OBJECTS* objects, int key_ship, int ID, int animation_columns, int animation_direction, int animation_row, int boundx, int boundy, int cur_frame, + int frame_count, int frame_delay, int frame_height, int frame_width, ALLEGRO_BITMAP* image, int lives, int max_frame, int score, int speed, int x, int y); +void cl_init_bullets(CLIENT_OBJECTS* objects, int key_bullet, int ID, int speed, int x, int y); +void cl_init_comets(CLIENT_OBJECTS* objects, int key_comet, int ID, int animation_columns, int animation_direction, int boundx, int boundy, int cur_frame, + int frame_count, int frame_delay, int frame_height, int frame_width, ALLEGRO_BITMAP* image, int max_frame, int speed, int x, int y); +void cl_init_explosions(CLIENT_OBJECTS* objects, int key_explosion, int animation_columns, int animation_direction, int cur_frame, + int frame_count, int frame_delay, int frame_height, int frame_width, ALLEGRO_BITMAP* image, int max_frame, int x, int y); + +#endif diff --git a/game/pause.c b/game/pause.c new file mode 100644 index 0000000..dbd7db9 --- /dev/null +++ b/game/pause.c @@ -0,0 +1,133 @@ +#include "common.h" +#include "pause.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void pause_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + al_hide_mouse_cursor(data->screen.display); + cl_change_state(data, SINGLE); + } + break; + } + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + cl_select_button(data); + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = true; + pause_push_button(data); + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + pause_push_button(data); + break; + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_ENTER: + data->keys[ENTER] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + cl_update_button(data); + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + pause_push_button(data); + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + cl_update_background(data, BG1); + cl_update_background(data, BG2); + } +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void pause_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG2); + cl_draw_header(data); + cl_draw_button(data); +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +void pause_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text) +{ + if(data->pairing.interface[PAUSE]->button_size > key_button) + { + CLIENT_FONT* font = data->media.fonts[key_font]; + int block_size = data->screen.height / 8; + + cl_add_interface_button( + data->pairing.interface[PAUSE]->button[key_button], + font->al_font, text, data->screen.width / 2, + (block_size * (key_button + 3)) + (block_size / 4) + (block_size / 2) - font->size, + (data->screen.width / 2) - (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 3) + (block_size / 4), + (data->screen.width / 2) + (750 * data->screen.scale_factor) / 2, + block_size * (key_button + 3) + block_size); + } +} + +static void pause_push_button(CLIENT_DATA* data) +{ + CLIENT_INTERFACE* interface = data->pairing.interface[data->state]; + + for(int i = 0; i < interface->button_size; i++) + if(interface->button[i]->selected) + { + cl_play_sound(data, SAMPLE_ENTER); + + switch(i) + { + case BUTTON_PAUSE_BACK: + { + interface->button[i]->selected = false; + al_hide_mouse_cursor(data->screen.display); + cl_change_state(data, SINGLE); + break; + } + case BUTTON_PAUSE_MENU: + { + interface->button[i]->selected = false; + cl_change_state(data, MENU); + break; + } + } + } +} + diff --git a/game/pause.h b/game/pause.h new file mode 100644 index 0000000..3743bea --- /dev/null +++ b/game/pause.h @@ -0,0 +1,29 @@ +/* + * File: pause.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.11 + */ + +#ifndef client_pause +#define client_pause + +enum pause_buttons +{ + BUTTON_PAUSE_BACK, + BUTTON_PAUSE_MENU +}; + +void pause_handling(CLIENT_DATA* data); +void pause_draw(CLIENT_DATA* data); +/************************************************************ + * PROCESSING + ***********************************************************/ +void pause_init_button(CLIENT_DATA* data, int key_button, int key_font, const char* text); +static void pause_push_button(CLIENT_DATA* data); + +#endif + + + diff --git a/game/single.c b/game/single.c new file mode 100644 index 0000000..95e681a --- /dev/null +++ b/game/single.c @@ -0,0 +1,462 @@ +#include +#include + +#include "common.h" +#include "single.h" + +/************************************************************ + * HANDLING + ***********************************************************/ + +void single_handling(CLIENT_DATA* data) +{ + if(data->event.current.type == ALLEGRO_EVENT_KEY_DOWN) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + { + if(!data->keys[ESCAPE]) + { + data->keys[ESCAPE] = true; + al_show_mouse_cursor(data->screen.display); + cl_change_state(data, PAUSE); + } + break; + } + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = true; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = true; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = true; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = true; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = true; + cl_fire_bullet(data); + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_KEY_UP) + { + switch (data->event.current.keyboard.keycode) + { + case ALLEGRO_KEY_ESCAPE: + data->keys[ESCAPE] = false; + break; + case ALLEGRO_KEY_LEFT: + data->keys[LEFT] = false; + break; + case ALLEGRO_KEY_RIGHT: + data->keys[RIGHT] = false; + break; + case ALLEGRO_KEY_UP: + data->keys[UP] = false; + break; + case ALLEGRO_KEY_DOWN: + data->keys[DOWN] = false; + break; + case ALLEGRO_KEY_SPACE: + data->keys[SPACE] = false; + break; + } + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_AXES) + { + + } + else if(data->event.current.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + { + + } + else if(data->event.current.type == ALLEGRO_EVENT_TIMER) + { + data->render = true; + + if(data->keys[UP]) + cl_move_ship_up(data); + else if(data->keys[DOWN]) + cl_move_ship_down(data); + else + cl_reset_ship_animation(data, 1); + + if(data->keys[LEFT]) + cl_move_ship_left(data); + else if(data->keys[RIGHT]) + cl_move_ship_right(data); + else + cl_reset_ship_animation(data, 2); + + cl_update_background(data, BG1); + cl_update_background(data, BG3); + cl_update_background(data, BG2); + + cl_update_explosions(data); + cl_update_bullet(data); + cl_start_comet(data); + cl_update_comet(data); + cl_collide_bullet(data); + cl_collide_comet(data); + + if(cl_dead_ship(data)) + { + cl_change_state(data, GAMEOVER); + al_show_mouse_cursor(data->screen.display); + } + } +} + +/************************************************************ + * DRAW + ***********************************************************/ + +void single_draw(CLIENT_DATA* data) +{ + cl_draw_background(data, BG1); + cl_draw_background(data, BG3); + cl_draw_background(data, BG2); + + cl_draw_ship(data); + cl_draw_bullet(data); + cl_draw_comet(data); + cl_draw_explosions(data); + + cl_draw_statistic(data); +} + +/************************************************************ + * PROCESSING + ***********************************************************/ + +void cl_init_objects(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + + cl_create_objects(objects, 1, 5, 10, 5); + cl_init_ships(objects, 0, 0, 3, 1, 1, 10, 12, 0, 0, 50, 41, 46, data->media.bitmaps[SHIP_R]->al_bitmap, 3, 3, 0, 6, 20, data->screen.height / 2); + + for(int i = 0; i < objects->bullet_size; i++) + cl_init_bullets(objects, i, 0, 10, 0, 0); + + for(int i = 0; i < objects->comet_size; i++) + cl_init_comets(objects, i, 0, 21, rand() % 2 ? 1 : -1, 35, 35, 0, 0, 2, 96, 96, data->media.bitmaps[COMET]->al_bitmap, 143, 5, 0, 0); + + for(int i = 0; i < objects->explosion_size; i++) + cl_init_explosions(objects, i, 8, 1, 0, 0, 1, 128, 128, data->media.bitmaps[EXPLOSION]->al_bitmap, 31, 0, 0); +} + +/************************************************************ + * SHIP + ***********************************************************/ + +static void cl_draw_ship(CLIENT_DATA* data) +{ + CLIENT_SHIP* ship = data->objects.ships[0]; + + int fx = (ship->cur_frame % ship->animation_columns) * ship->frame_width; + int fy = ship->animation_row * ship->frame_height; + + al_draw_bitmap_region(ship->image, fx, fy, ship->frame_width, ship->frame_height, + ship->x - ship->frame_width / 2, ship->y - ship->frame_height / 2, 0); +} + +static void cl_move_ship_up(CLIENT_DATA* data) +{ + CLIENT_SHIP* ship = data->objects.ships[0]; + + ship->animation_row = 0; + ship->y -= ship->speed; + if(ship->y < 0) + ship->y = 0; +} + +static void cl_move_ship_down(CLIENT_DATA* data) +{ + CLIENT_SHIP* ship = data->objects.ships[0]; + + ship->animation_row = 2; + ship->y += ship->speed; + if(ship->y > data->screen.height) + ship->y = data->screen.height; +} + +static void cl_move_ship_left(CLIENT_DATA* data) +{ + CLIENT_SHIP* ship = data->objects.ships[0]; + + ship->cur_frame = 2; + ship->x -= ship->speed; + if(ship->x < 0) + ship->x = 0; +} + +static void cl_move_ship_right(CLIENT_DATA* data) +{ + CLIENT_SHIP* ship = data->objects.ships[0]; + + ship->cur_frame = 1; + ship->x += ship->speed; + if(ship->x > 900 * data->screen.scale_factor) + ship->x = 900 * data->screen.scale_factor; +} + +static void cl_reset_ship_animation(CLIENT_DATA* data, int position) +{ + CLIENT_SHIP* ship = data->objects.ships[0]; + + if(position == 1) + ship->animation_row = 1; + else + ship->cur_frame = 0; +} + +static bool cl_dead_ship(CLIENT_DATA* data) +{ + return data->objects.ships[0]->lives <= 0; +} + +/************************************************************ + * BULLET + ***********************************************************/ + +static void cl_draw_bullet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + + for(int i = 0; i < objects->bullet_size; i++) + if(objects->bullets[i]->live) + al_draw_filled_circle(objects->bullets[i]->x, objects->bullets[i]->y, 2, al_map_rgb(255, 255, 255)); +} + +static void cl_fire_bullet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + + for(int i = 0; i < data->objects.bullet_size; i++) + if(!objects->bullets[i]->live) + { + objects->bullets[i]->x = objects->ships[0]->x + 17; + objects->bullets[i]->y = objects->ships[0]->y; + objects->bullets[i]->live = true; + + cl_play_sound(data, SAMPLE_SHOT); + + break; + } +} + +static void cl_update_bullet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + + for(int i = 0; i < data->objects.bullet_size; i++) + if(objects->bullets[i]->live) + { + objects->bullets[i]->x += objects->bullets[i]->speed; + if(objects->bullets[i]->x > data->screen.width) + objects->bullets[i]->live = false; + } +} + +static void cl_collide_bullet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + CLIENT_SHIP* ship = objects->ships[0]; + CLIENT_BULLET** bullets = objects->bullets; + CLIENT_COMET** comets = objects->comets; + + for(int i = 0; i < objects->bullet_size; i++) + if(bullets[i]->live) + { + for(int j = 0; j < objects->comet_size; j++) + if(comets[j]->live) + { + if(bullets[i]->x > (comets[j]->x - comets[j]->boundx) && + bullets[i]->x < (comets[j]->x + comets[j]->boundx) && + bullets[i]->y > (comets[j]->y - comets[j]->boundy) && + bullets[i]->y < (comets[j]->y + comets[j]->boundy)) + { + bullets[i]->live = false; + comets[j]->live = false; + + ship->score++; + + cl_start_explosions(data, bullets[i]->x, bullets[i]->y); + + cl_play_sound(data, SAMPLE_BOOM); + } + } + } +} + +/************************************************************ + * COMET + ***********************************************************/ + +static void cl_draw_comet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + CLIENT_COMET** comets = objects->comets; + + for(int i = 0; i < objects->comet_size; i++) + if(comets[i]->live) + { + int fx = (comets[i]->cur_frame % comets[i]->animation_columns) * comets[i]->frame_width; + int fy = (comets[i]->cur_frame / comets[i]->animation_columns) * comets[i]->frame_height; + + al_draw_bitmap_region(comets[i]->image, fx, fy, comets[i]->frame_width, comets[i]->frame_height, + comets[i]->x - comets[i]->frame_width / 2, comets[i]->y - comets[i]->frame_height / 2, 0); + } +} + +static void cl_start_comet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + CLIENT_COMET** comets = objects->comets; + + for(int i = 0; i < objects->comet_size; i++) + if(!comets[i]->live) + if(rand() % 500 == 0) + { + comets[i]->live = true; + comets[i]->x = data->screen.width; + comets[i]->y = 30 + rand() % (data->screen.height - 60); + break; + } +} + +static void cl_update_comet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + CLIENT_COMET** comets = objects->comets; + + for(int i = 0; i < objects->comet_size; i++) + if(comets[i]->live) + { + if(++comets[i]->frame_count >= comets[i]->frame_delay) + { + comets[i]->cur_frame += comets[i]->animation_direction; + if(comets[i]->cur_frame >= comets[i]->max_frame) + comets[i]->cur_frame = 0; + else if(comets[i]->cur_frame <= 0) + comets[i]->cur_frame = comets[i]->max_frame - 1; + + comets[i]->frame_count = 0; + } + + comets[i]->x -= comets[i]->speed; + } +} + +static void cl_collide_comet(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + CLIENT_SHIP* ship = data->objects.ships[0]; + CLIENT_COMET** comets = objects->comets; + + for(int i = 0; i < objects->comet_size; i++) + if(comets[i]->live) + { + if((comets[i]->x - comets[i]->boundx) < (ship->x + ship->boundx) && + (comets[i]->x + comets[i]->boundx) > (ship->x - ship->boundx) && + (comets[i]->y - comets[i]->boundy) < (ship->y + ship->boundy) && + (comets[i]->y + comets[i]->boundy) > (ship->y - ship->boundy)) + { + ship->lives--; + comets[i]->live = false; + + cl_start_explosions(data, ship->x, ship->y); + + cl_play_sound(data, SAMPLE_BOOM); + } + else if(comets[i]->x < 0) + { + comets[i]->live = false; + ship->lives--; + } + } +} + +/************************************************************ + * EXPLOSION + ***********************************************************/ + +static void cl_draw_explosions(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + CLIENT_EXPLOSION** explosions = objects->explosions; + + for(int i = 0; i < objects->explosion_size; i++) + if(explosions[i]->live) + { + int fx = (explosions[i]->cur_frame % explosions[i]->animation_columns) * explosions[i]->frame_width; + int fy = (explosions[i]->cur_frame / explosions[i]->animation_columns) * explosions[i]->frame_height; + + al_draw_bitmap_region(explosions[i]->image, fx, fy, explosions[i]->frame_width, explosions[i]->frame_height, + explosions[i]->x - explosions[i]->frame_width / 2, explosions[i]->y - explosions[i]->frame_height / 2, 0); + } +} + +static void cl_start_explosions(CLIENT_DATA* data, int x, int y) +{ + CLIENT_OBJECTS* objects = &data->objects; + CLIENT_EXPLOSION** explosions = objects->explosions; + + for(int i = 0; i < objects->explosion_size; i++) + if(!explosions[i]->live) + { + explosions[i]->live = true; + explosions[i]->x = x; + explosions[i]->y = y; + break; + } +} + +static void cl_update_explosions(CLIENT_DATA* data) +{ + CLIENT_OBJECTS* objects = &data->objects; + CLIENT_EXPLOSION** explosions = objects->explosions; + + for(int i = 0; i < objects->explosion_size; i++) + if(explosions[i]->live) + if(++explosions[i]->frame_count >= explosions[i]->frame_delay) + { + explosions[i]->cur_frame += explosions[i]->animation_direction; + if(explosions[i]->cur_frame >= explosions[i]->max_frame) + { + explosions[i]->cur_frame = 0; + explosions[i]->live = false; + } + + explosions[i]->frame_count = 0; + } +} + +/************************************************************ + * STATISTIC + ***********************************************************/ + +static void cl_draw_statistic(CLIENT_DATA* data) +{ + CLIENT_SHIP* ship = data->objects.ships[0]; + ALLEGRO_COLOR color = al_map_rgba_f(0.5, 0.0, 0.0, 0.2); + ALLEGRO_COLOR color_text = al_map_rgba_f(0.5, 0.5, 0.5, 0.2); + ALLEGRO_FONT* font = data->media.fonts[FONT_PS2P30]->al_font; + + char text[200] = {' ', '\0'}; + char num[5] = {'\0'}; + + al_draw_text(font, color, al_get_text_width(font, text), 5, 0, "ЖИЗНИ:"); + strcat(text, "ЖИЗНИ:"); + al_draw_textf(font, color_text, al_get_text_width(font, text), 5, 0, "%d", ship->lives); + sprintf(num, "%d", ship->lives); + strcat(text, num); + al_draw_text(font, color, al_get_text_width(font, text), 5, 0, " КОМЕТЫ:"); + strcat(text, " КОМЕТЫ:"); + al_draw_textf(font, color_text, al_get_text_width(font, text), 5, 0, "%d", ship->score); +} diff --git a/game/single.h b/game/single.h new file mode 100644 index 0000000..c7d4653 --- /dev/null +++ b/game/single.h @@ -0,0 +1,55 @@ +/* + * File: single.h + * Author: Alexander Zhirov + * Connection with me (telegram messenger): @alexanderzhirov + * + * Created on 2020.06.08 + */ + +#ifndef client_single +#define client_single + +void single_handling(CLIENT_DATA* data); +void single_draw(CLIENT_DATA* data); + +void cl_init_objects(CLIENT_DATA* data); + +/************************************************************ + * SHIP + ***********************************************************/ +static void cl_draw_ship(CLIENT_DATA* data); +static void cl_move_ship_up(CLIENT_DATA* data); +static void cl_move_ship_down(CLIENT_DATA* data); +static void cl_move_ship_left(CLIENT_DATA* data); +static void cl_move_ship_right(CLIENT_DATA* data); +static void cl_reset_ship_animation(CLIENT_DATA* data, int position); +static bool cl_dead_ship(CLIENT_DATA* data); +/************************************************************ + * BULLET + ***********************************************************/ +static void cl_draw_bullet(CLIENT_DATA* data); +static void cl_fire_bullet(CLIENT_DATA* data); +static void cl_update_bullet(CLIENT_DATA* data); +static void cl_collide_bullet(CLIENT_DATA* data); +/************************************************************ + * COMET + ***********************************************************/ +static void cl_draw_comet(CLIENT_DATA* data); +static void cl_start_comet(CLIENT_DATA* data); +static void cl_update_comet(CLIENT_DATA* data); +static void cl_collide_comet(CLIENT_DATA* data); +/************************************************************ + * EXPLOSIONS + ***********************************************************/ +static void cl_draw_explosions(CLIENT_DATA* data); +static void cl_start_explosions(CLIENT_DATA* data, int x, int y); +static void cl_update_explosions(CLIENT_DATA* data); +/************************************************************ + * STATISTIC + ***********************************************************/ +static void cl_draw_statistic(CLIENT_DATA* data); + +#endif + + + diff --git a/images/game.png b/images/game.png new file mode 100644 index 0000000..35ee07b Binary files /dev/null and b/images/game.png differ diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000..6654370 Binary files /dev/null and b/images/logo.png differ diff --git a/images/menu.png b/images/menu.png new file mode 100644 index 0000000..14ba880 Binary files /dev/null and b/images/menu.png differ