v1.0.0-dev

This commit is contained in:
Alexander Zhirov 2023-04-30 23:49:25 +03:00
commit 04d7285299
73 changed files with 6640 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.vscode
build
spaceshooter

20
README.md Normal file
View File

@ -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.

BIN
data/bitmaps/comet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
data/bitmaps/explosion.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

BIN
data/bitmaps/ship_green.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
data/bitmaps/ship_red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
data/bitmaps/starBG.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
data/bitmaps/starFG.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
data/bitmaps/starMG.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

BIN
data/fonts/VT323.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
data/samples/boom.ogg Normal file

Binary file not shown.

BIN
data/samples/button.ogg Normal file

Binary file not shown.

BIN
data/samples/enter.ogg Normal file

Binary file not shown.

BIN
data/samples/game.ogg Normal file

Binary file not shown.

BIN
data/samples/menu.ogg Normal file

Binary file not shown.

BIN
data/samples/shot.ogg Normal file

Binary file not shown.

84
deps Normal file
View File

@ -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)

59
game/CMakeLists.txt Normal file
View File

@ -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})

142
game/autors.c Normal file
View File

@ -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;
}
}
}

28
game/autors.h Normal file
View File

@ -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

834
game/common.c Normal file
View File

@ -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 <allegro5/allegro_primitives.h>
#include <stdio.h>
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);
}

159
game/common.h Normal file
View File

@ -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

45
game/data.c Normal file
View File

@ -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);
}

29
game/game.h Normal file
View File

@ -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

140
game/gameover.c Normal file
View File

@ -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);
}

29
game/gameover.h Normal file
View File

@ -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

55
game/lib/common.c Normal file
View File

@ -0,0 +1,55 @@
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_acodec.h>
#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);
}

53
game/lib/common.h Normal file
View File

@ -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

35
game/lib/event.c Normal file
View File

@ -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);
}

26
game/lib/event.h Normal file
View File

@ -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 <allegro5/allegro5.h>
#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

56
game/lib/instance.c Normal file
View File

@ -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());
}

39
game/lib/instance.h Normal file
View File

@ -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 <allegro5/allegro_audio.h>
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

235
game/lib/interface.c Normal file
View File

@ -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;
}

141
game/lib/interface.h Normal file
View File

@ -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 <allegro5/allegro_font.h>
#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

141
game/lib/media.c Normal file
View File

@ -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");
}
}
}

76
game/lib/media.h Normal file
View File

@ -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 <allegro5/allegro.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_audio.h>
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

12
game/lib/message.c Normal file
View File

@ -0,0 +1,12 @@
#include <allegro5/allegro_native_dialog.h>
#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);
}
}

18
game/lib/message.h Normal file
View File

@ -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 <stdbool.h>
/*
* error message
*/
void show_message_error(bool result, const char* message);
#endif

190
game/lib/screen.c Normal file
View File

@ -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();
}

58
game/lib/screen.h Normal file
View File

@ -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 <allegro5/allegro5.h>
#include <stdbool.h>
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

27
game/lib/timer.c Normal file
View File

@ -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);
}

25
game/lib/timer.h Normal file
View File

@ -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 <allegro5/allegro5.h>
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

112
game/main.c Normal file
View File

@ -0,0 +1,112 @@
#include <stdio.h>
#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;
}

162
game/menu.c Normal file
View File

@ -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;
}
}
}

32
game/menu.h Normal file
View File

@ -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

82
game/network/network.c Normal file
View File

@ -0,0 +1,82 @@
#include <stdio.h>
#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);
}

190
game/network/network.h Normal file
View File

@ -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 <enet/enet.h>
#include <stdbool.h>
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

219
game/networkcreate.c Normal file
View File

@ -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;
}

36
game/networkcreate.h Normal file
View File

@ -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

571
game/networkgame.c Normal file
View File

@ -0,0 +1,571 @@
#include <stdio.h>
#include <allegro5/allegro_primitives.h>
#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);
}
}

53
game/networkgame.h Normal file
View File

@ -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

212
game/networkjoin.c Normal file
View File

@ -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;
}

36
game/networkjoin.h Normal file
View File

@ -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

303
game/networklist.c Normal file
View File

@ -0,0 +1,303 @@
#include "common.h"
#include "networklist.h"
#include <stdio.h>
#include <allegro5/allegro_primitives.h>
/************************************************************
* 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;
}
}

33
game/networklist.h Normal file
View File

@ -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

150
game/networkmode.c Normal file
View File

@ -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;
}
}
}

30
game/networkmode.h Normal file
View File

@ -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

160
game/networkout.c Normal file
View File

@ -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;
}
}
}
}

27
game/networkout.h Normal file
View File

@ -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

433
game/networkparty.c Normal file
View File

@ -0,0 +1,433 @@
#include "common.h"
#include "networkparty.h"
#include "networkcreate.h"
#include <stdio.h>
#include <allegro5/allegro_primitives.h>
/************************************************************
* 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);
}

42
game/networkparty.h Normal file
View File

@ -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

199
game/objects/objects.c Normal file
View File

@ -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;
}

120
game/objects/objects.h Normal file
View File

@ -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 <stdbool.h>
#include <allegro5/allegro.h>
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

133
game/pause.c Normal file
View File

@ -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;
}
}
}
}

29
game/pause.h Normal file
View File

@ -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

462
game/single.c Normal file
View File

@ -0,0 +1,462 @@
#include <stdio.h>
#include <allegro5/allegro_primitives.h>
#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);
}

55
game/single.h Normal file
View File

@ -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

BIN
images/game.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

BIN
images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
images/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB