This commit is contained in:
2026-04-01 23:25:51 +02:00
commit 483576b78f
27 changed files with 4310 additions and 0 deletions

80
.clang-format Normal file
View File

@@ -0,0 +1,80 @@
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
SpacesBeforeTrailingComments: 1
AlignConsecutiveMacros: Consecutive
# AlignEscapedNewlines: LeftWithLastLine
AlignOperands: Align
AlignTrailingComments:
Kind: Always
AllowShortLambdasOnASingleLine: Empty
IndentWidth: 4
ColumnLimit: 180
UseTab: Never
AllowShortIfStatementsOnASingleLine: Never
UseCRLF: false
AlignArrayOfStructures: None
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: true
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AlwaysBreakTemplateDeclarations: Yes
PointerAlignment: Left
QualifierAlignment: Left
ReferenceAlignment: Left
ReflowComments: IndentOnly # ?
SpaceAroundPointerQualifiers: Before
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesInAngles: Never
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
NamespaceIndentation: All
SortIncludes: Never
AlwaysBreakBeforeMultilineStrings: false
BinPackArguments: true
# BinPackLongBracedList: true # ?
BinPackParameters: BinPack # ?
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: MultiLine
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BreakAdjacentStringLiterals: true
BreakArrays: false
BreakStringLiterals: true
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
IndentAccessModifiers: false
IndentPPDirectives: BeforeHash
InsertBraces: true
KeepEmptyLines: # ?
AtEndOfFile: false
AtStartOfBlock: false
AtStartOfFile: false
LineEnding: LF
PPIndentWidth: 4
PackConstructorInitializers: BinPack
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: true # ?
RemoveParentheses: MultipleParentheses
RemoveSemicolon: true
# SeparateDefinitionBlocks: Always # dont use
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
AccessModifierOffset: -4

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/.vscode/
/.vs/
/.cache/
/build/
/build_linux/

38
CMakeLists.txt Normal file
View File

@@ -0,0 +1,38 @@
cmake_minimum_required(VERSION 3.5.0)
project(KolyahGame)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
include(${CMAKE_SOURCE_DIR}/cmake/CPM.cmake)
CPMAddPackage("gh:raysan5/raylib#5.5")
CPMAddPackage("gh:lsalzman/enet#v1.3.18")
CPMAddPackage("gh:nemtrif/utfcpp#v4.0.6")
# CPMAddPackage("gh:zpl-c/enet#dfe906c400a2d68c61f7b5f40f51f7566503a6f6")
file(GLOB SOURCES
${CMAKE_SOURCE_DIR}/src/*.cpp
)
add_executable(${PROJECT_NAME} ${SOURCES})
cmake_policy(SET CMP0079 NEW)
# target_link_libraries(${PROJECT_NAME} PUBLIC raylib enet_static)
if (WIN32)
target_link_libraries(enet PUBLIC winmm ws2_32)
if (MSVC)
target_link_options(${PROJECT_NAME} PUBLIC /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup)
endif()
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC raylib enet utf8cpp)
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_SOURCE_DIR}/src
${enet_SOURCE_DIR}/include
)
# if(EXISTS ${CMAKE_SOURCE_DIR}/assets)
# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/assets" "$<TARGET_FILE_DIR:${PROJECT_NAME}>/assets")
# else()
# message("-- WARNING: Don't forget to copy resources from .jar file to a directory with the game before launching!")
# endif()

BIN
assets/citrim.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
assets/danilka22ah.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
assets/fullharmony.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/gradient.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
assets/invisedivine.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
assets/jaan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
assets/kolyah35.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
assets/level.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
assets/minecraft.ttf Normal file

Binary file not shown.

BIN
assets/player.pdn Normal file

Binary file not shown.

BIN
assets/playertest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

1291
cmake/CPM.cmake Normal file

File diff suppressed because it is too large Load Diff

9
file_to_header.py Normal file
View File

@@ -0,0 +1,9 @@
import sys
import pathlib
fname = pathlib.Path(sys.argv[1]).stem
data = open(sys.argv[1], 'rb').read()
print(f'inline uint8_t {fname}_data[{hex(len(data))}] = {{{",".join(map(hex, data))}}};')
print(f'\nconstexpr auto {fname}_data_size = {hex(len(data))};')

219
src/Game.cpp Normal file
View File

@@ -0,0 +1,219 @@
#include "Game.hpp"
#include <string>
#include <algorithm>
#include "Multiplayer.hpp"
#include "assets.hpp"
Game::Game() : camPos(0, 0), spawnPointChangedTime(0), chatOpen(false), entered(false) {}
void Game::start(std::string name) {
InitWindow(1280, 720, "SFF Sandbox..?");
SetTargetFPS(60);
// std::string texture = "assets/";
// std::string nicknamee = name;
// std::transform(nicknamee.begin(), nicknamee.end(), nicknamee.begin(), ::tolower);
// texture.append(nicknamee).append(".png");
player = Player(skinFromName(name), name);
// player.spawnPoint = {2100, -1088}; // middle
// player.spawnPoint = {3821, -1728}; // end
player.spawnPoint = {-66, -448}; // start
player.pos = player.spawnPoint;
level.load();
auto lastTime = GetTime();
SetExitKey(KEY_NULL);
std::vector<int> codepoints;
for (int i = 0x20; i <= 0x7e; i++) {
codepoints.push_back(i);
}
for (int i = 0x401; i <= 0x451; i++) {
codepoints.push_back(i);
}
const auto myFont = LoadFontFromMemory(".ttf", minecraft_data, minecraft_data_size, 20, codepoints.data(), codepoints.size());
// const auto gradText = LoadTexture("assets/gradient.png");
const auto gradText = texFromMem(gradient_data, gradient_data_size);
while (!WindowShouldClose()) {
auto time = GetTime();
float dt = time - lastTime;
serverTime += dt;
#ifdef _WIN32
if (dt > (1 / 30.f)) {
lastTime = time;
continue;
}
#endif
if (chatOpen) {
// Get char pressed (unicode character) on the queue
int key = GetCharPressed();
// Check if more characters have been pressed on the same frame
while (key > 0) {
// printf("%i\n", key);
// NOTE: Only allow keys in range [32..125]
// if ((key >= 32) && (key <= 125)) {
// chatMsg.append({(char)key});
// }
utf8::append(key, chatMsg);
key = GetCharPressed(); // Check next character in the queue
}
if (IsKeyPressedRepeat(KEY_BACKSPACE) || IsKeyPressed(KEY_BACKSPACE)) {
if (chatMsg.size() != 0) {
// chatMsg.pop_back();
auto it = chatMsg.end();
auto lastCP = utf8::prior(it, chatMsg.begin());
chatMsg = chatMsg.substr(0, it - chatMsg.begin());
}
}
if (IsKeyPressed(KEY_ENTER) && !chatMsg.empty()) {
char* packetData = new char[1 + 2 + chatMsg.size()];
packetData[0] = Header::MESSAGE;
*(uint16_t*)(packetData + 1) = chatMsg.size();
memcpy(packetData + 3, chatMsg.c_str(), chatMsg.size());
Multiplayer::get().sendPacket(packetData, 1 + 2 + chatMsg.size());
chatMsg.clear();
delete[] packetData;
// chatOpen = false;
}
}
if (IsKeyPressed(KEY_T) && !chatOpen) {
chatOpen = true;
}
if (IsKeyPressed(KEY_ESCAPE) && chatOpen) {
chatOpen = false;
}
level.update(dt);
player.update(dt);
auto& mp = Multiplayer::get();
if (mp.m_state != MultiplayerState::CONNECTING) {
mp.update(dt);
}
if (spawnPointChangedTime != 0) {
if (GetTime() - spawnPointChangedTime >= 0.5f) {
spawnPointChangedTime = 0;
}
}
for (auto& [_, p] : otherPlayers) {
if (p.vel.x != 0) {
p.animTime += dt;
if (p.animTime >= p.targetFrameTime) {
p.animTime -= p.targetFrameTime;
p.curFrame = (p.curFrame + 1) % (p.totalFrames - 1);
// printf("%i\n", curFrame);
}
} else {
p.curFrame = 0;
p.animTime = 0;
}
}
////////////////////////////
BeginDrawing();
ClearBackground(GRAY);
level.drawBack();
for (auto& [_, player] : otherPlayers) {
player.draw();
auto p = worldToScreen(player.pos);
auto w = MeasureText(player.name.c_str(), 20);
DrawText(player.name.c_str(), p.x + 32 - w / 2, p.y - 25, 20, RAYWHITE);
}
player.draw();
level.draw();
if (!entered) {
auto p = worldToScreen({71 * 64, -30 * 64 - 720});
DrawRectangle(p.x, p.y, 11 * 64, 6 * 64 + 720, {0, 0, 0, 255});
for (int y = -25; y > -40; y--) {
p = worldToScreen({70 * 64, y * 64.f});
DrawTexture(gradText, p.x, p.y, WHITE);
}
} else {
DrawTextEx(myFont, "Нажми T, чтобы открыть чат!", worldToScreen({73.5f * 64.f - MeasureTextEx(myFont, "Нажми T, чтобы открыть чат!", 40, 1).x / 2.0f, -23 * 64.f}), 40,
1, RAYWHITE);
}
// DrawText((std::to_string(player.pos.x) + " " + std::to_string(player.pos.y)).c_str(), 0, 0, 20, RAYWHITE);
// DrawText(("Tile: " + std::to_string((int)player.pos.x / 64) + " " + std::to_string((int)player.pos.y / 64)).c_str(), 0, 20, 20, RAYWHITE);
// DrawText(("FPS: " + std::to_string(GetFPS())).c_str(), 0, 40, 20, RAYWHITE);
if (spawnPointChangedTime != 0) {
// printf("%i\n", (uint8_t)(255 - 255 * (GetTime() - spawnPointChangedTime) / 0.5f));
DrawText("Checkpoint!", 640 - MeasureText("Checkpoint!", 40) / 2, 500, 40, Color {245, 245, 245, (uint8_t)(255 - 255 * (GetTime() - spawnPointChangedTime) / 0.5f)});
}
int msgY = 720;
if (chatOpen) {
DrawRectangle(0, 720 - 30 - 4, 1280, 30 + 4, {0, 0, 0, 100});
// DrawText(("> " + chatMsg).c_str(), 10, 720 - 30 + 2, 30, RAYWHITE);
DrawTextEx(myFont, ("> " + chatMsg).c_str(), {10, 720 - 30 + 2}, 20, 1, RAYWHITE);
msgY -= 36;
// for (auto i = chatMessages.size(); i--;) {
// auto& msg = chatMessages[i];
// DrawTextEx(myFont, msg.text.c_str(), {0, (float)msgY - 20}, 20, 1, RAYWHITE);
// // DrawText(msg.c_str(), 0, msgY - 20, 20, RAYWHITE);
// msgY -= 22;
// }
} else {
// for (auto i = chatMessages.size(); i--;) {
// auto& msg = chatMessages[i];
// if (GetTime() - msg.time <= 2) {
// DrawTextEx(myFont, msg.text.c_str(), {0, (float)msgY - 20}, 20, 1, {245, 245, 245, (uint8_t)(255 - (GetTime() - msg.time) / 2.f * 255.f)});
// // DrawText(msg.c_str(), 0, msgY - 20, 20, RAYWHITE);
// msgY -= 22;
// }
// }
// for (auto i = chatMessages.size(); i--;) {
// auto& msg = chatMessages[i];
// DrawTextEx(myFont, msg.text.c_str(), {0, (float)msgY - 20}, 20, 1, RAYWHITE);
// // DrawText(msg.c_str(), 0, msgY - 20, 20, RAYWHITE);
// msgY -= 22;
// }
}
for (auto i = chatMessages.size(); i--;) {
auto& msg = chatMessages[i];
DrawTextEx(myFont, msg.text.c_str(), {0, (float)msgY - 20}, 20, 1, RAYWHITE);
// DrawText(msg.c_str(), 0, msgY - 20, 20, RAYWHITE);
msgY -= 22;
}
// DrawText((std::to_string(player.vel.x) + " " + std::to_string(player.vel.y)).c_str(), 0, 20, 20, RAYWHITE);
EndDrawing();
lastTime = time;
}
CloseWindow();
}

62
src/Game.hpp Normal file
View File

@@ -0,0 +1,62 @@
#pragma once
#include "saferaylib.h"
#include "Player.hpp"
#include "Level.hpp"
#include "unordered_map"
#include "cmath"
#include "utf8.h"
#include "assets.hpp"
#include "algorithm"
inline Texture2D texFromMem(unsigned char* data, int size) {
return LoadTextureFromImage(LoadImageFromMemory(".png", data, size));
}
inline Texture2D skinFromName(std::string name) {
std::string lowerName = name;
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower);
if (lowerName == "citrim") {
return texFromMem(citrim_data, citrim_data_size);
} else if (lowerName == "danilka22ah") {
return texFromMem(danilka22ah_data, danilka22ah_data_size);
} else if (lowerName == "invisedivine") {
return texFromMem(invisedivine_data, invisedivine_data_size);
} else if (lowerName == "jaan") {
return texFromMem(jaan_data, jaan_data_size);
} else if (lowerName == "fullharmony") {
return texFromMem(fullharmony_data, fullharmony_data_size);
} else {
return texFromMem(kolyah35_data, kolyah35_data_size);
}
}
struct ChatMsg {
std::string text;
float time;
};
class Game {
public:
inline static Game& get() {
static Game inst;
return inst;
}
void start(std::string name);
inline Vector2 worldToScreen(const Vector2& p) { return Vector2 {p.x - camPos.x, p.y - camPos.y}; }
Vector2 camPos;
Level level;
Player player;
std::unordered_map<uint32_t, Player> otherPlayers;
std::string chatMsg;
std::vector<ChatMsg> chatMessages;
float spawnPointChangedTime;
float serverTime;
bool chatOpen;
bool entered;
private:
Game();
};

363
src/Level.cpp Normal file
View File

@@ -0,0 +1,363 @@
#include "Level.hpp"
#include "assets.hpp"
#include "Game.hpp"
Level::Level() {}
void Level::load() {
// tex = LoadTexture("assets/level.png");
tex = texFromMem(level_data, level_data_size);
for (short y = 4; y > -45; y--) {
for (short x = -10; x < 130; x++) {
background.push_back({BRICKGRAY, x, y, GRAY});
}
}
// Start room
for (short i = -11; i < 10; i++) {
tiles.push_back({BRICKGRAY, i, -5});
}
for (short i = -6; i > -15; i--) {
tiles.push_back({BRICKGRAY, -11, i});
}
for (short i = -9; i > -17; i--) {
tiles.push_back({BRICKGRAY, 9, i});
}
for (short y = -5; y < 15; y++) {
tiles.push_back({BRICKGRAY, 9, y});
tiles.push_back({BRICKGRAY, -11, y});
}
for (short x = -7; x < 6; x += 3) {
background.push_back({TORCH, x, -10});
}
background.push_back({SIGN, 6, -6});
background.push_back({BRICKGRAY, 9, -7, GRAY});
background.push_back({BRICKGRAY, 9, -6, GRAY});
background.push_back({BANNERBASEMENT, -10, -10});
background.push_back({BANNERBASEMENT, 8, -10});
// Main level
// First platforms
background.push_back({TORCH, 11, -8});
tiles.push_back({PLATFORMBIGLEFT, 11, -5});
tiles.push_back({PLATFORMBIGRIGHT, 12, -5});
background.push_back({TORCH, 15, -10});
tiles.push_back({PLATFORMBIGLEFT, 15, -7});
tiles.push_back({PLATFORMBIGRIGHT, 16, -7});
background.push_back({TORCH, 19, -6});
tiles.push_back({PLATFORMBIGLEFT, 19, -3});
tiles.push_back({PLATFORMBIGRIGHT, 20, -3});
background.push_back({TORCH, 24, -8});
tiles.push_back({PLATFORMBIGLEFT, 24, -5});
tiles.push_back({PLATFORMBIGRIGHT, 25, -5});
for (short x = 10; x < 30; x++) {
tiles.push_back({LAVA, x, 4});
}
// Checkpoint 1
background.push_back({BANNERSFF, 30, -10});
background.push_back({BANNERSFF, 36, -10});
checkpoints.push_back({CHECKPOINT, 33, -7});
background.push_back({TORCH, 33, -10});
for (short x = 30; x < 36; x++) {
tiles.push_back({BRICKGRAY, x, -6});
}
for (short y = -6; y < 15; y++) {
tiles.push_back({BRICKGRAY, 30, y});
tiles.push_back({BRICKGRAY, 36, y});
}
// Moving platforms
background.push_back({TORCH, 40, -9});
background.push_back({BANNERDOOMETERNAL, 41, -9});
background.push_back({TORCH, 42, -9});
background.push_back({TORCH, 45, -9});
background.push_back({BANNERDOOMETERNAL, 46, -9});
background.push_back({TORCH, 47, -9});
for (short x = 37; x < 53; x++) {
tiles.push_back({LAVA, x, 4});
}
// for (short x = 38; x < 49; x += 5) {
// tiles.push_back({PLATFORMBIGLEFT, x, -7});
// tiles.push_back({PLATFORMBIGRIGHT, static_cast<int16_t>(x + 1), -7});
// tiles.push_back({PLATFORMBIGLEFT, x, -10});
// tiles.push_back({PLATFORMBIGRIGHT, static_cast<int16_t>(x + 1), -10});
// tiles.push_back({PLATFORMBIGLEFT, x, -12});
// tiles.push_back({PLATFORMBIGRIGHT, static_cast<int16_t>(x + 1), -12});
// }
plats.push_back({{38 * 64.f, -12 * 64.f}, 0});
plats.push_back({{43 * 64.f, -12 * 64.f}, 1});
plats.push_back({{48 * 64.f, -12 * 64.f}, 0});
// Checkpoint 2
checkpoints.push_back({CHECKPOINT, 56, -7});
background.push_back({BANNERDOOMETERNAL, 53, -10});
background.push_back({BANNERDOOMETERNAL, 59, -10});
background.push_back({TORCH, 56, -10});
for (short x = 53; x < 60; x++) {
tiles.push_back({BRICKGRAY, x, -6});
}
for (short y = -6; y < 15; y++) {
tiles.push_back({BRICKGRAY, 53, y});
tiles.push_back({BRICKGRAY, 59, y});
}
// Way to upper platform
background.push_back({TORCH, 76, -9});
background.push_back({TORCH, 76, -8});
background.push_back({TORCH, 76, -7});
background.push_back({TORCH, 76, -6});
background.push_back({TORCH, 76, -5});
background.push_back({TORCH, 76, -4});
background.push_back({TORCH, 75, -8});
background.push_back({TORCH, 74, -7});
background.push_back({TORCH, 77, -8});
background.push_back({TORCH, 78, -7});
for (short x = 60; x < 80; x++) {
tiles.push_back({LAVA, x, 4});
}
for (short y = 4; y > -40; y--) {
tiles.push_back({BRICKGRAY, 80, y});
}
background.push_back({TORCH, 67, -8});
background.push_back({TORCH, 62, -10});
background.push_back({TORCH, 58, -12});
tiles.push_back({PLATFORMBIGLEFT, 64, -6});
tiles.push_back({PLATFORMBIGRIGHT, 65, -6});
tiles.push_back({PLATFORMBIGLEFT, 69, -8});
tiles.push_back({PLATFORMBIGRIGHT, 70, -8});
tiles.push_back({PLATFORMBIGLEFT, 64, -10});
tiles.push_back({PLATFORMBIGRIGHT, 65, -10});
tiles.push_back({PLATFORMBIGLEFT, 60, -12});
tiles.push_back({PLATFORMBIGRIGHT, 61, -12});
tiles.push_back({PLATFORMBIGLEFT, 56, -14});
tiles.push_back({PLATFORMBIGRIGHT, 57, -14});
// Upper platform
for (short x = 54; x > 0; x--) {
tiles.push_back({BRICKGRAY, x, -15});
}
background.push_back({BANNBERHL, 54, -19});
checkpoints.push_back({CHECKPOINT, 52, -16});
background.push_back({BANNBERHL, 50, -19});
background.push_back({TORCH, 52, -19});
tiles.push_back({BRICKGRAY, 30, -16});
tiles.push_back({BRICKGRAY, 10, -16});
for (short x = 47; x > 34; x -= 2) {
// tiles.push_back({SAW, x, -19});
// Vector2 pos = {x * 64.f, -19 * 64.f + 3 * 64 * (x - 34) / 2 / 7.f};
// Vector2 pos = {x * 64.f, -19 * 64.f};
// saws.push_back({pos, pos});
saws.push_back({{x * 64.f, -19 * 64.f}, (x - 34) / 2 / 7.f});
}
for (short x = 46; x > 34; x -= 2) {
background.push_back({TORCH, x, -19});
}
// for (short x = 46; x > 33; x -= 4) {
// tiles.push_back({TORCH, x, -19});
// }
for (short x = 29; x > 10; x--) {
tiles.push_back({LAVA, x, -16});
}
background.push_back({BANNERNIRVANA, 31, -19});
background.push_back({BANNERNIRVANA, 33, -19});
background.push_back({TORCH, 32, -19});
checkpoints.push_back({CHECKPOINT, 32, -16});
// Way to final corridor
background.push_back({TORCH, 24, -26});
background.push_back({TORCH, 24, -25});
background.push_back({TORCH, 24, -24});
background.push_back({TORCH, 24, -23});
background.push_back({TORCH, 24, -22});
background.push_back({TORCH, 24, -21});
background.push_back({TORCH, 24, -20});
background.push_back({TORCH, 25, -25});
background.push_back({TORCH, 26, -24});
background.push_back({TORCH, 23, -25});
background.push_back({TORCH, 22, -24});
tiles.push_back({PLATFORM, 27, -18});
background.push_back({TORCH, 30, -22});
tiles.push_back({PLATFORM, 30, -20});
tiles.push_back({PLATFORM, 33, -22});
tiles.push_back({PLATFORM, 35, -23});
background.push_back({TORCH, 35, -25});
tiles.push_back({PLATFORM, 32, -25});
tiles.push_back({PLATFORM, 36, -27});
tiles.push_back({PLATFORM, 40, -25});
background.push_back({TORCH, 40, -27});
tiles.push_back({PLATFORM, 44, -27});
tiles.push_back({PLATFORM, 48, -23});
background.push_back({TORCH, 48, -25});
tiles.push_back({PLATFORM, 52, -25});
// final corridor
for (short x = 56; x < 81; x++) {
tiles.push_back({BRICKGRAY, x, -25});
}
background.push_back({BANNERBASEMENT, 56, -28});
background.push_back({TORCH, 57, -28});
background.push_back({TORCH, 58, -28});
background.push_back({BANNERSFF, 59, -28});
background.push_back({TORCH, 60, -28});
background.push_back({TORCH, 61, -28});
background.push_back({BANNERDOOMETERNAL, 62, -28});
background.push_back({TORCH, 63, -28});
background.push_back({TORCH, 64, -28});
background.push_back({BANNBERHL, 65, -28});
background.push_back({TORCH, 66, -28});
background.push_back({TORCH, 67, -28});
background.push_back({BANNERNIRVANA, 68, -28});
checkpoints.push_back({CHECKPOINT, 68, -26});
// tiles.push_back({BRICKGRAY, 70, -28});
// tiles.push_back({BRICKGRAY, 70, -29});
for (short y = -28; y > -40; y--) {
tiles.push_back({BRICKGRAY, 70, y});
}
for (short x = 71; x < 80; x++) {
tiles.push_back({BRICKGRAY, x, -31});
}
tiles.push_back({TABLELEFT, 75, -26});
tiles.push_back({TABLERIGHT, 76, -26});
background.push_back({TORCH, 71, -29});
background.push_back({BALOON1, 72, -29});
background.push_back({BALOON2, 77, -30});
background.push_back({BALOON3, 73, -28});
background.push_back({TORCH, 79, -29});
background.push_back({BALOON4, 78, -29});
}
void Level::update(float dt) {
for (auto& saw : saws) {
saw.pos.y = -19 * 64.f + 3 * 64.f * (sinf(Game::get().serverTime * 2.2f + saw.offset * 2.f) / 2.f + 0.5f);
}
for (auto& plat : plats) {
plat.pos.y = -12 * 64.f + 4 * 64.f * (sinf((Game::get().serverTime + plat.offset * PI / 2) * 2.2f) / 2.f + 0.5f);
}
}
// #define ROUND_POS(x) (float)((int)(x))
#define ROUND_POS(x) floorf(x)
void Level::drawBack() {
// Behind player
for (const auto& tile : background) {
auto p = Game::get().worldToScreen({(float)tile.x * 64, (float)tile.y * 64});
if (p.x < -64.f || p.y < -64.f || p.x > 1280 || p.y > 720) {
continue;
}
auto tid = tile.id;
if (Game::get().entered && tile.id == BRICKGRAY) {
tid = WOOD;
}
DrawTexturePro(tex, {32.0f * (tid % 10), 32.0f * (tid / 10), 32.0f, 32.0f}, {ROUND_POS(p.x), ROUND_POS(p.y), 64.0f, 64.0f}, {0, 0}, 0, tile.col);
}
for (const auto& tile : checkpoints) {
auto p = Game::get().worldToScreen({(float)tile.x * 64, (float)tile.y * 64});
if (p.x < -64.f || p.y < -64.f || p.x > 1280 || p.y > 720) {
continue;
}
DrawTexturePro(tex, {32.0f * (tile.id % 10), 32.0f * (tile.id / 10), 32.0f, 32.0f}, {ROUND_POS(p.x), ROUND_POS(p.y), 64.0f, 64.0f}, {0, 0}, 0, tile.col);
}
}
void Level::draw() {
for (const auto& tile : tiles) {
auto p = Game::get().worldToScreen({(float)tile.x * 64, (float)tile.y * 64});
if (p.x < -64.f || p.y < -64.f || p.x > 1280 || p.y > 720) {
continue;
}
// DrawTexturePro(tex, {32.0f * (tile.id % 10), 32.0f * (tile.id / 10), 32.0f, 32.0f}, {ROUND_POS(p.x), ROUND_POS(p.y), 64.0f, 64.0f}, {0, 0}, 0, tile.col);
auto tid = tile.id;
if (Game::get().entered && tile.id == BRICKGRAY) {
tid = WOOD;
}
DrawTexturePro(tex, {32.0f * (tid % 10), 32.0f * (tid / 10), 32.0f, 32.0f}, {ROUND_POS(p.x), ROUND_POS(p.y), 64.0f, 64.0f}, {0, 0}, 0, tile.col);
}
for (const auto& saw : saws) {
auto p = Game::get().worldToScreen(saw.pos);
DrawTexturePro(tex, {32.0f * (SAW % 10), 32.0f * (SAW / 10), 32.0f, 32.0f}, {ROUND_POS(p.x), ROUND_POS(p.y), 64.0f, 64.0f}, {0, 0}, 0, WHITE);
}
auto c = Game::get().worldToScreen({4810, -1690});
DrawTexturePro(tex, {32.0f * (CAKE % 10), 32.0f * (CAKE / 10), 32.0f, 32.0f}, {ROUND_POS(c.x), ROUND_POS(c.y), 64.0f, 64.0f}, {0, 0}, 0, WHITE);
for (const auto& plat : plats) {
auto p = Game::get().worldToScreen(plat.pos);
DrawTexturePro(tex, {32.0f * (PLATFORMBIGLEFT % 10), 32.0f * (PLATFORMBIGLEFT / 10), 32.0f, 32.0f}, {ROUND_POS(p.x), ROUND_POS(p.y), 64.0f, 64.0f}, {0, 0}, 0, WHITE);
DrawTexturePro(tex, {32.0f * (PLATFORMBIGRIGHT % 10), 32.0f * (PLATFORMBIGRIGHT / 10), 32.0f, 32.0f}, {ROUND_POS(p.x + 64.f), ROUND_POS(p.y), 64.0f, 64.0f}, {0, 0}, 0,
WHITE);
}
}
float Level::collides(const Rectangle& rect, bool y) {
for (const auto& plat : plats) {
Rectangle tileRect = Rectangle {plat.pos.x, plat.pos.y + 44.f, 96.f, 64.f - 44.f};
if (CheckCollisionRecs(rect, tileRect)) {
auto colRect = GetCollisionRec(rect, tileRect);
if (colRect.height > 0 && y) {
return colRect.height;
}
if (colRect.width > 0 && !y) {
return colRect.width;
}
}
}
for (const auto& tile : tiles) {
Rectangle tileRect = Rectangle {tile.x * 64.0f, tile.y * 64.0f, 64.0, 64.0f};
if (tile.id == TABLELEFT) {
tileRect.y += 26.f;
tileRect.height -= 26.f;
} else if (tile.id == TABLERIGHT) {
tileRect.y += 26.f;
tileRect.height -= 26.f;
tileRect.width -= 32.f;
} else if (tile.id == PLATFORM) {
tileRect.y += 44.f;
tileRect.height -= 44.f;
tileRect.width -= 32.f;
} else if (tile.id == PLATFORMBIGLEFT) {
tileRect.y += 44.f;
tileRect.height -= 44.f;
} else if (tile.id == PLATFORMBIGRIGHT) {
tileRect.y += 44.f;
tileRect.height -= 44.f;
// tileRect.width -= 32.f;
} else if (tile.id == LAVA) {
tileRect.y += 24.f;
tileRect.height -= 24.f;
}
if (CheckCollisionRecs(rect, tileRect)) {
auto colRect = GetCollisionRec(rect, tileRect);
if (colRect.height > 0 && y) {
return colRect.height;
}
if (colRect.width > 0 && !y) {
return colRect.width;
}
}
}
return 0;
}

78
src/Level.hpp Normal file
View File

@@ -0,0 +1,78 @@
#pragma once
#include "saferaylib.h"
#include <cstdint>
#include <vector>
enum TextureTilePos {
BRICKGRAY = 0,
BRICKRED,
TORCH,
SAW,
CAKE,
TABLELEFT,
TABLERIGHT,
PLATFORMBIGLEFT,
PLATFORMBIGRIGHT,
PLATFORM,
CHECKPOINT,
BANNERBASEMENT,
BANNERSFF,
BANNERDOOMETERNAL,
SIGN,
BANNBERHL,
BANNERNIRVANA,
LAVA,
WHITEBRICKS,
BALOON1,
BALOON2,
BALOON3,
BALOON4,
WOOD
};
// 64x64 pxl
struct Tile {
uint8_t id;
int16_t x;
int16_t y;
Color col = WHITE;
// Vector2 size = {0, 0};
};
struct Saw {
// Vector2 startPos;
Vector2 pos;
float offset;
};
struct Platform {
// Vector2 startPos;
Vector2 pos;
float offset;
};
class Level {
public:
Level();
void load();
float collides(const Rectangle& rect, bool y);
void update(float dt);
void draw();
void drawBack();
std::vector<Tile> checkpoints;
std::vector<Tile> background;
std::vector<Tile> tiles;
std::vector<Saw> saws;
std::vector<Platform> plats;
private:
Texture2D tex;
// std::vector<Tile> tilesBig;
};

247
src/Multiplayer.cpp Normal file
View File

@@ -0,0 +1,247 @@
#include "Multiplayer.hpp"
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include "Game.hpp"
// #define SERVER_ADDRESS "127.0.0.1"
#define SERVER_ADDRESS "sffnetwork.su"
void Multiplayer::connect(const char* name) {
printf("name %s\n", name);
m_name = name;
m_state = MultiplayerState::CONNECTING;
client = enet_host_create(nullptr, 1, LAST_CHANNEL, 0, 0);
if (!client) {
printf("client null\n");
exit(1);
}
ENetAddress address;
enet_address_set_host(&address, SERVER_ADDRESS);
address.port = 7777;
peer = enet_host_connect(client, &address, LAST_CHANNEL, 0);
if (peer == nullptr) {
printf("peer null\n");
enet_host_destroy(client);
exit(1);
}
ENetEvent event;
auto res = enet_host_service(client, &event, 5000);
if (res <= 0 || event.type != ENET_EVENT_TYPE_CONNECT) {
enet_peer_reset(peer);
printf("Failed to connect to server!\n");
exit(1);
}
auto packet_size = 1 + 2 + strlen(name);
auto login_packet = new char[packet_size];
login_packet[0] = Header::IDENTIFICATION;
*(uint16_t*)(login_packet + 1) = strlen(name);
memcpy(login_packet + 3, name, strlen(name));
if (sendPacket(login_packet, packet_size)) {
printf("trying to reg!!\n");
m_state = MultiplayerState::LOGGING_IN;
}
}
int Multiplayer::sendPacket(char* data, int size, Channel channel, bool reliable) {
auto enetPacket = enet_packet_create(data, size, reliable ? ENET_PACKET_FLAG_RELIABLE : ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT);
return enet_peer_send(peer, channel, enetPacket) == 0;
}
void Multiplayer::update(float dt) {
ENetEvent event;
while (enet_host_service(client, &event, 0) > 0) {
switch (event.type) {
case ENET_EVENT_TYPE_RECEIVE: {
// printf("packet received\n");
auto bytes = event.packet->data;
// for (int i = 0; i < event.packet->dataLength; i++) {
// printf("%02X ", bytes[i]);
// }
// printf("\n");
switch (bytes[0]) {
case LOAD_PLAYER: { // all players get this when a new player connects
bytes++;
uint16_t nameLen = *(uint16_t*)bytes;
bytes += 2;
auto name = new char[nameLen + 1];
memcpy(name, bytes, nameLen);
bytes += nameLen;
name[nameLen] = 0;
uint32_t playerID = *(uint32_t*)bytes;
bytes += 4;
float serverTime = *(float*)bytes;
printf("- load player name %s id %i server time %f\n", name, playerID, serverTime);
Game::get().chatMessages.push_back({"Player " + std::string(name) + " has joined.", (float)GetTime()});
if (m_name == name) {
printf("- its me!\n");
m_id = playerID;
m_state = MultiplayerState::PLAYING;
Game::get().serverTime = serverTime;
char packet = Header::LOAD_PLAYERS;
sendPacket(&packet, 1);
} else {
// std::string texture = "assets/";
// std::string nicknamee = name;
// std::transform(nicknamee.begin(), nicknamee.end(), nicknamee.begin(), ::tolower);
// texture.append(nicknamee).append(".png");
auto p = Player(skinFromName(name), name);
p.pos.y = -400;
Game::get().otherPlayers[playerID] = p;
}
break;
}
case LOAD_PLAYERS: { // get list of all players on server with their id,pos,name
printf("- load players packet size %i\n", event.packet->dataLength);
bytes++;
auto num = *bytes;
bytes++;
for (int i = 0; i < num; i++) {
auto id = *(uint32_t*)bytes;
bytes += 4;
auto x = *(float*)bytes;
bytes += 4;
auto y = *(float*)bytes;
bytes += 4;
auto nameLen = *(uint16_t*)bytes;
bytes += 2;
auto name = new char[nameLen + 1];
name[nameLen] = 0;
memcpy(name, bytes, nameLen);
bytes += nameLen;
printf("- - player: x %f y %f name %s id %i\n", x, y, name, id);
// std::string texture = "assets/";
// std::string nicknamee = name;
// std::transform(nicknamee.begin(), nicknamee.end(), nicknamee.begin(), ::tolower);
// texture.append(nicknamee).append(".png");
auto p = Player(skinFromName(name), name);
// auto p = Player(texture.c_str(), name);
p.pos = {x, y};
Game::get().otherPlayers[id] = p;
}
break;
}
case PLAYER: { // pos of all players
bytes++;
auto num = *bytes;
bytes++;
for (int i = 0; i < num; i++) {
auto id = *(uint32_t*)bytes;
bytes += 4;
auto x = *(float*)bytes;
bytes += 4;
auto y = *(float*)bytes;
bytes += 4;
if (id == peer->connectID) {
continue;
}
if (Game::get().otherPlayers.contains(id)) {
auto& p = Game::get().otherPlayers[id];
// Game::get().otherPlayers[id].pos = {x, y};
auto delta_x = x - p.pos.x;
p.pos = {x, y};
p.vel.x = delta_x;
// p.walkRight = delta_x > 0;
if (delta_x > 0) {
p.walkRight = true;
} else if (delta_x < 0) {
p.walkRight = false;
}
}
}
break;
}
case MESSAGE: {
bytes++;
auto len = *(uint16_t*)bytes;
bytes += 2;
auto msg = new char[len + 1];
msg[len] = 0;
memcpy(msg, bytes, len);
Game::get().chatMessages.push_back({msg, (float)GetTime()});
delete[] msg;
break;
}
default: {
printf("- unk packet %i\n", bytes[0]);
break;
}
}
break;
}
case ENET_EVENT_TYPE_DISCONNECT: {
printf("Connection closed.\n");
break;
}
default: break;
}
}
m_updateTime += dt;
const auto POS_TIME = 1 / 30.f;
if (m_updateTime > POS_TIME) {
// printf("sending pos\n");
m_updateTime -= POS_TIME;
auto data = new char[1 + 4 + 4];
data[0] = Header::PLAYER;
*(float*)(data + 1) = Game::get().player.pos.x;
*(float*)(data + 1 + 4) = Game::get().player.pos.y;
sendPacket(data, 1 + 4 + 4);
delete[] data;
}
}

98
src/Multiplayer.hpp Normal file
View File

@@ -0,0 +1,98 @@
#pragma once
#include "saferaylib.h"
#include "cstdio"
#include "cstdint"
#include "string"
enum Channel : uint8_t {
EVERYTHING,
BLOCKS,
LAST_CHANNEL
};
enum Header : uint8_t {
// World headers (also uses in mp)
PLAYER,
BLOCK,
CHUNK,
WORLD,
ENTITY,
INVENTORY_ITEM,
// Multiplayer headers
IDENTIFICATION,
DISCONNECT,
LOAD_CHUNK,
UNLOAD_CHUNK,
LOAD_PLAYER,
UNLOAD_PLAYER,
BLOCK_PLACE,
BLOCK_DESTROY,
NETWORK_ERROR,
ARRAY,
TERRAIN,
LOAD_TERRAIN,
LOAD_PLAYERS,
MESSAGE,
LOAD_MESSAGE,
NULL_PACKET = 0xFF
};
enum MultiplayerState {
CONNECTING,
LOGGING_IN,
LOADING_TERRAIN,
PLAYING,
ERROR
};
class Multiplayer {
public:
static Multiplayer& get() {
static Multiplayer inst;
return inst;
}
// ~Multiplayer() {
// printf("MP distr\n");
// char data = Header::DISCONNECT;
// sendPacket(&data, 1);
// if (peer) {
// enet_peer_reset(peer);
// peer = nullptr;
// }
// if (client) {
// enet_host_destroy(client);
// client = nullptr;
// }
// }
Multiplayer() : m_state(MultiplayerState::CONNECTING), client(nullptr), peer(nullptr), m_updateTime(0) {
printf("MP constr\n");
if (enet_initialize() != 0) {
printf("An error occurred while initializing ENet.\n");
exit(1);
}
atexit(enet_deinitialize);
}
void connect(const char* name);
int sendPacket(char* data, int size, Channel channel = EVERYTHING, bool reliable = true);
void update(float dt);
MultiplayerState m_state;
private:
ENetHost* client;
ENetPeer* peer;
std::string m_name;
uint32_t m_id;
float m_updateTime;
bool connected = false;
};

131
src/Player.cpp Normal file
View File

@@ -0,0 +1,131 @@
#include "Player.hpp"
#include "Game.hpp"
#include <algorithm>
Player::Player(const char* texName, std::string name, const Vector2& frameSize, int fps) : Player(LoadTexture(texName), name, frameSize, fps) {}
Player::Player(Texture2D tex, std::string name, const Vector2& frameSize, int fps)
: pos(0, 0), animTime(0), targetFrameTime(1.0f / fps), curFrame(0), vel(0, 0), onGround(false), walkRight(true), name(name), tex(tex) {
totalFrames = (int)(tex.width / frameSize.x);
}
void Player::update(float dt) {
bool co = Game::get().chatOpen;
// // Should be removed from release build
// if (IsKeyDown(KEY_R) && !co) {
// // pos = {-66, -400};
// pos = spawnPoint;
// }
if (IsKeyDown(KEY_A) && !co) {
vel.x = -500;
walkRight = false;
} else if (IsKeyDown(KEY_D) && !co) {
vel.x = 500;
walkRight = true;
} else {
vel.x = 0;
}
if ((IsKeyDown(KEY_SPACE) || IsKeyDown(KEY_W)) && !co
#if 1
&& onGround
#endif
) {
onGround = false;
// vel.y = -47000 * dt;
// vel.y = -(47000 * (1.f / 60));
vel.y = -(49000 * (1.f / 60));
}
// vel.y += 2000 * dt;
vel.y += 2300 * dt;
pos.y += vel.y * dt;
auto playerRect = Rectangle {pos.x + 10, pos.y, 64 - 20, 128};
auto colY = Game::get().level.collides(playerRect, true);
if (colY != 0) {
pos.y -= colY * (vel.y > 0 ? 1 : -1);
if (vel.y > 0) {
onGround = true;
}
vel.y = 0;
} else {
onGround = false;
}
pos.x += vel.x * dt;
playerRect = Rectangle {pos.x + 10, pos.y, 64 - 20, 128};
auto colX = Game::get().level.collides(playerRect, false);
pos.x -= colX * (vel.x > 0 ? 1 : -1);
if (vel.x != 0) {
animTime += dt;
if (animTime >= targetFrameTime) {
animTime -= targetFrameTime;
curFrame = (curFrame + 1) % (totalFrames - 1);
// printf("%i\n", curFrame);
}
}
if (vel.x == 0) {
curFrame = 0;
animTime = 0;
}
playerRect = Rectangle {pos.x + 10, pos.y, 64 - 20, 128};
for (auto& tile : Game::get().level.checkpoints) {
Rectangle tileRect = Rectangle {tile.x * 64.0f, tile.y * 64.0f, 64.0, 64.0f};
if (CheckCollisionRecs(playerRect, tileRect) && Game::get().spawnPointChangedTime == 0) {
spawnPoint = {tile.x * 64.0f - 32.f, tile.y * 64.0f};
Game::get().spawnPointChangedTime = GetTime();
break;
}
}
for (auto& tile : Game::get().level.tiles) {
if (tile.id == LAVA) {
Rectangle tileRect = Rectangle {tile.x * 64.0f - 2, tile.y * 64.0f - 2, 64.0 + 4, 64.0f + 4};
tileRect.x += 2;
tileRect.width -= 4;
tileRect.y += 24.f;
tileRect.height -= 24.f;
if (CheckCollisionRecs(tileRect, playerRect)) {
pos = spawnPoint;
vel = {0, 0};
break;
}
}
}
for (auto& saw : Game::get().level.saws) {
Rectangle tileRect = Rectangle {saw.pos.x + 2, saw.pos.y + 2, 64.0 - 4, 64.0f - 4};
if (CheckCollisionRecs(tileRect, playerRect)) {
pos = spawnPoint;
vel = {0, 0};
break;
}
}
if (pos.y > -1900 && pos.y < -1700 && pos.x > 4500) {
Game::get().entered = true;
}
// Game::get().camPos.x = fmax(pos.x - 640 + 32, -11 * 64.f);
Game::get().camPos.x = std::clamp(pos.x - 640 + 32, -11 * 64.f, 81 * 64.f - 1280);
Game::get().camPos.y = fmin(pos.y - 360 + 64, 4 * 64.f - 720 + 64);
}
void Player::draw() {
// DrawTextureRec(tex, {(float)tex.width / totalFrames * curFrame, 0, (float)tex.width / totalFrames, (float)tex.height}, pos, WHITE);
auto p = Game::get().worldToScreen(pos);
auto ffframe = (vel.x != 0) ? curFrame + 1 : curFrame;
if (walkRight) {
DrawTexturePro(tex, {(float)tex.width / totalFrames * ffframe, 0, (float)tex.width / totalFrames, (float)tex.height},
{p.x, p.y, (float)tex.width / totalFrames * 2, (float)tex.height * 2}, {0, 0}, 0, WHITE);
} else {
DrawTexturePro(tex, {(float)tex.width / totalFrames * (ffframe), 0, -(float)tex.width / totalFrames, (float)tex.height},
{p.x, p.y, (float)tex.width / totalFrames * 2, (float)tex.height * 2}, {0, 0}, 0, WHITE);
}
}

27
src/Player.hpp Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include "saferaylib.h"
#include "string"
class Player {
public:
Player() {}
Player(const char* texName, std::string name, const Vector2& frameSize = {32, 64}, int fps = 7);
Player(Texture2D tex, std::string name, const Vector2& frameSize = {32, 64}, int fps = 7);
void update(float dt);
void draw();
Vector2 pos;
Vector2 vel;
std::string name;
Vector2 spawnPoint;
bool walkRight;
float animTime;
int curFrame;
int totalFrames;
float targetFrameTime;
private:
Texture2D tex;
bool onGround;
};

1528
src/assets.hpp Normal file

File diff suppressed because one or more lines are too long

31
src/main.cpp Normal file
View File

@@ -0,0 +1,31 @@
#include "Game.hpp"
#include "Multiplayer.hpp"
#include "thread"
int main(int argc, char** argv) {
auto& mp = Multiplayer::get();
#if KOLYAH_MODE
// std::thread(&Multiplayer::connect, &mp, "Kolyah35").detach();
std::string name = "Kolyah35";
#else
if (argc != 2) {
printf("specify ur name in args\n");
return 1;
}
// std::thread(&Multiplayer::connect, &mp, argv[1]).detach();
std::string name = argv[1];
#endif
std::thread(&Multiplayer::connect, &mp, name.c_str()).detach();
Game::get().start(name);
// printf("hi!\n");
// char data = Header::DISCONNECT;
// Multiplayer::get().sendPacket(&data, 1);
return 0;
}

103
src/saferaylib.h Normal file
View File

@@ -0,0 +1,103 @@
#pragma once
#if defined(_WIN32)
// To avoid conflicting windows.h symbols with raylib, some flags are defined
// WARNING: Those flags avoid inclusion of some Win32 headers that could be required
// by user at some point and won't be included...
//-------------------------------------------------------------------------------------
// If defined, the following flags inhibit definition of the indicated items.
#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_
#define NOVIRTUALKEYCODES // VK_*
#define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_*
#define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
#define NOSYSMETRICS // SM_*
#define NOMENUS // MF_*
#define NOICONS // IDI_*
#define NOKEYSTATES // MK_*
#define NOSYSCOMMANDS // SC_*
#define NORASTEROPS // Binary and Tertiary raster ops
#define NOSHOWWINDOW // SW_*
#define OEMRESOURCE // OEM Resource values
#define NOATOM // Atom Manager routines
#define NOCLIPBOARD // Clipboard routines
#define NOCOLOR // Screen colors
#define NOCTLMGR // Control and Dialog routines
#define NODRAWTEXT // DrawText() and DT_*
#define NOGDI // All GDI defines and routines
#define NOKERNEL // All KERNEL defines and routines
#define NOUSER // All USER defines and routines
// #define NONLS // All NLS defines and routines
#define NOMB // MB_* and MessageBox()
#define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines
#define NOMETAFILE // typedef METAFILEPICT
#define NOMINMAX // Macros min(a,b) and max(a,b)
#define NOMSG // typedef MSG and associated routines
#define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_*
#define NOSCROLL // SB_* and scrolling routines
#define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc.
#define NOSOUND // Sound driver routines
#define NOTEXTMETRIC // typedef TEXTMETRIC and associated routines
#define NOWH // SetWindowsHook and WH_*
#define NOWINOFFSETS // GWL_*, GCL_*, associated routines
#define NOCOMM // COMM driver routines
#define NOKANJI // Kanji support stuff.
#define NOHELP // Help engine interface.
#define NOPROFILER // Profiler interface.
#define NODEFERWINDOWPOS // DeferWindowPos routines
#define NOMCX // Modem Configuration Extensions
#define MMNOSOUND
// Type required before windows.h inclusion
typedef struct tagMSG* LPMSG;
#include <enet/enet.h> // Now windows.h won't define CloseWindow, DrawText, etc.
// #include <windows.h>
// Type required by some unused function...
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
#include <objbase.h>
#include <mmreg.h>
#include <mmsystem.h>
// Some required types defined for MSVC/TinyC compiler
#if defined(_MSC_VER) || defined(__TINYC__)
#include "propidl.h"
#endif
#endif
// #define WIN32_LEAN_AND_MEAN
// #define NOMINMAX
// #define NOGDI
#if defined(__linux__)
#include <enet/enet.h> // Now windows.h won't define CloseWindow, DrawText, etc.
#endif
// // Explicitly undefine remaining problematic macros
// #ifdef CloseWindow
// #undef CloseWindow
// #endif
// #ifdef DrawText
// #undef DrawText
// #endif
#include "raylib.h"
//////////////////////////////////////////////////////////////////////////////////////////
#define KOLYAH_MODE 0