diff --git a/.dockerignore b/.dockerignore
index 169e1b6..4d7abb3 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,6 +2,10 @@
 cmake-build-debug/
 cmake-build-release/
 
+# IDE folders
+.vscode/
+.idea/
+
 # Dockerfile (in order to allow changes without rebuilding)
 Dockerfile
 
diff --git a/Dockerfile b/Dockerfile
index d4ec8c1..4e2fe96 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,7 +17,7 @@ ENV VCPKG_FORCE_SYSTEM_BINARIES=1
 # Install vcpkg and the required libraries
 RUN git clone https://github.com/Microsoft/vcpkg.git
 RUN bash ./vcpkg/bootstrap-vcpkg.sh
-RUN ./vcpkg/vcpkg install boost-system cryptopp effolkronium-random libmysql libevent lzo fmt spdlog argon2
+RUN ./vcpkg/vcpkg install cryptopp effolkronium-random libmariadb libevent lzo fmt spdlog argon2
 
 COPY . .
 
diff --git a/README.md b/README.md
index f07e890..0a85423 100644
--- a/README.md
+++ b/README.md
@@ -7,14 +7,34 @@ For-profit usage of this material is certainly illegal without the proper
 licensing agreements and is hereby discouraged (not legal advice). Even so, the
 nature of this project is HIGHLY EXPERIMENTAL - bugs are to be expected for now.
 
-## 1. Building and usage
-
-### A. Use Docker to instantly bring up a server (recommended)
+## 1. Usage
 We aim to provide Docker images which _just work_ for your convenience.
 A Docker Compose project is maintained in the [Deployment project](https://git.old-metin2.com/metin2/deploy).
 Please head over there for further instructions.
 
-### B. Build the binaries yourself (for advanced users)
+## 2. Building
+### A. Building Docker images
+#### Building a Docker image from the repository
+In order to build a local Docker image on your local architecture, just build the
+provided Dockerfile in this project:
+
+```shell
+docker build -t metin2/server:test --provenance=false .
+```
+
+#### Publishing a multiplatform Docker image manually
+This command is reserved only for repository maintainers in order to publish
+new Docker images for public use with the Deployment project.
+
+**WARNING:** Using WSL for building might lead to QEMU segmentation fault issues;
+this can be worked around by using `binfmt` and `qemu-user-static` as described 
+[here](https://github.com/docker/buildx/issues/1170#issuecomment-1159350550).
+
+```shell
+docker build --push -t git.old-metin2.com/metin2/server:<IMAGE-TAG-HERE> --platform linux/amd64,linux/arm64 --provenance=false .
+```
+
+### B. Building the binaries yourself (for advanced users)
 _Sadly, we're unable to provide hand-holding services. You should have some C++ development experience
 going forward with this route._
 
@@ -23,6 +43,7 @@ variety. This project is also compatible with WSL, even though WSL can be buggy
 at times. FreeBSD/Windows compatibility is untested and unsupported for the
 time being - there are other projects out there if that's what you want.
 
+#### Setting up the requirements
 On your Linux box, install the dependencies for `vcpkg` and the other libraries
 we're going to install.
 ```shell
@@ -39,18 +60,21 @@ Install `vcpkg` according to the [latest instructions](https://vcpkg.io/en/getti
 
 Build and install the required libraries:
 ```shell
-vcpkg install boost-system cryptopp effolkronium-random libmysql libevent lzo fmt spdlog argon2
+vcpkg install cryptopp effolkronium-random libmariadb libevent lzo fmt spdlog argon2
 ```
 
-Then, it's time to build your binaries. Your commands should look along the lines of:
+#### Building the binaries
+Instead of building the binaries directly from the CLI, we recommend using an IDE, since
+you're probably doing some kind of development anyway. See the "Development" section for more information on that.
+
+If you decide do build from the command line, make sure to find the right path for `vcpkg.cmake` and run the following:
 ```shell
 mkdir build/
 cd build && cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake ..
 make -j $(nproc)
 ```
 
-If everything goes right, you should now have compiled binaries you should just be able to use
-as a drop-in replacement for your BSD binaries in your favourite serverfiles.
+If everything goes right, you should now have compiled binaries in the `build/` directory.
 
 ## 2. Development
 The preferred IDE in order to develop and debug the server is [CLion](https://www.jetbrains.com/clion/),
@@ -103,7 +127,6 @@ This is a very serious security risk and one of the reasons this project is stil
 
 ## 5. Further plans
 - Migrate `db.conf` and `game.conf` to a modern dotenv-like format, which would enable pretty nice Docker images.
-- Add a health check to the Docker image.
 - Use the [fmt](https://fmt.dev/latest/index.html) library for safe and modern string formatting.
 - Handle kernel signals (SIGTERM, SIGHUP etc.) for gracefully shutting down the game server.
 - Improve memory safety.
diff --git a/src/db/CMakeLists.txt b/src/db/CMakeLists.txt
index 36a78d3..88d9380 100644
--- a/src/db/CMakeLists.txt
+++ b/src/db/CMakeLists.txt
@@ -20,23 +20,19 @@ endif()
 # Treat char variables as signed, especially useful for ARM builds
 target_compile_options(${PROJECT_NAME} PUBLIC -fsigned-char)
 
-# Find dependencies
+# Find and link dependencies
 
 #
 # vcpkg dependencies
 #
 
-# Boost
-find_package(Boost COMPONENTS system REQUIRED)
-target_link_libraries (${PROJECT_NAME} PRIVATE Boost::boost Boost::system)
-
 # Libevent
 find_package(Libevent CONFIG REQUIRED)
-target_link_libraries(${PROJECT_NAME} PRIVATE libevent::core libevent::extra libevent::pthreads)
+target_link_libraries(${PROJECT_NAME} libevent::core libevent::extra libevent::pthreads)
 
 # effolkronium/random
 find_package(effolkronium_random CONFIG REQUIRED)
-target_link_libraries(${PROJECT_NAME} PRIVATE effolkronium_random)
+target_link_libraries(${PROJECT_NAME} effolkronium_random)
 
 #
 # System-provided dependencies
@@ -45,9 +41,9 @@ target_link_libraries(${PROJECT_NAME} PRIVATE effolkronium_random)
 # Pthreads
 set(THREADS_PREFER_PTHREAD_FLAG ON)
 find_package(Threads REQUIRED)
-target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads)
+target_link_libraries(${PROJECT_NAME} Threads::Threads)
 
 # LibBSD
-target_link_libraries(${PROJECT_NAME} PRIVATE bsd)
+target_link_libraries(${PROJECT_NAME} bsd)
 
-target_link_libraries(${PROJECT_NAME} PRIVATE libpoly libsql libthecore)
+target_link_libraries(${PROJECT_NAME} libpoly libsql libthecore)
diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt
index 12c85b8..776ec90 100644
--- a/src/game/CMakeLists.txt
+++ b/src/game/CMakeLists.txt
@@ -20,15 +20,15 @@ endif()
 # Treat char variables as signed, especially useful for ARM builds
 target_compile_options(${PROJECT_NAME} PUBLIC -fsigned-char)
 
-# Find dependencies
+# Find and link dependencies
 
 #
 # vcpkg dependencies
 #
 
-# MySQL
-find_package(unofficial-libmysql REQUIRED)
-target_link_libraries(${PROJECT_NAME} unofficial::libmysql::libmysql)
+# MariaDB
+find_package(unofficial-libmariadb REQUIRED)
+target_link_libraries(${PROJECT_NAME} unofficial::libmariadb)
 
 # Argon2
 find_package(unofficial-argon2 CONFIG REQUIRED)
@@ -36,11 +36,7 @@ target_link_libraries(${PROJECT_NAME} unofficial::argon2::libargon2)
 
 # Crypto++
 find_package(cryptopp CONFIG REQUIRED)
-target_link_libraries (${PROJECT_NAME} cryptopp::cryptopp)
-
-# Boost
-find_package(Boost REQUIRED)
-target_link_libraries (${PROJECT_NAME} Boost::boost)
+target_link_libraries(${PROJECT_NAME} cryptopp::cryptopp)
 
 # Libevent
 find_package(Libevent CONFIG REQUIRED)
diff --git a/src/game/src/DragonSoul.cpp b/src/game/src/DragonSoul.cpp
index 6d3a249..21dfede 100644
--- a/src/game/src/DragonSoul.cpp
+++ b/src/game/src/DragonSoul.cpp
@@ -9,7 +9,6 @@
 #include "dragon_soul_table.h"
 #include "log.h"
 #include "DragonSoul.h"
-#include <boost/lexical_cast.hpp>
 
 typedef std::vector <std::string> TTokenVector;
 
@@ -389,7 +388,7 @@ bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtract
 		pDH->SetSocket(ITEM_SOCKET_CHARGING_AMOUNT_IDX, iCharge);
 		ch->AutoGiveItem(pDH, true);
 
-		std::string s = boost::lexical_cast <std::string> (iCharge);
+		std::string s = std::to_string(iCharge);
 		s += "%s";
 		LogManager::instance().ItemLog(ch, pItem, "DS_HEART_EXTRACT_SUCCESS", s.c_str());
 		ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Dragon Stone remaining duration has been extracted."));
diff --git a/src/game/src/IFileMonitor.h b/src/game/src/IFileMonitor.h
index 808919e..4fa0218 100644
--- a/src/game/src/IFileMonitor.h
+++ b/src/game/src/IFileMonitor.h
@@ -1,7 +1,6 @@
 #ifndef IFILEMONITOR_INCLUDED
 #define IFILEMONITOR_INCLUDED
 
-//#include <boost/function.hpp>
 #include <unordered_map>
 
 enum eFileUpdatedOptions
diff --git a/src/game/src/affect.cpp b/src/game/src/affect.cpp
index cde2ac2..7227e89 100644
--- a/src/game/src/affect.cpp
+++ b/src/game/src/affect.cpp
@@ -1,31 +1,13 @@
-
 #include "stdafx.h"
-
-#ifndef DEBUG_ALLOC
-#include <boost/pool/object_pool.hpp>
-#endif
-
 #include "affect.h"
 
-#ifndef DEBUG_ALLOC
-boost::object_pool<CAffect> affect_pool;
-#endif
-
 CAffect* CAffect::Acquire()
 {
-#ifndef DEBUG_ALLOC
-	return affect_pool.malloc();
-#else
 	return M2_NEW CAffect;
-#endif
 }
 
 void CAffect::Release(CAffect* p)
 {
-#ifndef DEBUG_ALLOC
-	affect_pool.free(p);
-#else
 	M2_DELETE(p);
-#endif
 }
 
diff --git a/src/game/src/auction_manager.cpp b/src/game/src/auction_manager.cpp
index 03cbff7..d9cdd88 100644
--- a/src/game/src/auction_manager.cpp
+++ b/src/game/src/auction_manager.cpp
@@ -10,7 +10,6 @@
 #include "item_manager.h"
 #include "log.h"
 #include "db.h"
-#include <boost/bind.hpp>
 #include "item.h"
 #include "desc_client.h"
 #include <common/tables.h>
diff --git a/src/game/src/char.cpp b/src/game/src/char.cpp
index ae92060..b3e8910 100644
--- a/src/game/src/char.cpp
+++ b/src/game/src/char.cpp
@@ -4244,7 +4244,7 @@ bool CHARACTER::RequestToParty(LPCHARACTER leader)
 
 void CHARACTER::DenyToParty(LPCHARACTER member)
 {
-	SPDLOG_DEBUG("DenyToParty {} member {} {}", GetName(), member->GetName(), (void*) get_pointer(member->m_pkPartyRequestEvent));
+	SPDLOG_DEBUG("DenyToParty {} member {} {}", GetName(), member->GetName(), (void*) member->m_pkPartyRequestEvent.get());
 
 	if (!member->m_pkPartyRequestEvent)
 		return;
@@ -4270,7 +4270,7 @@ void CHARACTER::DenyToParty(LPCHARACTER member)
 
 void CHARACTER::AcceptToParty(LPCHARACTER member)
 {
-	SPDLOG_DEBUG("AcceptToParty {} member {} {}", GetName(), member->GetName(), (void*) get_pointer(member->m_pkPartyRequestEvent));
+	SPDLOG_DEBUG("AcceptToParty {} member {} {}", GetName(), member->GetName(), (void*) member->m_pkPartyRequestEvent.get());
 
 	if (!member->m_pkPartyRequestEvent)
 		return;
diff --git a/src/game/src/char_affect.cpp b/src/game/src/char_affect.cpp
index cd5cb4c..d67ddcd 100644
--- a/src/game/src/char_affect.cpp
+++ b/src/game/src/char_affect.cpp
@@ -160,7 +160,7 @@ void CHARACTER::StartAffectEvent()
 	char_event_info* info = AllocEventInfo<char_event_info>();
 	info->ch = this;
 	m_pkAffectEvent = event_create(affect_event, info, passes_per_sec);
-	SPDLOG_DEBUG("StartAffectEvent {} {} {}", GetName(), (void*) this, (void*) get_pointer(m_pkAffectEvent));
+	SPDLOG_DEBUG("StartAffectEvent {} {} {}", GetName(), (void*) this, (void*) m_pkAffectEvent.get());
 }
 
 void CHARACTER::ClearAffect(bool bSave)
diff --git a/src/game/src/char_battle.cpp b/src/game/src/char_battle.cpp
index a7979cb..7a09363 100644
--- a/src/game/src/char_battle.cpp
+++ b/src/game/src/char_battle.cpp
@@ -1420,7 +1420,7 @@ void CHARACTER::Dead(LPCHARACTER pkKiller, bool bImmediateDead)
 	{
 		if (m_pkDeadEvent)
 		{
-			SPDLOG_DEBUG("DEAD_EVENT_CANCEL: {} {} {}", GetName(), (void*) this, (void*) get_pointer(m_pkDeadEvent));
+			SPDLOG_DEBUG("DEAD_EVENT_CANCEL: {} {} {}", GetName(), (void*) this, (void*) m_pkDeadEvent.get());
 			event_cancel(&m_pkDeadEvent);
 		}
 
@@ -1456,7 +1456,7 @@ void CHARACTER::Dead(LPCHARACTER pkKiller, bool bImmediateDead)
 			}
 		}
 
-		SPDLOG_DEBUG("DEAD_EVENT_CREATE: {} {} {}", GetName(), (void*) this, (void*) get_pointer(m_pkDeadEvent));
+		SPDLOG_DEBUG("DEAD_EVENT_CREATE: {} {} {}", GetName(), (void*) this, (void*) m_pkDeadEvent.get());
 	}
 
 	if (m_pkExchange != NULL)
diff --git a/src/game/src/char_manager.cpp b/src/game/src/char_manager.cpp
index f475753..17e92d7 100644
--- a/src/game/src/char_manager.cpp
+++ b/src/game/src/char_manager.cpp
@@ -16,10 +16,6 @@
 #include "questlua.h"
 #include "locale_service.h"
 
-#ifndef __GNUC__
-#include <boost/bind.hpp>
-#endif
-
 CHARACTER_MANAGER::CHARACTER_MANAGER() :
 	m_iVIDCount(0),
 	m_pkChrSelectedStone(NULL),
@@ -646,9 +642,7 @@ struct FuncUpdateAndResetChatCounter
 void CHARACTER_MANAGER::Update(int iPulse)
 {
 	using namespace std;
-#ifdef __GNUC__
 	using namespace __gnu_cxx;
-#endif
 
 	BeginPendingDestroy();
 
@@ -659,11 +653,7 @@ void CHARACTER_MANAGER::Update(int iPulse)
 			// 컨테이너 복사
 			CHARACTER_VECTOR v;
 			v.reserve(m_map_pkPCChr.size());
-#ifdef __GNUC__
 			transform(m_map_pkPCChr.begin(), m_map_pkPCChr.end(), back_inserter(v), select2nd<NAME_MAP::value_type>());
-#else
-			transform(m_map_pkPCChr.begin(), m_map_pkPCChr.end(), back_inserter(v), boost::bind(&NAME_MAP::value_type::second, _1));
-#endif
 
 			if (0 == (iPulse % PASSES_PER_SEC(5)))
 			{
@@ -686,11 +676,8 @@ void CHARACTER_MANAGER::Update(int iPulse)
 		{
 			CHARACTER_VECTOR v;
 			v.reserve(m_set_pkChrState.size());
-#ifdef __GNUC__
 			transform(m_set_pkChrState.begin(), m_set_pkChrState.end(), back_inserter(v), identity<CHARACTER_SET::value_type>());
-#else
-			v.insert(v.end(), m_set_pkChrState.begin(), m_set_pkChrState.end());
-#endif
+
 			for_each(v.begin(), v.end(), bind2nd(mem_fun(&CHARACTER::UpdateStateMachine), iPulse));
 		}
 	}
@@ -1029,16 +1016,10 @@ void CHARACTER_MANAGER::FlushPendingDestroy()
 CharacterVectorInteractor::CharacterVectorInteractor(const CHARACTER_SET & r)
 {
 	using namespace std;
-#ifdef __GNUC__
 	using namespace __gnu_cxx;
-#endif
 
 	reserve(r.size());
-#ifdef __GNUC__
 	transform(r.begin(), r.end(), back_inserter(*this), identity<CHARACTER_SET::value_type>());
-#else
-	insert(end(), r.begin(), r.end());
-#endif
 
 	if (CHARACTER_MANAGER::instance().BeginPendingDestroy())
 		m_bMyBegin = true;
diff --git a/src/game/src/dragon_soul_table.cpp b/src/game/src/dragon_soul_table.cpp
index 2fd7510..40dc078 100644
--- a/src/game/src/dragon_soul_table.cpp
+++ b/src/game/src/dragon_soul_table.cpp
@@ -3,7 +3,7 @@
 #include "group_text_parse_tree.h"
 #include "dragon_soul_table.h"
 #include "item_manager.h"
-#include <boost/lexical_cast.hpp>
+
 const std::string g_astGradeName[] =
 {
 	"grade_normal",
@@ -789,7 +789,7 @@ bool DragonSoulTable::GetRefineStrengthValues(BYTE ds_type, BYTE material_type,
 			stDragonSoulName.c_str(), g_astMaterialName[material_type].c_str());
 		return false;
 	}
-	std::string stStrengthIdx = boost::lexical_cast <std::string> ((int)strength_idx);
+	std::string stStrengthIdx = std::to_string((int)strength_idx);
 
 	if (!m_pRefineStrengthTableNode->GetGroupValue(stDragonSoulName, g_astMaterialName[material_type], stStrengthIdx, prob))
 	{
diff --git a/src/game/src/event.cpp b/src/game/src/event.cpp
index 9b08dd2..942b4fb 100644
--- a/src/game/src/event.cpp
+++ b/src/game/src/event.cpp
@@ -30,7 +30,7 @@ LPEVENT event_create_ex(TEVENTFUNC func, event_info_data* info, int when)
 #ifdef M2_USE_POOL
 	new_event = event_pool.Construct();
 #else
-	new_event = M2_NEW event;
+	new_event = std::make_shared<event>();
 #endif
 
 	assert(NULL != new_event);
@@ -136,7 +136,7 @@ int event_process(int pulse)
 		}
 		else
 		{
-			new_time = (the_event->func) (get_pointer(the_event), processing_time);
+			new_time = (the_event->func) (the_event, processing_time);
 			
 			if (new_time <= 0 || the_event->is_force_to_end)
 			{
@@ -201,17 +201,3 @@ int event_count()
 {
 	return cxx_q.Size();
 }
-
-void intrusive_ptr_add_ref(EVENT* p) {
-	++(p->ref_count);
-}
-
-void intrusive_ptr_release(EVENT* p) {
-	if ( --(p->ref_count) == 0 ) {
-#ifdef M2_USE_POOL
-		event_pool.Destroy(p);
-#else
-		M2_DELETE(p);
-#endif
-	}
-}
diff --git a/src/game/src/event.h b/src/game/src/event.h
index 32b8025..0db8048 100644
--- a/src/game/src/event.h
+++ b/src/game/src/event.h
@@ -4,10 +4,9 @@
  *
  *      Author: 김한주 (aka. 비엽, Cronan), 송영진 (aka. myevan, 빗자루)
  */
-#ifndef __INC_LIBTHECORE_EVENT_H__
-#define __INC_LIBTHECORE_EVENT_H__
+#pragma once
 
-#include <boost/intrusive_ptr.hpp>
+#include <memory>
 
 #ifdef M2_USE_POOL
 #include "pool.h"
@@ -34,7 +33,7 @@ private:
 };
 	
 typedef struct event EVENT;
-typedef boost::intrusive_ptr<EVENT> LPEVENT;
+typedef std::shared_ptr<EVENT> LPEVENT;
 typedef int (*TEVENTFUNC) (LPEVENT event, int processing_time);
 
 #define EVENTFUNC(name)	int (name) (LPEVENT event, int processing_time)
@@ -63,9 +62,6 @@ struct event
 	size_t ref_count;
 };
 
-extern void intrusive_ptr_add_ref(EVENT* p);
-extern void intrusive_ptr_release(EVENT* p);
-
 template<class T> // T should be a subclass of event_info_data
 T* AllocEventInfo() {
 #ifdef M2_USE_POOL
@@ -89,5 +85,3 @@ extern void		event_set_verbose(int level);
 
 extern event_info_data* FindEventInfo(DWORD dwID);
 extern event_info_data*	event_info(LPEVENT event);
-
-#endif
diff --git a/src/game/src/fifo_allocator.h b/src/game/src/fifo_allocator.h
deleted file mode 100644
index 1a6e806..0000000
--- a/src/game/src/fifo_allocator.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef _FIFO_ALLOCATOR_H_
-#define _FIFO_ALLOCATOR_H_
-
-#include <deque>
-
-#ifdef __GNUC__
-#include <tr1/unordered_map>
-#define std std::tr1
-#else
-#include <unordered_map>
-#define std boost
-#endif
-
-// Allocator implementation detail with simple FIFO grow-only pool.
-// It relies on default CRT malloc/free.
-class FifoAllocator {
-public:
-	FifoAllocator() {}
-	~FifoAllocator() {}
-
-	void SetUp() {}
-	void TearDown() {
-		CleanUp(); // deallocate pooled blocks
-	}
-
-	void* Alloc(size_t size) {
-		void* p = NULL;
-		PoolType& pool = pool_map_[size];
-		if (pool.size() < kWatermark) {
-			p = ::malloc(size);
-		} else {
-			p = pool.front();
-			pool.pop_front();
-		}
-		if (p != NULL) {
-			alloc_map_[p] = size;
-		}
-		return p;
-	}
-	void Free(void* p) {
-		if (p == NULL) {
-			return;
-		}
-		AllocMapType::iterator it = alloc_map_.find(p);
-		if (it == alloc_map_.end()) {
-			return;
-		}
-		size_t size = it->second;
-		alloc_map_.erase(it);
-		PoolMapType::iterator it2 = pool_map_.find(size);
-		if (it2 == pool_map_.end()) {
-			return;
-		}
-		PoolType& pool = it2->second;
-		pool.push_back(p);
-	}
-
-private:
-	void CleanUp() {
-		PoolMapType::iterator it = pool_map_.begin(), end = pool_map_.end();
-		for ( ; it != end; ++it) {
-			PoolType& pool = it->second;
-			PoolType::iterator it2 = pool.begin(), end2 = pool.end();
-			for ( ; it2 != end2; ++it2) {
-				::free(*it2);
-			}
-			pool.clear();
-		}
-		pool_map_.clear();
-	}
-
-	typedef std::deque<void*> PoolType;
-	typedef std::unordered_map<size_t, PoolType> PoolMapType;
-	typedef std::unordered_map<void*, size_t> AllocMapType;
-
-	static const size_t kWatermark = 4; // FIFO enforcement level
-
-	PoolMapType pool_map_;
-	AllocMapType alloc_map_;
-};
-
-#endif // _FIFO_ALLOCATOR_H_
diff --git a/src/game/src/horse_rider.cpp b/src/game/src/horse_rider.cpp
index 3eabab6..9d24bfb 100644
--- a/src/game/src/horse_rider.cpp
+++ b/src/game/src/horse_rider.cpp
@@ -247,7 +247,7 @@ EVENTFUNC(horse_stamina_consume_event)
 	}
 
 	hr->CheckHorseHealthDropTime();
-	SPDLOG_DEBUG("HORSE STAMINA - {}", (void*) get_pointer(event));
+	SPDLOG_DEBUG("HORSE STAMINA - {}", (void*) event.get());
 	return delta;
 }
 
@@ -278,7 +278,7 @@ EVENTFUNC(horse_stamina_regen_event)
 	}
 
 	hr->CheckHorseHealthDropTime();
-	SPDLOG_DEBUG("HORSE STAMINA + {}", (void*) get_pointer(event));
+	SPDLOG_DEBUG("HORSE STAMINA + {}", (void*) event.get());
 
 
 	return delta;
@@ -292,7 +292,7 @@ void CHorseRider::StartStaminaConsumeEvent()
 	if (GetHorseHealth() <= 0)
 		return;
 
-	SPDLOG_DEBUG("HORSE STAMINA REGEN EVENT CANCEL {}", (void*) get_pointer(m_eventStaminaRegen));
+	SPDLOG_DEBUG("HORSE STAMINA REGEN EVENT CANCEL {}", (void*) m_eventStaminaRegen.get());
 	event_cancel(&m_eventStaminaRegen);
 
 	if (m_eventStaminaConsume)
@@ -302,7 +302,7 @@ void CHorseRider::StartStaminaConsumeEvent()
 
 	info->hr = this;
 	m_eventStaminaConsume = event_create(horse_stamina_consume_event, info, PASSES_PER_SEC(HORSE_STAMINA_CONSUME_INTERVAL));
-	SPDLOG_DEBUG("HORSE STAMINA CONSUME EVENT CREATE {}", (void*) get_pointer(m_eventStaminaConsume));
+	SPDLOG_DEBUG("HORSE STAMINA CONSUME EVENT CREATE {}", (void*) m_eventStaminaConsume.get());
 }
 
 void CHorseRider::StartStaminaRegenEvent()
@@ -313,7 +313,7 @@ void CHorseRider::StartStaminaRegenEvent()
 	if (GetHorseHealth() <= 0)
 		return;
 
-	SPDLOG_DEBUG("HORSE STAMINA CONSUME EVENT CANCEL {}", (void*) get_pointer(m_eventStaminaConsume));
+	SPDLOG_DEBUG("HORSE STAMINA CONSUME EVENT CANCEL {}", (void*) m_eventStaminaConsume.get());
 	event_cancel(&m_eventStaminaConsume);
 
 	if (m_eventStaminaRegen)
@@ -323,7 +323,7 @@ void CHorseRider::StartStaminaRegenEvent()
 
 	info->hr = this;
 	m_eventStaminaRegen = event_create(horse_stamina_regen_event, info, PASSES_PER_SEC(HORSE_STAMINA_REGEN_INTERVAL));
-	SPDLOG_DEBUG("HORSE STAMINA REGEN EVENT CREATE {}", (void*) get_pointer(m_eventStaminaRegen));
+	SPDLOG_DEBUG("HORSE STAMINA REGEN EVENT CREATE {}", (void*) m_eventStaminaRegen.get());
 }
 
 // Health
@@ -358,7 +358,7 @@ void CHorseRider::UpdateHorseHealth(int iHealth, bool bSend)
 
 void CHorseRider::HorseDie()
 {
-	SPDLOG_DEBUG("HORSE DIE {} {}", (void*) get_pointer(m_eventStaminaRegen), (void*) get_pointer(m_eventStaminaConsume));
+	SPDLOG_DEBUG("HORSE DIE {} {}", (void*) m_eventStaminaRegen.get(), (void*) m_eventStaminaConsume.get());
 	UpdateHorseStamina(-m_Horse.sStamina);
 	event_cancel(&m_eventStaminaRegen);
 	event_cancel(&m_eventStaminaConsume);
diff --git a/src/game/src/questmanager.cpp b/src/game/src/questmanager.cpp
index d1065f0..85323ce 100644
--- a/src/game/src/questmanager.cpp
+++ b/src/game/src/questmanager.cpp
@@ -1676,7 +1676,7 @@ namespace quest
 
 	void CQuestManager::AddServerTimer(const std::string& name, DWORD arg, LPEVENT event)
 	{
-		SPDLOG_DEBUG("XXX AddServerTimer {} {} {}", name, arg, (void*) get_pointer(event));
+		SPDLOG_DEBUG("XXX AddServerTimer {} {} {}", name, arg, (void*) event.get());
 		if (m_mapServerTimer.find(make_pair(name, arg)) != m_mapServerTimer.end())
 		{
 			SPDLOG_ERROR("already registered server timer name:{} arg:{}", name, arg);
diff --git a/src/game/src/questpc.cpp b/src/game/src/questpc.cpp
index 766087c..f229ac4 100644
--- a/src/game/src/questpc.cpp
+++ b/src/game/src/questpc.cpp
@@ -165,7 +165,7 @@ namespace quest
 	{
 		RemoveTimer(name);
 		m_TimerMap.insert(make_pair(name, pEvent));
-		SPDLOG_DEBUG("QUEST add timer {} {}", (void*) get_pointer(pEvent), m_TimerMap.size());
+		SPDLOG_DEBUG("QUEST add timer {} {}", (void*) pEvent.get(), m_TimerMap.size());
 	}
 
 	void PC::RemoveTimerNotCancel(const string & name)
@@ -174,7 +174,7 @@ namespace quest
 
 		if (it != m_TimerMap.end())
 		{
-			SPDLOG_DEBUG("QUEST remove with no cancel {}", (void*) get_pointer(it->second));
+			SPDLOG_DEBUG("QUEST remove with no cancel {}", (void*) it->second.get());
 			m_TimerMap.erase(it);
 		}
 
@@ -187,7 +187,7 @@ namespace quest
 
 		if (it != m_TimerMap.end())
 		{
-			SPDLOG_DEBUG("QUEST remove timer {}", (void*) get_pointer(it->second));
+			SPDLOG_DEBUG("QUEST remove timer {}", (void*) it->second.get());
 			CancelTimerEvent(&it->second);
 			m_TimerMap.erase(it);
 		}
diff --git a/src/game/src/shop_manager.cpp b/src/game/src/shop_manager.cpp
index 3ffca46..f8330bc 100644
--- a/src/game/src/shop_manager.cpp
+++ b/src/game/src/shop_manager.cpp
@@ -2,29 +2,23 @@
 #include "../../libgame/include/grid.h"
 #include "constants.h"
 #include "utils.h"
-#include "config.h"
 #include "shop.h"
 #include "desc.h"
-#include "desc_manager.h"
 #include "char.h"
 #include "char_manager.h"
 #include "item.h"
 #include "item_manager.h"
-#include "buffer_manager.h"
 #include "packet.h"
-#include "log.h"
 #include "db.h"
 #include "questmanager.h"
 #include "monarch.h"
 #include "mob_manager.h"
 #include "locale_service.h"
-#include "desc_client.h"
 #include "shop_manager.h"
 #include "group_text_parse_tree.h"
 #include "shopEx.h"
-#include <boost/algorithm/string/predicate.hpp>
-#include "shop_manager.h"
 #include <cctype>
+#include <algorithm>
 
 CShopManager::CShopManager()
 {
@@ -388,11 +382,11 @@ bool ConvertToShopItemTable(IN CGroupNode* pNode, OUT TShopTableEx& shopTable)
 		stCoinType = "Gold";
 	}
 	
-	if (boost::iequals(stCoinType, "Gold"))
+	if (iequals(stCoinType, "Gold"))
 	{
 		shopTable.coinType = SHOP_COIN_TYPE_GOLD;
 	}
-	else if (boost::iequals(stCoinType, "SecondaryCoin"))
+	else if (iequals(stCoinType, "SecondaryCoin"))
 	{
 		shopTable.coinType = SHOP_COIN_TYPE_SECONDARY_COIN;
 	}
@@ -442,11 +436,11 @@ bool ConvertToShopItemTable(IN CGroupNode* pNode, OUT TShopTableEx& shopTable)
 		stSort = "None";
 	}
 
-	if (boost::iequals(stSort, "Asc"))
+	if (iequals(stSort, "Asc"))
 	{
 		std::sort(shopItems.begin(), shopItems.end(), CompareShopItemName);
 	}
-	else if(boost::iequals(stSort, "Desc"))
+	else if (iequals(stSort, "Desc"))
 	{
 		std::sort(shopItems.rbegin(), shopItems.rend(), CompareShopItemName);
 	}
diff --git a/src/game/src/utils.cpp b/src/game/src/utils.cpp
index f12ab0d..362a137 100644
--- a/src/game/src/utils.cpp
+++ b/src/game/src/utils.cpp
@@ -230,3 +230,12 @@ bool WildCaseCmp(const char *w, const char *s)
 	return false;
 }
 
+bool ichar_equals(char a, char b)
+{
+	return std::tolower(static_cast<unsigned char>(a)) == std::tolower(static_cast<unsigned char>(b));
+}
+
+bool iequals(const std::string& a, const std::string& b)
+{
+	return std::equal(a.begin(), a.end(), b.begin(), b.end(), ichar_equals);
+}
diff --git a/src/game/src/utils.h b/src/game/src/utils.h
index f3baec5..938392a 100644
--- a/src/game/src/utils.h
+++ b/src/game/src/utils.h
@@ -1,8 +1,6 @@
+#pragma once
 
-#ifndef __INC_METIN_II_UTILS_H__
-#define __INC_METIN_II_UTILS_H__
-
-#include <math.h>
+#include <cmath>
 
 #define IS_SET(flag, bit)		((flag) & (bit))
 #define SET_BIT(var, bit)		((var) |= (bit))
@@ -64,5 +62,5 @@ extern int parse_time_str(const char* str);
 
 extern bool WildCaseCmp(const char *w, const char *s);
 
-#endif /* __INC_METIN_II_UTILS_H__ */
-
+extern bool ichar_equals(char a, char b);
+extern bool iequals(const std::string& a, const std::string& b);
diff --git a/src/game/src/wedding.cpp b/src/game/src/wedding.cpp
index 9028707..ffb9a4e 100644
--- a/src/game/src/wedding.cpp
+++ b/src/game/src/wedding.cpp
@@ -68,7 +68,7 @@ namespace marriage
 	{
 		if (m_pEndEvent)
 		{
-			SPDLOG_ERROR("WeddingMap::SetEnded - ALREADY EndEvent(m_pEndEvent={})", (void*) get_pointer(m_pEndEvent));
+			SPDLOG_ERROR("WeddingMap::SetEnded - ALREADY EndEvent(m_pEndEvent={})", (void*) m_pEndEvent.get());
 			return;
 		}
 
diff --git a/src/libgame/CMakeLists.txt b/src/libgame/CMakeLists.txt
index 3d774fa..3ce45ef 100644
--- a/src/libgame/CMakeLists.txt
+++ b/src/libgame/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.8)
 
 project(libgame CXX)
 
@@ -11,12 +11,11 @@ file(GLOB SOURCES
 # Include header files
 include_directories("include")
 
-find_package(Boost REQUIRED)
-
 # Create shared library
 add_library(${PROJECT_NAME} STATIC ${SOURCES})
 
-if (Boost_FOUND)
-  include_directories(${Boost_INCLUDE_DIRS})
-  target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
-endif (Boost_FOUND)
\ No newline at end of file
+# Find and link dependencies
+
+# spdlog
+find_package(spdlog CONFIG REQUIRED)
+target_link_libraries(${PROJECT_NAME} PRIVATE spdlog::spdlog)
diff --git a/src/liblua/CMakeLists.txt b/src/liblua/CMakeLists.txt
index c6724c7..5cff03d 100644
--- a/src/liblua/CMakeLists.txt
+++ b/src/liblua/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.8)
 
 project(liblua CXX)
 
diff --git a/src/libpoly/CMakeLists.txt b/src/libpoly/CMakeLists.txt
index 10c1f8c..94fc291 100644
--- a/src/libpoly/CMakeLists.txt
+++ b/src/libpoly/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.8)
 
 project(libpoly CXX)
 
diff --git a/src/libsql/CMakeLists.txt b/src/libsql/CMakeLists.txt
index 504c474..7da83f5 100644
--- a/src/libsql/CMakeLists.txt
+++ b/src/libsql/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.8)
 
 project(libsql CXX)
 
@@ -14,10 +14,12 @@ include_directories("include")
 # Create shared library
 add_library(${PROJECT_NAME} STATIC ${SOURCES})
 
-# Find dependencies
-find_package(unofficial-libmysql REQUIRED)
-target_link_libraries(${PROJECT_NAME} PRIVATE unofficial::libmysql::libmysql)
+# Find and link dependencies
 
-find_package(Boost REQUIRED)
-include_directories(${Boost_INCLUDE_DIRS})
-target_link_libraries(${PROJECT_NAME} PRIVATE ${Boost_LIBRARIES})
+# MariaDB
+find_package(unofficial-libmariadb REQUIRED)
+target_link_libraries(${PROJECT_NAME} PUBLIC unofficial::libmariadb)
+
+# spdlog
+find_package(spdlog CONFIG REQUIRED)
+target_link_libraries(${PROJECT_NAME} PRIVATE spdlog::spdlog)
diff --git a/src/libsql/src/CAsyncSQL.cpp b/src/libsql/src/CAsyncSQL.cpp
index 796dbee..6a1ac11 100644
--- a/src/libsql/src/CAsyncSQL.cpp
+++ b/src/libsql/src/CAsyncSQL.cpp
@@ -143,7 +143,7 @@ bool CAsyncSQL::Connect()
 	if (0 != mysql_options(&m_hDB, MYSQL_OPT_RECONNECT, &reconnect))
         SPDLOG_ERROR("Setting MYSQL_OPT_RECONNECT via mysql_options failed: {}", mysql_error(&m_hDB));
 
-	SPDLOG_INFO("AsyncSQL: connected to {} (reconnect {})", m_stHost, m_hDB.reconnect);
+	SPDLOG_INFO("AsyncSQL: connected to {}", m_stHost);
 
 	// db cache는 common db의 LOCALE 테이블에서 locale을 알아오고, 이후 character set을 수정한다.
 	// 따라서 최초 Connection을 맺을 때에는 locale을 모르기 때문에 character set을 정할 수가 없음에도 불구하고,
diff --git a/src/libthecore/CMakeLists.txt b/src/libthecore/CMakeLists.txt
index 490d549..45a03b6 100644
--- a/src/libthecore/CMakeLists.txt
+++ b/src/libthecore/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.8)
 
 project(libthecore CXX)
 
@@ -14,14 +14,7 @@ include_directories("include")
 # Create shared library
 add_library(${PROJECT_NAME} STATIC ${SOURCES})
 
-#
-# vcpkg dependencies
-#
-
-# Boost
-find_package(Boost REQUIRED)
-include_directories(${Boost_INCLUDE_DIRS})
-target_link_libraries(${PROJECT_NAME} PRIVATE ${Boost_LIBRARIES})
+# Find and link dependencies
 
 # fmt
 find_package(fmt CONFIG REQUIRED)
diff --git a/src/quest/CMakeLists.txt b/src/quest/CMakeLists.txt
index c41364b..3a5220a 100644
--- a/src/quest/CMakeLists.txt
+++ b/src/quest/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.8)
 
 project(quest CXX)
 
@@ -7,19 +7,13 @@ file(GLOB_RECURSE sources
   src/*.c
 )
 
+# Add the src directory to the include path
 include_directories(src)
 
-# Find dependencies
-find_package(Boost REQUIRED)
-
 add_executable(${PROJECT_NAME} ${sources})
 set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "qc")
 
-# Link dependencies if found
-if (Boost_FOUND)
-  include_directories(${Boost_INCLUDE_DIRS})
-  target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
-endif (Boost_FOUND)
+# Find and link dependencies
 
+# liblua
 target_link_libraries(${PROJECT_NAME} liblua)
-target_include_directories(${PROJECT_NAME} PUBLIC . ../liblua)
\ No newline at end of file
diff --git a/src/quest/src/qc.cc b/src/quest/src/qc.cc
index ea24d26..d81962c 100644
--- a/src/quest/src/qc.cc
+++ b/src/quest/src/qc.cc
@@ -20,18 +20,9 @@ extern "C" {
 #include <sstream>
 #include <utility>
 #include <vector>
-
-#ifndef __WIN32__
 #include <unistd.h>
-#else
-#include <boost/typeof/typeof.hpp>
-#define typeof(t) BOOST_TYPEOF(t)
-#include <direct.h>
-#define mkdir(path, mode) _mkdir(path)
-#endif
-#include <sys/types.h>
 #include <sys/stat.h>
-#include <errno.h>
+#include <cerrno>
 
 #include "crc32.h"