diff --git a/.gitignore b/.gitignore index 3bb5150..c1f8c10 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ log.txt test_log.txt Spylike-v* lib/bin -lib/include \ No newline at end of file +lib/include +build/* diff --git a/Makefile b/Makefile index 9a75c41..abb0a93 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,10 @@ CXX=g++ CPPFLAGS=-std=c++2a -Iinclude -Igame/include -Ilib/include -DMA_NO_PULSEAUDIO -LDLIBS= -OBJS=graphics/*.cpp logging/*.cpp models/*.cpp level/*.cpp audio/*.cpp game/*.cpp game/entities/*.cpp game/UI/*.cpp util/*.cpp main.cpp +LDLIBS=-Llib/bin +SOURCES=$(wildcard graphics/*.cpp logging/*.cpp models/*.cpp level/*.cpp audio/*.cpp game/*.cpp game/entities/*.cpp game/UI/*.cpp util/*.cpp main.cpp) +OBJS=$(patsubst %.cpp, build/%.o, $(SOURCES)) VER=vA1 +USE_DISCORD=1 ifndef PDCURSES_BACKEND ifeq ($(OS),Windows_NT) @@ -12,6 +14,7 @@ ifndef PDCURSES_BACKEND ifeq ($(UNAME_S),Linux) ifndef USE_NCURSES USE_NCURSES=1 + CPPFLAGS+= -DUSE_NCURSESW endif PDCURSES_BACKEND=x11 LDLIBS+= -lpthread -lm -ldl @@ -22,21 +25,46 @@ endif ifeq ($(USE_NCURSES), 1) LDLIBS+= -lncursesw else - LDLIBS+= -Llib/bin -lpdcurses + LDLIBS+= -lpdcurses endif ifndef PDCURSES_BACKEND $(error "OS not detected or supported - please specify PDCurses backend (wincon, x11, sdl2)) endif +ifeq ($(USE_DISCORD), 1) + $(shell mkdir -p lib/bin) + $(shell mkdir -p lib/include) + ifeq ($(UNAME_S),Linux) + $(shell cp -u lib/discord-rpc-linux/linux-dynamic/include/*.h lib/include) + $(shell cp -u lib/discord-rpc-linux/linux-dynamic/lib/libdiscord-rpc.so lib/bin) + LDLIBS+= -ldiscord-rpc + CPPFLAGS+= -DUSE_DISCORD + else + USE_DISCORD=0 + endif +endif + +$(shell mkdir -p lib/include) +$(shell cp lib/miniaudio/miniaudio.h lib/include/miniaudio.h) + build: build-pdcurses build: $(OBJS) - cp lib/miniaudio/miniaudio.h lib/include/miniaudio.h - $(CXX) $(CPPFLAGS) -o Spylike-$(VER) $(OBJS) $(LDLIBS) + $(CXX) $(CPPFLAGS) -o Spylike-$(VER) $(OBJS) $(LDLIBS) -Wl,-rpath=lib/bin + +build/%.o: %.cpp + mkdir -p $(@D) + $(CXX) $(CPPFLAGS) -c -o $@ $(LDLIBS) $^ -debug: CPPFLAGS+= -g -O0 +debug: CPPFLAGS+= -g -O0 -v debug: build +clean: + rm -rf lib/bin/* + rm -rf lib/include/* + rm -rf build/* + rm -rf lib/src/* + build-pdcurses: cd lib && mkdir -p bin cd lib && mkdir -p include diff --git a/Spylike-TestSuite-vA1.exe b/Spylike-TestSuite-vA1.exe deleted file mode 100644 index 00cace7..0000000 Binary files a/Spylike-TestSuite-vA1.exe and /dev/null differ diff --git a/events.txt b/events.txt index ab9a76e..a7947ea 100644 --- a/events.txt +++ b/events.txt @@ -8,7 +8,11 @@ CAMERA_MoveUp: Moves the camera up by one unit. (CameraEvent) CAMERA_MoveDown: Moves the camera down by one unit. (CameraEvent) CAMERA_MoveRight: Moves the camera right by one unit. (CameraEvent) CAMERA_MoveLeft: Moves the camera left by one unit. (CameraEvent) -CAMERA_Move: Moves the camera to pos specified in CameraEvent.pos. +CAMERA_Move: Moves the camera origin to pos specified in CameraEvent.pos. +CAMERA_MoveCenter: Centers the camera at pos specified in CameraEvent.pos. +CAMERA_MoveCenterH: Centers the camera horizontally at pos specified in CameraEvent.pos, ignoring y +CAMERA_MoveCenterX: Centers the camera vertically at pos specified in CameraEvent.pos, ignoring x + Audio: AUDIO_PlayMusic: Plays the music with filepath [rootPath]/AudioPlayEvent.sound and volume AudioPlayEvent.volume @@ -24,4 +28,4 @@ MENU_ButtonClick: Calls when any button is clicked, ID given in MenuButtonEvent. LEVEL_change: Changes the level to LevelChangeEvent.levelPath GAME_KeyCollect: The key for the final boss door was collected. GAME_DoorRequest: Event for the door to check whether it can be opened. -GAME_DoorResponse: Response from the game manager about GAME_DoorRequest, result in bool DoorResponse.result. \ No newline at end of file +GAME_DoorResponse: Response from the game manager about GAME_DoorRequest, result in bool DoorResponse.result. diff --git a/game/UI/menus.cpp b/game/UI/menus.cpp index 44938a4..3436697 100644 --- a/game/UI/menus.cpp +++ b/game/UI/menus.cpp @@ -16,7 +16,7 @@ void MenuButton::click() { eventManager->emit(ev); } -void MenuButton::draw(GeometryRenderer& painter) { +void MenuButton::draw(TextRenderManager& painter) { std::string drawnText = text; // note that subtracting 2 from width may cause integer overflow(???) so we have to do it this way if (((text.length() + 2) > width) || (height < 3)) { @@ -43,7 +43,7 @@ void MenuButton::on_event(Event& e) {} void MenuButton::on_update() {} -void Menu::draw(GeometryRenderer& painter) { +void Menu::draw(TextRenderManager& painter) { Coordinate selectionPos = buttons.find(currentSelection)->second.pos; Coordinate arrowPos = Coordinate(selectionPos.x + buttons.find(currentSelection)->second.width/2, selectionPos.y - 1); painter.draw(arrowPos, 'v', "UI"); @@ -53,7 +53,7 @@ void Menu::draw(GeometryRenderer& painter) { } } -void PauseMenu::draw(GeometryRenderer& painter) { +void PauseMenu::draw(TextRenderManager& painter) { /* painter.drawString(Coordinate(1, 1), "" "|||\n" @@ -68,12 +68,12 @@ void PauseMenu::draw(GeometryRenderer& painter) { Menu::draw(painter); } -void GameOverMenu::draw(GeometryRenderer& painter) { +void GameOverMenu::draw(TextRenderManager& painter) { painter.drawString(Coordinate(painter.getScreenWidth()/2-8, 1), "GAME OVER!", "UI"); Menu::draw(painter); } -void StartMenu::draw(GeometryRenderer& painter) { +void StartMenu::draw(TextRenderManager& painter) { painter.drawString(Coordinate(painter.getScreenWidth()/2-12, 1), "WELCOME TO SPYLIKE!", "UI"); painter.drawString(Coordinate(painter.getScreenWidth()/2-7, 2), "CONTROLS:", "UI"); painter.drawString(Coordinate(painter.getScreenWidth()/2-10, 3), "W,A,S,D MOVEMENT", "UI"); diff --git a/game/entities/character.cpp b/game/entities/character.cpp index ee981ea..ccb8fd4 100644 --- a/game/entities/character.cpp +++ b/game/entities/character.cpp @@ -5,12 +5,13 @@ #include #include #include +#include extern SpylikeLogger LOGGER; void Player::on_init() { eventManager->subscribe(shared_from_this(), "INPUT_KeyPress"); - SpylikeEvents::CameraEvent ce("CAMERA_Move", getPos()); + SpylikeEvents::CameraEvent ce("CAMERA_MoveCenter", getPos()); eventManager->emit(ce); } @@ -51,9 +52,7 @@ void Player::on_event(Event& e) { else if (getPos().x > newCharPos.x) newCharPos.x--; else if (getPos().y > newCharPos.y) newCharPos.y--; else newCharPos.y++; - if (world->isInMap(newCharPos)) { - world->moveEntity(character->getID(), newCharPos); - } + world->moveEntity(character->getID(), newCharPos); } } } @@ -83,13 +82,7 @@ void Player::on_event(Event& e) { newPos.x++; } } - if (world->isInMap(newPos)) { - bool res = world->moveEntity(getID(), newPos); - if (res) { - SpylikeEvents::CameraEvent ce("CAMERA_Move", newPos); - eventManager->emit(ce); - } - } + world->moveEntity(getID(), newPos); } } else { @@ -106,13 +99,9 @@ void Player::on_event(Event& e) { xVel = 1; } } - if (world->isInMap(newPos)) { - bool res = world->moveEntity(getID(), newPos); - if (res) { - SpylikeEvents::CameraEvent ce("CAMERA_Move", newPos); - eventManager->emit(ce); - slideTimer.reset(); - } + bool res = world->moveEntity(getID(), newPos); + if (res) { + slideTimer.reset(); } } else if (ke.c == 'w' || ke.c == ' ' && (yVel == 0)) { @@ -128,7 +117,18 @@ void Player::on_event(Event& e) { } } -void Player::draw(GeometryRenderer& painter) { +void Player::draw(Camera& painter) { + if (world->worldType == WorldType::Platform) { + int yDist = getPos().y - painter.getOrigin().y; + nextCamPos = Coordinate(getPos().x - painter.getScreenWidth()/2, painter.getOrigin().y); + changePosFlag = true; + if (yDist > 3*(painter.getScreenHeight()/4)) { + nextCamPos.y = painter.getOrigin().y + painter.getScreenHeight()/4; + } + else if (yDist < painter.getScreenHeight()/4) { + nextCamPos.y = painter.getOrigin().y - painter.getScreenHeight()/4; + } + } if (state == PState::Hurt) { painter.drawString(getPos(), hurtSprite.getCurrentFrame(), "Entity"); hurtSprite.nextFrame(); @@ -143,18 +143,23 @@ void Player::draw(GeometryRenderer& painter) { } void Player::on_update() { - if (world->worldType == WorldType::Platform) { + if (world->worldType == WorldType::Roguelike) { + SpylikeEvents::CameraEvent ce("CAMERA_MoveCenter", getPos()); + eventManager->emit(ce); + } + else if (world->worldType == WorldType::Platform) { + if (changePosFlag && world->active) { + SpylikeEvents::CameraEvent ce("CAMERA_Move", nextCamPos); + eventManager->emit(ce); + changePosFlag = false; + } moveTimer.tick(); slideTimer.tick(); if (yVel > 0 && (moveTimer.getElapsed() > 3/yVel)) { Coordinate newPos = Coordinate(getPos().x+xVel, getPos().y-1); - if (world->isInMap(newPos)) { - bool res = world->moveEntity(getID(), newPos); - if (res) { - yVel--; - SpylikeEvents::CameraEvent ce("CAMERA_MoveUp", newPos); - eventManager->emit(ce); - } + bool res = world->moveEntity(getID(), newPos); + if (res) { + yVel--; } else yVel = 0; slideTimer.reset(); @@ -163,14 +168,12 @@ void Player::on_update() { else { if (moveTimer.getElapsed() > 2) { Coordinate below = Coordinate(getPos().x, getPos().y+1); - if (world->isInMap(below)) { - bool res = world->moveEntity(getID(), below); - if (res && slideTimer.getElapsed() > 2) { - Coordinate newPos = Coordinate(below.x+xVel, below.y); - bool res = world->moveEntity(getID(), newPos); - if (!res) xVel = 0; - slideTimer.reset(); - } + bool res = world->moveEntity(getID(), below); + if (res && slideTimer.getElapsed() > 2) { + Coordinate newPos = Coordinate(below.x+xVel, below.y); + bool res = world->moveEntity(getID(), newPos); + if (!res) xVel = 0; + slideTimer.reset(); } moveTimer.reset(); } @@ -196,6 +199,11 @@ void Player::on_update() { if (attackTimer.getElapsed() > 2) state = PState::Idle; } } + + if (!changePosFlag && world->active) { + SpylikeEvents::CameraEvent ce("CAMERA_MoveCenterH", getPos()); + eventManager->emit(ce); + } } void Player::on_collide(std::shared_ptr collider) { @@ -244,7 +252,7 @@ void Goblin::on_update() { else xDir = 1; if (world->worldType == WorldType::Platform) yDir = 0; Coordinate newPos(getPos().x + xDir, getPos().y + yDir); - if (world->isInMap(newPos)) world->moveEntity(getID(), newPos); + world->moveEntity(getID(), newPos); } else state = GobState::Idle; } @@ -254,16 +262,14 @@ void Goblin::on_update() { if (world->worldType == WorldType::Platform) { if (moveTimer.getElapsed() > 2) { Coordinate below = Coordinate(getPos().x, getPos().y+1); - if (world->isInMap(below)) { - bool res = world->moveEntity(getID(), below); - falling = res; - } + bool res = world->moveEntity(getID(), below); + falling = res; moveTimer.reset(); } } } -void Goblin::draw(GeometryRenderer& painter) { +void Goblin::draw(Camera& painter) { if (state == GobState::Found) { painter.draw(Coordinate(getPos().x, getPos().y-1), '!', "Effect"); } @@ -285,7 +291,7 @@ void Goblin::hurt(int damage) { if (health <= 0) kill(); } -void Skeleton::draw(GeometryRenderer& painter) { +void Skeleton::draw(Camera& painter) { painter.draw(getPos(), '&', "Entity"); } @@ -304,20 +310,19 @@ void Skeleton::on_update() { if (res.size() > 0) { std::shared_ptr player = res[0]; int xVel = 0; - if (player->getPos().x > getPos().x) xVel = 100; - else if (player->getPos().x < getPos().x) xVel = -100; + if (player->getPos().x > getPos().x) xVel = 45; + else if (player->getPos().x < getPos().x) xVel = -45; int yVel = 0; if (player->getPos().y != getPos().y) { int yDir = abs(player->getPos().y - getPos().y)/(player->getPos().y - getPos().y); if (player->getPos().x != getPos().x) yVel = yDir*abs((xVel*(player->getPos().y - getPos().y))/(player->getPos().x - getPos().x)); - else yVel = yDir; + else yVel = yDir*10; } - Coordinate arrowPos = Coordinate(getPos().x+(xVel/100), getPos().y+(yVel/100)); - auto tile = world->getTile(arrowPos); - if (!tile || tile->getEntities().size() == 0) { + if (xVel != 0 || yVel != 0) { std::shared_ptr arrow = std::make_shared(xVel, yVel); arrow->init(eventManager); - world->registerEntity(arrow, arrowPos); + world->registerEntity(arrow, getPos()); + arrow->update(); } } fireTimer.reset(); @@ -328,29 +333,25 @@ void Skeleton::hurt(int damage) { health -= damage; } -void SkeletonArrow::draw(GeometryRenderer& painter) { +void SkeletonArrow::draw(Camera& painter) { painter.draw(getPos(), '#', "Entity"); } void SkeletonArrow::on_update() { - moveTimer.tick(); - if (moveTimer.getElapsed() > 2) { - moveTimer.reset(); - xFlag += xVel; - yFlag += yVel; - Coordinate newPos = getPos(); - if (abs(xFlag) >= 100) { - newPos.x = newPos.x + (abs(xVel)/xVel)*(abs(xFlag)/100); - xFlag = 0; - } - if (abs(yFlag) >= 100) { - newPos.y = newPos.y + abs(yVel)/yVel*(abs(yFlag)/100); - yFlag = 0; - } - if (newPos != getPos()) { - if (world->isInMap(newPos)) world->moveEntity(getID(), newPos); - else kill(); - } + xFlag += xVel; + yFlag += yVel; + Coordinate newPos = getPos(); + if (abs(xFlag) >= 100) { + newPos.x += abs(xVel)/xVel; + xFlag = 0; + } + if (abs(yFlag) >= 100) { + newPos.y += abs(yVel)/yVel; + yFlag = 0; + } + if (newPos != getPos()) { + bool res = world->moveEntity(getID(), newPos); + if (!res) kill(); } } @@ -371,7 +372,7 @@ void Boss::on_init() { } } -void Boss::draw(GeometryRenderer& painter) { +void Boss::draw(Camera& painter) { painter.draw(getPos(), '/', "Entity"); painter.draw(Coordinate(getPos().x+1, getPos().y), '\\', "Entity"); painter.draw(Coordinate(getPos().x+1, getPos().y-1), ')', "Entity"); @@ -398,11 +399,11 @@ void Boss::on_update() { Coordinate arrowPos = Coordinate(getPos().x-1, getPos().y); int yVel; if ((fireTimer.getElapsed() % 20) % 3 == 0) yVel = 0; - else if ((fireTimer.getElapsed() % 20) % 3 == 1) yVel = -30; - else yVel = -20; + else if ((fireTimer.getElapsed() % 20) % 3 == 1) yVel = -15; + else yVel = -10; auto tile = world->getTile(arrowPos); if (!tile || tile->getEntities().size() == 0) { - std::shared_ptr arrow = std::make_shared(-300, yVel); + std::shared_ptr arrow = std::make_shared(-60, yVel); arrow->init(eventManager); world->registerEntity(arrow, arrowPos); } @@ -413,9 +414,9 @@ void Boss::on_update() { } else if (state == BossState::Attack2) { fireTimer.tick(); - if ((fireTimer.getElapsed() % 15) == 0) { + if ((fireTimer.getElapsed() % 25) == 0) { for (int y=0; y<3; y++) { - std::shared_ptr arrow = std::make_shared(-300, 0); + std::shared_ptr arrow = std::make_shared(-75, 0); arrow->init(eventManager); world->registerEntity(arrow, Coordinate(getPos().x, getPos().y-y)); } diff --git a/game/entities/geometry.cpp b/game/entities/geometry.cpp index ec40b40..9f9d701 100644 --- a/game/entities/geometry.cpp +++ b/game/entities/geometry.cpp @@ -1,5 +1,9 @@ #include "geometry.h" -void Wall::draw(GeometryRenderer& painter) { +void Wall::draw(Camera& painter) { + #ifdef USE_NCURSESW + painter.draw(Coordinate(getPos().x, getPos().y), L"\u2592", "Entity"); + #else painter.draw(Coordinate(getPos().x, getPos().y), '~', "Entity"); + #endif } diff --git a/game/entities/misc.cpp b/game/entities/misc.cpp index c128f32..febc859 100644 --- a/game/entities/misc.cpp +++ b/game/entities/misc.cpp @@ -12,11 +12,12 @@ void LevelTransition::on_collide(std::shared_ptr collider) { void Key::on_collide(std::shared_ptr collider) { std::shared_ptr player = std::dynamic_pointer_cast(collider); if (player) { + isCollidable = false; Event ev("GAME_KeyCollect"); eventManager->emit(ev); + collectedTimer.reset(); + state = KeyState::Collected; } - collectedTimer.reset(); - state = KeyState::Collected; } void Key::on_update() { @@ -26,7 +27,7 @@ void Key::on_update() { } } -void Key::draw(GeometryRenderer& painter) { +void Key::draw(Camera& painter) { switch (state) { case (KeyState::Idle): { painter.draw(getPos(), '%', "Entity"); @@ -65,7 +66,7 @@ void Door::on_update() { } } -void Door::draw(GeometryRenderer& painter) { +void Door::draw(Camera& painter) { painter.draw(getPos(), '=', "Entity"); if (state == DoorState::FailedOpen) { painter.drawString(Coordinate(getPos().x-10, getPos().y-1), "Get a key first!", "Effect"); diff --git a/game/entities/obstacle.cpp b/game/entities/obstacle.cpp index eba764c..afcbe56 100644 --- a/game/entities/obstacle.cpp +++ b/game/entities/obstacle.cpp @@ -3,7 +3,7 @@ #include #include -void Lava::draw(GeometryRenderer& painter) { +void Lava::draw(Camera& painter) { painter.draw(getPos(), '#', "Entity"); } @@ -28,7 +28,7 @@ void Lava::on_update() { } -void LavaGenerator::draw(GeometryRenderer& painter) { +void LavaGenerator::draw(Camera& painter) { painter.draw(getPos(), '#', "Entity"); } @@ -47,7 +47,7 @@ void LavaGenerator::on_update() { } } -void Spike::draw(GeometryRenderer& painter) { +void Spike::draw(Camera& painter) { painter.draw(getPos(), '#', "Entity"); } diff --git a/game/game.cpp b/game/game.cpp index 334cc1a..b5c91f4 100644 --- a/game/game.cpp +++ b/game/game.cpp @@ -1,5 +1,12 @@ #include #include +#include +#include +#include +#include +#include +#include + #include "rendering.h" #include "scheduling.h" #include "camera.h" @@ -14,11 +21,10 @@ #include "obstacle.h" #include "game.h" #include "geometry.h" -#include -#include -#include -#include -#include + +#ifdef USE_DISCORD +#include "discord_rpc.h" +#endif extern SpylikeLogger LOGGER; @@ -28,37 +34,61 @@ std::string formatSeconds(int seconds) { return std::to_string(minutes) + ":" + std::to_string(seconds); } +GameManager::GameManager() { + #ifdef USE_DISCORD + memset(&handlers, 0, sizeof(handlers)); + handlers.ready = handleDiscordReady; + handlers.disconnected = handleDiscordDisconnected; + handlers.errored = handleDiscordError; + handlers.joinGame = handleDiscordJoin; + handlers.spectateGame = handleDiscordSpectate; + handlers.joinRequest = handleDiscordJoinRequest; + Discord_Initialize(DISCORD_CLIENT_ID, &handlers, 1, NULL); + #endif +} + + void GameManager::RunLevelTask::update() { + auto& theMap = manager.map; manager.camera->clearScreen(); Coordinate origin = manager.camera->getOrigin(); - int yOff = manager.camera->getYOffset(); - int xOff = manager.camera->getXOffset(); - for (int y=(origin.y+yOff); y>(origin.y+yOff-(2*manager.camera->getScreenHeight())); y--) { - for (int x=(origin.x-xOff); x<(origin.x-xOff+(2*manager.camera->getScreenWidth())); x++) { + for (int y=origin.y; y<(origin.y+manager.camera->getScreenHeight()); y++) { + for (int x=origin.x; x<(origin.x+manager.camera->getScreenWidth()); x++) { + if (theMap->isInMap(Coordinate(x, y))) { + theMap->updateTile(Coordinate(x, y)); + } + if (manager.killUpdates) { + manager.killUpdates = false; + return; + } + } + + } + for (int y=origin.y; y<(origin.y+manager.camera->getScreenHeight()); y++) { + for (int x=origin.x; x<(origin.x+manager.camera->getScreenWidth()); x++) { if (manager.map->isInMap(Coordinate(x, y))) { - manager.map->updateTile(Coordinate(x, y)); - manager.map->drawTile(Coordinate(x, y), *manager.gameRenderer); + manager.map->drawTile(Coordinate(x, y), *manager.camera); } } + } //manager.menuRenderer->drawBox(Coordinate(0, 0), Coordinate(manager.menuManager->getScreenWidth(), manager.menuManager->getScreenHeight()), "Overlay"); //manager.menuManager->renderToScreen(); manager.camera->toggleAbsolute(); - manager.gameRenderer->drawString(Coordinate(0, 0), "Health: " + std::to_string(manager.playerHealth), "UI"); - manager.gameRenderer->drawString(Coordinate(0, 1), "Time elapsed: " + formatSeconds(manager.scheduler.timeElapsed()), "UI"); + manager.camera->drawString(Coordinate(0, 0), "Health: " + std::to_string(manager.playerHealth), "UI"); + manager.camera->drawString(Coordinate(0, 1), "Time elapsed: " + formatSeconds(manager.scheduler.timeElapsed()), "UI"); manager.camera->toggleAbsolute(); manager.camera->renderToScreen(); manager.inputManager->update(); - } void GameManager::TickTask::update() {} void GameManager::MenuTask::update() { manager.menuManager->clearScreen(); - manager.activeMenu->draw(*manager.menuRenderer); + manager.activeMenu->draw(*manager.menuManager); manager.activeMenu->update(); - manager.menuRenderer->drawBox(Coordinate(0, 0), Coordinate(manager.menuManager->getScreenWidth(), manager.menuManager->getScreenHeight()-1), "Overlay"); + manager.menuManager->drawBox(Coordinate(0, 0), Coordinate(manager.menuManager->getScreenWidth(), manager.menuManager->getScreenHeight()-1), "Overlay"); manager.menuManager->renderToScreen(); manager.menuInputManager->update(); } @@ -79,6 +109,8 @@ void GameManager::quit() { } void GameManager::loadLevel(Level level) { + if (map) map->active = false; + killUpdates = true; LOGGER.log("Loading level", DEBUG); eventManager->clear(); eventManager->subscribe(camera, "CAMERA_MoveUp"); @@ -86,6 +118,9 @@ void GameManager::loadLevel(Level level) { eventManager->subscribe(camera, "CAMERA_MoveLeft"); eventManager->subscribe(camera, "CAMERA_MoveRight"); eventManager->subscribe(camera, "CAMERA_Move"); + eventManager->subscribe(camera, "CAMERA_MoveCenter"); + eventManager->subscribe(camera, "CAMERA_MoveCenterH"); + eventManager->subscribe(camera, "CAMERA_MoveCenterV"); eventManager->subscribe(audioManager, "AUDIO_PlayMusic"); eventManager->subscribe(audioManager, "AUDIO_PauseMusic"); eventManager->subscribe(shared_from_this(), "MENU_Show"); @@ -105,6 +140,15 @@ void GameManager::loadLevel(Level level) { map->registerEntity(entPair.first, entPair.second); } if (!audioManager->isPlaying()) audioManager->playMusic("1-1.wav", 0.25); + #ifdef USE_DISCORD + DiscordRichPresence discordPresence; + memset(&discordPresence, 0, sizeof(discordPresence)); + discordPresence.state = level.title.c_str(); + discordPresence.details = "Playing a level"; + discordPresence.largeImageKey = "rg_logo"; + Discord_UpdatePresence(&discordPresence); + Discord_RunCallbacks(); + #endif } // Note: You must close any active menus, before showing a new one. @@ -173,7 +217,6 @@ void GameManager::on_event(Event& e) { void GameManager::run() { std::vector layers {RenderLayer("Entity", 1), RenderLayer("Effect", 2), RenderLayer("UI", 3), RenderLayer("Overlay", 4)}; camera = std::make_shared(screen, 80, 30, layers); - camera->setOffset(30, 20); menuManager = std::make_shared(screen, layers); @@ -181,11 +224,7 @@ void GameManager::run() { menuEventManager = std::make_shared(); inputManager = std::make_shared(eventManager, screen); menuInputManager = std::make_shared(menuEventManager, screen); - GeometryRenderer theRenderer = GeometryRenderer(*camera); - gameRenderer = &theRenderer; - GeometryRenderer theMenuRenderer = GeometryRenderer(*menuManager); - menuRenderer = &theMenuRenderer; - + audioManager = std::make_shared("game/resource/audio/"); Level level = load_from_file("game/resource/levels/1-3.spm"); diff --git a/game/include/character.h b/game/include/character.h index c07817c..2770962 100644 --- a/game/include/character.h +++ b/game/include/character.h @@ -28,8 +28,10 @@ class Player : public Character { void on_event(Event& e) override; void on_update() override; void on_init() override; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; void on_collide(std::shared_ptr collider) override; + Coordinate nextCamPos = Coordinate(-1, -1); + bool changePosFlag = false; public: void hurt(int damage) override; }; @@ -42,7 +44,7 @@ class Goblin : public Character { bool falling = false; void on_event(Event& e) override {} void on_update() override; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; void on_collide(std::shared_ptr collider) override; public: void hurt(int damage) override; @@ -52,7 +54,7 @@ class Skeleton : public Character { Timer fireTimer; void on_event(Event& e) override {} void on_update() override; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; void on_collide(std::shared_ptr collider) override; public: void hurt(int damage) override; @@ -61,9 +63,8 @@ class Skeleton : public Character { class SkeletonArrow : public TileEntity { void on_event(Event& e) override {} void on_update() override; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; void on_collide(std::shared_ptr collider) override; - Timer moveTimer; Coordinate initialPos; int xFlag=0; int yFlag=0; @@ -82,7 +83,7 @@ class Boss : public Character { Sprite alertSprite{alertFrames, 1}; void on_event(Event& e) override {} void on_update() override; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; void on_collide(std::shared_ptr collider) override {} void on_init() override; public: diff --git a/include/game.h b/game/include/game.h similarity index 80% rename from include/game.h rename to game/include/game.h index 2bf49d2..f87ee23 100644 --- a/include/game.h +++ b/game/include/game.h @@ -20,6 +20,11 @@ #include #include +#ifdef USE_DISCORD +#include "discord_rpc.h" +const char* const DISCORD_CLIENT_ID="1189761699511812186"; +#endif + extern SpylikeLogger LOGGER; inline Level load_from_file(std::string path) { @@ -84,11 +89,16 @@ inline Level load_from_file(std::string path) { } entities[ent] = Coordinate(entX, entY); } - return Level(levelType, width, height, entities); + std::string filename = path.substr(path.find_last_of("/\\") + 1); + std::string title = filename.substr(0, filename.find(".spm")); + return Level(title, levelType, width, height, entities); } class GameManager : public EventHandler, public std::enable_shared_from_this { bool paused; + #ifdef USE_DISCORD + DiscordEventHandlers handlers; + #endif FrameScheduler scheduler = FrameScheduler(20); NcursesTerminalScreen screen = NcursesTerminalScreen(80, 30); std::shared_ptr eventManager; @@ -97,13 +107,12 @@ class GameManager : public EventHandler, public std::enable_shared_from_this menuInputManager; std::shared_ptr camera; std::shared_ptr menuManager; - GeometryRenderer* gameRenderer; - GeometryRenderer* menuRenderer; std::shared_ptr activeMenu; std::shared_ptr map; std::shared_ptr audioManager; int playerHealth = 100; bool keyCollected = false; + bool killUpdates = false; class RunLevelTask : public ScheduledTask { GameManager& manager; public: @@ -128,7 +137,27 @@ class GameManager : public EventHandler, public std::enable_shared_from_thisuserId); + LOGGER.log("Discord RPC connected (User ID: " + uID + ")", DEBUG); + } + + static void handleDiscordDisconnected(int errcode, const char* message) {} + + static void handleDiscordError(int errcode, const char* message) {} + + static void handleDiscordJoin(const char* secret) {} + + static void handleDiscordSpectate(const char* secret) {} + + static void handleDiscordJoinRequest(const DiscordUser* request) {} + #endif + public: + GameManager(); void loadLevel(Level level); void pause(); void quit(); diff --git a/game/include/geometry.h b/game/include/geometry.h index 4589a26..aab6dee 100644 --- a/game/include/geometry.h +++ b/game/include/geometry.h @@ -11,7 +11,7 @@ class Geometry: public TileEntity { class Wall : public Geometry { void on_update() override {}; void on_event(Event& e) override {}; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; void on_collide(std::shared_ptr collider) override {}; }; diff --git a/game/include/menus.h b/game/include/menus.h index 9a261e8..9e9629e 100644 --- a/game/include/menus.h +++ b/game/include/menus.h @@ -19,7 +19,7 @@ class MenuButton : public SpritedObject { const int height; Coordinate pos; // top left MenuButton(Coordinate pos, int width, int height, std::string buttonText, std::string buttonID); - void draw(GeometryRenderer& painter); + void draw(TextRenderManager& painter); void click(); std::string getButtonID(); }; @@ -36,7 +36,7 @@ class Menu : public SpritedObject { void on_init() override; public: Menu(int width, int height): width{width}, height{height} {} - virtual void draw(GeometryRenderer& painter); + virtual void draw(TextRenderManager& painter); void addButton(MenuButton button); void setSelection(std::string buttonID); void selectNext(); @@ -46,19 +46,19 @@ class Menu : public SpritedObject { class PauseMenu : public Menu { public: PauseMenu(int width, int height): Menu(width, height) {} - void draw(GeometryRenderer& painter) override; + void draw(TextRenderManager& painter) override; }; class GameOverMenu : public Menu { public: GameOverMenu(int width, int height): Menu(width, height) {} - void draw(GeometryRenderer& painter) override; + void draw(TextRenderManager& painter) override; }; class StartMenu : public Menu { public: StartMenu(int width, int height): Menu(width, height) {} - void draw(GeometryRenderer& painter) override; + void draw(TextRenderManager& painter) override; }; namespace SpylikeMenus { diff --git a/game/include/misc.h b/game/include/misc.h index 6e98bac..e4fafcb 100644 --- a/game/include/misc.h +++ b/game/include/misc.h @@ -13,7 +13,7 @@ class LevelTransition : public TileEntity { void on_collide(std::shared_ptr collider) override; void on_event(Event& e) override {} void on_update() override {} - void draw(GeometryRenderer& painter) override {} + void draw(Camera& painter) override {} public: LevelTransition(std::string levelPath) : TileEntity(true), levelPath{levelPath} {} }; @@ -25,7 +25,7 @@ class Key : public TileEntity { void on_collide(std::shared_ptr collider) override; void on_event(Event& e) override {} void on_update() override; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; public: Key() : TileEntity(true) {} @@ -39,7 +39,7 @@ class Door : public TileEntity { void on_event(Event& e) override; void on_collide(std::shared_ptr collider) override; void on_update() override; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; public: Door() : TileEntity(true) {} }; diff --git a/game/include/obstacle.h b/game/include/obstacle.h index 3a04316..0fbcbd5 100644 --- a/game/include/obstacle.h +++ b/game/include/obstacle.h @@ -7,7 +7,7 @@ class Lava : public TileEntity { void on_event(Event& e) override {} void on_update() override; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; void on_collide(std::shared_ptr collider) override; int count = 0; Timer moveTimer; @@ -18,7 +18,7 @@ class Lava : public TileEntity { class LavaGenerator : public TileEntity { void on_event(Event& e) override {} void on_update() override; - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; void on_collide(std::shared_ptr collider) override; public: LavaGenerator() : TileEntity(true) {} @@ -27,7 +27,7 @@ class LavaGenerator : public TileEntity { class Spike : public TileEntity { void on_event(Event& e) override {} void on_update() override {} - void draw(GeometryRenderer& painter) override; + void draw(Camera& painter) override; void on_collide(std::shared_ptr collider) override; public: Spike() : TileEntity(true) {} diff --git a/graphics/camera.cpp b/graphics/camera.cpp index 1591ba5..cabd5fd 100644 --- a/graphics/camera.cpp +++ b/graphics/camera.cpp @@ -11,13 +11,37 @@ Camera::Camera(TerminalScreen& screen, int width, int height, std::vector= 0) && (cameraMapped.y >= 0)) { + if ((cameraMapped.x <= width) && (cameraMapped.y <= height)) { + TextRenderManager::draw(cameraMapped, c, layerName); + } + } + } + else drawAbsolute(coord, c, layerName); +} + +void Camera::draw(Coordinate coord, std::wstring c, std::string layerName) { + if (!absolute) { + Coordinate cameraMapped(coord.x - origin.x, coord.y - origin.y); + if ((cameraMapped.x >= 0) && (cameraMapped.y >= 0)) { + if ((cameraMapped.x <= width) && (cameraMapped.y <= height)) { + TextRenderManager::draw(cameraMapped, c, layerName); + } + } + } + else drawAbsolute(coord, c, layerName); +} +#else +void Camera::draw(Coordinate coord, char c, std::string layerName) { + if (!absolute) { + Coordinate cameraMapped(coord.x - origin.x, coord.y - origin.y); if ((cameraMapped.x >= 0) && (cameraMapped.y >= 0)) { if ((cameraMapped.x <= width) && (cameraMapped.y <= height)) { TextRenderManager::draw(cameraMapped, c, layerName); @@ -31,6 +55,8 @@ void Camera::drawAbsolute(Coordinate coord, char c, std::string layerName) { TextRenderManager::draw(coord, c, layerName); } +#endif + void Camera::toggleAbsolute() { if (absolute) absolute = false; else absolute = true; @@ -56,5 +82,17 @@ void Camera::on_event(Event& e) { SpylikeEvents::CameraEvent& ce = dynamic_cast(e); setOrigin(ce.pos); } + if (e.type == "CAMERA_MoveCenter") { + SpylikeEvents::CameraEvent& ce = dynamic_cast(e); + setOrigin(Coordinate(ce.pos.x-getScreenWidth()/2, ce.pos.y-getScreenHeight()/2)); + } + if (e.type == "CAMERA_MoveCenterH") { + SpylikeEvents::CameraEvent& ce = dynamic_cast(e); + setOrigin(Coordinate(ce.pos.x-getScreenWidth()/2, origin.y)); + } + if (e.type == "CAMERA_MoveCenterV") { + SpylikeEvents::CameraEvent& ce = dynamic_cast(e); + setOrigin(Coordinate(origin.x, ce.pos.y-getScreenHeight()/2)); + } } diff --git a/graphics/rendering.cpp b/graphics/rendering.cpp index cae45c0..8559edf 100644 --- a/graphics/rendering.cpp +++ b/graphics/rendering.cpp @@ -8,6 +8,7 @@ #include #include #include +#include extern SpylikeLogger LOGGER; @@ -19,11 +20,38 @@ TextRenderManager::TextRenderManager(TerminalScreen& scr, std::vector rows; + std::wstring brow; + #else std::vector rows; std::string brow; + #endif for (int j=0; j 1) { for (int y=0; y<=lastDelta; y++) { - manager.draw(Coordinate(currentPos.x, currentPos.y-(y*signY)), c, layerName); + draw(Coordinate(currentPos.x, currentPos.y-(y*signY)), c, layerName); } } currentPos.x += signX; } } -void GeometryRenderer::drawBox(Coordinate p1, Coordinate p2, std::string layerName) { +void TextRenderManager::drawBox(Coordinate p1, Coordinate p2, std::string layerName) { Coordinate p3 = Coordinate(p1.x, p2.y); Coordinate p4 = Coordinate(p2.x, p1.y); drawLine(p1, p3, '|', layerName); @@ -166,11 +221,3 @@ void GeometryRenderer::drawBox(Coordinate p1, Coordinate p2, std::string layerNa drawLine(p2, p3, '-', layerName); drawLine(p1, p4, '-', layerName); } - -int GeometryRenderer::getScreenWidth() { - return manager.getScreenWidth(); -} - -int GeometryRenderer::getScreenHeight() { - return manager.getScreenHeight(); -} diff --git a/graphics/screen.cpp b/graphics/screen.cpp index 60995c1..ec7478d 100644 --- a/graphics/screen.cpp +++ b/graphics/screen.cpp @@ -7,7 +7,7 @@ extern SpylikeLogger LOGGER; NcursesTerminalScreen::NcursesTerminalScreen(int w, int h) : TerminalScreen(w, h) { - setlocale(LC_ALL, "en_US.UTF-8"); + setlocale(LC_ALL, ""); initscr(); cbreak(); noecho(); @@ -24,6 +24,14 @@ void NcursesTerminalScreen::write(int x, int y, char c) { mvwaddch(win, y, x, c); } +#ifdef USE_NCURSESW +void NcursesTerminalScreen::write(int x, int y, std::wstring c) { + assert(x <= width); + assert(y <= height); + mvwaddwstr(win, y, x, c.c_str()); +} +#endif + void NcursesTerminalScreen::write(int x, int y, std::string s) { assert(x <= width); assert(y <= height); diff --git a/include/camera.h b/include/camera.h index f752353..036ae4e 100644 --- a/include/camera.h +++ b/include/camera.h @@ -12,19 +12,22 @@ class Camera : public TextRenderManager, public EventHandler { Coordinate origin; int width; int height; - int offsetX=0; - int offsetY=0; bool absolute=false; public: Camera(TerminalScreen& screen, int width, int height, std::vector layers); void setOrigin(Coordinate pos); - void setOffset(int x, int y); - int getXOffset() { return offsetX; } - int getYOffset() { return offsetY; } Coordinate getOrigin(); // takes a world coordinate, converts to camera coordinates and draws. + #ifdef USE_NCURSESW + void draw(Coordinate coord, char c, std::string layerName) override; + void draw(Coordinate coord, std::wstring c, std::string layerName) override; + template void drawAbsolute(Coordinate coord, Char c, std::string layerName) { + TextRenderManager::draw(coord, c, layerName); + } + #else void draw(Coordinate coord, char c, std::string layerName) override; void drawAbsolute(Coordinate coord, char c, std::string layerName); + #endif void toggleAbsolute(); void on_event(Event& e) override; }; diff --git a/include/entity.h b/include/entity.h index 5d0dcd0..c6b28fb 100644 --- a/include/entity.h +++ b/include/entity.h @@ -11,7 +11,7 @@ class ManagedEntity : public TileEntity { public: TileEntity& parent; void on_update(); - void draw(GeometryRenderer& painter); + void draw(Camera& painter); void on_event(Event& e); }; diff --git a/include/levelmap.h b/include/levelmap.h index fb68c27..c4855da 100644 --- a/include/levelmap.h +++ b/include/levelmap.h @@ -3,6 +3,7 @@ #include "objects.h" #include "rendering.h" +#include "camera.h" #include "logger.h" #include #include @@ -24,15 +25,16 @@ typedef int EntityID; enum WorldType { Roguelike, Platform }; -class TileEntity : public SpritedObject, public std::enable_shared_from_this { +class Camera; // forward dec defined in camera.h + +class TileEntity : public Object, public std::enable_shared_from_this { std::shared_ptr parent = nullptr; std::vector> children; bool alive = true; protected: std::shared_ptr world; public: - // getter/setter - const bool isCollidable; + bool isCollidable; const Tile* tile = nullptr; void setTile(Tile* tileObj); void setParent(std::shared_ptr ent); @@ -47,6 +49,7 @@ class TileEntity : public SpritedObject, public std::enable_shared_from_this collider) {} + virtual void draw(Camera& painter) = 0; TileEntity(bool collidable) : isCollidable{collidable} {} }; @@ -72,13 +75,14 @@ class LevelMap : public std::enable_shared_from_this { int currentID; int getNextID(); public: + bool active = true; const int width; const int height; const WorldType worldType; LevelMap(int width, int height, std::shared_ptr eventManager, IDBlock idRange, WorldType wt=Platform); std::shared_ptr getTile(Coordinate coord); void updateTile(Coordinate coord); - void drawTile(Coordinate coord, GeometryRenderer& painter); + void drawTile(Coordinate coord, Camera& painter); void destroyTile(Coordinate coord); std::shared_ptr findEntity(int entityID); // Searches for entities of type Ent within range tiles of origin and returns them. If range=0, searches everything @@ -103,11 +107,12 @@ class LevelMap : public std::enable_shared_from_this { }; struct Level { + std::string title; WorldType worldType; int width; int height; std::map, Coordinate> entities; - Level(WorldType wt, int w, int h, std::map, Coordinate> entities) : worldType{wt}, width{w}, height{h}, entities{entities} {} + Level(std::string title, WorldType wt, int w, int h, std::map, Coordinate> entities) : title{title}, worldType{wt}, width{w}, height{h}, entities{entities} {} }; #endif diff --git a/include/logger.h b/include/logger.h index 7426f7d..7677ccd 100644 --- a/include/logger.h +++ b/include/logger.h @@ -6,6 +6,11 @@ #include #include +#ifdef USE_NCURSESW +#include +#include +#endif + enum LogLevel {DEBUG=0, ERROR=1, CRITICAL=2}; class SpylikeLogger { @@ -30,6 +35,14 @@ class SpylikeLogger { logfile.close(); } } + #ifdef USE_NCURSESW + // Based on https://stackoverflow.com/questions/4804298/how-to-convert-wstring-into-string + void log(std::wstring text, LogLevel level) { + std::wstring_convert, wchar_t> converter; + std::string converted = converter.to_bytes(text); + log(converted, level); + } + #endif private: std::string filename; LogLevel loglevel; diff --git a/include/objects.h b/include/objects.h index 12e3dd2..4a390af 100644 --- a/include/objects.h +++ b/include/objects.h @@ -35,7 +35,7 @@ class Object : public EventHandler { class SpritedObject : public Object { public: - virtual void draw(GeometryRenderer& painter) = 0; + virtual void draw(TextRenderManager& painter) = 0; }; diff --git a/include/rendering.h b/include/rendering.h index 538dda8..d4df5d0 100644 --- a/include/rendering.h +++ b/include/rendering.h @@ -51,7 +51,11 @@ struct coordHash { class TextRenderManager { TerminalScreen& screen; + #ifdef USE_NCURSESW + typedef std::unordered_map TextLayer; + #else typedef std::unordered_map TextLayer; + #endif std::unordered_map layersCache; //std::unordered_map toUpdate; std::vector orderedLayers; @@ -59,28 +63,25 @@ class TextRenderManager { public: TextRenderManager(TerminalScreen& screen, std::vector layers); virtual void draw(Coordinate coord, char c, std::string layerName); + #ifdef USE_NCURSESW + virtual void draw(Coordinate coord, std::wstring c, std::string layerName); + #endif void renderToScreen(); - void clearLayer(std::string layerName); + void clearLayer(std::string layerName); void clearCache(); void clearScreen(); - void lock() { locked = true; } // prevents any new draws from taking effect - pauses the camera - void unlock() { locked = false; } - int getScreenWidth(); - int getScreenHeight(); - std::string getSnapshot(); -}; - -class GeometryRenderer { - protected: - TextRenderManager& manager; - public: - GeometryRenderer(TextRenderManager& renderManager); - void draw(Coordinate coord, char c, std::string layerName); + void lock() { locked = true; } // prevents any new draws from taking effect - pauses the camera + void unlock() { locked = false; } void drawString(Coordinate pos, std::string str, std::string layerName); void drawLine(Coordinate p1, Coordinate p2, char c, std::string layerName); void drawBox(Coordinate p1, Coordinate p2, std::string layerName); - int getScreenWidth(); - int getScreenHeight(); + int getScreenWidth(); + int getScreenHeight(); + #ifdef USE_NCURSESW + std::wstring getSnapshot(); + #else + std::string getSnapshot(); + #endif }; #endif diff --git a/include/screen.h b/include/screen.h index d76df90..c11bb55 100644 --- a/include/screen.h +++ b/include/screen.h @@ -16,6 +16,9 @@ class TerminalScreen { const int height; TerminalScreen(int w, int h) : width{w}, height{h} {} virtual void write(int x, int y, char c) = 0; + #ifdef USE_NCURSESW + virtual void write(int x, int y, std::wstring c) = 0; + #endif virtual void write(int x, int y, std::string s) = 0; virtual void update() = 0; //virtual char* read(int x, int y) = 0; @@ -31,8 +34,11 @@ class NcursesTerminalScreen : public TerminalScreen { public: NcursesTerminalScreen(int w, int h); void write(int x, int y, char c); + #ifdef USE_NCURSESW + void write(int x, int y, std::wstring c); + #endif void write(int x, int y, std::string s); - void update(); + void update(); //char* read(int x, int y); char getInput(); //MouseEvent getMouse(); diff --git a/include/worldentities.h b/include/worldentities.h index d18d0a0..94299af 100644 --- a/include/worldentities.h +++ b/include/worldentities.h @@ -13,7 +13,7 @@ class GeometryTile : public TileEntity { char sprite; public: GeometryTile(char sprite) : sprite(sprite) {} - void on_draw(GeometryRenderer& painter); + void on_draw(Camera& painter); }; #endif diff --git a/level/entity.cpp b/level/entity.cpp index a825562..32999b1 100644 --- a/level/entity.cpp +++ b/level/entity.cpp @@ -5,7 +5,7 @@ //TODO: Still not entirely sure how to implement this and how it will be used void ManagedEntity::on_update() { parent.update(); } -void ManagedEntity::draw(GeometryRenderer& painter) { parent.draw(painter); } +void ManagedEntity::draw(Camera& painter) { parent.draw(painter); } void ManagedEntity::on_event(Event& e) { parent.event(e); } void ManagerEntity::createChild(Coordinate pos) { } diff --git a/level/levelmap.cpp b/level/levelmap.cpp index 27900ae..a7c038d 100644 --- a/level/levelmap.cpp +++ b/level/levelmap.cpp @@ -67,8 +67,10 @@ std::vector> Tile::getEntities() { } void TileEntity::kill() { - world->removeEntity(shared_from_this()); - alive = false; + if (alive) { + world->removeEntity(shared_from_this()); + alive = false; + } } bool TileEntity::isAlive() { @@ -134,16 +136,18 @@ void LevelMap::destroyTile(Coordinate coord) { } void LevelMap::removeEntity(std::shared_ptr ent) { - auto currentTile = getTile(ent->tile->pos); // entity's tile is const - if (currentTile) { - currentTile->removeEntity(ent->getID()); - if (currentTile->getEntities().size() == 0) { - destroyTile(currentTile->pos); - } - for (auto child : ent->getChildren()) { - removeEntity(child); + if (ent) { + auto currentTile = getTile(ent->tile->pos); // entity's tile is const + if (currentTile) { + currentTile->removeEntity(ent->getID()); + if (currentTile->getEntities().size() == 0) { + destroyTile(currentTile->pos); + } + for (auto child : ent->getChildren()) { + removeEntity(child); + } + trackedEntities.erase(ent->getID()); } - trackedEntities.erase(ent->getID()); } } @@ -167,6 +171,7 @@ std::shared_ptr LevelMap::findEntity(int entityID) { bool LevelMap::moveEntity(std::shared_ptr ent, Coordinate pos) { LOGGER.log("Moving entity " + std::to_string(ent->getID()) + " to coordinate (" + std::to_string(pos.x) + "," + std::to_string(pos.y) + ")", DEBUG); + if (!isInMap(pos)) return false; if (ent) { std::vector> movedChildren; bool result = false; @@ -227,7 +232,7 @@ void LevelMap::updateTile(Coordinate coord) { } } -void LevelMap::drawTile(Coordinate coord, GeometryRenderer& painter) { +void LevelMap::drawTile(Coordinate coord, Camera& painter) { std::shared_ptr tile = getTile(coord); if (tile != nullptr) { for (auto ent : tile->getEntities()) { diff --git a/lib/discord-rpc-linux/linux-dynamic/include/discord_register.h b/lib/discord-rpc-linux/linux-dynamic/include/discord_register.h new file mode 100644 index 0000000..16fb42f --- /dev/null +++ b/lib/discord-rpc-linux/linux-dynamic/include/discord_register.h @@ -0,0 +1,26 @@ +#pragma once + +#if defined(DISCORD_DYNAMIC_LIB) +#if defined(_WIN32) +#if defined(DISCORD_BUILDING_SDK) +#define DISCORD_EXPORT __declspec(dllexport) +#else +#define DISCORD_EXPORT __declspec(dllimport) +#endif +#else +#define DISCORD_EXPORT __attribute__((visibility("default"))) +#endif +#else +#define DISCORD_EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command); +DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId); + +#ifdef __cplusplus +} +#endif diff --git a/lib/discord-rpc-linux/linux-dynamic/include/discord_rpc.h b/lib/discord-rpc-linux/linux-dynamic/include/discord_rpc.h new file mode 100644 index 0000000..2fd8683 --- /dev/null +++ b/lib/discord-rpc-linux/linux-dynamic/include/discord_rpc.h @@ -0,0 +1,124 @@ +#pragma once +#include + +// clang-format off + +#if defined(DISCORD_DYNAMIC_LIB) +# if defined(_WIN32) +# if defined(DISCORD_BUILDING_SDK) +# define DISCORD_EXPORT __declspec(dllexport) +# else +# define DISCORD_EXPORT __declspec(dllimport) +# endif +# else +# define DISCORD_EXPORT __attribute__((visibility("default"))) +# endif +#else +# define DISCORD_EXPORT +#endif + +// clang-format on + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DiscordButton { + const char* label; + const char* url; +} DiscordButton; + +typedef struct DiscordRichPresence { + const char* state; /* max 128 bytes */ + const char* details; /* max 128 bytes */ + int64_t startTimestamp; + int64_t endTimestamp; + const char* largeImageKey; /* max 32 bytes */ + const char* largeImageText; /* max 128 bytes */ + const char* smallImageKey; /* max 32 bytes */ + const char* smallImageText; /* max 128 bytes */ + const char* partyId; /* max 128 bytes */ + int partySize; + int partyMax; + int partyPrivacy; + const char* matchSecret; /* max 128 bytes */ + const char* joinSecret; /* max 128 bytes */ + const char* spectateSecret; /* max 128 bytes */ + int8_t instance; + const DiscordButton* buttons; +} DiscordRichPresence; + +typedef struct DiscordUser { + const char* userId; + const char* username; + const char* discriminator; + const char* globalName; + const char* avatar; +} DiscordUser; + +typedef struct DiscordEventHandlers { + void (*ready)(const DiscordUser* user); + void (*disconnected)(int errorCode, const char* message); + void (*errored)(int errorCode, const char* message); + void (*debug)(char isOut, const char* opcodeName, const char* message, uint32_t messageLength); + void (*joinGame)(const char* joinSecret); + void (*spectateGame)(const char* spectateSecret); + void (*joinRequest)(const DiscordUser* user); + void (*invited)(/* DISCORD_ACTIVITY_ACTION_TYPE_ */ int8_t type, + const DiscordUser* user, + const DiscordRichPresence* activity, + const char* sessionId, + const char* channelId, + const char* messageId); +} DiscordEventHandlers; + +#define DISCORD_REPLY_NO 0 +#define DISCORD_REPLY_YES 1 +#define DISCORD_REPLY_IGNORE 2 + +#define DISCORD_PARTY_PRIVATE 0 +#define DISCORD_PARTY_PUBLIC 1 + +#define DISCORD_ACTIVITY_ACTION_TYPE_JOIN 1 +#define DISCORD_ACTIVITY_ACTION_TYPE_SPECTATE 2 + +#define DISCORD_ACTIVITY_TYPE_PLAYING 0 +#define DISCORD_ACTIVITY_TYPE_STREAMING 1 +#define DISCORD_ACTIVITY_TYPE_LISTENING 2 +#define DISCORD_ACTIVITY_TYPE_WATCHING 3 +#define DISCORD_ACTIVITY_TYPE_CUSTOM 4 +#define DISCORD_ACTIVITY_TYPE_COMPETING 5 + +DISCORD_EXPORT void Discord_Initialize(const char* applicationId, + DiscordEventHandlers* handlers, + int autoRegister, + const char* optionalSteamId); +DISCORD_EXPORT void Discord_Shutdown(void); + +/* checks for incoming messages, dispatches callbacks */ +DISCORD_EXPORT void Discord_RunCallbacks(void); + +/* If you disable the lib starting its own io thread, you'll need to call this from your own */ +#ifdef DISCORD_DISABLE_IO_THREAD +DISCORD_EXPORT void Discord_UpdateConnection(void); +#endif + +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); +DISCORD_EXPORT void Discord_ClearPresence(void); + +DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); + +DISCORD_EXPORT void Discord_AcceptInvite(const char* userId, + /* DISCORD_ACTIVITY_ACTION_TYPE_ */ int8_t type, + const char* sessionId, + const char* channelId, + const char* messageId); + +DISCORD_EXPORT void Discord_OpenActivityInvite(/* DISCORD_ACTIVITY_ACTION_TYPE_ */ int8_t type); +DISCORD_EXPORT void Discord_OpenGuildInvite(const char* code); + +DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers); + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/lib/discord-rpc-linux/linux-dynamic/lib/libdiscord-rpc.so b/lib/discord-rpc-linux/linux-dynamic/lib/libdiscord-rpc.so new file mode 100644 index 0000000..2252159 Binary files /dev/null and b/lib/discord-rpc-linux/linux-dynamic/lib/libdiscord-rpc.so differ diff --git a/lib/discord-rpc-linux/linux-static/include/discord_register.h b/lib/discord-rpc-linux/linux-static/include/discord_register.h new file mode 100644 index 0000000..16fb42f --- /dev/null +++ b/lib/discord-rpc-linux/linux-static/include/discord_register.h @@ -0,0 +1,26 @@ +#pragma once + +#if defined(DISCORD_DYNAMIC_LIB) +#if defined(_WIN32) +#if defined(DISCORD_BUILDING_SDK) +#define DISCORD_EXPORT __declspec(dllexport) +#else +#define DISCORD_EXPORT __declspec(dllimport) +#endif +#else +#define DISCORD_EXPORT __attribute__((visibility("default"))) +#endif +#else +#define DISCORD_EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command); +DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId); + +#ifdef __cplusplus +} +#endif diff --git a/lib/discord-rpc-linux/linux-static/include/discord_rpc.h b/lib/discord-rpc-linux/linux-static/include/discord_rpc.h new file mode 100644 index 0000000..2fd8683 --- /dev/null +++ b/lib/discord-rpc-linux/linux-static/include/discord_rpc.h @@ -0,0 +1,124 @@ +#pragma once +#include + +// clang-format off + +#if defined(DISCORD_DYNAMIC_LIB) +# if defined(_WIN32) +# if defined(DISCORD_BUILDING_SDK) +# define DISCORD_EXPORT __declspec(dllexport) +# else +# define DISCORD_EXPORT __declspec(dllimport) +# endif +# else +# define DISCORD_EXPORT __attribute__((visibility("default"))) +# endif +#else +# define DISCORD_EXPORT +#endif + +// clang-format on + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DiscordButton { + const char* label; + const char* url; +} DiscordButton; + +typedef struct DiscordRichPresence { + const char* state; /* max 128 bytes */ + const char* details; /* max 128 bytes */ + int64_t startTimestamp; + int64_t endTimestamp; + const char* largeImageKey; /* max 32 bytes */ + const char* largeImageText; /* max 128 bytes */ + const char* smallImageKey; /* max 32 bytes */ + const char* smallImageText; /* max 128 bytes */ + const char* partyId; /* max 128 bytes */ + int partySize; + int partyMax; + int partyPrivacy; + const char* matchSecret; /* max 128 bytes */ + const char* joinSecret; /* max 128 bytes */ + const char* spectateSecret; /* max 128 bytes */ + int8_t instance; + const DiscordButton* buttons; +} DiscordRichPresence; + +typedef struct DiscordUser { + const char* userId; + const char* username; + const char* discriminator; + const char* globalName; + const char* avatar; +} DiscordUser; + +typedef struct DiscordEventHandlers { + void (*ready)(const DiscordUser* user); + void (*disconnected)(int errorCode, const char* message); + void (*errored)(int errorCode, const char* message); + void (*debug)(char isOut, const char* opcodeName, const char* message, uint32_t messageLength); + void (*joinGame)(const char* joinSecret); + void (*spectateGame)(const char* spectateSecret); + void (*joinRequest)(const DiscordUser* user); + void (*invited)(/* DISCORD_ACTIVITY_ACTION_TYPE_ */ int8_t type, + const DiscordUser* user, + const DiscordRichPresence* activity, + const char* sessionId, + const char* channelId, + const char* messageId); +} DiscordEventHandlers; + +#define DISCORD_REPLY_NO 0 +#define DISCORD_REPLY_YES 1 +#define DISCORD_REPLY_IGNORE 2 + +#define DISCORD_PARTY_PRIVATE 0 +#define DISCORD_PARTY_PUBLIC 1 + +#define DISCORD_ACTIVITY_ACTION_TYPE_JOIN 1 +#define DISCORD_ACTIVITY_ACTION_TYPE_SPECTATE 2 + +#define DISCORD_ACTIVITY_TYPE_PLAYING 0 +#define DISCORD_ACTIVITY_TYPE_STREAMING 1 +#define DISCORD_ACTIVITY_TYPE_LISTENING 2 +#define DISCORD_ACTIVITY_TYPE_WATCHING 3 +#define DISCORD_ACTIVITY_TYPE_CUSTOM 4 +#define DISCORD_ACTIVITY_TYPE_COMPETING 5 + +DISCORD_EXPORT void Discord_Initialize(const char* applicationId, + DiscordEventHandlers* handlers, + int autoRegister, + const char* optionalSteamId); +DISCORD_EXPORT void Discord_Shutdown(void); + +/* checks for incoming messages, dispatches callbacks */ +DISCORD_EXPORT void Discord_RunCallbacks(void); + +/* If you disable the lib starting its own io thread, you'll need to call this from your own */ +#ifdef DISCORD_DISABLE_IO_THREAD +DISCORD_EXPORT void Discord_UpdateConnection(void); +#endif + +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); +DISCORD_EXPORT void Discord_ClearPresence(void); + +DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); + +DISCORD_EXPORT void Discord_AcceptInvite(const char* userId, + /* DISCORD_ACTIVITY_ACTION_TYPE_ */ int8_t type, + const char* sessionId, + const char* channelId, + const char* messageId); + +DISCORD_EXPORT void Discord_OpenActivityInvite(/* DISCORD_ACTIVITY_ACTION_TYPE_ */ int8_t type); +DISCORD_EXPORT void Discord_OpenGuildInvite(const char* code); + +DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers); + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/lib/discord-rpc-linux/linux-static/lib/libdiscord-rpc.a b/lib/discord-rpc-linux/linux-static/lib/libdiscord-rpc.a new file mode 100644 index 0000000..ea5a933 Binary files /dev/null and b/lib/discord-rpc-linux/linux-static/lib/libdiscord-rpc.a differ diff --git a/log2.txt b/log2.txt deleted file mode 100644 index a1de2f2..0000000 --- a/log2.txt +++ /dev/null @@ -1 +0,0 @@ -[?1049h(B[?7h[?1006;1000hHealth: 100~~~~~~~~~~~~~Time elapsed: 0:0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~!~~~~$~~~~~~~~~~~~~~~~~~~~~~ ~~~~ ~~~~~~@~~~#########~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~###### -------------------------------------------------------------------------------|WELCOME TO SPYLIKE! |CONTROLS: |W,A,S,D MOVEMENT |V,B,N,G ATTACK |ESC PAUSE |||| |v |------------------------------ ||||| || Start game || Quit | ||||| |------------------------------ ||||||||||||||-------------------------------------------------------------------------------|v | | | v|v | | | v|v | | | v|v | | | v|v | | | v[?1006;1000l[?1049l [?1l> \ No newline at end of file diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..6856e14 Binary files /dev/null and b/logo.png differ