From: EliasFleckenstein03 <54945686+EliasFleckenstein03@users.noreply.github.com> Date: Fri, 14 Feb 2020 16:44:21 +0000 (+0100) Subject: Add files via upload X-Git-Tag: 3.0~4 X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=79a2a56c3d65cb9b151d9e4f1b7666a5bee0129c;p=dragonblocks-bedrock.git Add files via upload --- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4f3b030 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.0) +project(dragonblocks) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) +add_executable(dragonblocks + src/game.cpp + src/graphics.cpp + src/inventory.cpp + src/main.cpp + src/map.cpp + src/mapgen.cpp + src/mods.cpp + src/node.cpp + src/texture.cpp + src/threads.cpp + src/util.cpp +) + +target_link_libraries(dragonblocks + GL + freeglut + lua5.3 + pthread + png16 + m +) diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..2f173d8 --- /dev/null +++ b/README.txt @@ -0,0 +1,82 @@ +DRAGONBLOCKS BEDROCK EDITION +Written in C++ +An Open Source Project by Elias Fleckenstein + +1. General + 1.1. What this is about + Dragonblocks originaly was a Browsergame I made that should be some kind of 2D Minetest (Minetest (www.minetest.net) is a game similar to + Minecraft, except Minetest is free & open source and is meant to be modded). The JavaScript Edition is hosted at www.dragonblocks.tk and + further developed then this C++ Version, through the C++ Version has advantages like map saving and lot larger map. I decided to call the + C++ Version "Bedrock Edition" as a joke for the Minecraft C++ Version is Called Bedrock or Pocket Edition. + 1.2. Version + This is the Dragonblocks Bedrock Edition 3.0. + 1.4. Bugs + Please Report Bugs to eliasfleckenstein@web.de. + 1.5. License + Copyright 2020 Elias Fleckenstein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + +2. Starting the Game + 2.1. Platform Compability + This Game was developed on linux, therefore following instructions are only for linux users, basically because I have no idea how to + port the game to other platforms. Feel free to add building instructions for other systems over github. + 2.3. Download + You can download the game using git: + $ git clone https:// + 2.2. Dependencies: + You need Freeglut, OpenGl, Cmake, Liblua and Libpng. + If you are on Debian/Ubuntu You can install them over apt: + $ sudo apt install liblua5.3-dev freeglut3-dev libgl1-mesa-dev cmake libpng-dev + 2.3. Building + to Build dragonblocks run: + $ cd dragonblocks + $ cmake . + $ make + 2.4. Exectute + 2.4.1. Run-In-Place + Invoke dragonblocks by typing: + $ cd dragonblocks + $ bin/dragonblocks --worldname + To see a list of worlds do: + $ bin/dragonblocks --worldlist + You can select a world from this list or create a new one. + For more info run: + $ bin/dragonblocks --help + 2.4.2. Installation + You can install dragonblocks by doing: + $ sudo ./install.sh + It will copy the dragonblocks directory to /usr/share/dragonblocks and place a script in + /usr/bin/dragonblocks that starts dragonblocks. + +3. Developing + 3.1. The Lua Modding API + If you want to add a lua file to the game, place it in the game folder and add a dofile() in game/init.lua + Note: The lua api currently consists of only two functions. If you want to add something I'm open to ideas or code. + dragonblocks.register_node(obj) + Register a new node + obj has to contain: + name: string - the itemstring. It should follow the convention "modulename:nodename" + texture: string - the texture path. Textures should be placed in the textures folder and have to be 16 x 16 px. + obj can contain: + stable: boolean - Nodes like water or air are unstable. [default = true] + hidden: boolean - The Node will be hidden in the invenotry. [default = false] + translucent: boolean - Whether the node's texture should be transparent. [default = false] + dragonblocks.log(text) + Log something. + 3.2. The C++ API + The C++ API is probably to big to explain here, but if you do C++ you should understand it. In case you have questions, feel free to + ask them on github. You can also contribute code if you want. diff --git a/builtin/cpp.lua b/builtin/cpp.lua new file mode 100644 index 0000000..a6cd19d --- /dev/null +++ b/builtin/cpp.lua @@ -0,0 +1,5 @@ +local cpp_last_node = 0 +function cpp_get_next_node() + cpp_last_node = cpp_last_node + 1 + return core.nodes[cpp_last_node] +end diff --git a/builtin/functions.lua b/builtin/functions.lua new file mode 100644 index 0000000..124d049 --- /dev/null +++ b/builtin/functions.lua @@ -0,0 +1,3 @@ +dragonblocks.log = function(text) + print("[LUA] "..text) +end diff --git a/builtin/init.lua b/builtin/init.lua new file mode 100644 index 0000000..cafcae1 --- /dev/null +++ b/builtin/init.lua @@ -0,0 +1,15 @@ +core = {} +dragonblocks = {} +dragonblocks.settings = {} + +dofile("builtin/register.lua") +dofile("builtin/functions.lua") +dofile("builtin/cpp.lua") + +--local popenfile = io.popen("ls game") +--for filename in popenfile:lines() do +-- dofile("game/"..filename.."/init.lua") +--end +--popenfile:close() + +dofile("game/init.lua") diff --git a/builtin/register.lua b/builtin/register.lua new file mode 100644 index 0000000..eaf3322 --- /dev/null +++ b/builtin/register.lua @@ -0,0 +1,20 @@ +core.nodes = {} +dragonblocks.register_node = function(obj) + if obj and obj.name and obj.texture then + core.nodes[#core.nodes+1] = {} + core.nodes[#core.nodes].name = obj.name + core.nodes[#core.nodes].texture = obj.texture + core.nodes[#core.nodes].stable = false + if obj.stable == nil or obj.stable == true then + core.nodes[#core.nodes].stable = true + end + core.nodes[#core.nodes].hidden = false + if obj.hidden then + core.nodes[#core.nodes].hidden = true + end + core.nodes[#core.nodes].translucent = false + if obj.translucent then + core.nodes[#core.nodes].translucent = true + end + end +end diff --git a/game/init.lua b/game/init.lua new file mode 100644 index 0000000..00e904c --- /dev/null +++ b/game/init.lua @@ -0,0 +1,7 @@ +dragonblocks.log(" ____ _ _ _ ") +dragonblocks.log("| _ \\ _ __ __ _ __ _ ___ _ __ | |__ | | ___ ___| | _____ ") +dragonblocks.log("| | | | '__/ _` |/ _` |/ _ \\| '_ \\| '_ \\| |/ _ \\ / __| |/ / __| ") +dragonblocks.log("| |_| | | | (_| | (_| | (_) | | | | |_) | | (_) | (__| <\\__ \\ ") +dragonblocks.log("|____/|_| \\__,_|\\__, |\\___/|_| |_|_.__/|_|\\___/ \\___|_|\\_\\___/ ") +dragonblocks.log(" |___/ ") +dofile("game/nodes.lua") diff --git a/game/nodes.lua b/game/nodes.lua new file mode 100644 index 0000000..88b321d --- /dev/null +++ b/game/nodes.lua @@ -0,0 +1,50 @@ +dragonblocks.register_node({ + name = "dragonblocks:air", + texture = "textures/air.png", + stable = false, + hidden = true, + translucent = true, +}) +dragonblocks.register_node({ + name = "dragonblocks:stone", + texture = "textures/stone.png" +}) +dragonblocks.register_node({ + name = "dragonblocks:dirt", + texture = "textures/dirt.png" +}) +dragonblocks.register_node({ + name = "dragonblocks:grass", + texture = "textures/grass.png" +}) +dragonblocks.register_node({ + name = "dragonblocks:wood", + texture = "textures/wood.png" +}) +dragonblocks.register_node({ + name = "dragonblocks:water", + texture = "textures/water.png", + stable = false, + translucent = true, +}) +dragonblocks.register_node({ + name = "dragonblocks:leaves", + texture = "textures/leaves.png", + translucent = true, +}) +dragonblocks.register_node({ + name = "dragonblocks:bedrock", + texture = "textures/bedrock.png" +}) +dragonblocks.register_node({ + name = "dragonblocks:mese", + texture = "textures/mese.png" +}) +dragonblocks.register_node({ + name = "dragonblocks:sand", + texture = "textures/sand.png" +}) +dragonblocks.register_node({ + name = "dragonblocks:cobble", + texture = "textures/cobble.png" +}) diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..639c232 --- /dev/null +++ b/install.sh @@ -0,0 +1,7 @@ +#! /bin/bash +cp . /usr/share/dragonblocks -R +echo " +cd /usr/share/dragonblocks +bin/dragonblocks \$* +" > /usr/bin/dragonblocks +chmod +x /usr/bin/dragonblocks diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..5af8be6 --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include +#include +#include "mods.h" +#include "game.h" +using namespace std; + +void Game::log(string text, int level){ + string prefix; + int color; + switch(level){ + case WARNING: + color = ORANGE; + prefix = "WARNING"; + break; + case ERROR: + color = RED; + prefix = "ERROR"; + break; + case INFO: + color = LIGHTBLUE; + prefix = "INFO"; + break; + case LOG: + color = BLUE; + prefix = "LOG"; + break; + case EASTEREGG: + color = VIOLET; + prefix = "EASTEREGG"; + default: break; + } + cout << "\e[3" << color << "m" << "[" << prefix << "] \e[0m" << text << endl; + if(logfile_fd) + fprintf(logfile_fd, "[%s] %s\n", prefix.c_str(), text.c_str()); +} +void Game::log(string text){ + log(text, LOG); +} +void Game::help(){ + cout << "Usage: " << argv[0] << "[OPTIONS]" << endl; + cout << "Options:" << endl; + cout << "\t" << "-h" << "\t" << "--help" << "\t\t\t" << "Display this help and exit." << endl; + cout << "\t" << "-v" << "\t" << "--version" << "\t\t" << "Display version info." << endl; + cout << "\t" << "-p" << "\t" << "--worldpath [PATH]" << "\t" << "Set world path." << endl; + cout << "\t" << "-w" << "\t" << "--worldname [PATH]" << "\t" << "Select world by name (Worlds are placed in ~/.dragonblocks/worlds/)." << endl; + cout << "\t" << "-r" << "\t" << "--worldlist" << "\t\t" << "Show a list of your worlds." << endl; + cout << "\t" << "-s" << "\t" << "--seed [NUMBER]" << "\t\t" << "Set seed." << endl; + cout << "\t" << "-l" << "\t" << "--logfile [PATH]" << "\t" << "Set logfile." << endl; +} +void Game::version(){ + cout << "DRAGONBLOCKS BEDROCK EDITION" << endl; + cout << "Written in C++" << endl; + cout << "An Open Source Project by Elias Fleckenstein" << endl; + cout << "Dragonblocks " << VERSION << endl; +} +void Game::worldlist(){ + log("Your worlds:"); + DIR *folder; + struct dirent *entry; + int files = 0; + + folder = opendir(((string)getenv("HOME")+"/.dragonblocks/worlds/").c_str()); + if(!folder){ + Game::log("Cant Open World Directory", ERROR); + exit(EXIT_FAILURE); + } + while(entry = readdir(folder)) + { + files++; + if(files > 2) + cout << "\t" << entry->d_name; + } + if(files <= 2) + cout << "\tYou have no Worlds yet."; + cout << endl; + closedir(folder); + + return; +} diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..53ac862 --- /dev/null +++ b/src/game.h @@ -0,0 +1,43 @@ +#ifndef _GAME_H_ +#define _GAME_H_ +#include +#include + +#include "map.h" +#include "inventory.h" + +#define WARNING 1 +#define ERROR 2 +#define INFO -1 +#define EASTEREGG 17 +#define LOG 0 + +#define VERSION "3.0" + +#define BLACK 0 +#define RED 1 +#define GREEN 2 +#define ORANGE 3 +#define BLUE 4 +#define VIOLET 5 +#define LIGHTBLUE 6 +#define GREY 7 + +class Game{ + public: + static int *argc; + static char **argv; + static int seed; + static std::string mapfile; + static std::string logfile; + static FILE *logfile_fd; + static Map *map; + static void log(std::string); + static void log(std::string, int); + static void help(); + static void version(); + static void worldlist(); + static Inventory *inventory; +}; + +#endif diff --git a/src/graphics.cpp b/src/graphics.cpp new file mode 100644 index 0000000..c8011c0 --- /dev/null +++ b/src/graphics.cpp @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include "graphics.h" +#include "util.h" +#include "game.h" +#include "mapgen.h" + +position Graphics::pointed; +position Graphics::pos = {MAPWIDTH/2 - DISPLAYWIDTH/2, MAPHEIGHT/2 - DISPLAYHEIGHT/2}; + +using namespace std; +void Graphics::display(){ + glClear(GL_COLOR_BUFFER_BIT); + //sky + drawRectangle(0, 0, DISPLAYWIDTH*BLOCKWIDTH, DISPLAYHEIGHT*BLOCKWIDTH, "#87CEEB"); + //map + for(int x = 0; x < DISPLAYWIDTH; x++){ + for(int y = 0; y < DISPLAYHEIGHT; y++){ + Game::map -> getNode(x+pos.x, y+pos.y) -> texture -> draw(x*BLOCKWIDTH, y*BLOCKWIDTH, BLOCKWIDTH, BLOCKWIDTH); + } + } + //pointed block + if(pointed.x < DISPLAYWIDTH){ + drawRectangle(pointed.x * BLOCKWIDTH, pointed.y * BLOCKWIDTH, BLOCKWIDTH, 1, COLOR_BLACK); + drawRectangle(pointed.x * BLOCKWIDTH + BLOCKWIDTH - 1, pointed.y * BLOCKWIDTH, 1, BLOCKWIDTH, COLOR_BLACK); + drawRectangle(pointed.x * BLOCKWIDTH, pointed.y * BLOCKWIDTH + BLOCKWIDTH - 1, BLOCKWIDTH, 1, COLOR_BLACK); + drawRectangle(pointed.x * BLOCKWIDTH, pointed.y * BLOCKWIDTH, 1, BLOCKWIDTH, COLOR_BLACK); + } + //inventory + + drawRectangle(DISPLAYWIDTH*BLOCKWIDTH, 0, INVWIDTH, DISPLAYHEIGHT*BLOCKWIDTH, "#B4B4B4"); + drawRectangle(DISPLAYWIDTH*BLOCKWIDTH, Game::inventory->selected * INVWIDTH, INVWIDTH, INVWIDTH, "#636363"); + for(int i = 0; i < Game::inventory->count; i++) + Game::inventory -> getSlot(i) -> texture -> draw(BLOCKWIDTH*DISPLAYWIDTH + (INVWIDTH-INVBLOCKWIDTH)/2, i * INVWIDTH + (INVWIDTH-INVBLOCKWIDTH)/2, INVBLOCKWIDTH, INVBLOCKWIDTH); + //infotext + writeText(5, 5, (string)"Dragonblocks "+VERSION, GLUT_BITMAP_9_BY_15, COLOR_WHITE); + string infotext = "pos: ("+to_string(pos.x)+", "+to_string(pos.y)+"), seed: "+to_string(Game::seed); + if(pointed.x < DISPLAYWIDTH) + infotext += ", pointed: "+ Game::map->getNode(pointed.x+pos.x, pointed.y+pos.y)->name + "("+to_string(pointed.x+pos.x)+", "+to_string(pointed.y+pos.y)+")"; + writeText(5, 20, infotext, GLUT_BITMAP_9_BY_15, COLOR_WHITE); + //writeText(5, 35, "world: "+Game::mapfile, GLUT_BITMAP_9_BY_15, COLOR_WHITE); + glFlush(); +} +void Graphics::reshape(int width, int height){ + glViewport(0, 0, width, height); /* Establish viewing area to cover entire window. */ + glMatrixMode(GL_PROJECTION); /* Start modifying the projection matrix. */ + glLoadIdentity(); /* Reset project matrix. */ + glOrtho(0, width, 0, height, -1, 1); /* Map abstract coords directly to window coords. */ + glScalef(1, -1, 1); /* Invert Y axis so increasing Y goes down. */ + glTranslatef(0, -height, 0); /* Shift origin up to upper-pos.x corner. */ +} +void Graphics::init(){ + glutInit(Game::argc, Game::argv); + glutCreateWindow("Dragonblocks"); + glutReshapeWindow(DISPLAYWIDTH*BLOCKWIDTH+INVWIDTH, DISPLAYHEIGHT*BLOCKWIDTH); + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyboard); + glutSpecialFunc(special); + glutMouseFunc(mouse); + glutPassiveMotionFunc(motion); + glutMotionFunc(motion); + glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glutMainLoop(); +} +void Graphics::keyboard(unsigned char key, int x, int y){ +} +void Graphics::special(int key, int x, int y){ + switch(key){ + case GLUT_KEY_LEFT: + if(pos.x > 0) + pos.x--; + break; + case GLUT_KEY_UP: + if(pos.y > 0) + pos.y--; + break; + case GLUT_KEY_RIGHT: + if(pos.x < MAPWIDTH-DISPLAYWIDTH) + pos.x++; + break; + case GLUT_KEY_DOWN: + if(pos.y < MAPHEIGHT-DISPLAYHEIGHT) + pos.y++; + break; + } +} +void Graphics::mouse(int key, int action, int x, int y){ + if(action == 0){ + if(x < BLOCKWIDTH*DISPLAYWIDTH){ + switch(key){ + case 0: + if(Game::map -> getNode(pointed.x+pos.x, pointed.y+pos.y)->stable) + Game::map -> setNode(pointed.x+pos.x, pointed.y+pos.y, MAPGEN_AIR); + break; + case 2: + if(! Game::map -> getNode(pointed.x+pos.x, pointed.y+pos.y)->stable) + Game::map -> setNode(pointed.x+pos.x, pointed.y+pos.y, Game::inventory->getSelectedSlot()); + break; + } + } + else{ + Game::inventory->select(y/INVWIDTH); + } + } +} +void Graphics::motion(int x, int y){ + pointed.x = x / BLOCKWIDTH; + pointed.y = y / BLOCKWIDTH; +} +void Graphics::writeText(int x, int y, string text, void *font, color c){ + glColor3f(c.red, c.green, c.blue); + glRasterPos2i(x, y+10); + char *s = strdup(text.c_str()); + --s; + while(*++s) + glutBitmapCharacter(font, *s); +} +void Graphics::drawRectangle(int x, int y, int width, int height, color c){ + glColor3f(c.red, c.green, c.blue); + glBegin(GL_POLYGON); + glVertex2i(x, y); + glVertex2i(x+width, y); + glVertex2i(x+width, y+height); + glVertex2i(x, y+height); + glEnd(); +} diff --git a/src/graphics.h b/src/graphics.h new file mode 100644 index 0000000..d1d23ab --- /dev/null +++ b/src/graphics.h @@ -0,0 +1,38 @@ +#ifndef _GRAPHICS_H_ +#define _GRAPHICS_H_ + +#include +#include "texture.h" +#include "util.h" + + +#define BLOCKWIDTH 32 +#define DISPLAYWIDTH 25 +#define DISPLAYHEIGHT 25 +#define INVBLOCKWIDTH 64 +#define INVWIDTH 80 + +#define COLOR_WHITE {1,1,1} +#define COLOR_BLACK {0,0,0} + + +class Graphics{ + public: + static void init(); + + static position pointed; + static position pos; + + //handlers + static void display(); + static void keyboard(unsigned char, int, int); + static void mouse(int, int, int, int); + static void special(int, int, int); + static void reshape(int, int); + static void motion(int, int); + + //functions + static void drawRectangle(int, int, int, int, color); + static void writeText(int, int, std::string, void*, color); +}; +#endif diff --git a/src/inventory.cpp b/src/inventory.cpp new file mode 100644 index 0000000..257b181 --- /dev/null +++ b/src/inventory.cpp @@ -0,0 +1,24 @@ +#include "node.h" +#include "inventory.h" +Inventory::Inventory(){ + count = 0; + selected = 0; + for(int i = 0; i < Node::count; i++){ + if(! Node::getNodeById(i) -> hidden){ + list[count] = Node::getNodeById(i); + count++; + } + } +} +Node *Inventory::getSlot(int nr){ + if(nr >= 0 && nr < count) + return list[nr]; + return list[0]; +} +void Inventory::select(int nr){ + if(nr >= 0 && nr < count) + selected = nr; +} +Node *Inventory::getSelectedSlot(){ + return list[selected]; +} diff --git a/src/inventory.h b/src/inventory.h new file mode 100644 index 0000000..64f6b17 --- /dev/null +++ b/src/inventory.h @@ -0,0 +1,17 @@ +#ifndef _INVENTORY_H_ +#define _INVENTORY_H_ + +#include "node.h" + +class Inventory{ + public: + int count; + int selected; + Node *list[MAXNODES]; + Node *getSlot(int); + void select(int); + Node *getSelectedSlot(); + Inventory(); +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..3bfa32c --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "graphics.h" +#include "map.h" +#include "game.h" +#include "node.h" +#include "mapgen.h" +#include "mods.h" +#include "threads.h" +#include "inventory.h" + +using namespace std; + +Map *Game::map; +string Game::mapfile; +string Game::logfile; +int Game::seed; +char **Game::argv; +int *Game::argc; +FILE *Game::logfile_fd; +Inventory *Game::inventory; + +int main(int argc, char **argv){ + if((string)argv[0] != "bin/dragonblocks"){ + string command = "cd ..; bin/dragonblocks -w world "; + while(*++argv) + command += *argv; + exit(system(command.c_str())); + } + create_dir_if_not_exists((string)getenv("HOME")+"/.dragonblocks"); + create_dir_if_not_exists((string)getenv("HOME")+"/.dragonblocks/worlds"); + Game::argc = &argc; + Game::argv = argv; + Game::seed = time(0); + Game::logfile = (string)getenv("HOME")+"/.dragonblocks/dragonblocks.log"; + const char *short_options = "hrvs:l:w:p:"; + const struct option long_options[] = { + {"help", 0, NULL, 'h'}, + {"version", 0, NULL, 'v'}, + {"worldname", 1, NULL, 'w'}, + {"worldpath", 1, NULL, 'p'}, + {"worldlist", 0, NULL, 'r'}, + {"seed", 1, NULL, 's'}, + {"logfile", 1, NULL, 'l'}, + {NULL, 0, NULL, 0}, + }; + int next_option; + while((next_option = getopt_long(argc, argv, short_options, long_options, NULL)) != -1){ + switch(next_option){ + case 'h': + Game::help(); + exit(EXIT_SUCCESS); + break; + case 'v': + Game::version(); + exit(EXIT_SUCCESS); + break; + case 'p': + Game::mapfile = optarg; + break; + case 'w': + Game::mapfile = (string)getenv("HOME")+"/.dragonblocks/worlds/"+optarg; + break; + case 's': + Game::seed = atoi(optarg); + break; + case 'l': + Game::logfile = optarg; + break; + case 'r': + Game::worldlist(); + exit(0); + break; + case '?': + Game::log("Invalid Usage", ERROR); + Game::help(); + exit(EXIT_FAILURE); + break; + }; + } + if(Game::logfile_fd = fopen(Game::logfile.c_str(), "a")) + fprintf(Game::logfile_fd, "\n--------------------------------------------------\n"); + else + Game::log((string)"Failed to open log file " + Game::logfile, WARNING); + Game::log((string)"Welcome to Dragonblocks "+VERSION); + srand(Game::seed); + new Node("unknown_node", "textures/unknown_node.png", true, true, false); + Mods::init(); + Game::inventory = new Inventory(); + Game::map = new Map(); + if(Game::mapfile == ""){ + Game::log("No World Specified", ERROR); + exit(EXIT_FAILURE); + } + if(fopen(Game::mapfile.c_str(), "r")) + Game::map->load(); + else + Mapgen(); + Threads::startMapBackupThread(); + Threads::startGraphicUpdateThread(); + Threads::addSignalHandlers(); + Graphics::init(); + Game::log("Closed Window, Exiting."); + Game::map -> save(); + return 0; +} + diff --git a/src/map.cpp b/src/map.cpp new file mode 100644 index 0000000..7e5f3bd --- /dev/null +++ b/src/map.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include "map.h" +#include "node.h" +#include "game.h" +using namespace std; +Node *Map::getNode(int x, int y){ + if(x < MAPWIDTH && y < MAPHEIGHT && x > -1 && y > -1) + return content[x][y]; + return NULL; +} +void Map::setNode(int x, int y, Node *n){ + if(x < MAPWIDTH && y < MAPHEIGHT && x > -1 && y > -1) + content[x][y] = n; +} +void Map::setNode(int x, int y, string n){ + setNode(x, y, Node::getNodeByName(n)); +} +void Map::load(){ + Game::log("Loading Map from " + Game::mapfile); + FILE *mapfile = fopen(Game::mapfile.c_str(), "r"); + if(mapfile){ + for(int x = 0; x < MAPWIDTH; x++) + for(int y = 0; y < MAPHEIGHT; y++){ + char buffer[512] = {0}; + fscanf(mapfile, "%s", buffer); + setNode(x, y, buffer); + } + fclose(mapfile); + Game::log("Loaded Map"); + } + else{ + Game::log("Could not Load Map.", ERROR); + exit(EXIT_FAILURE); + } +} +void Map::save(){ + Game::log("Saving Map to " + Game::mapfile); + FILE *mapfile = fopen(Game::mapfile.c_str(), "w"); + if(mapfile){ + for(int x = 0; x < MAPWIDTH; x++){ + for(int y = 0; y < MAPHEIGHT; y++) + fprintf(mapfile,"%s ", getNode(x,y)->name.c_str()); + fprintf(mapfile, "\n"); + } + fclose(mapfile); + Game::log("Saved Map"); + } + else + Game::log("Could not Save Map.", ERROR); +} diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..c7c83cc --- /dev/null +++ b/src/map.h @@ -0,0 +1,21 @@ +#ifndef _MAP_H_ +#define _MAP_H_ + +#include + +#include "node.h" + +#define MAPWIDTH 500 +#define MAPHEIGHT 100 + +class Map{ + public: + Node *getNode(int, int); + void setNode(int, int, Node *); + void setNode(int, int, std::string); + void load(); + void save(); + private: + Node *content[MAPWIDTH][MAPHEIGHT]; +}; +#endif diff --git a/src/mapgen.cpp b/src/mapgen.cpp new file mode 100644 index 0000000..cb2efe1 --- /dev/null +++ b/src/mapgen.cpp @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#include "mapgen.h" +#include "map.h" +#include "node.h" +#include "util.h" +#include "game.h" + +using namespace std; +void Mapgen(){ + Game::log("Generating Map"); + //Air + for(int x = 0; x < MAPWIDTH; x++){ + for(int y = 0; y < MAPHEIGHT; y++){ + Game::map->setNode(x,y,MAPGEN_AIR); + } + } + //Seed 13 Easteregg + if(Game::seed == 13){ + for(int x = 0; x < MAPWIDTH; x++){ + for(int y = 0; y < MAPHEIGHT; y++){ + Game::map->setNode(x,y,MAPGEN_BEDROCK); + } + } + Game::log("LOL Seed 13", EASTEREGG); + return; + } + //Bottom + int bottom[MAPWIDTH]; + bottom[0] = random(MAPHEIGHT/2 - MAPHEIGHT/10, MAPHEIGHT/2); + for(int x = 1; x < MAPWIDTH; x++){ + bottom[x] = bottom[x-1] + random(-1,1); + } + //Smooth + for(int x = 1; x < MAPWIDTH-1; x++){ + if(bottom[x] > bottom[x+1] && bottom[x] > bottom[x-1]) bottom[x]--; + else if(bottom[x] < bottom[x+1] && bottom[x] < bottom[x-1])bottom[x]++; + } + //Dirt with Grass + for(int x = 0; x < MAPWIDTH; x++){ + Game::map->setNode(x,bottom[x],MAPGEN_GRASS); + } + //Dirt + for(int x = 0; x < MAPWIDTH; x++){ + for(int y = bottom[x]+1; y < bottom[x]+5; y++){ + Game::map->setNode(x,y,MAPGEN_DIRT); + } + } + //Stone + for(int x = 0; x < MAPWIDTH; x++){ + for(int y = bottom[x]+5; y < MAPHEIGHT; y++){ + Game::map->setNode(x,y,MAPGEN_STONE); + } + } + //Mese + for(int x = 0; x < MAPWIDTH; x++){ + for(int y = bottom[x]+10; y < MAPHEIGHT; y++){ + if((rand() % 100) == 0) Game::map->setNode(x,y,MAPGEN_MESE); + } + } + //Bedrock + for(int x = 0; x < MAPWIDTH; x++){ + Game::map->setNode(x,MAPHEIGHT-1,MAPGEN_BEDROCK); + if(random(0,1) == 0){ + Game::map->setNode(x,MAPHEIGHT-2,MAPGEN_BEDROCK); + if(random(0,2) == 0){ + Game::map->setNode(x,MAPHEIGHT-3,MAPGEN_BEDROCK); + } + } + } + //Water + int flatcount = 0; + for(int x = 1; x < MAPWIDTH; x++){ + if(bottom[x] == bottom[x-1]) flatcount++; + else if(flatcount > 7){ + int leftborder = rand() % 2; + int rightborder = rand() % 2; + for(int mx = x-flatcount-3; mx < x+2; mx++){ + for(int y = bottom[mx];y < bottom[mx]+5;y++){ + if(Game::map->getNode(mx,y) == MAPGEN_STONE) break; + if(Game::map->getNode(mx,y) == MAPGEN_DIRT || Game::map->getNode(mx,y) == MAPGEN_GRASS) Game::map->setNode(mx,y,MAPGEN_SAND); + } + } + for(int mx = x-flatcount+leftborder;mx < x-1-rightborder;mx++) Game::map->setNode(mx,bottom[x-1],MAPGEN_WATER); + for(int mx = x-flatcount+1+leftborder;mx < x-2-rightborder;mx++) Game::map->setNode(mx,bottom[x-1]+1,MAPGEN_WATER); + for(int mx = x-flatcount+2+leftborder; mx < x-3-rightborder;mx++) Game::map->setNode(mx,bottom[x-1]+2,MAPGEN_WATER); + flatcount = 0; + } + else flatcount = 0; + } + //Tree + int treecount = rand() % MAPWIDTH/10; + int treepos[treecount]; + for(int i = 0; i < treecount; i++){ + while(true){ + bool cont = true; + treepos[i] = rand() % MAPWIDTH; + for(int j = 0; j < i; j++){ + if(abs(treepos[j]-treepos[i]) < 3) cont = false; + } + if(!(Game::map->getNode(treepos[i],bottom[treepos[i]]) == MAPGEN_GRASS)) cont = false; + if(cont) break; + } + int x = treepos[i]; + int y = bottom[x] - 1; + Game::map->setNode(x,y,MAPGEN_WOOD); + Game::map->setNode(x,y-1,MAPGEN_WOOD); + Game::map->setNode(x,y-2,MAPGEN_LEAVES); + Game::map->setNode(x,y-3,MAPGEN_LEAVES); + Game::map->setNode(x,y-4,MAPGEN_LEAVES); + Game::map->setNode(x-1,y-2,MAPGEN_LEAVES); + Game::map->setNode(x-1,y-3,MAPGEN_LEAVES); + Game::map->setNode(x-1,y-4,MAPGEN_LEAVES); + Game::map->setNode(x+1,y-2,MAPGEN_LEAVES); + Game::map->setNode(x+1,y-3,MAPGEN_LEAVES); + Game::map->setNode(x+1,y-4,MAPGEN_LEAVES); + } + } diff --git a/src/mapgen.h b/src/mapgen.h new file mode 100644 index 0000000..50400aa --- /dev/null +++ b/src/mapgen.h @@ -0,0 +1,21 @@ +#ifndef _MAPGEN_H_ +#define _MAPGEN_H_ + +#include "map.h" + +#define MAPGEN_AIR Node::getNodeByName("dragonblocks:air") +#define MAPGEN_GRASS Node::getNodeByName("dragonblocks:grass") +#define MAPGEN_DIRT Node::getNodeByName("dragonblocks:dirt") +#define MAPGEN_STONE Node::getNodeByName("dragonblocks:stone") +#define MAPGEN_BEDROCK Node::getNodeByName("dragonblocks:bedrock") +#define MAPGEN_MESE Node::getNodeByName("dragonblocks:mese") +#define MAPGEN_LEAVES Node::getNodeByName("dragonblocks:leaves") +#define MAPGEN_WOOD Node::getNodeByName("dragonblocks:wood") +#define MAPGEN_WATER Node::getNodeByName("dragonblocks:water") +#define MAPGEN_SAND Node::getNodeByName("dragonblocks:sand") + +void Mapgen(); + + + +#endif diff --git a/src/mods.cpp b/src/mods.cpp new file mode 100644 index 0000000..9bc1442 --- /dev/null +++ b/src/mods.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +#include "node.h" +#include "mods.h" +#include "game.h" +#include "util.h" +#include "graphics.h" + +using namespace std; + +lua_State *Mods::lua_vm; + +void Mods::init(){ + Game::log("Initializing Mods"); + lua_vm = luaL_newstate(); + luaL_openlibs(lua_vm); + if(! check_lua(luaL_dofile(lua_vm, "builtin/init.lua"))){ + Game::log("Failed to load Builtin", ERROR); + exit(EXIT_FAILURE); + return; + } + + for(;;){ + lua_getglobal(lua_vm, "cpp_get_next_node"); + if(!lua_isfunction(lua_vm, -1)){ + Game::log("Lua is sick. What's Wrong with her?", EASTEREGG); + Game::log("No, seriously, something is wrong with the lua builtin (it is missing the function cpp_get_next_node)", ERROR); + exit(EXIT_FAILURE); + } + lua_pcall(lua_vm, 0, 1, 0); + if(! lua_istable(lua_vm, -1)) + break; + + lua_pushstring(lua_vm, "name"); + lua_gettable(lua_vm, -2); + if(!lua_isstring(lua_vm,-1)) + continue; + string name = lua_tostring(lua_vm,-1); + lua_pop(lua_vm, 1); + + lua_pushstring(lua_vm, "texture"); + lua_gettable(lua_vm, -2); + if(!lua_isstring(lua_vm,-1)) + continue; + string texture = lua_tostring(lua_vm,-1); + lua_pop(lua_vm, 1); + + lua_pushstring(lua_vm, "hidden"); + lua_gettable(lua_vm, -2); + if(!lua_isboolean(lua_vm,-1)) + continue; + bool hidden = lua_toboolean(lua_vm,-1); + lua_pop(lua_vm, 1); + + lua_pushstring(lua_vm, "stable"); + lua_gettable(lua_vm, -2); + if(!lua_isboolean(lua_vm,-1)) + continue; + bool stable = lua_toboolean(lua_vm,-1); + lua_pop(lua_vm, 1); + + lua_pushstring(lua_vm, "translucent"); + lua_gettable(lua_vm, -2); + if(!lua_isboolean(lua_vm,-1)) + continue; + bool translucent = lua_toboolean(lua_vm,-1); + lua_pop(lua_vm, 1); + + new Node(name, texture, hidden, stable, translucent); + Game::log("Registered Node " + name, INFO); + } +} +bool Mods::check_lua(int code){ + if(code == LUA_OK) + return true; + else{ + error(lua_tostring(lua_vm, -1)); + return false; + } +} +void Mods::error(string text){ + Game::log("\e[34mlua: \e[0m" + text, ERROR); +} diff --git a/src/mods.h b/src/mods.h new file mode 100644 index 0000000..5e06c82 --- /dev/null +++ b/src/mods.h @@ -0,0 +1,19 @@ +#ifndef _MODS_H_ +#define _MODS_H_ + +#include + +extern "C"{ + #include + #include + #include +} + +class Mods{ + public: + static lua_State *lua_vm; + static bool check_lua(int); + static void init(); + static void error(std::string); +}; +#endif diff --git a/src/node.cpp b/src/node.cpp new file mode 100644 index 0000000..9fcd618 --- /dev/null +++ b/src/node.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include "node.h" +#include "game.h" +#include "texture.h" +using namespace std; + +int Node::count = 0; +Node *Node::list[MAXNODES]; + +Node::Node(string n, string t, bool h, bool s, bool tr){ + if (Node::count >= MAXNODES) + Game::log("Too many registered Nodes", ERROR); + else{ + name = n; + id = Node::count; + hidden = h; + stable = s; + Node::list[id] = this; + texture = new Texture(t,tr); + Node::count++; + } +} +Node *Node::getNodeById(int id){ + if(id < count && id > -1) + return list[id]; + return list[0]; +} +Node *Node::getNodeByName(string name){ + for(int i = 0; i < count; i++){ + if(list[i]->name == name ){ + return list[i]; + } + } + Game::log("Node "+name+" not found", WARNING); + return list[0]; +} +bool Node::operator==(Node *node){ + return id == node->id; +} +bool Node::operator==(string n){ + return name == n; +} diff --git a/src/node.h b/src/node.h new file mode 100644 index 0000000..027bcbd --- /dev/null +++ b/src/node.h @@ -0,0 +1,25 @@ +#ifndef _NODE_H_ +#define _NODE_H_ +#include +#include "texture.h" +#define MAXNODES 1024 + + +class Node{ + public: + int id; + std::string name; + static Node *getNodeById(int); + static Node *getNodeByName(std::string); + static Node *list[MAXNODES]; + static int count; + bool operator==(Node *); + bool operator==(std::string); + Texture *texture; + bool hidden; + bool stable; + bool translucent; + Node(std::string, std::string, bool, bool, bool); +}; +#endif + diff --git a/src/texture.cpp b/src/texture.cpp new file mode 100644 index 0000000..a0d88fc --- /dev/null +++ b/src/texture.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "game.h" +#include "graphics.h" +#include "texture.h" + + +using namespace std; + + +Texture::Texture(string filename, bool t){ + translucent = t; + dummyimage = false; + FILE *file = fopen(filename.c_str(), "rb"); + if(!file){ + Game::log("Failed to Load Image " + filename + ": File not found. Using a dummy Image.", WARNING); + dummyimage = true; + return; + } + png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + assert(png); + png_infop info = png_create_info_struct(png); + assert(info); + png_init_io(png, file); + png_read_info(png, info); + width = png_get_image_width(png, info); + height = png_get_image_height(png, info); + color_type = png_get_color_type(png, info); + bit_depth = png_get_bit_depth(png, info); + if(bit_depth == 16) + png_set_strip_16(png); + if(color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png); + #ifndef _WIN32 + if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_gray_1_2_4_to_8(png); + #endif + if(png_get_valid(png, info, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png); + if(color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE) + png_set_filler(png, 0xFF, PNG_FILLER_AFTER); + if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + png_read_update_info(png, info); + row_pointers = (png_bytep*)malloc(sizeof(png_bytep) *height); + for(int y = 0; y < height; y++) { + row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info)); + } + png_read_image(png, row_pointers); + fclose(file); + png_destroy_read_struct(&png, &info, NULL); +} +void Texture::draw(int displayX, int displayY, int displayWidth, int displayHeight){ + if(dummyimage){ + Graphics::drawRectangle(displayX, displayY, displayWidth, displayHeight, {0, 0, 0}); + return; + } + int scaleX = (float)displayWidth/width; + int scaleY = (float)displayHeight/height; + for(int y = 0; y < height; y++) { + png_bytep row = row_pointers[y]; + for(int x = 0; x < width; x++) { + png_bytep px = &(row[x * 4]); + if(!translucent || px[0] || px[1] || px[2]) + Graphics::drawRectangle(x*scaleX + displayX, y*scaleY + displayY, scaleX, scaleY, {(float)px[0]/255, (float)px[1]/255, (float)px[2]/255}); + } + } +} diff --git a/src/texture.h b/src/texture.h new file mode 100644 index 0000000..6a059bf --- /dev/null +++ b/src/texture.h @@ -0,0 +1,20 @@ +#ifndef _TEXTURE_H_ +#define _TEXTURE_H_ + +#include +#include + +class Texture{ + public: + int width; + int height; + void draw(int, int, int, int); + Texture(std::string, bool); + private: + png_byte color_type; + png_byte bit_depth; + png_bytep *row_pointers; + bool dummyimage; + bool translucent; +}; +#endif diff --git a/src/threads.cpp b/src/threads.cpp new file mode 100644 index 0000000..b4471a4 --- /dev/null +++ b/src/threads.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include +#include "threads.h" +#include "graphics.h" +#include "game.h" + + +using namespace std; + +void Threads::startMapBackupThread(){ + Game::log("Starting Map Backup Thread"); + pthread_t thread_id; + pthread_create(&thread_id, NULL, &mapBackupThread, NULL); +} +void *Threads::mapBackupThread(void *unused){ + while(true){ + sleep(MAP_BACKUP_INTERVAL); + Game::map -> save(); + } + return NULL; +} +void Threads::startGraphicUpdateThread(){ + Game::log("Starting Graphic Update Thread"); + pthread_t thread_id; + pthread_create(&thread_id, NULL, &graphicUpdateThread, NULL); +} +void *Threads::graphicUpdateThread(void *unused){ + while(true){ + usleep(1); + if(glutGetWindow()) + glutPostRedisplay(); + } + return NULL; +} +void Threads::addSignalHandlers(){ +#ifndef _WIN32 + struct sigaction sa_sigterm; + sa_sigterm.sa_handler = &signal_handler; + sigaction(SIGTERM, &sa_sigterm, NULL); + + struct sigaction sa_sigint; + sa_sigint.sa_handler = &signal_handler; + sigaction(SIGINT, &sa_sigint, NULL); +#endif +} +void Threads::signal_handler(int signal_number){ +#ifndef _WIN32 + Game::log((string)"Got "+sys_siglist[signal_number]+" Signal, Exiting."); + Game::map -> save(); + exit(0); +#endif +} diff --git a/src/threads.h b/src/threads.h new file mode 100644 index 0000000..e8fce5b --- /dev/null +++ b/src/threads.h @@ -0,0 +1,17 @@ +#ifndef _THREADS_H_ +#define _THREADS_H_ + +#define MAP_BACKUP_INTERVAL 15 + +class Threads{ + public: + static void startMapBackupThread(); + static void addSignalHandlers(); + static void startGraphicUpdateThread(); + private: + static void *mapBackupThread(void *); + static void *graphicUpdateThread(void *); + static void signal_handler(int); +}; +#endif + diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..600a742 --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "game.h" + +using namespace std; +int random(int min, int max){ + return min + rand() % (max - min + 1); +} +color::color(const char *htmlcolor){ + unsigned int r, g, b; + sscanf(htmlcolor, "#%2x%2x%2x", &r, &g, &b); + red = (float) r / 255; + green = (float) g / 255; + blue = (float) b / 255; +} +color::color(float r, float g, float b){ + red = r; + green = g; + blue = b; +} +void create_dir_if_not_exists(string d){ + const char *dir = d.c_str(); + struct stat dir_exists_st = {0}; + if(stat(dir, &dir_exists_st) == -1){ + Game::log((string)dir + " doesn't exist, creating", INFO); + #ifdef _WIN32 + mkdir(dir); + #else + mkdir(dir, 0700); + #endif + } +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..05419cd --- /dev/null +++ b/src/util.h @@ -0,0 +1,20 @@ +#ifndef _UTIL_H_ +#define _UTIL_H_ +#include +class color{ + public: + float red; + float green; + float blue; + color(const char *); + color(float, float, float); +}; +class position{ + public: + int x; + int y; +}; + +int random(int, int); +void create_dir_if_not_exists(std::string d); +#endif diff --git a/textures/air.png b/textures/air.png new file mode 100644 index 0000000..cfdb4c8 Binary files /dev/null and b/textures/air.png differ diff --git a/textures/bedrock.png b/textures/bedrock.png new file mode 100644 index 0000000..2d29423 Binary files /dev/null and b/textures/bedrock.png differ diff --git a/textures/cobble.png b/textures/cobble.png new file mode 100644 index 0000000..d379840 Binary files /dev/null and b/textures/cobble.png differ diff --git a/textures/dirt.png b/textures/dirt.png new file mode 100644 index 0000000..afe4a2e Binary files /dev/null and b/textures/dirt.png differ diff --git a/textures/grass.png b/textures/grass.png new file mode 100644 index 0000000..2608cd7 Binary files /dev/null and b/textures/grass.png differ diff --git a/textures/leaves.png b/textures/leaves.png new file mode 100644 index 0000000..ba09fe1 Binary files /dev/null and b/textures/leaves.png differ diff --git a/textures/mese.png b/textures/mese.png new file mode 100644 index 0000000..e30994e Binary files /dev/null and b/textures/mese.png differ diff --git a/textures/sand.png b/textures/sand.png new file mode 100644 index 0000000..645a300 Binary files /dev/null and b/textures/sand.png differ diff --git a/textures/stone.png b/textures/stone.png new file mode 100644 index 0000000..63cb7c4 Binary files /dev/null and b/textures/stone.png differ diff --git a/textures/unknown_node.png b/textures/unknown_node.png new file mode 100644 index 0000000..cb59ff4 Binary files /dev/null and b/textures/unknown_node.png differ diff --git a/textures/water.png b/textures/water.png new file mode 100644 index 0000000..00500e9 Binary files /dev/null and b/textures/water.png differ diff --git a/textures/wood.png b/textures/wood.png new file mode 100644 index 0000000..10e297b Binary files /dev/null and b/textures/wood.png differ