changeset 121:789b23e01f52

misc: reorganize hierarchy, closes #2490
author David Demelier <markand@malikania.fr>
date Mon, 05 Oct 2020 13:25:06 +0200
parents b3429b26d60d
children d1ec1aa3fbe0
files .hgignore CMakeLists.txt cmake/MolkoDefineExecutable.cmake cmake/MolkoDefineLibrary.cmake cmake/MolkoDefineTest.cmake doxygen/CMakeLists.txt doxygen/page-howto-initialization.c extern/libsqlite/CMakeLists.txt libadventure/CMakeLists.txt libadventure/adventure/mainmenu_state.c libadventure/adventure/mainmenu_state.h libadventure/adventure/panic_state.c libadventure/adventure/panic_state.h libadventure/adventure/splashscreen_state.c libadventure/adventure/splashscreen_state.h libcore/CMakeLists.txt libcore/core/action.h libcore/core/animation.c libcore/core/animation.h libcore/core/assets/fonts/ComicNeue-Regular.ttf libcore/core/assets/fonts/DejaVuSans.ttf libcore/core/assets/fonts/DejaVuSansCondensed.ttf libcore/core/assets/fonts/Lato-Regular.ttf libcore/core/assets/fonts/knights-quest.ttf libcore/core/assets/fonts/pirata-one.ttf libcore/core/assets/fonts/teutonic1.ttf libcore/core/assets/images/message.png libcore/core/assets/images/message.xcf libcore/core/assets/maps/test.map libcore/core/assets/sprites/test-walk.png libcore/core/assets/sprites/test-walk.xcf libcore/core/assets/tilesets/test.png libcore/core/button.c libcore/core/button.h libcore/core/checkbox.c libcore/core/checkbox.h libcore/core/clock.c libcore/core/clock.h libcore/core/color.h libcore/core/debug.c libcore/core/debug.h libcore/core/error.c libcore/core/error.h libcore/core/error_p.h libcore/core/event.c libcore/core/event.h libcore/core/font.c libcore/core/font.h libcore/core/frame.c libcore/core/frame.h libcore/core/game.c libcore/core/game.h libcore/core/image.c libcore/core/image.h libcore/core/inhibit.c libcore/core/inhibit.h libcore/core/inventory.c libcore/core/inventory.h libcore/core/inventory_dialog.c libcore/core/inventory_dialog.h libcore/core/item.h libcore/core/key.h libcore/core/label.c libcore/core/label.h libcore/core/map.c libcore/core/map.h libcore/core/map_state.c libcore/core/map_state.h libcore/core/maths.c libcore/core/maths.h libcore/core/message.c libcore/core/message.h libcore/core/mouse.h libcore/core/painter.c libcore/core/painter.h libcore/core/panic.c libcore/core/panic.h libcore/core/plat.h libcore/core/rbuf.c libcore/core/rbuf.h libcore/core/save.c libcore/core/save.h libcore/core/script.c libcore/core/script.h libcore/core/sound.c libcore/core/sound.h libcore/core/sprite.c libcore/core/sprite.h libcore/core/state.h libcore/core/sys.c libcore/core/sys.h libcore/core/texture.c libcore/core/texture.h libcore/core/texture_p.h libcore/core/theme.c libcore/core/theme.h libcore/core/util.c libcore/core/util.h libcore/core/wait.c libcore/core/wait.h libcore/core/walksprite.c libcore/core/walksprite.h libcore/core/window.c libcore/core/window.h libcore/core/window_p.h molko/CMakeLists.txt molko/main.c src/adventure/CMakeLists.txt src/adventure/mainmenu_state.c src/adventure/mainmenu_state.h src/adventure/panic_state.c src/adventure/panic_state.h src/adventure/splashscreen_state.c src/adventure/splashscreen_state.h src/core/CMakeLists.txt src/core/action.h src/core/animation.c src/core/animation.h src/core/assets/fonts/ComicNeue-Regular.ttf src/core/assets/fonts/DejaVuSans.ttf src/core/assets/fonts/DejaVuSansCondensed.ttf src/core/assets/fonts/Lato-Regular.ttf src/core/assets/fonts/knights-quest.ttf src/core/assets/fonts/pirata-one.ttf src/core/assets/fonts/teutonic1.ttf src/core/assets/images/message.png src/core/assets/images/message.xcf src/core/assets/maps/test.map src/core/assets/sprites/test-walk.png src/core/assets/sprites/test-walk.xcf src/core/assets/tilesets/test.png src/core/button.c src/core/button.h src/core/checkbox.c src/core/checkbox.h src/core/clock.c src/core/clock.h src/core/color.h src/core/debug.c src/core/debug.h src/core/error.c src/core/error.h src/core/error_p.h src/core/event.c src/core/event.h src/core/font.c src/core/font.h src/core/frame.c src/core/frame.h src/core/game.c src/core/game.h src/core/image.c src/core/image.h src/core/inhibit.c src/core/inhibit.h src/core/inventory.c src/core/inventory.h src/core/inventory_dialog.c src/core/inventory_dialog.h src/core/item.h src/core/key.h src/core/label.c src/core/label.h src/core/map.c src/core/map.h src/core/map_state.c src/core/map_state.h src/core/maths.c src/core/maths.h src/core/message.c src/core/message.h src/core/mouse.h src/core/painter.c src/core/painter.h src/core/panic.c src/core/panic.h src/core/plat.h src/core/rbuf.c src/core/rbuf.h src/core/save.c src/core/save.h src/core/script.c src/core/script.h src/core/sound.c src/core/sound.h src/core/sprite.c src/core/sprite.h src/core/state.h src/core/sys.c src/core/sys.h src/core/texture.c src/core/texture.h src/core/texture_p.h src/core/theme.c src/core/theme.h src/core/util.c src/core/util.h src/core/wait.c src/core/wait.h src/core/walksprite.c src/core/walksprite.h src/core/window.c src/core/window.h src/core/window_p.h src/molko/CMakeLists.txt src/molko/main.c tests/test-color.c tests/test-error.c tests/test-inventory.c tests/test-rbuf.c tests/test-save.c tests/test-script.c tools/bcc/CMakeLists.txt tools/map/CMakeLists.txt
diffstat 214 files changed, 29156 insertions(+), 29068 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Oct 05 13:05:09 2020 +0200
+++ b/.hgignore	Mon Oct 05 13:25:06 2020 +0200
@@ -7,3 +7,6 @@
 
 # macOS specific.
 \.DS_Store$
+
+# CMake build directory.
+^build$
--- a/CMakeLists.txt	Mon Oct 05 13:05:09 2020 +0200
+++ b/CMakeLists.txt	Mon Oct 05 13:25:06 2020 +0200
@@ -24,9 +24,12 @@
 set(CMAKE_C_EXTENSIONS Off)
 set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
 
+set_property(GLOBAL PROPERTY USE_FOLDERS On)
+
 include(GNUInstallDirs)
 
 include(cmake/MolkoBuildAssets.cmake)
+include(cmake/MolkoDefineExecutable.cmake)
 include(cmake/MolkoDefineLibrary.cmake)
 include(Cmake/MolkoDefineTest.cmake)
 
@@ -43,8 +46,8 @@
 add_subdirectory(tools/bcc)
 add_subdirectory(tools/map)
 
-add_subdirectory(src/core)
-add_subdirectory(src/adventure)
-add_subdirectory(src/molko)
+add_subdirectory(libcore)
+add_subdirectory(libadventure)
+add_subdirectory(molko)
 
 add_subdirectory(tests)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/MolkoDefineExecutable.cmake	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,49 @@
+#
+# MolkoDefineTest.cmake -- CMake build system for molko
+#
+# Copyright (c) 2020 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+include(${CMAKE_CURRENT_LIST_DIR}/MolkoBuildAssets.cmake)
+
+function(molko_define_executable)
+	set(options)
+	set(oneValueArgs FOLDER TARGET)
+	set(multiValueArgs ASSETS FLAGS INCLUDES LIBRARIES SOURCES)
+
+	cmake_parse_arguments(EXE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+	if (NOT EXE_TARGET)
+		message(FATAL_ERROR "Missing TARGET argument")
+	endif ()
+	if (NOT EXE_SOURCES)
+		message(FATAL_ERROR "Missing SOURCES argument")
+	endif ()
+
+	molko_build_assets("${EXE_ASSETS}" OUTPUTS)
+
+	add_executable(${EXE_TARGET} ${EXE_SOURCES} ${OUTPUTS})
+	target_compile_definitions(${EXE_TARGET} PRIVATE ${EXE_FLAGS})
+	target_include_directories(${EXE_TARGET} PRIVATE ${EXE_INCLUDES})
+	target_link_libraries(
+		${EXE_TARGET}
+		PRIVATE
+			${EXE_LIBRARIES}
+	)
+
+	if (EXE_FOLDER)
+		set_target_properties(${EXE_TARGET} PROPERTIES FOLDER ${EXE_FOLDER})
+	endif ()
+endfunction()
--- a/cmake/MolkoDefineLibrary.cmake	Mon Oct 05 13:05:09 2020 +0200
+++ b/cmake/MolkoDefineLibrary.cmake	Mon Oct 05 13:25:06 2020 +0200
@@ -25,6 +25,7 @@
 # molko_define_library(
 #   TARGET              target name
 #   SOURCES             src1, src2, srcn
+#   FOLDER              (Optional) optional subfolder to organize
 #   TYPE                (Optional) type of library
 #   ASSETS              (Optional) list of assets
 #   LIBRARIES           (Optional) libraries to link
@@ -50,14 +51,15 @@
 # The arguments ASSETS contains a list of assets to be converted during the
 # build. The file hierarchy is conserved in the ${CMAKE_CURRENT_BINARY_DIR}.
 #
-# If EXPORT boolean parameter is set, the library is exported and installed.
+# If FOLDER option is set, it is organized into its name under the IDE if
+# supported.
 #
 
 include(${CMAKE_CURRENT_LIST_DIR}/MolkoBuildAssets.cmake)
 
 function(molko_define_library)
 	set(options)
-	set(oneValueArgs TARGET TYPE)
+	set(oneValueArgs FOLDER TARGET TYPE)
 	set(multiValueArgs ASSETS LIBRARIES PRIVATE_FLAGS PRIVATE_INCLUDES PUBLIC_FLAGS PUBLIC_INCLUDES SOURCES)
 
 	cmake_parse_arguments(LIB "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
@@ -108,4 +110,8 @@
 				C_STANDARD_REQUIRED On
 		)
 	endif ()
+
+	if (LIB_FOLDER)
+		set_target_properties(${LIB_TARGET} PROPERTIES FOLDER ${LIB_FOLDER})
+	endif ()
 endfunction()
--- a/cmake/MolkoDefineTest.cmake	Mon Oct 05 13:05:09 2020 +0200
+++ b/cmake/MolkoDefineTest.cmake	Mon Oct 05 13:25:06 2020 +0200
@@ -46,4 +46,5 @@
 			${TEST_LIBRARIES}
 	)
 	add_test(NAME ${TEST_TARGET} COMMAND test-${TEST_TARGET})
+	set_target_properties(test-${TEST_TARGET} PROPERTIES FOLDER tests)
 endfunction()
--- a/doxygen/CMakeLists.txt	Mon Oct 05 13:05:09 2020 +0200
+++ b/doxygen/CMakeLists.txt	Mon Oct 05 13:25:06 2020 +0200
@@ -28,7 +28,8 @@
 		doxygen/page-howto-initialization.c
 		doxygen/page-faq.c
 		doxygen/page-examples.c
-		src
+		libadventure
+		libcore
 	)
 	set(DOXYGEN_ALLOW_UNICODE_NAMES YES)
 	set(DOXYGEN_AUTOLINK_SUPPORT NO)
@@ -57,4 +58,6 @@
 		ALL
 		WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
 	)
+
+	set_target_properties(doxygen PROPERTIES FOLDER misc)
 endif ()
--- a/doxygen/page-howto-initialization.c	Mon Oct 05 13:05:09 2020 +0200
+++ b/doxygen/page-howto-initialization.c	Mon Oct 05 13:25:06 2020 +0200
@@ -19,8 +19,8 @@
  *
  * | System  | Init function    | Close function     | Remarks                |
  * |---------|------------------|--------------------|------------------------|
- * | General | \ref sys_init    | \ref sys_finish    | Required for most API  |
- * | Window  | \ref window_init | \ref window_finish | Required by some parts |
+ * | General | sys_init         | sys_finish    | Required for most API  |
+ * | Window  | window_init      | window_finish | Required by some parts |
  *
  * All init functions set an error code if any and you're encouraged to test the
  * result and check the error if any.
--- a/extern/libsqlite/CMakeLists.txt	Mon Oct 05 13:05:09 2020 +0200
+++ b/extern/libsqlite/CMakeLists.txt	Mon Oct 05 13:25:06 2020 +0200
@@ -21,6 +21,7 @@
 molko_define_library(
 	TARGET libsqlite
 	SOURCES sqlite3.c sqlite3.h
+	FOLDER extern
 	PUBLIC_INCLUDES
 		$<BUILD_INTERFACE:${libsqlite_SOURCE_DIR}>
 		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libadventure/CMakeLists.txt	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,39 @@
+#
+# CMakeLists.txt -- CMake build system for libadventure
+#
+# Copyright (c) 2020 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(libadventure)
+
+set(
+	SOURCES
+	${libadventure_SOURCE_DIR}/adventure/mainmenu_state.c
+	${libadventure_SOURCE_DIR}/adventure/mainmenu_state.h
+	${libadventure_SOURCE_DIR}/adventure/panic_state.c
+	${libadventure_SOURCE_DIR}/adventure/panic_state.h
+	${libadventure_SOURCE_DIR}/adventure/splashscreen_state.c
+	${libadventure_SOURCE_DIR}/adventure/splashscreen_state.h
+)
+
+molko_define_library(
+	TARGET libadventure
+	SOURCES ${SOURCES}
+	LIBRARIES libcore
+	PUBLIC_INCLUDES
+		$<BUILD_INTERFACE:${libadventure_SOURCE_DIR}>
+)
+
+source_group(adventure FILES ${SOURCES})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libadventure/adventure/mainmenu_state.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,212 @@
+/*
+ * mainmenu_state.c -- game main menu
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <core/event.h>
+#include <core/font.h>
+#include <core/game.h>
+#include <core/image.h>
+#include <core/map_state.h>
+#include <core/painter.h>
+#include <core/panic.h>
+#include <core/state.h>
+#include <core/sys.h>
+#include <core/texture.h>
+#include <core/window.h>
+
+#include "mainmenu_state.h"
+#include "splashscreen_state.h"
+
+#define SPEED 120
+#define SEC   1000
+
+enum substate {
+	SUBSTATE_MOVING,
+	SUBSTATE_WAITING
+};
+
+static int x;
+static int y;
+static unsigned int selection;
+static int destination;
+static enum substate substate;
+static struct texture image;
+
+/* Menu items. */
+static struct {
+	struct texture texture;
+	int x;
+	int y;
+} items[3];
+
+static void
+enter(void)
+{
+	struct font font = { 0 };
+
+	if (!font_open(&font, sys_datapath("fonts/pirata-one.ttf"), 30))
+		panic();
+
+	substate = SUBSTATE_MOVING;
+	x = splashscreen_state_data.x;
+	y = splashscreen_state_data.y;
+	destination = window.h / 4;
+
+	/* TODO: change continue color if no game exists. */
+	font_render(&font, &items[0].texture, "New game");
+	items[0].x = (window.w / 2) - (items[0].texture.w / 2);
+	items[0].y = window.h * 0.75;
+
+	font_render(&font, &items[1].texture, "Continue");
+	items[1].x = items[0].x;
+	items[1].y = items[0].y + items[0].texture.h;
+
+	font_render(&font, &items[2].texture, "Quit");
+	items[2].x = items[0].x;
+	items[2].y = items[1].y + items[1].texture.h;
+
+	font_finish(&font);
+}
+
+static void
+new(void)
+{
+	/* TODO: convenient map_state_start function? */
+
+	/* Prepare map. */
+	if (!map_data_open(&map_state_data.map.data, sys_datapath("maps/test.map")))
+		panic();
+	if (!map_init(&map_state_data.map.map, &map_state_data.map.data))
+		panic();
+
+	/* Prepare image and sprite. */
+	if (!(image_open(&image, sys_datapath("sprites/test-walk.png"))))
+		panic();
+
+	sprite_init(&map_state_data.player.sprite, &image, 48, 48);
+	game_switch(&map_state, false);
+}
+
+static void
+resume(void)
+{
+}
+
+static void
+quit(void)
+{
+	game_quit();
+}
+
+static void
+perform(void)
+{
+	assert(selection < 3);
+
+	static void (*handlers[])(void) = {
+		[0] = new,
+		[1] = resume,
+		[2] = quit
+	};
+
+	handlers[selection]();
+}
+
+static void
+handle(const union event *event)
+{
+	if (substate != SUBSTATE_WAITING)
+		return;
+
+	switch (event->type) {
+	case EVENT_KEYDOWN:
+		switch (event->key.key) {
+		case KEY_UP:
+			selection = selection == 0 ? 2 : selection - 1;
+			break;
+		case KEY_DOWN:
+			selection = (selection + 1) % 3;
+			break;
+		case KEY_ENTER:
+			perform();
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+update(unsigned int ticks)
+{
+	switch (substate) {
+	case SUBSTATE_MOVING:
+		y -= SPEED * ticks / SEC;
+
+		if (y <= destination) {
+			y = destination;
+			substate = SUBSTATE_WAITING;
+		}
+
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+draw(void)
+{
+	painter_set_color(0xffffffff);
+	painter_clear();
+	texture_draw(&splashscreen_state_data.text, x, y);
+
+	if (substate == SUBSTATE_WAITING) {
+		texture_draw(&items[0].texture, items[0].x, items[0].y);
+		texture_draw(&items[1].texture, items[1].x, items[1].y);
+		texture_draw(&items[2].texture, items[2].x, items[2].y);
+
+		/* Selection cursor. */
+
+		/* TODO: a sword here. */
+		painter_set_color(0x000000ff);
+		painter_draw_rectangle(items[selection].x - 30,
+		    items[selection].y + 11, 15, 15);
+	}
+}
+
+static void
+leave(void)
+{
+	texture_finish(&items[0].texture);
+	texture_finish(&items[1].texture);
+	memset(items, 0, sizeof (items));
+}
+
+struct state mainmenu_state = {
+	.enter = enter,
+	.handle = handle,
+	.update = update,
+	.draw = draw,
+	.leave = leave
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libadventure/adventure/mainmenu_state.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,32 @@
+/*
+ * mainmenu_state.h -- game main menu
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_MAINMENU_STATE_H
+#define MOLKO_MAINMENU_STATE_H
+
+/**
+ * \file mainmenu_state.h
+ * \brief Game main menu.
+ */
+
+/**
+ * \brief Main menu state.
+ */
+extern struct state mainmenu_state;
+
+#endif /* !MOLKO_MAINMENU_STATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libadventure/adventure/panic_state.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,227 @@
+/*
+ * panic_state.c -- panic state
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <core/error.h>
+#include <core/event.h>
+#include <core/font.h>
+#include <core/game.h>
+#include <core/painter.h>
+#include <core/sys.h>
+#include <core/texture.h>
+#include <core/util.h>
+#include <core/window.h>
+#include <core/map_state.h>
+
+#include <core/assets/fonts/Lato-Regular.h>
+
+#include "panic_state.h"
+
+#define BACKGROUND 0x4f5070ff
+#define FOREGROUND 0xffffffff
+
+#define SIZE 16
+#define PADDING 20
+
+#define OUT "molko-adventure.txt"
+
+struct label {
+	const char *text;
+	struct texture texture;
+};
+
+static struct {
+	struct font font;
+} data;
+
+static struct label headers[] = {
+	{ "An unrecoverable error occured and the game cannot continue.", 0 },
+	{ "Please report the detailed error as provided below.", 0 },
+};
+
+static struct label bottom[] = {
+	{ "Press <s> to save information and generate a core dump.", 0 },
+	{ "Press <q> to quit without saving information.", 0 }
+};
+
+static struct label lerror;
+
+static void
+die(const char *fmt, ...)
+{
+	assert(fmt);
+
+	va_list ap;
+
+	va_start(ap, fmt);
+	fprintf(stderr, "abort: ");
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	exit(1);
+}
+
+static void
+enter(void)
+{
+}
+
+static void
+dump(void)
+{
+	FILE *fp;
+
+	if (!(fp = fopen(OUT, "w")))
+		goto dump;
+
+	/* Print various information. */
+	fprintf(fp, "Molko's Adventure crash dump report\n");
+	fprintf(fp, "== state map dump ==\n");
+	fprintf(fp, "map:\n");
+	fprintf(fp, "  w     %u\n", map_state_data.map.data.w);
+	fprintf(fp, "  h     %u\n", map_state_data.map.data.h);
+	fprintf(fp, "player:\n");
+	fprintf(fp, "  x:    %u\n", map_state_data.player.x);
+	fprintf(fp, "  y:    %u\n", map_state_data.player.y);
+	fprintf(fp, "view:\n");
+	fprintf(fp, "  w:    %u\n", map_state_data.view.w);
+	fprintf(fp, "  h:    %u\n", map_state_data.view.h);
+	fprintf(fp, "  x:    %u\n", map_state_data.view.x);
+	fprintf(fp, "  y:    %u\n", map_state_data.view.y);
+
+dump:
+	if (fp)
+		fclose(fp);
+
+	abort();
+}
+
+static void
+handle_keydown(const struct event_key *ev)
+{
+	assert(ev);
+
+	switch (ev->key) {
+	case KEY_q:
+		game_quit();
+		break;
+	case KEY_s:
+		dump();
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+handle(const union event *ev)
+{
+	assert(ev);
+
+	switch (ev->type) {
+	case EVENT_KEYDOWN:
+		handle_keydown(&ev->key);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+generate(struct label labels[], size_t labelsz)
+{
+	assert(labels);
+
+	for (size_t i = 0; i < labelsz; ++i) {
+		if (texture_ok(&labels[i].texture))
+			continue;
+
+		data.font.color = FOREGROUND;
+		font_render(&data.font, &labels[i].texture, labels[i].text);
+
+		if (!texture_ok(&labels[i].texture))
+			die("%s\n", error());
+	}
+}
+
+static void
+update(unsigned int ticks)
+{
+	(void)ticks;
+
+	lerror.text = error();
+
+	generate(headers, NELEM(headers));
+	generate(&lerror, 1);
+	generate(bottom, NELEM(bottom));
+}
+
+static void
+draw(void)
+{
+	int y = PADDING;
+
+	painter_set_target(NULL);
+	painter_set_color(BACKGROUND);
+	painter_clear();
+
+	/* Header. */
+	for (size_t i = 0; i < NELEM(headers); ++i) {
+		texture_draw(&headers[i].texture, PADDING, y);
+		y += headers[i].texture.h + 2;
+	}
+
+	/* Error message. */
+	texture_draw(&lerror.texture, PADDING, y + PADDING);
+
+	/* Bottom. */
+	y = window.h - PADDING;
+	y -= bottom[0].texture.h;
+
+	for (size_t i = 0; i < NELEM(bottom); ++i) {
+		texture_draw(&bottom[i].texture, PADDING, y);
+		y -= bottom[i].texture.h + 2;
+	}
+}
+
+static void
+leave(void)
+{
+}
+
+struct state panic_state = {
+	.enter = enter,
+	.handle = handle,
+	.update = update,
+	.draw = draw,
+	.leave = leave
+};
+
+void
+panic_state_init(void)
+{
+	/*
+	 * If the panic state can not be loaded we're unable to show any
+	 * useful information to the screen so as last resort print them
+	 * on the console.
+	 */
+	if (!(font_openmem(&data.font, Lato_Regular, sizeof (Lato_Regular), SIZE)))
+		die("%s", error());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libadventure/adventure/panic_state.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,45 @@
+/*
+ * panic_state.h -- panic state
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_PANIC_STATE_H
+#define MOLKO_PANIC_STATE_H
+
+/**
+ * \file panic_state.h
+ * \brief Panic state.
+ */
+
+#include <core/state.h>
+
+/**
+ * \brief Global panic state structure.
+ */
+extern struct state panic_state;
+
+/**
+ * Call this function as early as possible to be able to use this state even on
+ * memory allocation errors.
+ *
+ * \note You must still initialize the system before.
+ * \see \ref sys_init
+ * \see \ref window_init
+ */
+void
+panic_state_init(void);
+
+#endif /* !MOLKO_PANIC_STATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libadventure/adventure/splashscreen_state.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,97 @@
+/*
+ * splashscreen_state.c -- splash screen state
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <core/font.h>
+#include <core/game.h>
+#include <core/image.h>
+#include <core/map.h>
+#include <core/map_state.h>
+#include <core/painter.h>
+#include <core/panic.h>
+#include <core/state.h>
+#include <core/sys.h>
+#include <core/texture.h>
+#include <core/window.h>
+
+#include "splashscreen_state.h"
+#include "mainmenu_state.h"
+
+#define DELAY 2000
+
+struct splashscreen_state_data splashscreen_state_data;
+
+static void
+enter(void)
+{
+	struct font font = {
+		.color = 0x000000ff
+	};
+
+	if (!(font_open(&font, sys_datapath("fonts/teutonic1.ttf"), 130)))
+		panic();
+	if (!(font_render(&font, &splashscreen_state_data.text, "Molko's Adventure")))
+		panic();
+
+	/* Compute position. */
+	const unsigned int w = splashscreen_state_data.text.w;
+	const unsigned int h = splashscreen_state_data.text.h;
+
+	splashscreen_state_data.x = (window.w / 2) - (w / 2);
+	splashscreen_state_data.y = (window.h / 2) - (h / 2);
+
+	font_finish(&font);
+}
+
+static void
+leave(void)
+{
+	/* We don't delete the texture because it is used by mainmenu_state. */
+}
+
+static void
+handle(const union event *event)
+{
+	(void)event;
+}
+
+static void
+update(unsigned int ticks)
+{
+	splashscreen_state_data.elapsed += ticks;
+
+	if (splashscreen_state_data.elapsed >= DELAY)
+		game_switch(&mainmenu_state, false);
+}
+
+static void
+draw(void)
+{
+	painter_set_color(0xffffffff);
+	painter_clear();
+	texture_draw(&splashscreen_state_data.text,
+		splashscreen_state_data.x,
+		splashscreen_state_data.y);
+}
+
+struct state splashscreen_state = {
+	.enter = enter,
+	.leave = leave,
+	.handle = handle,
+	.update = update,
+	.draw = draw
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libadventure/adventure/splashscreen_state.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,44 @@
+/*
+ * splashscreen_state.h -- splash screen state
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_SPLASHSCREEN_ADVENTURE_H
+#define MOLKO_SPLASHSCREEN_ADVENTURE_H
+
+/**
+ * \file splashscreen_state.h
+ * \brief Splash screen state.
+ */
+
+#include <core/texture.h>
+
+/**
+ * \brief Data for splashscreen.
+ */
+extern struct splashscreen_state_data {
+	struct texture text;            /*!< (RW) Texture for the text. */
+	int x;                          /*!< (RW) Position in x. */
+	int y;                          /*!< (RW) Position in y. */
+	unsigned int elapsed;           /*!< (RW) Time elapsed. */
+} splashscreen_state_data;              /*!< (RW) Global state data. */
+
+/**
+ * \brief Splash screen state.
+ */
+extern struct state splashscreen_state;
+
+#endif /* !MOLKO_SPLASHSCREEN_ADVENTURE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/CMakeLists.txt	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,136 @@
+#
+# CMakeLists.txt -- CMake build system for libcore
+#
+# Copyright (c) 2020 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(libcore)
+
+set(
+	ASSETS
+	${libcore_SOURCE_DIR}/core/assets/maps/test.map
+	${libcore_SOURCE_DIR}/core/assets/images/message.png
+	${libcore_SOURCE_DIR}/core/assets/sprites/test-walk.png
+	${libcore_SOURCE_DIR}/core/assets/fonts/DejaVuSansCondensed.ttf
+	${libcore_SOURCE_DIR}/core/assets/fonts/DejaVuSans.ttf
+	${libcore_SOURCE_DIR}/core/assets/fonts/Lato-Regular.ttf
+	${libcore_SOURCE_DIR}/core/assets/fonts/ComicNeue-Regular.ttf
+	${libcore_SOURCE_DIR}/core/assets/fonts/pirata-one.ttf
+	${libcore_SOURCE_DIR}/core/assets/fonts/teutonic1.ttf
+	${libcore_SOURCE_DIR}/core/assets/fonts/knights-quest.ttf
+	${libcore_SOURCE_DIR}/core/assets/tilesets/test.png
+)
+
+set(
+	SOURCES
+	${libcore_SOURCE_DIR}/core/action.h
+	${libcore_SOURCE_DIR}/core/animation.c
+	${libcore_SOURCE_DIR}/core/animation.h
+	${libcore_SOURCE_DIR}/core/button.c
+	${libcore_SOURCE_DIR}/core/button.h
+	${libcore_SOURCE_DIR}/core/checkbox.c
+	${libcore_SOURCE_DIR}/core/checkbox.h
+	${libcore_SOURCE_DIR}/core/clock.c
+	${libcore_SOURCE_DIR}/core/clock.h
+	${libcore_SOURCE_DIR}/core/color.h
+	${libcore_SOURCE_DIR}/core/debug.c
+	${libcore_SOURCE_DIR}/core/debug.h
+	${libcore_SOURCE_DIR}/core/error.c
+	${libcore_SOURCE_DIR}/core/error.h
+	${libcore_SOURCE_DIR}/core/error_p.h
+	${libcore_SOURCE_DIR}/core/event.c
+	${libcore_SOURCE_DIR}/core/event.h
+	${libcore_SOURCE_DIR}/core/font.c
+	${libcore_SOURCE_DIR}/core/font.h
+	${libcore_SOURCE_DIR}/core/frame.c
+	${libcore_SOURCE_DIR}/core/frame.h
+	${libcore_SOURCE_DIR}/core/game.c
+	${libcore_SOURCE_DIR}/core/game.h
+	${libcore_SOURCE_DIR}/core/image.c
+	${libcore_SOURCE_DIR}/core/image.h
+	${libcore_SOURCE_DIR}/core/inhibit.c
+	${libcore_SOURCE_DIR}/core/inhibit.h
+	${libcore_SOURCE_DIR}/core/inventory.c
+	${libcore_SOURCE_DIR}/core/inventory.h
+	${libcore_SOURCE_DIR}/core/inventory_dialog.c
+	${libcore_SOURCE_DIR}/core/inventory_dialog.h
+	${libcore_SOURCE_DIR}/core/item.h
+	${libcore_SOURCE_DIR}/core/key.h
+	${libcore_SOURCE_DIR}/core/label.c
+	${libcore_SOURCE_DIR}/core/label.h
+	${libcore_SOURCE_DIR}/core/map.c
+	${libcore_SOURCE_DIR}/core/map.h
+	${libcore_SOURCE_DIR}/core/map_state.c
+	${libcore_SOURCE_DIR}/core/map_state.h
+	${libcore_SOURCE_DIR}/core/maths.c
+	${libcore_SOURCE_DIR}/core/maths.h
+	${libcore_SOURCE_DIR}/core/message.c
+	${libcore_SOURCE_DIR}/core/message.h
+	${libcore_SOURCE_DIR}/core/mouse.h
+	${libcore_SOURCE_DIR}/core/painter.c
+	${libcore_SOURCE_DIR}/core/painter.h
+	${libcore_SOURCE_DIR}/core/panic.c
+	${libcore_SOURCE_DIR}/core/panic.h
+	${libcore_SOURCE_DIR}/core/plat.h
+	${libcore_SOURCE_DIR}/core/rbuf.c
+	${libcore_SOURCE_DIR}/core/rbuf.h
+	${libcore_SOURCE_DIR}/core/save.c
+	${libcore_SOURCE_DIR}/core/save.h
+	${libcore_SOURCE_DIR}/core/script.c
+	${libcore_SOURCE_DIR}/core/script.h
+	${libcore_SOURCE_DIR}/core/sound.c
+	${libcore_SOURCE_DIR}/core/sound.h
+	${libcore_SOURCE_DIR}/core/sprite.c
+	${libcore_SOURCE_DIR}/core/sprite.h
+	${libcore_SOURCE_DIR}/core/state.h
+	${libcore_SOURCE_DIR}/core/sys.c
+	${libcore_SOURCE_DIR}/core/sys.h
+	${libcore_SOURCE_DIR}/core/texture.c
+	${libcore_SOURCE_DIR}/core/texture.h
+	${libcore_SOURCE_DIR}/core/texture_p.h
+	${libcore_SOURCE_DIR}/core/theme.c
+	${libcore_SOURCE_DIR}/core/theme.h
+	${libcore_SOURCE_DIR}/core/util.c
+	${libcore_SOURCE_DIR}/core/util.h
+	${libcore_SOURCE_DIR}/core/wait.c
+	${libcore_SOURCE_DIR}/core/wait.h
+	${libcore_SOURCE_DIR}/core/walksprite.c
+	${libcore_SOURCE_DIR}/core/walksprite.h
+	${libcore_SOURCE_DIR}/core/window.c
+	${libcore_SOURCE_DIR}/core/window.h
+	${libcore_SOURCE_DIR}/core/window_p.h
+)
+
+molko_define_library(
+	TARGET libcore
+	SOURCES ${SOURCES}
+	ASSETS ${ASSETS}
+	LIBRARIES
+		libsqlite
+		SDL2::SDL2
+		SDL2::image
+		SDL2::mixer
+		SDL2::ttf
+	PRIVATE_FLAGS
+		BINDIR="${CMAKE_INSTALL_BINDIR}"
+		PREFIX="${CMAKE_INSTALL_PREFIX}"
+		SHAREDIR="${CMAKE_INSTALL_DATADIR}"
+	PUBLIC_FLAGS
+		_XOPEN_SOURCE=700
+	PUBLIC_INCLUDES
+		$<BUILD_INTERFACE:${libcore_SOURCE_DIR}>
+)
+
+source_group(core FILES ${SOURCES})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/action.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,100 @@
+/*
+ * action.h -- action states
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ACTION_H
+#define ACTION_H
+
+/**
+ * \file action.h
+ * \brief Action states.
+ * \ingroup actions
+ */
+
+#include <stdbool.h>
+
+union event;
+
+/**
+ * \brief Action flags.
+ */
+enum action_flags {
+	ACTION_NONE,                            /*!< No flags */
+	ACTION_AUTO_LEAVE       = (1 << 0)      /*!< Action is removed on state change */
+};
+
+/**
+ * \brief Action structure.
+ */
+struct action {
+	/**
+	 * (RW)
+	 *
+	 * Optional flags.
+	 */
+	enum action_flags flags;
+
+	/**
+	 * (RW)
+	 *
+	 * Arbitrary user data.
+	 */
+	void *data;
+
+	/**
+	 * (RW)
+	 *
+	 * Handle event.
+	 */
+	void (*handle)(struct action *, const union event *event);
+
+	/**
+	 * (RW)
+	 *
+	 * Update the action.
+	 *
+	 * If returns true, the action is removed.
+	 */
+	bool (*update)(struct action *, unsigned int);
+
+	/**
+	 * (RW)
+	 *
+	 * Draw the aciton.
+	 */
+	void (*draw)(struct action *);
+
+	/**
+	 * (RW)
+	 *
+	 * Called when the action was completed.
+	 *
+	 * This callback is mostly provided to allow the user doing something
+	 * else once an action is complete. Predefined actions should not use
+	 * this callback by themselves.
+	 */
+	void (*end)(struct action *a);
+
+	/**
+	 * (RW)
+	 *
+	 * Close the action before removal.
+	 */
+	void (*finish)(struct action *);
+};
+
+#endif /* !ACTION_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/animation.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,84 @@
+/*
+ * animation.c -- basic animations
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "animation.h"
+#include "sprite.h"
+
+void
+animation_init(struct animation *an, struct sprite *sprite, unsigned int delay)
+{
+	assert(an);
+	assert(sprite);
+
+	an->sprite = sprite;
+	an->row = 0;
+	an->column = 0;
+	an->delay = delay;
+	an->elapsed = 0;
+}
+
+bool
+animation_is_complete(const struct animation *an)
+{
+	assert(an);
+
+	return an->row == an->sprite->nrows &&
+	       an->column == an->sprite->ncols &&
+	       an->elapsed >= an->delay;
+}
+
+void
+animation_start(struct animation *an)
+{
+	assert(an);
+
+	an->row = 0;
+	an->column = 0;
+	an->elapsed = 0;
+}
+
+void
+animation_update(struct animation *an, unsigned int ticks)
+{
+	assert(an);
+
+	an->elapsed += ticks;
+
+	if (an->elapsed < an->delay)
+		return;
+
+	/* Increment column first */
+	if (++an->column >= an->sprite->ncols) {
+		/*
+		 * Increment row, if we reach the last row it means we are
+		 * at the last frame.
+		 */
+		if (++an->row >= an->sprite->nrows)
+			an->row = an->sprite->nrows;
+		else
+			an->column = 0;
+	}
+}
+
+void
+animation_draw(struct animation *an, int x, int y)
+{
+	sprite_draw(an->sprite, an->row, an->column, x, y);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/animation.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,91 @@
+/*
+ * animation.h -- basic animations
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_ANIMATION_H
+#define MOLKO_ANIMATION_H
+
+/**
+ * \file animation.h
+ * \brief Basic animations.
+ * \ingroup drawing
+ */
+
+#include <stdbool.h>
+
+struct sprite;
+
+/**
+ * \brief Animation object
+ */
+struct animation {
+	struct sprite *sprite;  /*!< Sprite to use (RW) */
+	unsigned int row;       /*!< current row (RO) */
+	unsigned int column;    /*!< current column (RO) */
+	unsigned int delay;     /*!< delay between frames (RW) */
+	unsigned int elapsed;   /*!< elapsed time since last frame (RO) */
+};
+
+/**
+ * Initialize the animation.
+ *
+ * The animation does not take sprite ownership, it must be valid until
+ * animation is no longer used.
+ *
+ * \pre an != NULL
+ * \pre sprite != NULL
+ * \param an the animation
+ * \param sprite the sprite to use
+ * \param delay the delay between frames in milliseconds
+ */
+void
+animation_init(struct animation *an, struct sprite *sprite, unsigned int delay);
+
+/**
+ * Start an animation.
+ *
+ * \pre an != NULL
+ * \param an the animation
+ */
+void
+animation_start(struct animation *an);
+
+/**
+ * Update the animation.
+ *
+ * You must call this function at each loop iteration to update the animation
+ * frame depending on its delay.
+ *
+ * \pre an != NULL
+ * \param an the animation
+ * \param ticks the elapsed ticks since the last call
+ */
+void
+animation_update(struct animation *an, unsigned int ticks);
+
+/**
+ * Draw the animation.
+ *
+ * \pre an != NULL
+ * \param an the animation
+ * \param x the X coordinate
+ * \param y the Y coordinate
+ */
+void
+animation_draw(struct animation *an, int x, int y);
+
+#endif /* !MOLKO_ANIMATION_H */
Binary file libcore/core/assets/fonts/ComicNeue-Regular.ttf has changed
Binary file libcore/core/assets/fonts/DejaVuSans.ttf has changed
Binary file libcore/core/assets/fonts/DejaVuSansCondensed.ttf has changed
Binary file libcore/core/assets/fonts/Lato-Regular.ttf has changed
Binary file libcore/core/assets/fonts/knights-quest.ttf has changed
Binary file libcore/core/assets/fonts/pirata-one.ttf has changed
Binary file libcore/core/assets/fonts/teutonic1.ttf has changed
Binary file libcore/core/assets/images/message.png has changed
Binary file libcore/core/assets/images/message.xcf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/assets/maps/test.map	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,20009 @@
+title|World
+origin|700|400
+width|100
+height|100
+tilewidth|32
+tileheight|32
+layer|background
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+111
+112
+112
+112
+112
+112
+112
+112
+112
+113
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+141
+142
+142
+142
+142
+142
+142
+142
+142
+143
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+141
+142
+142
+142
+142
+142
+142
+142
+142
+143
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+141
+142
+142
+142
+142
+142
+142
+142
+142
+143
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+141
+142
+142
+142
+142
+142
+142
+142
+142
+143
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+141
+142
+142
+142
+142
+142
+142
+142
+142
+143
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+141
+142
+142
+142
+142
+142
+142
+142
+142
+143
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+171
+172
+172
+172
+172
+172
+172
+172
+172
+173
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+21
+layer|foreground
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+407
+408
+409
+410
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+437
+438
+439
+440
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+467
+468
+469
+470
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+497
+498
+499
+500
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+527
+528
+529
+530
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+557
+558
+559
+560
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+587
+588
+589
+590
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+893
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+893
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+893
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+893
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+893
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+tileset|test.png
Binary file libcore/core/assets/sprites/test-walk.png has changed
Binary file libcore/core/assets/sprites/test-walk.xcf has changed
Binary file libcore/core/assets/tilesets/test.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/button.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,78 @@
+/*
+ * button.c -- GUI button
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "button.h"
+#include "event.h"
+#include "maths.h"
+#include "theme.h"
+
+static bool
+is_boxed(const struct button *button, const struct event_click *click)
+{
+	assert(button);
+	assert(click);
+	assert(click->type == EVENT_CLICKDOWN || click->type == EVENT_CLICKUP);
+
+	return maths_is_boxed(button->x, button->y, button->w, button->h,
+	    click->x, click->y);
+}
+
+void
+button_handle(struct button *button, const union event *ev)
+{
+	assert(button);
+	assert(ev);
+
+	switch (ev->type) {
+	case EVENT_CLICKDOWN:
+		if (is_boxed(button, &ev->click))
+			button->state = BUTTON_STATE_PRESSED;
+		break;
+	case EVENT_CLICKUP:
+		/*
+		 * If the button was pressed, indicate that the button is
+		 * finally activated. This let the user to move the cursor
+		 * outside the button to "forget" the press.
+		 */
+		if (!is_boxed(button, &ev->click))
+			button->state = BUTTON_STATE_NONE;
+		else if (button->state == BUTTON_STATE_PRESSED)
+			button->state = BUTTON_STATE_ACTIVATED;
+		break;
+	default:
+		break;
+	}
+}
+
+void
+button_reset(struct button *button)
+{
+	assert(button);
+
+	button->state = BUTTON_STATE_NONE;
+}
+
+void
+button_draw(struct button *button)
+{
+	assert(button);
+
+	theme_draw_button(button->theme, button);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/button.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,85 @@
+/*
+ * button.h -- GUI button
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_BUTTON_H
+#define MOLKO_BUTTON_H
+
+/**
+ * \file button.h
+ * \brief GUI button.
+ */
+
+union event;
+
+struct theme;
+
+/**
+ * \brief Button state.
+ */
+enum button_state {
+	BUTTON_STATE_NONE,              /*!< Button is inactive. */
+	BUTTON_STATE_PRESSED,           /*!< Button is currently pressed. */
+	BUTTON_STATE_ACTIVATED          /*!< Button is considered activated. */
+};
+
+/**
+ * \brief GUI button.
+ */
+struct button {
+	int x;                          /*!< (RW) Position in x. */
+	int y;                          /*!< (RW) Position in y. */
+	unsigned int w;                 /*!< (RW) Width. */
+	unsigned int h;                 /*!< (RW) Height. */
+	const char *text;               /*!< (RW, ref) Text to draw. */
+	enum button_state state;        /*!< (RW) Button state. */
+	struct theme *theme;            /*!< (RW, ref, optional) Theme to use. */
+};
+
+/**
+ * Handle the event.
+ *
+ * You should always call this function even if the event is completely
+ * unrelated.
+ *
+ * \pre button != NULL
+ * \pre ev != NULL
+ * \param button the button
+ * \param ev the event
+ */
+void
+button_handle(struct button *button, const union event *ev);
+
+/**
+ * Use this function once the button has been considered activated.
+ *
+ * \pre button != NULL
+ * \param button the button
+ */
+void
+button_reset(struct button *button);
+
+/**
+ * Draw the button.
+ *
+ * \pre button != NULL
+ * \param button the button
+ */
+void
+button_draw(struct button *button);
+
+#endif /* !MOLKO_BUTTON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/checkbox.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,55 @@
+/*
+ * checkbox.c -- GUI checkbox
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "checkbox.h"
+#include "theme.h"
+#include "event.h"
+#include "maths.h"
+
+static bool
+is_boxed(const struct checkbox *cb, const struct event_click *click)
+{
+	assert(cb);
+	assert(click && click->type == EVENT_CLICKDOWN);
+
+	return maths_is_boxed(cb->x, cb->y, cb->w, cb->h, click->x, click->y);
+}
+
+void
+checkbox_handle(struct checkbox *cb, const union event *ev)
+{
+	assert(cb);
+	assert(ev);
+
+	switch (ev->type) {
+	case EVENT_CLICKDOWN:
+		if (is_boxed(cb, &ev->click))
+			cb->checked = !cb->checked;
+		break;
+	default:
+		break;
+	}
+}
+
+void
+checkbox_draw(const struct checkbox *cb)
+{
+	theme_draw_checkbox(cb->theme, cb);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/checkbox.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,64 @@
+/*
+ * checkbox.h -- GUI checkbox
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_CHECKBOX_H
+#define MOLKO_CHECKBOX_H
+
+/**
+ * \file checkbox.h
+ * \brief GUI checkbox.
+ */
+
+#include <stdbool.h>
+
+union event;
+
+/**
+ * \brief GUI checkbox.
+ */
+struct checkbox {
+	int x;                  /*!< (RW) Position in x. */
+	int y;                  /*!< (RW) Position in y. */
+	unsigned int w;         /*!< (RW) Width. */
+	unsigned int h;         /*!< (RW) Height. */
+	const char *label;      /*!< (RW, ref) Text to show. */
+	bool checked;           /*!< (RW) Is activated? */
+	struct theme *theme;    /*!< (RW, ref, optional) Theme to use. */
+};
+
+/**
+ * Draw the checkbox.
+ *
+ * \pre cb != NULL
+ * \pre ev != NULL
+ * \param cb the checkbox
+ * \param ev the event
+ */
+void
+checkbox_handle(struct checkbox *cb, const union event *ev);
+
+/**
+ * Draw the checkbox.
+ *
+ * \pre cb != NULL
+ * \param cb the checkbox
+ */
+void
+checkbox_draw(const struct checkbox *cb);
+
+#endif /* !MOLKO_CHECKBOX_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/clock.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,33 @@
+/*
+ * clock.c -- track elapsed time
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <SDL.h>
+
+#include "clock.h"
+
+void
+clock_start(struct clock *clock)
+{
+	clock->ticks = SDL_GetTicks();
+}
+
+unsigned int
+clock_elapsed(const struct clock *clock)
+{
+	return SDL_GetTicks() - clock->ticks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/clock.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,54 @@
+/*
+ * clock.h -- track elapsed time
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_CLOCK_H
+#define MOLKO_CLOCK_H
+
+/**
+ * \file clock.h
+ * \brief Track elapsed time.
+ * \ingroup basics
+ */
+
+/**
+ * \brief Clock structure.
+ */
+struct clock {
+	unsigned int ticks;     /*!< time point on initialization */
+};
+
+/**
+ * Start the clock and track elapsed time.
+ *
+ * \pre clock != NULL
+ * \param clock the clock
+ */
+void
+clock_start(struct clock *clock);
+
+/**
+ * Tell the measured time.
+ *
+ * \pre clock != NULL
+ * \param clock the clock
+ * \return the elapsed time in milliseconds
+ */
+unsigned int
+clock_elapsed(const struct clock *clock);
+
+#endif /* !MOLKO_CLOCK_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/color.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,74 @@
+/*
+ * color.h -- basic color routines
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_COLOR_H
+#define MOLKO_COLOR_H
+
+/**
+ * \file color.h
+ * \brief Basic color routines.
+ */
+
+/**
+ * Get red component of hexadecimal color.
+ *
+ * \param c the hexadecimal color
+ * \return the red component
+ */
+#define COLOR_R(c)              (c >> 24 & 0xff)
+
+/**
+ * Get green component of hexadecimal color.
+ *
+ * \param c the hexadecimal color
+ * \return the green component
+ */
+#define COLOR_G(c)              (c >> 16 & 0xff)
+
+/**
+ * Get blue component of hexadecimal color.
+ *
+ * \param c the hexadecimal color
+ * \return the blue component
+ */
+#define COLOR_B(c)              (c >> 8  & 0xff)
+
+/**
+ * Get alpha component of hexadecimal color.
+ *
+ * \param c the hexadecimal color
+ * \return the alpha component
+ */
+#define COLOR_A(c)              (c       & 0xff)
+
+/**
+ * Convert individual RGBA components into a hexadecimal color.
+ *
+ * \param r the red component
+ * \param g the green component
+ * \param b the blue component
+ * \param a the alpha component
+ * \return the hexadecimal color
+ */
+#define COLOR_HEX(r, g, b, a)   \
+        ((r << 24 & 0xff000000) | \
+         (g << 16 & 0x00ff0000) | \
+         (b << 8  & 0x0000ff00) | \
+         (a       & 0x000000ff))
+
+#endif /* !MOLKO_COLOR_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/debug.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,73 @@
+/*
+ * debug.c -- debugging interfaces
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "debug.h"
+#include "font.h"
+#include "texture.h"
+
+#define PADDING_X 5
+#define PADDING_Y 5
+
+struct debug_options debug_options = {
+	.default_color = 0x0000ffff,
+	.default_style = FONT_STYLE_ANTIALIASED
+};
+
+void
+debug_printf(struct debug_report *report, const char *fmt, ...)
+{
+	assert(report);
+	assert(fmt);
+
+	va_list ap;
+
+	va_start(ap, fmt);
+	debug_vprintf(report, fmt, ap);
+	va_end(ap);
+}
+
+void
+debug_vprintf(struct debug_report *report, const char *fmt, va_list ap)
+{
+	assert(report);
+	assert(fmt);
+
+	char line[DEBUG_LINE_MAX];
+	struct texture tex;
+	struct font *font;
+	unsigned int gapy;
+
+	vsnprintf(line, sizeof (line), fmt, ap);
+
+	font = report->font ? report->font : debug_options.default_font;
+	font->color = report->color;
+	font->style = report->style;
+
+	if (!font_render(font, &tex, line))
+		return;
+
+	gapy = (PADDING_Y * (report->count)) +
+	    (font_height(font) * (report->count));
+	report->count++;
+
+	texture_draw(&tex, PADDING_X, gapy);
+	texture_finish(&tex);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/debug.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,133 @@
+/*
+ * debug.h -- debugging interfaces
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_DEBUG_H
+#define MOLKO_DEBUG_H
+
+/**
+ * \file debug.h
+ * \brief Debugging interfaces.
+ *
+ * This module provides functions to draw debugging information within the game
+ * window. It is mostly used for information only when state of the game is
+ * better inspected via direct window information rather than writing in the
+ * console.
+ *
+ * Predefined core states may print debugging information if
+ * debug_options.enabled variable is set to true. However, you need to specify
+ * the font to use in order to work.
+ *
+ * Each call to \ref debug_printf or \ref debug_vprintf automatically adjust
+ * next coordinate for rendering the text. As such, user may simply print
+ * several lines of text without having to deal with that manually.
+ *
+ * Example, activate global debugging.
+ *
+ * \code
+ * struct font *f = font_openf("foo.ttf", 10);
+ *
+ * if (!f)
+ * 	error_fatal();
+ *
+ * debug_options.default_font = f;
+ * debug_options.enabled = true;
+ * \endcode
+ *
+ * Example, print debugging information manually.
+ *
+ * \code
+ * struct debug_report report = {
+ * 	.color = 0x00ff00ff,
+ * 	.font = myfont          // Optional if debug_options.default_font is set.
+ * };
+ *
+ * debug_printf("current position: %d, %d\n", x, y);
+ * \endcode
+ */
+
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include "font.h"
+
+/**
+ * Maximum content length per report.
+ */
+#define DEBUG_LINE_MAX 1024
+
+/**
+ * \brief Debugging options.
+ *
+ * Fill this structure with appropriate values to change debugging behavior
+ * in core API.
+ */
+struct debug_options {
+	struct font *default_font;      /*!< (RW) Default font for reports. */
+	enum font_style default_style;  /*!< (RW) Default font style. */
+	unsigned long default_color;    /*!< (RW) Default font color. */
+	bool enable;                    /*!< (RW) Enable core API debugging. */
+};
+
+/**
+ * \brief Debug context.
+ *
+ * Use this structure each time you need to print one or more messages.
+ */
+struct debug_report {
+	struct font *font;              /*!< (RW) Font to use. */
+	enum font_style style;          /*!< (RW) Font style to use. */
+	unsigned long color;            /*!< (RW) Font foreground color to use. */
+	unsigned int count;             /*!< (PV) Number of messages already printed. */
+};
+
+/**
+ * Global debugging options.
+ */
+extern struct debug_options debug_options;
+
+/**
+ * Convenient macro to initialize \ref debug_report with default values.
+ */
+#define DEBUG_INIT_DEFAULTS {                   \
+        .font = debug_options.default_font,     \
+        .color = debug_options.default_color,   \
+        .style = debug_options.default_style    \
+}
+
+/**
+ * Print debugging information into the screen.
+ *
+ * \pre report != NULL
+ * \pre fmt != NULL
+ * \param report the reporting context
+ * \param fmt the printf(3) format string
+ * \note The message length must not exceed DEBUG_LINE_MAX, otherwise its
+ *       result is truncated.
+ */
+void
+debug_printf(struct debug_report *report, const char *fmt, ...);
+
+/**
+ * Similar to \ref debug_printf but with a va_list object.
+ *
+ * \see \ref debug_printf
+ */
+void
+debug_vprintf(struct debug_report *report, const char *fmt, va_list ap);
+
+#endif /* !MOLKO_DEBUG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/error.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,78 @@
+/*
+ * error.c -- error routines
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "error_p.h"
+
+#include <SDL.h>
+
+static char buffer[2048];
+
+const char *
+error(void)
+{
+	return buffer;
+}
+
+bool
+error_errno(void)
+{
+	error_printf("%s", strerror(errno));
+
+	return false;
+}
+
+bool
+error_printf(const char *fmt, ...)
+{
+	assert(fmt);
+
+	va_list ap;
+
+	va_start(ap, fmt);
+	error_vprintf(fmt, ap);
+	va_end(ap);
+
+	return false;
+}
+
+bool
+error_vprintf(const char *fmt, va_list ap)
+{
+	assert(fmt);
+
+	vsnprintf(buffer, sizeof (buffer), fmt, ap);
+
+	return false;
+}
+
+/* private: error_p.h */
+
+bool
+error_sdl(void)
+{
+	error_printf("%s", SDL_GetError());
+
+	return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/error.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,71 @@
+/*
+ * error.h -- error routines
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_ERROR_H
+#define MOLKO_ERROR_H
+
+/**
+ * \file error.h
+ * \brief Error routines.
+ * \ingroup basics
+ */
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include "plat.h"
+
+/**
+ * Get the last error returned.
+ *
+ * \return The error string.
+ */
+const char *
+error(void);
+
+/**
+ * Convenient helper that sets last error from global C errno and then return
+ * false.
+ *
+ * \return Always false.
+ */
+bool
+error_errno(void);
+
+/**
+ * Set the game error with a printf-like format.
+ *
+ * \pre fmt != NULL
+ * \param fmt the format string
+ * \return Always false.
+ */
+bool
+error_printf(const char *fmt, ...) PLAT_PRINTF(1, 2);
+
+/**
+ * Similar to \ref error_printf.
+ *
+ * \pre fmt != NULL
+ * \param fmt the format stinrg
+ * \param ap the variadic arguments pointer
+ * \return Always false.
+ */
+bool
+error_vprintf(const char *fmt, va_list ap) PLAT_PRINTF(1, 0);
+
+#endif /* !MOLKO_ERROR_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/error_p.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,33 @@
+/*
+ * error.h -- (PRIVATE) error routines
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_ERROR_P_H
+#define MOLKO_ERROR_P_H
+
+#include <stdbool.h>
+
+/**
+ * Convenient handler that sets the game error to the last SDL error and then
+ * return false.
+ *
+ * \return false
+ */
+bool
+error_sdl(void);
+
+#endif /* !MOLKO_ERROR_P_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/event.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,255 @@
+/*
+ * event.c -- event management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <SDL.h>
+
+#include "event.h"
+
+/* Maintain with enum key constants in key.h */
+static const struct {
+	SDL_Keycode key;
+	enum key value;
+} keymap[] = {
+	{ SDLK_RETURN,          KEY_ENTER               },
+	{ SDLK_ESCAPE,          KEY_ESCAPE              },
+	{ SDLK_BACKSPACE,       KEY_BACKSPACE           },
+	{ SDLK_TAB,             KEY_TAB                 },
+	{ SDLK_SPACE,           KEY_SPACE               },
+	{ SDLK_EXCLAIM,         KEY_EXCLAIM             },
+	{ SDLK_QUOTEDBL,        KEY_DOUBLE_QUOTE        },
+	{ SDLK_HASH,            KEY_HASH                },
+	{ SDLK_PERCENT,         KEY_PERCENT             },
+	{ SDLK_DOLLAR,          KEY_DOLLAR              },
+	{ SDLK_AMPERSAND,       KEY_AMPERSAND           },
+	{ SDLK_QUOTE,           KEY_QUOTE               },
+	{ SDLK_LEFTPAREN,       KEY_LEFT_PAREN          },
+	{ SDLK_RIGHTPAREN,      KEY_RIGHT_PAREN         },
+	{ SDLK_ASTERISK,        KEY_ASTERISK            },
+	{ SDLK_PLUS,            KEY_PLUS                },
+	{ SDLK_COMMA,           KEY_COMMA               },
+	{ SDLK_MINUS,           KEY_MINUS               },
+	{ SDLK_PERIOD,          KEY_PERIOD              },
+	{ SDLK_SLASH,           KEY_SLASH               },
+	{ SDLK_0,               KEY_0                   },
+	{ SDLK_1,               KEY_1                   },
+	{ SDLK_2,               KEY_2                   },
+	{ SDLK_3,               KEY_3                   },
+	{ SDLK_4,               KEY_4                   },
+	{ SDLK_5,               KEY_5                   },
+	{ SDLK_6,               KEY_6                   },
+	{ SDLK_7,               KEY_7                   },
+	{ SDLK_8,               KEY_8                   },
+	{ SDLK_9,               KEY_9                   },
+	{ SDLK_COLON,           KEY_COLON               },
+	{ SDLK_SEMICOLON,       KEY_SEMICOLON           },
+	{ SDLK_LESS,            KEY_LESS                },
+	{ SDLK_EQUALS,          KEY_EQUALS              },
+	{ SDLK_GREATER,         KEY_GREATER             },
+	{ SDLK_QUESTION,        KEY_QUESTION            },
+	{ SDLK_AT,              KEY_AT                  },
+	{ SDLK_LEFTBRACKET,     KEY_LEFT_BRACKET        },
+	{ SDLK_BACKSLASH,       KEY_BACKSLASH           },
+	{ SDLK_RIGHTBRACKET,    KEY_RIGHT_BRACKET       },
+	{ SDLK_CARET,           KEY_CARET               },
+	{ SDLK_UNDERSCORE,      KEY_UNDERSCORE          },
+	{ SDLK_BACKQUOTE,       KEY_BACKQUOTE           },
+	{ SDLK_a,               KEY_a                   },
+	{ SDLK_b,               KEY_b                   },
+	{ SDLK_c,               KEY_c                   },
+	{ SDLK_d,               KEY_d                   },
+	{ SDLK_e,               KEY_e                   },
+	{ SDLK_f,               KEY_f                   },
+	{ SDLK_g,               KEY_g                   },
+	{ SDLK_h,               KEY_h                   },
+	{ SDLK_i,               KEY_i                   },
+	{ SDLK_j,               KEY_j                   },
+	{ SDLK_k,               KEY_k                   },
+	{ SDLK_l,               KEY_l                   },
+	{ SDLK_m,               KEY_m                   },
+	{ SDLK_n,               KEY_n                   },
+	{ SDLK_o,               KEY_o                   },
+	{ SDLK_p,               KEY_p                   },
+	{ SDLK_q,               KEY_q                   },
+	{ SDLK_r,               KEY_r                   },
+	{ SDLK_s,               KEY_s                   },
+	{ SDLK_t,               KEY_t                   },
+	{ SDLK_u,               KEY_u                   },
+	{ SDLK_v,               KEY_v                   },
+	{ SDLK_w,               KEY_w                   },
+	{ SDLK_x,               KEY_x                   },
+	{ SDLK_y,               KEY_y                   },
+	{ SDLK_z,               KEY_z                   },
+	{ SDLK_CAPSLOCK,        KEY_CAPSLOCK            },
+	{ SDLK_F1,              KEY_F1                  },
+	{ SDLK_F2,              KEY_F2                  },
+	{ SDLK_F3,              KEY_F3                  },
+	{ SDLK_F4,              KEY_F4                  },
+	{ SDLK_F5,              KEY_F5                  },
+	{ SDLK_F6,              KEY_F6                  },
+	{ SDLK_F7,              KEY_F7                  },
+	{ SDLK_F8,              KEY_F8                  },
+	{ SDLK_F9,              KEY_F9                  },
+	{ SDLK_F10,             KEY_F10                 },
+	{ SDLK_F11,             KEY_F11                 },
+	{ SDLK_F12,             KEY_F12                 },
+	{ SDLK_F13,             KEY_F13                 },
+	{ SDLK_F14,             KEY_F14                 },
+	{ SDLK_F15,             KEY_F15                 },
+	{ SDLK_F16,             KEY_F16                 },
+	{ SDLK_F17,             KEY_F17                 },
+	{ SDLK_F18,             KEY_F18                 },
+	{ SDLK_F19,             KEY_F19                 },
+	{ SDLK_F20,             KEY_F20                 },
+	{ SDLK_F21,             KEY_F21                 },
+	{ SDLK_F22,             KEY_F22                 },
+	{ SDLK_F23,             KEY_F23                 },
+	{ SDLK_F24,             KEY_F24                 },
+	{ SDLK_PRINTSCREEN,     KEY_PRINTSCREEN         },
+	{ SDLK_SCROLLLOCK,      KEY_SCROLLLOCK          },
+	{ SDLK_PAUSE,           KEY_PAUSE               },
+	{ SDLK_INSERT,          KEY_INSERT              },
+	{ SDLK_HOME,            KEY_HOME                },
+	{ SDLK_PAGEUP,          KEY_PAGEUP              },
+	{ SDLK_DELETE,          KEY_DELETE              },
+	{ SDLK_END,             KEY_END                 },
+	{ SDLK_PAGEDOWN,        KEY_PAGEDOWN            },
+	{ SDLK_RIGHT,           KEY_RIGHT               },
+	{ SDLK_LEFT,            KEY_LEFT                },
+	{ SDLK_DOWN,            KEY_DOWN                },
+	{ SDLK_UP,              KEY_UP                  },
+	{ SDLK_KP_DIVIDE,       KEY_KP_DIVIDE           },
+	{ SDLK_KP_MULTIPLY,     KEY_KP_MULTIPLY         },
+	{ SDLK_KP_MINUS,        KEY_KP_MINUS            },
+	{ SDLK_KP_PLUS,         KEY_KP_PLUS             },
+	{ SDLK_KP_ENTER,        KEY_KP_ENTER            },
+	{ SDLK_KP_1,            KEY_KP_1                },
+	{ SDLK_KP_2,            KEY_KP_2                },
+	{ SDLK_KP_3,            KEY_KP_3                },
+	{ SDLK_KP_4,            KEY_KP_4                },
+	{ SDLK_KP_5,            KEY_KP_5                },
+	{ SDLK_KP_6,            KEY_KP_6                },
+	{ SDLK_KP_7,            KEY_KP_7                },
+	{ SDLK_KP_8,            KEY_KP_8                },
+	{ SDLK_KP_9,            KEY_KP_9                },
+	{ SDLK_KP_0,            KEY_KP_0                },
+	{ SDLK_KP_PERIOD,       KEY_KP_PERIOD           },
+	{ SDLK_KP_COMMA,        KEY_KP_COMMA            },
+	{ SDLK_MENU,            KEY_MENU                },
+	{ SDLK_MUTE,            KEY_MUTE                },
+	{ SDLK_VOLUMEUP,        KEY_VOLUME_UP           },
+	{ SDLK_VOLUMEDOWN,      KEY_VOLUME_DOWN         },
+	{ SDLK_LCTRL,           KEY_LCTRL               },
+	{ SDLK_LSHIFT,          KEY_LSHIFT              },
+	{ SDLK_LALT,            KEY_LALT                },
+	{ SDLK_LGUI,            KEY_LSUPER              },
+	{ SDLK_RCTRL,           KEY_RCTRL               },
+	{ SDLK_RSHIFT,          KEY_RSHIFT              },
+	{ SDLK_RALT,            KEY_RALT                },
+	{ SDLK_RGUI,            KEY_RSUPER              },
+	{ 0,                    -1                      }
+};
+
+/* Maintain with enum mouse_button constants in mouse.h */
+static const struct {
+	int key;
+	enum mouse_button value;
+} buttons[] = {
+	{ SDL_BUTTON_LEFT,      MOUSE_BUTTON_LEFT       },
+	{ SDL_BUTTON_MIDDLE,    MOUSE_BUTTON_MIDDLE     },
+	{ SDL_BUTTON_RIGHT,     MOUSE_BUTTON_RIGHT      },
+	{ -1,                   MOUSE_BUTTON_UNKNOWN    }
+};
+
+static void
+convert_key(const SDL_Event *event, union event *ev)
+{
+	ev->type = event->type == SDL_KEYDOWN ? EVENT_KEYDOWN : EVENT_KEYUP;
+	ev->key.key = KEY_UNKNOWN;
+
+	for (size_t i = 0; keymap[i].key != 0; ++i) {
+		if (keymap[i].key == event->key.keysym.sym) {
+			ev->key.key = keymap[i].value;
+			break;
+		}
+	}
+}
+
+static void
+convert_mouse(const SDL_Event *event, union event *ev)
+{
+	ev->type = EVENT_MOUSE;
+	ev->mouse.buttons = 0;
+	ev->mouse.x = event->motion.x;
+	ev->mouse.y = event->motion.y;
+
+	if (event->motion.state & SDL_BUTTON_LMASK)
+		ev->mouse.buttons |= MOUSE_BUTTON_LEFT;
+	if (event->motion.state & SDL_BUTTON_MMASK)
+		ev->mouse.buttons |= MOUSE_BUTTON_MIDDLE;
+	if (event->motion.state & SDL_BUTTON_RMASK)
+		ev->mouse.buttons |= MOUSE_BUTTON_RIGHT;
+}
+
+static void
+convert_click(const SDL_Event *event, union event *ev)
+{
+	ev->type = event->type == SDL_MOUSEBUTTONDOWN ? EVENT_CLICKDOWN : EVENT_CLICKUP;
+	ev->click.button = MOUSE_BUTTON_UNKNOWN;
+	ev->click.x = event->button.x;
+	ev->click.y = event->button.y;
+
+	for (size_t i = 0; buttons[i].value != MOUSE_BUTTON_UNKNOWN; ++i) {
+		if (buttons[i].key == event->button.button) {
+			ev->click.button = buttons[i].value;
+			break;
+		}
+	}
+}
+
+bool
+event_poll(union event *ev)
+{
+	SDL_Event event;
+
+	/*
+	 * Loop until we find an event we want to report, we skip unneeded
+	 * ones.
+	 */
+	while (SDL_PollEvent(&event)) {
+		switch (event.type) {
+		case SDL_QUIT:
+			ev->type = EVENT_QUIT;
+			return true;
+		case SDL_KEYDOWN:
+		case SDL_KEYUP:
+			convert_key(&event, ev);
+			return true;
+		case SDL_MOUSEMOTION:
+			convert_mouse(&event, ev);
+			return true;
+		case SDL_MOUSEBUTTONDOWN:
+		case SDL_MOUSEBUTTONUP:
+			convert_click(&event, ev);
+			return true;
+		default:
+			continue;
+		}
+	}
+
+	return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/event.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,92 @@
+/*
+ * event.h -- event management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_EVENT_H
+#define MOLKO_EVENT_H
+
+/**
+ * \file event.h
+ * \brief Event management.
+ * \ingroup input
+ */
+
+#include <stdbool.h>
+
+#include "key.h"
+#include "mouse.h"
+
+/**
+ * \brief Kind of event.
+ */
+enum event_type {
+	EVENT_CLICKDOWN,        /*!< Mouse click down (\ref event_click) */
+	EVENT_CLICKUP,          /*!< Mouse click released (\ref event_click) */
+	EVENT_KEYDOWN,          /*!< Single key down (\ref event_key) */
+	EVENT_KEYUP,            /*!< Single key released (\ref event_key) */
+	EVENT_MOUSE,            /*!< Mouse moved (\ref event_mouse) */
+	EVENT_QUIT,             /*!< Quit request */
+};
+
+/**
+ * \brief Key event.
+ */
+struct event_key {
+	enum event_type type;           /*!< EVENT_KEYDOWN or EVENT_KEYUP */
+	enum key key;                   /*!< Which key */
+};
+
+/**
+ * \brief Mouse motion event.
+ */
+struct event_mouse {
+	enum event_type type;           /*!< EVENT_MOUSE */
+	enum mouse_button buttons;      /*!< OR'ed buttons that are pressed */
+	int x;                          /*!< Mouse position in x */
+	int y;                          /*!< Mouse position in y */
+};
+
+/**
+ * \brief Mouse click event.
+ */
+struct event_click {
+	enum event_type type;           /*!< EVENT_CLICKDOWN or EVENT_CLICKUP */
+	enum mouse_button button;       /*!< Unique button that was pressed */
+	int x;                          /*!< Mouse position in x */
+	int y;                          /*!< Mouse position in y */
+};
+
+/**
+ * \brief Store events.
+ */
+union event {
+	enum event_type type;           /*!< Which kind of event */
+	struct event_key key;           /*!< Key event */
+	struct event_mouse mouse;       /*!< Mouse motion event */
+	struct event_click click;       /*!< Mouse click event */
+};
+
+/**
+ * Fetch the next event or return false if there are not.
+ *
+ * \param ev the event
+ * \return true if the event was filled or false otherwise
+ */
+bool
+event_poll(union event *ev);
+
+#endif /* !MOLKO_EVENT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/font.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,112 @@
+/*
+ * font.c -- basic font management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <SDL_ttf.h>
+
+#include "color.h"
+#include "error.h"
+#include "error_p.h"
+#include "font.h"
+#include "texture_p.h"
+#include "util.h"
+
+bool
+font_open(struct font *font, const char *path, unsigned int size)
+{
+	assert(font);
+	assert(path);
+
+	if (!(font->handle = TTF_OpenFont(path, size)))
+		return error_sdl();
+
+	return true;
+}
+
+bool
+font_openmem(struct font *font, const void *buffer, size_t buflen, unsigned int size)
+{
+	assert(font);
+	assert(buffer);
+
+	SDL_RWops *ops;
+
+	if (!(ops = SDL_RWFromConstMem(buffer, buflen)) ||
+	   (!(font->handle = TTF_OpenFontRW(ops, true, size))))
+		return error_sdl();
+
+	return true;
+}
+
+bool
+font_ok(const struct font *font)
+{
+	assert(font);
+
+	return font->handle;
+}
+
+bool
+font_render(struct font *font, struct texture *tex, const char *text)
+{
+	assert(font);
+	assert(text);
+
+	SDL_Color fg = {
+		.r = COLOR_R(font->color),
+		.g = COLOR_G(font->color),
+		.b = COLOR_B(font->color),
+		.a = COLOR_A(font->color)
+	};
+	SDL_Surface *surface;
+	SDL_Surface *(*func)(TTF_Font *, const char *, SDL_Color);
+
+	switch (font->style) {
+	case FONT_STYLE_ANTIALIASED:
+		func = TTF_RenderUTF8_Blended;
+		break;
+	default:
+		func = TTF_RenderUTF8_Solid;
+		break;
+	}
+
+	if (!(surface = func(font->handle, text, fg)))
+		return error_sdl();
+
+	return texture_from_surface(tex, surface);
+}
+
+unsigned int
+font_height(const struct font *font)
+{
+	assert(font);
+
+	return TTF_FontHeight(font->handle);
+}
+
+void
+font_finish(struct font *font)
+{
+	assert(font);
+
+	if (font->handle)
+		TTF_CloseFont(font->handle);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/font.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,123 @@
+/*
+ * font.h -- basic font management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_FONT_H
+#define MOLKO_FONT_H
+
+/**
+ * \file font.h
+ * \brief Basic font management.
+ * \ingroup drawing
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct texture;
+
+/**
+ * \brief Font style for rendering.
+ */
+enum font_style {
+	FONT_STYLE_ANTIALIASED,         /*!< Pretty antialiasing looking. */
+	FONT_STYLE_NONE                 /*!< No antialiasing. */
+};
+
+/**
+ * \brief Font object.
+ */
+struct font {
+	enum font_style style;          /*!< (RW) Style for rendering. */
+	unsigned long color;            /*!< (RW) Color for rendering. */
+	void *handle;                   /*!< (RO) Native handle. */
+};
+
+/**
+ * Open font from path file.
+ *
+ * \pre font != NULL
+ * \pre path != NULL
+ * \param font the font to initialize
+ * \param path the path to the font
+ * \param size the desired size
+ * \return False on errors.
+ */
+bool
+font_open(struct font *font, const char *path, unsigned int size);
+
+/**
+ * Open font from memory buffer.
+ *
+ * \pre font != NULL
+ * \pre buffer != NULL
+ * \param font the font to initialize
+ * \param buffer the memory buffer
+ * \param buflen the memory buffer length
+ * \param size the desired size
+ * \warning The buffer must remain valid until font is closed
+ * \return False on errors.
+ */
+bool
+font_openmem(struct font *font, const void *buffer, size_t buflen, unsigned int size);
+
+/**
+ * Tells if the font was properly opened.
+ *
+ * \pre font != NULL
+ * \param font the font to check
+ * \return True if the native handle was opened.
+ */
+bool
+font_ok(const struct font *font);
+
+/**
+ * Render some text into the texture.
+ *
+ * This function use the current color/style and other properties in the font
+ * to render the texture.
+ *
+ * \pre font != NULL
+ * \pre tex != NULL
+ * \param font the font to use
+ * \param tex the texture to generate
+ * \param text the UTF-8 text
+ * \return False on errors.
+ */
+bool
+font_render(struct font *font, struct texture *tex, const char *text);
+
+/**
+ * Get the maximum height for all glyphs.
+ *
+ * \pre font != NULL
+ * \param font the font handle
+ * \return the height in pixels
+ */
+unsigned int
+font_height(const struct font *font);
+
+/**
+ * Close the font.
+ *
+ * \pre font != NULL
+ * \param font the font handle
+ */
+void
+font_finish(struct font *font);
+
+#endif /* !MOLKO_FONT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/frame.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,30 @@
+/*
+ * frame.h -- GUI frame
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "frame.h"
+#include "theme.h"
+
+void
+frame_draw(const struct frame *frame)
+{
+	assert(frame);
+
+	theme_draw_frame(frame->theme, frame);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/frame.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,58 @@
+/*
+ * frame.h -- GUI frame
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_FRAME_H
+#define MOLKO_FRAME_H
+
+/**
+ * \file frame.h
+ * \brief GUI frame.
+ */
+
+struct theme;
+
+/**
+ * \brief Frame style.
+ */
+enum frame_style {
+	FRAME_STYLE_NORMAL,
+	FRAME_STYLE_BOX
+};
+
+/**
+ * \brief GUI frame.
+ */
+struct frame {
+	int x;                  /*!< (RW) Position in x. */
+	int y;                  /*!< (RW) Position in y. */
+	unsigned int w;         /*!< (RW) Width. */
+	unsigned int h;         /*!< (RW) Height. */
+	enum frame_style style; /*!< (RW) Frame style. */
+	struct theme *theme;    /*!< (RW, ref, optional) Theme to use. */
+};
+
+/**
+ * Draw the frame.
+ *
+ * \pre frame != NULL
+ * \param frame the frame to draw
+ */
+void
+frame_draw(const struct frame *frame);
+
+#endif /* !MOLKO_FRAME_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/game.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,167 @@
+/*
+ * game.c -- main game object
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "game.h"
+#include "state.h"
+#include "painter.h"
+
+struct game game;
+
+static struct action *
+find_empty_action(void)
+{
+	static struct action null;
+
+	for (struct action *a = game.actions; a != &game.actions[GAME_ACTIONS_MAX]; ++a)
+		if (memcmp(a, &null, sizeof (struct action)) == 0)
+			return a;
+
+	return NULL;
+}
+
+static void
+clear_actions(void)
+{
+	for (struct action *a = game.actions; a != &game.actions[GAME_ACTIONS_MAX]; ++a) {
+		/* These actions are removed on state change. */
+		if (a->flags & ACTION_AUTO_LEAVE) {
+			if (a->finish)
+				a->finish(a);
+
+			memset(a, 0, sizeof (struct action));
+		}
+	}
+}
+
+static void
+handle_actions(const union event *event)
+{
+	for (struct action *a = game.actions; a != &game.actions[GAME_ACTIONS_MAX]; ++a)
+		if (a->handle)
+			a->handle(a, event);
+}
+
+static void
+update_actions(unsigned int ticks)
+{
+	for (size_t i = 0; i < GAME_ACTIONS_MAX; ++i) {
+		struct action *a = &game.actions[i];
+
+		if (!a->update)
+			continue;
+
+		if (a->update(a, ticks)) {
+			if (a->end)
+				a->end(a);
+			if (a->finish)
+				a->finish(a);
+
+			memset(&game.actions[i], 0, sizeof (struct action));
+		}
+	}
+}
+
+static void
+draw_actions(void)
+{
+	for (size_t i = 0; i < GAME_ACTIONS_MAX; ++i)
+		if (game.actions[i].draw)
+			game.actions[i].draw(&game.actions[i]);
+}
+
+void
+game_switch(struct state *state, bool quick)
+{
+	assert(state);
+
+	if (quick) {
+		game.state = state;
+		game.state->enter();
+	} else
+		game.state_next = state;
+}
+
+void
+game_handle(const union event *event)
+{
+	assert(event);
+
+	if (game.state && !(game.inhibit & INHIBIT_STATE_INPUT))
+		game.state->handle(event);
+
+	handle_actions(event);
+}
+
+void
+game_update(unsigned int ticks)
+{
+	if (!(game.inhibit & INHIBIT_STATE_UPDATE)) {
+		/* Change state if any. */
+		if (game.state_next) {
+			/* Inform the current state we're gonna leave it. */
+			if (game.state)
+				game.state->leave();
+
+			game.state = game.state_next;
+			game.state->enter();
+			game.state_next = NULL;
+
+			/* Remove any actions that must be deleted. */
+			clear_actions();
+		}
+
+		if (game.state)
+			game.state->update(ticks);
+	}
+
+	update_actions(ticks);
+}
+
+void
+game_draw(void)
+{
+	if (game.state && !(game.inhibit & INHIBIT_STATE_DRAW))
+		game.state->draw();
+
+	draw_actions();
+	painter_present();
+}
+
+void
+game_add_action(const struct action *action)
+{
+	assert(action);
+
+	struct action *pos;
+
+	if ((pos = find_empty_action()))
+		memcpy(pos, action, sizeof (struct action));
+}
+
+void
+game_quit(void)
+{
+	if (game.state && game.state->leave)
+		game.state->leave();
+
+	game.state = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/game.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,118 @@
+/*
+ * game.h -- main game object
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_GAME_H
+#define MOLKO_GAME_H
+
+/**
+ * \file game.h
+ * \brief Main game object.
+ */
+
+#include <stdbool.h>
+
+#include "action.h"
+#include "inhibit.h"
+
+/**
+ * \brief Max number of actions allowed at the same time.
+ */
+#define GAME_ACTIONS_MAX 128
+
+struct state;
+
+union event;
+
+/**
+ * \brief Main game object.
+ */
+struct game {
+	/* Inhibition */
+	enum inhibit inhibit;           /*!< (RW) What to disable. */
+
+	/* Game states. */
+	struct state *state;            /*!< (RO) Current state  */
+	struct state *state_next;       /*!< (RO) Next state */
+
+	/** Array of actions. */
+	struct action actions[GAME_ACTIONS_MAX];
+};
+
+/**
+ * Global game object.
+ */
+extern struct game game;
+
+/**
+ * Request to change state.
+ *
+ * This function will only update state after the next \ref  game_update call
+ * unless quick is set to true.
+ *
+ * \pre state != NULL
+ * \param state the new state
+ * \param quick quickly change the state
+ */
+void
+game_switch(struct state *state, bool quick);
+
+/**
+ * Handle input event.
+ *
+ * \param event the event
+ */
+void
+game_handle(const union event *event);
+
+/**
+ * Update the game state.
+ *
+ * \param ticks the number of milliseconds between last frame
+ */
+void
+game_update(unsigned int ticks);
+
+/**
+ * Draw the game using the current state.
+ */
+void
+game_draw(void);
+
+/**
+ * Add an action to the game.
+ *
+ * If there are no room for the action, action is discarded. Make sure to not
+ * exceed the limit GAME_ACTIONS_MAX.
+ *
+ * \pre action != NULL
+ * \param action the action to copy
+ * \note The core API **never** add actions by itself.
+ */
+void
+game_add_action(const struct action *action);
+
+/**
+ * Stop the game.
+ *
+ * This will effectively stop the current state but the main loop may continue
+ * until it has completed.
+ */
+void
+game_quit(void);
+
+#endif /* !MOLKO_GAME_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/image.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,69 @@
+/*
+ * image.c -- basic image management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <SDL_image.h>
+
+#include "error_p.h"
+#include "texture.h"
+#include "window.h"
+#include "window_p.h"
+
+static void
+dimensions(struct texture *tex)
+{
+	int w, h;
+
+	if (SDL_QueryTexture(tex->handle, NULL, NULL, &w, &h) < 0)
+		tex->w = tex->h = 0;
+	else {
+		tex->w = w;
+		tex->h = h;
+	}
+}
+
+bool
+image_open(struct texture *tex, const char *path)
+{
+	assert(tex);
+	assert(path);
+
+	if (!(tex->handle = IMG_LoadTexture(RENDERER(), path)))
+		return error_sdl();
+
+	dimensions(tex);
+
+	return true;
+}
+
+bool
+image_openmem(struct texture *tex, const void *buffer, size_t size)
+{
+	assert(buffer);
+
+	SDL_RWops *ops = SDL_RWFromConstMem(buffer, size);
+
+	if (!ops || !(tex->handle = IMG_LoadTexture_RW(RENDERER(), ops, true)))
+		return error_sdl();
+
+	dimensions(tex);
+
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/image.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,60 @@
+/*
+ * image.h -- basic image management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_IMAGE_H
+#define MOLKO_IMAGE_H
+
+/**
+ * \file image.h
+ * \brief Basic image management.
+ * \ingroup drawing
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct texture;
+
+/**
+ * Open a file from a path.
+ *
+ * \pre tex != NULL
+ * \pre path != NULL
+ * \param tex the texture to initialize
+ * \param path the path to the file
+ * \return False on errors.
+ */
+bool
+image_open(struct texture *tex, const char *path);
+
+/**
+ * Open a file from a memory buffer.
+ *
+ * The buffer must be valid until the image is no longer used.
+ *
+ * \pre tex != NULL
+ * \pre buffer != NULL
+ * \param tex the texture to initialize
+ * \param buffer the memory buffer
+ * \param size the memory size
+ * \return False on errors.
+ */
+bool
+image_openmem(struct texture *tex, const void *buffer, size_t size);
+
+#endif /* !MOLKO_IMAGE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/inhibit.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,53 @@
+/*
+ * inhibit.c -- disable specific game behavior
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "action.h"
+#include "inhibit.h"
+#include "game.h"
+#include "util.h"
+
+static bool
+update(struct action *a, unsigned int ticks)
+{
+	(void)ticks;
+
+	game.inhibit = *((enum inhibit *)a->data);
+
+	return true;
+}
+
+static void
+finish(struct action *a)
+{
+	free(a->data);
+}
+
+void
+inhibit_action(enum inhibit mode, struct action *a)
+{
+	assert(a);
+
+	memset(a, 0, sizeof (struct action));
+	a->data = ememdup(&mode, sizeof (enum inhibit));
+	a->update = update;
+	a->finish = finish;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/inhibit.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,68 @@
+/*
+ * inhibit.h -- disable specific game behavior
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_INHIBIT_H
+#define MOLKO_INHIBIT_H
+
+/**
+ * \file inhibit.h
+ * \brief Disable specific game behavior.
+ */
+
+struct action;
+
+/**
+ * \brief Game inhibition.
+ *
+ * This enum is used to alter the game behavior.
+ */
+enum inhibit {
+	/**
+	 * Nothing.
+	 */
+	INHIBIT_NONE,
+
+	/**
+	 * Disable input handling in current state.
+	 */
+	INHIBIT_STATE_INPUT        = (1 << 0),
+
+	/**
+	 * Disable current state updates.
+	 */
+	INHIBIT_STATE_UPDATE       = (1 << 1),
+
+	/**
+	 * Disable current state rendering.
+	 */
+	INHIBIT_STATE_DRAW         = (1 << 2)
+};
+
+/**
+ * Create an action to inhibit the system.
+ *
+ * The mode will replace the actual inhibit modes rather than adding new flags.
+ *
+ * \pre a != NULL
+ * \param mode the new mode
+ * \param a the action to fill
+ */
+void
+inhibit_action(enum inhibit mode, struct action *a);
+
+#endif /* !MOLKO_INHIBIT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/inventory.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,210 @@
+/*
+ * inventory.c -- inventory of items
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "inventory.h"
+#include "item.h"
+
+#define INVENTORY_TOTAL (INVENTORY_ROWS_MAX * INVENTORY_COLS_MAX)
+
+static bool
+can_be_used(struct inventory_slot *slot, const struct item *item)
+{
+	assert(item);
+
+	/* Empty slot. */
+	if (!slot->item)
+		return false;
+
+	/* Not same object. */
+	if (strcmp(slot->item->name, item->name) != 0)
+		return false;
+
+	/* No space in this slot. */
+	if (slot->amount >= slot->item->stackable)
+		return false;
+
+	return true;
+}
+
+static struct inventory_slot *
+find(struct inventory *iv, const struct item *item)
+{
+	assert(iv);
+	assert(item);
+
+	/* First pass: find an entry with the same item. */
+	for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r)
+		for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c)
+			if (can_be_used(&iv->items[r][c], item))
+				return &iv->items[r][c];
+
+	/* Second pass: try to find an empty slot. */
+	for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r)
+		for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c)
+			if (!iv->items[r][c].item)
+				return &iv->items[r][c];
+
+	return NULL;
+}
+
+static unsigned
+provide(struct inventory_slot *slot, struct item *item, unsigned int amount)
+{
+	assert(slot);
+
+	unsigned int avail;
+
+	/* The slot may be empty, make sure it contains this item. */
+	slot->item = item;
+
+	/*
+	 * Example:
+	 *
+	 * The slot has already 10 items.
+	 * The slot item is stackble up to 64 items.
+	 *
+	 * When pushing:
+	 *
+	 * 80: 54 pushed, 26 left
+	 * 30: 30 pushed, 0 left.
+	 */
+	avail = slot->item->stackable - slot->amount;
+
+	if (amount > avail) {
+		slot->amount += avail;
+		amount -= avail;
+	} else {
+		slot->amount += amount;
+		amount = 0;
+	}
+
+	return amount;
+}
+
+static bool
+merge(struct inventory_slot *slot, struct inventory_slot *other)
+{
+	assert(slot);
+	assert(slot->item);
+	assert(other);
+
+	/* Not compatible, return false to let the sorting continue. */
+	if (slot->item != other->item)
+		return false;
+
+	while (slot->amount < slot->item->stackable && other->amount) {
+		slot->amount++;
+		other->amount--;
+	}
+
+	/* No more amount in the other slot, empty it. */
+	if (other->amount == 0U)
+		memset(other, 0, sizeof (*other));
+
+	return slot->amount >= slot->item->stackable;
+}
+
+static void
+sort(struct inventory *iv, struct inventory_slot *slot, int r, int c)
+{
+	assert(slot);
+	assert(slot->item);
+
+	/* Merge until the end of thiw row. */
+	for (c = c + 1; c < INVENTORY_COLS_MAX; ++c)
+		if (merge(slot, &iv->items[r][c]))
+			return;
+
+	/* Merge the next rows. */
+	for (r = r + 1; r < INVENTORY_ROWS_MAX; ++r)
+		for (c = 0; c < INVENTORY_COLS_MAX; ++c)
+			if (merge(slot, &iv->items[r][c]))
+				return;
+}
+
+unsigned int
+inventory_push(struct inventory *iv, struct item *item, unsigned int amount)
+{
+	assert(iv);
+	assert(item);
+
+	while (amount) {
+		struct inventory_slot *slot;
+
+		if (!(slot = find(iv, item)))
+			break;
+
+		/* Add as much as we can in this slot. */
+		amount = provide(slot, item, amount);
+	}
+
+	return amount;
+}
+
+static int
+compare_slot(const void *v1, const void *v2)
+{
+	const struct inventory_slot *slot1 = v1;
+	const struct inventory_slot *slot2 = v2;
+	int cmp;
+
+	/* Two null slots compare equal. */
+	if (!slot1->item && !slot2->item)
+		return 0;
+
+	/* Null left should be moved after. */
+	if (!slot1->item)
+		return 1;
+
+	/* Null right slots should be moved after. */
+	if (!slot2->item)
+		return -1;
+
+	/* If they are identical, use amount to sort. */
+	if ((cmp = strcmp(slot1->item->name, slot2->item->name)) == 0)
+		return (long long int)slot2->amount - (long long int)slot1->amount;
+
+	return cmp;
+}
+
+void
+inventory_sort(struct inventory *iv)
+{
+	assert(iv);
+
+	for (int r = 0; r < INVENTORY_ROWS_MAX; ++r)
+		for (int c = 0; c < INVENTORY_COLS_MAX; ++c)
+			if (iv->items[r][c].item)
+				sort(iv, &iv->items[r][c], r, c);
+
+	/* Sort by names AND by amount. */
+	qsort(iv->items, INVENTORY_TOTAL, sizeof (struct inventory_slot), compare_slot);
+}
+
+void
+inventory_clear(struct inventory *iv)
+{
+	assert(iv);
+
+	memset(iv, 0, sizeof (*iv));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/inventory.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,94 @@
+/*
+ * inventory.h -- inventory of items
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_INVENTORY_H
+#define MOLKO_INVENTORY_H
+
+/**
+ * \file inventory.h
+ * \brief Inventory of items.
+ */
+
+/**
+ * \brief Maximum number of rows.
+ */
+#define INVENTORY_ROWS_MAX      3
+
+/**
+ * \brief Maximum number of columns.
+ */
+#define INVENTORY_COLS_MAX      10
+
+struct item;
+
+/**
+ * \brief Inventory slot.
+ *
+ * This structure describe a 'cell' into the inventory. It references a item
+ * and has a given amount of it.
+ */
+struct inventory_slot {
+	struct item *item;      /*!< (RO, ref) Pointer to the item. */
+	unsigned int amount;    /*!< (RO) Number of items in this slot. */
+};
+
+/**
+ * \brief Inventory structure.
+ */
+struct inventory {
+	/**
+	 * (RW)
+	 *
+	 * Grid of objects.
+	 */
+	struct inventory_slot items[INVENTORY_ROWS_MAX][INVENTORY_COLS_MAX];
+};
+
+/**
+ * Try to push as much as possible the given item.
+ *
+ * \pre iv != NULL
+ * \pre item != NULL
+ * \param iv the inventory
+ * \param item the item to reference
+ * \param amount the desired amount
+ * \return 0 if all items were pushed or the number left otherwise
+ */
+unsigned int
+inventory_push(struct inventory *iv, struct item *item, unsigned int amount);
+
+/**
+ * Sort the inventory.
+ *
+ * \pre iv != NULL
+ * \pre item != NULL
+ * \param iv the inventory
+ */
+void
+inventory_sort(struct inventory *iv);
+
+/**
+ * Clears the inventory.
+ *
+ * \pre iv != NULL
+ * \param iv the inventory
+ */
+void
+inventory_clear(struct inventory *iv);
+
+#endif /* !MOLKO_INVENTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/inventory_dialog.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,321 @@
+/*
+ * inventory_dialog.h -- dialog for items
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "button.h"
+#include "event.h"
+#include "frame.h"
+#include "game.h"
+#include "inventory.h"
+#include "inventory_dialog.h"
+#include "item.h"
+#include "maths.h"
+#include "painter.h"
+#include "texture.h"
+#include "window.h"
+
+#define ITEM_SIZE       64
+#define ITEM_PADDING    32
+
+#define GRID_WIDTH      ((INVENTORY_COLS_MAX * ITEM_SIZE) +             \
+                        ((INVENTORY_COLS_MAX + 1) * ITEM_PADDING))
+#define GRID_HEIGHT     ((INVENTORY_ROWS_MAX * ITEM_SIZE) +             \
+                        ((INVENTORY_ROWS_MAX + 1) * ITEM_PADDING))
+
+#define LABEL_WIDTH     (GRID_WIDTH)
+#define LABEL_HEIGHT    (64)
+
+#define BUTTON_HEIGHT   (32)
+#define BUTTON_WIDTH    ((GRID_WIDTH) / 4)
+
+/*
+ * The frame looks like this:
+ *
+ * +----------------------------+
+ * | [] [] [] [] [] [] [] [] [] |
+ * | [] [] [] [] [] [] [] [] [] |
+ * | [] [] [] [] [] [] [] [] [] |
+ * +----------------------------+
+ * | Item name                  |
+ * | Item description           |
+ * +----------------------------+
+ *                       [ Sort ]
+ *
+ * Where space between cells is determined with ITEM_PADDING macro.
+ */
+
+static unsigned int
+total_width(void)
+{
+	return GRID_WIDTH;
+}
+
+static unsigned int
+total_height(void)
+{
+	return GRID_HEIGHT + LABEL_HEIGHT + BUTTON_HEIGHT;
+}
+
+static void
+compute_box_position(const struct inventory_dialog *dlg, int r, int c, int *x, int *y)
+{
+	assert(dlg);
+	assert(x);
+	assert(y);
+
+	*x = dlg->fgrid.x + ((c * ITEM_SIZE) + ((c + 1) * ITEM_PADDING));
+	*y = dlg->fgrid.y + ((r * ITEM_SIZE) + ((r + 1) * ITEM_PADDING));
+}
+
+static void
+draw_grid_item_frame(int x, int y)
+{
+	struct frame frame = {
+		.x = x,
+		.y = y,
+		.w = ITEM_SIZE,
+		.h = ITEM_SIZE,
+		.style = FRAME_STYLE_BOX
+	};
+
+	frame_draw(&frame);
+}
+
+static void
+draw_grid_item_icon(struct item *item, int x, int y)
+{
+	struct texture *icon = item->icon;
+
+	texture_scale(icon, 0, 0, icon->w, icon->h, x, y, ITEM_SIZE, ITEM_SIZE, 0.0);
+}
+
+static void
+draw_grid_item_amount(struct inventory_slot *slot, int x, int y)
+{
+	char nstr[16];
+	struct label label = {
+		.text = nstr,
+		.x = x,
+		.y = y
+	};
+
+	/* Draw the number of item in this slot. */
+	snprintf(nstr, sizeof (nstr), "%d", slot->amount);
+	label_draw(&label);
+}
+
+static void
+draw_grid_item(struct inventory_slot *slot, int x, int y, bool selected)
+{
+	draw_grid_item_frame(x, y);
+
+	if (slot->item) {
+		draw_grid_item_icon(slot->item, x, y);
+		draw_grid_item_amount(slot, x, y);
+	}
+
+	if (selected) {
+		x -= 16;
+		y += (ITEM_SIZE / 2) - 4;
+		painter_draw_circle(x, y, 8);
+	}
+}
+
+static void
+draw_grid_items(const struct inventory_dialog *dlg)
+{
+	int x, y;
+	bool selected;
+
+	for (int r = 0; r < INVENTORY_ROWS_MAX; ++r) {
+		for (int c = 0; c < INVENTORY_COLS_MAX; ++c) {
+			selected = r == dlg->selrow && c == dlg->selcol;
+			compute_box_position(dlg, r, c, &x, &y);
+			draw_grid_item(&dlg->inv->items[r][c], x, y, selected);
+		}
+	}
+}
+
+static void
+draw_label(struct inventory_dialog *dlg)
+{
+	assert(dlg);
+
+	struct item *item = dlg->inv->items[dlg->selrow][dlg->selcol].item;
+
+	frame_draw(&dlg->fname);
+	frame_draw(&dlg->fdesc);
+
+	if (item) {
+		dlg->lname.text = item->name;
+		dlg->ldesc.text = item->summary;
+		label_draw(&dlg->lname);
+		label_draw(&dlg->ldesc);
+	}
+}
+
+void
+inventory_dialog_open(struct inventory_dialog *dlg)
+{
+	assert(dlg);
+	assert(dlg->inv);
+
+	int tw, th;
+
+	dlg->state = INVENTORY_DIALOG_SHOWING;
+
+	tw = total_width();
+	th = total_height();
+
+	/* Grid frame position. */
+	dlg->fgrid.w = GRID_WIDTH;
+	dlg->fgrid.h = GRID_HEIGHT;
+	dlg->fgrid.x = dlg->x;
+	dlg->fgrid.y = dlg->y;
+
+	/* Name label. */
+	dlg->fname.w = dlg->lname.w = LABEL_WIDTH;
+	dlg->fname.h = dlg->lname.h = LABEL_HEIGHT / 2;
+	dlg->fname.x = dlg->lname.x = dlg->x;
+	dlg->fname.y = dlg->lname.y = dlg->y + GRID_HEIGHT;
+	dlg->lname.x += ITEM_PADDING;
+	dlg->lname.flags = LABEL_NO_HCENTER;
+
+	/* Description label. */
+	dlg->fdesc.w = dlg->ldesc.w = LABEL_WIDTH;
+	dlg->fdesc.h = dlg->ldesc.h = LABEL_HEIGHT / 2;
+	dlg->fdesc.x = dlg->ldesc.x = dlg->y;
+	dlg->fdesc.y = dlg->ldesc.y = dlg->y + GRID_HEIGHT + (LABEL_HEIGHT / 2);
+	dlg->ldesc.x += ITEM_PADDING;
+	dlg->ldesc.flags = LABEL_NO_HCENTER;
+
+	/* Button sort. */
+	dlg->bsort.x = dlg->x;
+	dlg->bsort.y = dlg->y + GRID_HEIGHT + LABEL_HEIGHT;
+	dlg->bsort.w = BUTTON_WIDTH;
+	dlg->bsort.h = BUTTON_HEIGHT;
+	dlg->bsort.text = "Sort";
+}
+
+static void
+handle_keydown(struct inventory_dialog *dlg, const struct event_key *ev)
+{
+	assert(ev && ev->type == EVENT_KEYDOWN);
+
+	switch (ev->key) {
+	case KEY_LEFT:
+		if (dlg->selcol == 0)
+			dlg->selcol = INVENTORY_COLS_MAX - 1;
+		else
+			dlg->selcol--;
+		break;
+	case KEY_RIGHT:
+		dlg->selcol = (dlg->selcol + 1) % INVENTORY_COLS_MAX;
+		break;
+	case KEY_UP:
+		if (dlg->selrow == 0)
+			dlg->selrow = INVENTORY_ROWS_MAX - 1;
+		else
+			dlg->selrow--;
+		break;
+	case KEY_DOWN:
+		dlg->selrow = (dlg->selrow + 1) % INVENTORY_ROWS_MAX;
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+handle_clickdown(struct inventory_dialog *dlg, const struct event_click *ev)
+{
+	assert(dlg);
+	assert(ev && ev->type == EVENT_CLICKDOWN);
+
+	int x, y;
+
+	for (int r = 0; r < INVENTORY_ROWS_MAX; ++r) {
+		for (int c = 0; c < INVENTORY_COLS_MAX; ++c) {
+			compute_box_position(dlg, r, c, &x, &y);
+
+			if (maths_is_boxed(x, y, ITEM_SIZE, ITEM_SIZE, ev->x, ev->y)) {
+				dlg->selrow = r;
+				dlg->selcol = c;
+			}
+		}
+	}
+}
+
+void
+inventory_dialog_handle(struct inventory_dialog *dlg, const union event *event)
+{
+	assert(event);
+
+	switch (event->type) {
+	case EVENT_KEYDOWN:
+		handle_keydown(dlg, &event->key);
+		break;
+	case EVENT_CLICKDOWN:
+		handle_clickdown(dlg, &event->click);
+		break;
+	default:
+		break;
+	}
+
+	button_handle(&dlg->bsort, event);
+
+	if (dlg->bsort.state == BUTTON_STATE_ACTIVATED) {
+		inventory_sort(dlg->inv);
+		button_reset(&dlg->bsort);
+	}
+}
+
+void
+inventory_dialog_update(struct inventory_dialog *dlg, unsigned int ticks)
+{
+	assert(dlg);
+
+	(void)ticks;
+}
+
+void
+inventory_dialog_move(struct inventory_dialog *dlg, int x, int y)
+{
+	assert(dlg);
+}
+
+void
+inventory_dialog_draw(struct inventory_dialog *dlg)
+{
+	assert(dlg);
+
+	frame_draw(&dlg->fgrid);
+	draw_grid_items(dlg);
+	draw_label(dlg);
+	button_draw(&dlg->bsort);
+}
+
+void
+inventory_dialog_finish(struct inventory_dialog *dlg)
+{
+	assert(dlg);
+
+	dlg->state = INVENTORY_DIALOG_NONE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/inventory_dialog.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,76 @@
+/*
+ * inventory_dialog.h -- dialog for items
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INVENTORY_DIALOG_H
+#define INVENTORY_DIALOG_H
+
+#include "button.h"
+#include "label.h"
+#include "frame.h"
+
+union event;
+
+struct inventory;
+struct theme;
+
+/**
+ * \brief Inventory dialog state.
+ */
+enum inventory_dialog_state {
+	INVENTORY_DIALOG_NONE,
+	INVENTORY_DIALOG_SHOWING
+};
+
+/**
+ * \brief Inventory dialog.
+ */
+struct inventory_dialog {
+	int x;                                  /*!< (RO) Position in x. */
+	int y;                                  /*!< (RO) Position in y. */
+	struct inventory *inv;                  /*!< (RW, ref) Inventory to use. */
+	struct theme *theme;                    /*!< (RW, ref, optional) Theme to use. */
+	struct button bsort;                    /*!< (RO) Button sort. */
+	struct frame fgrid;                     /*!< (RO) Grid frame. */
+	struct frame fname;                     /*!< (RO) Frame for name. */
+	struct frame fdesc;                     /*!< (RO) Frame for description. */
+	struct label lname;                     /*!< (RO) Label for name. */
+	struct label ldesc;                     /*!< (RO) Label for description. */
+	enum inventory_dialog_state state;      /*!< (RO) Current dialog state. */
+	unsigned int selrow;                    /*!< (RO) Current selected row. */
+	unsigned int selcol;                    /*!< (RO) Current selected column. */
+};
+
+void
+inventory_dialog_open(struct inventory_dialog *dlg);
+
+void
+inventory_dialog_handle(struct inventory_dialog *dlg, const union event *event);
+
+void
+inventory_dialog_update(struct inventory_dialog *dlg, unsigned int ticks);
+
+void
+inventory_dialog_move(struct inventory_dialog *dlg, int x, int y);
+
+void
+inventory_dialog_draw(struct inventory_dialog *dlg);
+
+void
+inventory_dialog_finish(struct inventory_dialog *dlg);
+
+#endif /* !INVENTORY_DIALOG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/item.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,61 @@
+/*
+ * item.h -- inventory items
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_ITEM_H
+#define MOLKO_ITEM_H
+
+/**
+ * \file item.h
+ * \brief Inventory items.
+ */
+
+#include <stdbool.h>
+
+/**
+ * \brief Maximum count of an item into a stack.
+ */
+#define ITEM_STACK_MAX  64
+
+struct character;
+struct texture;
+
+/**
+ * \brief Inventory items.
+ */
+struct item {
+	const char *name;               /*!< (RW) Name of item. */
+	const char *summary;            /*!< (RW) Summary description. */
+	struct texture *icon;           /*!< (RW, ref) Icon to show. */
+	unsigned int stackable;         /*!< (RW) Stack count allowed. */
+
+	/**
+	 * (RW)
+	 *
+	 * Execute the action for this character.
+	 */
+	void (*exec)(const struct item *, struct character *);
+
+	/**
+	 * (RW, optional)
+	 *
+	 * Tells if the item can be used in this context.
+	 */
+	bool (*allowed)(const struct item *, const struct character *);
+};
+
+#endif /* !MOLKO_ITEM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/key.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,191 @@
+/*
+ * key.h -- keyboard definitions
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_KEY_H
+#define MOLKO_KEY_H
+
+/**
+ * \file key.h
+ * \brief Keyboard definitions.
+ * \ingroup input
+ */
+
+/**
+ * \brief Key codes.
+ */
+enum key {
+	KEY_UNKNOWN,
+	KEY_ENTER,
+	KEY_ESCAPE,
+	KEY_BACKSPACE,
+	KEY_TAB,
+	KEY_SPACE,
+	KEY_EXCLAIM,
+	KEY_DOUBLE_QUOTE,
+	KEY_HASH,
+	KEY_PERCENT,
+	KEY_DOLLAR,
+	KEY_AMPERSAND,
+	KEY_QUOTE,
+	KEY_LEFT_PAREN,
+	KEY_RIGHT_PAREN,
+	KEY_ASTERISK,
+	KEY_PLUS,
+	KEY_COMMA,
+	KEY_MINUS,
+	KEY_PERIOD,
+	KEY_SLASH,
+	KEY_0,
+	KEY_1,
+	KEY_2,
+	KEY_3,
+	KEY_4,
+	KEY_5,
+	KEY_6,
+	KEY_7,
+	KEY_8,
+	KEY_9,
+	KEY_COLON,
+	KEY_SEMICOLON,
+	KEY_LESS,
+	KEY_EQUALS,
+	KEY_GREATER,
+	KEY_QUESTION,
+	KEY_AT,
+	KEY_LEFT_BRACKET,
+	KEY_BACKSLASH,
+	KEY_RIGHT_BRACKET,
+	KEY_CARET,
+	KEY_UNDERSCORE,
+	KEY_BACKQUOTE,
+	KEY_a,
+	KEY_b,
+	KEY_c,
+	KEY_d,
+	KEY_e,
+	KEY_f,
+	KEY_g,
+	KEY_h,
+	KEY_i,
+	KEY_j,
+	KEY_k,
+	KEY_l,
+	KEY_m,
+	KEY_n,
+	KEY_o,
+	KEY_p,
+	KEY_q,
+	KEY_r,
+	KEY_s,
+	KEY_t,
+	KEY_u,
+	KEY_v,
+	KEY_w,
+	KEY_x,
+	KEY_y,
+	KEY_z,
+	KEY_CAPSLOCK,
+	KEY_F1,
+	KEY_F2,
+	KEY_F3,
+	KEY_F4,
+	KEY_F5,
+	KEY_F6,
+	KEY_F7,
+	KEY_F8,
+	KEY_F9,
+	KEY_F10,
+	KEY_F11,
+	KEY_F12,
+	KEY_F13,
+	KEY_F14,
+	KEY_F15,
+	KEY_F16,
+	KEY_F17,
+	KEY_F18,
+	KEY_F19,
+	KEY_F20,
+	KEY_F21,
+	KEY_F22,
+	KEY_F23,
+	KEY_F24,
+	KEY_PRINTSCREEN,
+	KEY_SCROLLLOCK,
+	KEY_PAUSE,
+	KEY_INSERT,
+	KEY_HOME,
+	KEY_PAGEUP,
+	KEY_DELETE,
+	KEY_END,
+	KEY_PAGEDOWN,
+	KEY_RIGHT,
+	KEY_LEFT,
+	KEY_DOWN,
+	KEY_UP,
+	KEY_NUMLOCKCLEAR,
+	KEY_KP_DIVIDE,
+	KEY_KP_MULTIPLY,
+	KEY_KP_MINUS,
+	KEY_KP_PLUS,
+	KEY_KP_ENTER,
+	KEY_KP_00,
+	KEY_KP_000,
+	KEY_KP_1,
+	KEY_KP_2,
+	KEY_KP_3,
+	KEY_KP_4,
+	KEY_KP_5,
+	KEY_KP_6,
+	KEY_KP_7,
+	KEY_KP_8,
+	KEY_KP_9,
+	KEY_KP_0,
+	KEY_KP_PERIOD,
+	KEY_KP_COMMA,
+	KEY_MENU,
+	KEY_MUTE,
+	KEY_VOLUME_UP,
+	KEY_VOLUME_DOWN,
+	KEY_LCTRL,
+	KEY_LSHIFT,
+	KEY_LALT,
+	KEY_LSUPER,
+	KEY_RCTRL,
+	KEY_RSHIFT,
+	KEY_RALT,
+	KEY_RSUPER,
+};
+
+/**
+ * \brief Keybord modifiers.
+ *
+ * This enumeration is usually stored as OR'ed flags as several modifiers can
+ * be pressed at a time.
+ */
+enum keymod {
+	KEYMOD_LSHIFT   = 1 << 0,       /*!< Left shift */
+	KEYMOD_LCTRL    = 1 << 1,       /*!< Left control */
+	KEYMOD_LALT     = 1 << 2,       /*!< Left alt */
+	KEYMOD_LSUPER   = 1 << 3,       /*!< Left super (logo) */
+	KEYMOD_RSHIFT   = 1 << 4,       /*!< Right shift */
+	KEYMOD_RCTRL    = 1 << 5,       /*!< Right control */
+	KEYMOD_RALT     = 1 << 6,       /*!< Right alt */
+	KEYMOD_RSUPER   = 1 << 7        /*!< Right super (logo) */
+};
+
+#endif /* !MOLKO_KEY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/label.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,30 @@
+/*
+ * label.c -- GUI label
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "label.h"
+#include "theme.h"
+
+void
+label_draw(const struct label *label)
+{
+	assert(label);
+
+	theme_draw_label(label->theme, label);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/label.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,62 @@
+/*
+ * label.h -- GUI label
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_LABEL_H
+#define MOLKO_LABEL_H
+
+/**
+ * \file label.h
+ * \brief GUI label.
+ */
+
+struct theme;
+
+/**
+ * \brief Label flags.
+ */
+enum label_flags {
+	LABEL_NONE,                             /*!< No flags. */
+	LABEL_NO_SHADOW         = (1 << 0),     /*!< Disable shadow. */
+	LABEL_NO_VCENTER        = (1 << 1),     /*!< Disable vertical centering. */
+	LABEL_NO_HCENTER        = (1 << 2)      /*!< Disable horizontal centering. */
+};
+
+/**
+ * \brief GUI label.
+ */
+struct label {
+	int x;                  /*!< (RW) Position in x. */
+	int y;                  /*!< (RW) Position in y. */
+	unsigned int w;         /*!< (RW) Width. */
+	unsigned int h;         /*!< (RW) Height. */
+	const char *text;       /*!< (RW, ref) Text to show. */
+	enum label_flags flags; /*!< (RW) Optional flags. */
+	unsigned long color;    /*!< (RW) Color to use (0 = use theme). */
+	struct theme *theme;    /*!< (RW, ref, optional) Theme to use. */
+};
+
+/**
+ * Draw the label.
+ *
+ * \pre label != NULL
+ * \param label the label to draw
+ */
+void
+label_draw(const struct label *label);
+
+#endif /* !MOLKO_LABEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/map.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,225 @@
+/*
+ * map.c -- game map
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "error_p.h"
+#include "image.h"
+#include "map.h"
+#include "painter.h"
+#include "sprite.h"
+#include "sys.h"
+#include "texture.h"
+#include "window.h"
+
+/* Create %<v>c string literal for scanf */
+#define MAX_F(v) MAX_F_(v)
+#define MAX_F_(v) "%" #v "c"
+
+static void
+parse_layer(struct map_data *data, const char *line, FILE *fp)
+{
+	char layer_name[32 + 1] = { 0 };
+	struct map_layer *layer;
+	size_t amount, current;
+
+	/* Determine layer. */
+	if (sscanf(line, "layer|%32s", layer_name) <= 0)
+		return;
+	if (strcmp(layer_name, "background") == 0)
+		layer = &data->layers[0];
+	else if (strcmp(layer_name, "foreground") == 0)
+		layer = &data->layers[1];
+	else
+		return;
+
+	/* Check if weight/height has been specified. */
+	if (data->w == 0 || data->h == 0)
+		return;
+
+	amount = data->w * data->h;
+	current = 0;
+
+	if (!(layer->tiles = calloc(amount, sizeof (unsigned short))))
+		return;
+
+	for (int tile; fscanf(fp, "%d", &tile) && current < amount; ++current)
+		layer->tiles[current] = tile;
+}
+
+static void
+parse(struct map_data *data, const char *line, FILE *fp)
+{
+	if (strncmp(line, "title", 5) == 0)
+		sscanf(line, "title|" MAX_F(MAP_TITLE_MAX), data->title);
+	else if (strncmp(line, "width", 5) == 0)
+		sscanf(line, "width|%u", &data->w);
+	else if (strncmp(line, "height", 6) == 0)
+		sscanf(line, "height|%u", &data->h);
+	else if (strncmp(line, "tilewidth", 9) == 0)
+		sscanf(line, "tilewidth|%hu", &data->tile_w);
+	else if (strncmp(line, "tileheight", 10) == 0)
+		sscanf(line, "tileheight|%hu", &data->tile_h);
+	else if (strncmp(line, "origin", 6) == 0)
+		sscanf(line, "origin|%d|%d", &data->origin_x, &data->origin_y);
+	else if (strncmp(line, "tileset", 7) == 0)
+		sscanf(line, "tileset|" MAX_F(MAP_TILESET_MAX), data->tileset);
+	else if (strncmp(line, "layer", 5) == 0)
+		parse_layer(data, line, fp);
+}
+
+static bool
+check(struct map_data *data)
+{
+	if (strlen(data->title) == 0)
+		return error_printf("data has no title");
+	if (data->w == 0 || data->h == 0)
+		return error_printf("data has null sizes");
+	if (data->tile_w == 0 || data->tile_h == 0)
+		return error_printf("data has null tile sizes");
+	if (!data->layers[0].tiles || !data->layers[1].tiles)
+		return error_printf("could not allocate data");
+
+	return true;
+}
+
+static void
+draw_layer(struct map *map, const struct map_layer *layer)
+{
+	assert(map);
+	assert(layer);
+
+	struct sprite sprite;
+	int x = 0, y = 0;
+
+	sprite_init(&sprite, &map->tileset, map->data->tile_w, map->data->tile_h);
+
+	for (unsigned int r = 0; r < map->data->w; ++r) {
+		for (unsigned int c = 0; c < map->data->h; ++c) {
+			unsigned int si = r * map->data->w + c;
+			unsigned int sr = (layer->tiles[si] - 1) / sprite.ncols;
+			unsigned int sc = (layer->tiles[si] - 1) % sprite.nrows;
+
+			if (layer->tiles[si] != 0)
+				sprite_draw(&sprite, sr, sc, x, y);
+
+			x += map->data->tile_w;
+		}
+
+		x = 0;
+		y += map->data->tile_h;
+	}
+}
+
+bool
+map_data_open(struct map_data *data, const char *path)
+{
+	assert(data);
+	assert(path);
+
+	memset(data, 0, sizeof (*data));
+
+	FILE *fp = fopen(path, "r");
+	char line[BUFSIZ];
+
+	if (!fp)
+		return false;
+
+	while (fgets(line, sizeof (line), fp)) {
+		/* Remove \n if any */
+		line[strcspn(line, "\n")] = '\0';
+		parse(data, line, fp);
+	}
+
+	fclose(fp);
+
+	if (!check(data)) {
+		map_data_finish(data);
+		return false;
+	}
+
+	/* Compute real size. */
+	data->real_w = data->w * data->tile_w;
+	data->real_h = data->h * data->tile_h;
+
+	return true;
+}
+
+void
+map_data_finish(struct map_data *data)
+{
+	assert(data);
+
+	free(data->layers[0].tiles);
+	free(data->layers[1].tiles);
+
+	memset(data, 0, sizeof (*data));
+}
+
+bool
+map_init(struct map *map, struct map_data *data)
+{
+	assert(map);
+	assert(data);
+
+	if (!(image_open(&map->tileset, sys_datapath("tilesets/%s", data->tileset))))
+		goto failure;
+	if (!(texture_new(&map->picture, data->real_w, data->real_h)))
+		goto failure;
+
+	map->data = data;
+	map_repaint(map);
+
+	return true;
+
+failure:
+	map_data_finish(data);
+
+	return false;
+}
+
+void
+map_draw(struct map *map, int srcx, int srcy)
+{
+	texture_scale(&map->picture, srcx, srcy, window.w, window.h,
+	    0, 0, window.w, window.h, 0.0);
+}
+
+void
+map_repaint(struct map *map)
+{
+	PAINTER_BEGIN(&map->picture);
+	draw_layer(map, &map->data->layers[0]);
+	draw_layer(map, &map->data->layers[1]);
+	PAINTER_END();
+}
+
+void
+map_finish(struct map *map)
+{
+	assert(map);
+
+	texture_finish(&map->tileset);
+	texture_finish(&map->picture);
+
+	memset(map, 0, sizeof (*map));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/map.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,143 @@
+/*
+ * map.h -- game map
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_MAP_H
+#define MOLKO_MAP_H
+
+/**
+ * \file map.h
+ * \brief Game map.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "texture.h"
+
+/**
+ * \brief Max title length for a map.
+ */
+#define MAP_TITLE_MAX   32
+
+/**
+ * \brief Max filename for tilesets.
+ */
+#define MAP_TILESET_MAX FILENAME_MAX
+
+/**
+ * \brief Map layer.
+ */
+struct map_layer {
+	unsigned short *tiles;          /*!< (RO) Array of tiles, depending on the map size. */
+};
+
+/**
+ * \brief Map definition structure.
+ *
+ * This structure only defines the map characteristics. It does not have any
+ * logic and is left for game state.
+ */
+struct map_data {
+	char title[MAP_TITLE_MAX];      /*!< (RW) The map title. */
+	char tileset[MAP_TILESET_MAX];  /*!< (RO) Name of tileset to use. */
+	int origin_x;                   /*!< (RO) Where the player starts in X. */
+	int origin_y;                   /*!< (RO) Where the player starts in Y. */
+	unsigned int real_w;            /*!< (RO) Real width in pixels. */
+	unsigned int real_h;            /*!< (RO) Real height in pixels. */
+	unsigned int w;                 /*!< (RO) Map width in cells. */
+	unsigned int h;                 /*!< (RO) Map height in cells. */
+	unsigned short tile_w;          /*!< (RO) Pixels per cell (width). */
+	unsigned short tile_h;          /*!< (RO) Pixels per cell (height). */
+	struct map_layer layers[2];     /*!< (RO) Layers (background, foreground). */
+};
+
+/**
+ * \brief High level map object.
+ *
+ * This structure reference a map and perform drawing operations.
+ */
+struct map {
+	struct map_data *data;          /*!< (RW, ref) Map data. */
+	struct texture tileset;         /*!< (RW) Tileset to use. */
+	struct texture picture;         /*!< (RO) Map drawn into a picture. */
+};
+
+/**
+ * Open a map defintion
+ *
+ * \pre data != NULL
+ * \pre path != NULL
+ * \param data the map defintion to fill
+ * \param path the path to the map
+ * \return True if successfully loaded.
+ */
+bool
+map_data_open(struct map_data *data, const char *path);
+
+/**
+ * Dispose the map definition data.
+ *
+ * \pre data != NULL
+ * \param data the map definition
+ */
+void
+map_data_finish(struct map_data *data);
+
+/**
+ * Initialize this map.
+ *
+ * \pre map != NULL
+ * \pre data != NULL
+ * \param map the map to initialize
+ * \param data the definition to reference
+ * \return False on errors.
+ */
+bool
+map_init(struct map *map, struct map_data *data);
+
+/**
+ * Render a map.
+ *
+ * \pre map != NULL
+ * \param map the map to render
+ * \param srcx the x coordinate region
+ * \param srcy the y coordinate region
+ */
+void
+map_draw(struct map *map, int srcx, int srcy);
+
+/**
+ * Force map repaint on its texture.
+ *
+ * \pre map != NULL
+ * \param map the map to repaint
+ * \warning This function does not render anything on the screen.
+ */
+void
+map_repaint(struct map *map);
+
+/**
+ * Dispose map resources.
+ *
+ * \pre map != NULL
+ * \param map the map to close
+ */
+void
+map_finish(struct map *map);
+
+#endif /* !MOLKO_MAP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/map_state.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,350 @@
+/*
+ * map_state.c -- state when player is on a map
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "debug.h"
+#include "event.h"
+#include "game.h"
+#include "map.h"
+#include "map_state.h"
+#include "painter.h"
+#include "state.h"
+#include "texture.h"
+#include "walksprite.h"
+#include "window.h"
+
+/*
+ * This is the speed the player moves on the map.
+ *
+ * SPEED represents the number of pixels it must move per SEC.
+ * SEC simply represends the number of milliseconds in one second.
+ */
+#define SPEED 100
+#define SEC   1000
+
+/*
+ * Those are margins within the edge of the screen. The camera always try to
+ * keep those padding between the player and the screen.
+ */
+#define MARGIN_WIDTH    80
+#define MARGIN_HEIGHT   80
+
+/*
+ * Convenient macros to access the state data.
+ */
+#define MAP()           (&map_state_data.map)
+#define PLAYER()        (&map_state_data.player)
+#define VIEW()          (&map_state_data.view)
+
+/*
+ * This structure defines the possible movement of the player as flags since
+ * it's possible to make diagonal movements.
+ */
+enum movement {
+	MOVING_UP       = 1 << 0,
+	MOVING_RIGHT    = 1 << 1,
+	MOVING_DOWN     = 1 << 2,
+	MOVING_LEFT     = 1 << 3
+};
+
+/*
+ * A bit of explanation within this array. The structure walksprite requires
+ * an orientation between 0-7 depending on the user direction.
+ *
+ * Since keys for moving the character may be pressed at the same time, we need
+ * a conversion table from "key pressed" to "orientation".
+ *
+ * When an orientation is impossible, it is set to -1. Example, when both left
+ * and right are pressed.
+ *
+ * MOVING_UP    = 0001 = 0x1
+ * MOVING_RIGHT = 0010 = 0x2
+ * MOVING_DOWN  = 0100 = 0x3
+ * MOVING_LEFT  = 1000 = 0x4
+ */
+static unsigned int orientations[16] = {
+	[0x1] = 0,
+	[0x2] = 2,
+	[0x3] = 1,
+	[0x4] = 4,
+	[0x6] = 3,
+	[0x8] = 6,
+	[0x9] = 7,
+	[0xC] = 5
+};
+
+/*
+ * Additional data that is not necessary to expose in map_state_data.
+ */
+static struct {
+	struct {
+		enum movement moving;
+		struct walksprite ws;
+	} player;
+
+	struct {
+		int x;
+		int y;
+		unsigned int w;
+		unsigned int h;
+	} margin;
+} cache;
+
+static void
+center(void)
+{
+	VIEW()->x = PLAYER()->x - (VIEW()->w / 2);
+	VIEW()->y = PLAYER()->y - (VIEW()->h / 2);
+
+	if (VIEW()->x < 0)
+		VIEW()->x = 0;
+	else if ((unsigned int)VIEW()->x > MAP()->data.real_w - VIEW()->w)
+		VIEW()->x = MAP()->data.real_w - VIEW()->w;
+
+	if (VIEW()->y < 0)
+		VIEW()->y = 0;
+	else if ((unsigned int)VIEW()->y > MAP()->data.real_h - VIEW()->h)
+		VIEW()->y = MAP()->data.real_h - VIEW()->h;
+}
+
+static void
+enter(void)
+{
+	/* Adjust map properties. */
+	struct map *m = &map_state_data.map.map;
+
+	map_repaint(m);
+	MAP()->data.real_w = m->picture.w;
+	MAP()->data.real_h = m->picture.h;
+
+	/* Adjust view. */
+	VIEW()->w = window.w;
+	VIEW()->h = window.h;
+
+	/* Adjust margin. */
+	cache.margin.w = VIEW()->w - (MARGIN_WIDTH * 2);
+	cache.margin.h = VIEW()->h - (MARGIN_HEIGHT * 2);
+
+	/* Center the view by default. */
+	center();
+
+	/* Final bits. */
+	walksprite_init(&cache.player.ws, &PLAYER()->sprite, 300);
+}
+
+static void
+leave(void)
+{
+}
+
+static void
+handle_keydown(const union event *event)
+{
+	switch (event->key.key) {
+	case KEY_UP:
+		cache.player.moving |= MOVING_UP;
+		break;
+	case KEY_RIGHT:
+		cache.player.moving |= MOVING_RIGHT;
+		break;
+	case KEY_DOWN:
+		cache.player.moving |= MOVING_DOWN;
+		break;
+	case KEY_LEFT:
+		cache.player.moving |= MOVING_LEFT;
+		break;
+	default:
+		break;
+	}
+
+	PLAYER()->angle = orientations[cache.player.moving];
+}
+
+static void
+handle_keyup(const union event *event)
+{
+	switch (event->key.key) {
+	case KEY_UP:
+		cache.player.moving &= ~(MOVING_UP);
+		break;
+	case KEY_RIGHT:
+		cache.player.moving &= ~(MOVING_RIGHT);
+		break;
+	case KEY_DOWN:
+		cache.player.moving &= ~(MOVING_DOWN);
+		break;
+	case KEY_LEFT:
+		cache.player.moving &= ~(MOVING_LEFT);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+move_right(unsigned int delta)
+{
+	PLAYER()->x += delta;
+
+	if (PLAYER()->x > (int)(cache.margin.x + cache.margin.w)) {
+		VIEW()->x = (PLAYER()->x - VIEW()->w) + MARGIN_WIDTH;
+
+		if (VIEW()->x >= (int)(MAP()->data.real_w - VIEW()->w))
+			VIEW()->x = MAP()->data.real_w - VIEW()->w;
+	}
+
+	if (PLAYER()->x > (int)MAP()->data.real_w - 48)
+		PLAYER()->x = MAP()->data.real_w - 48;
+}
+
+static void
+move_left(unsigned int delta)
+{
+	PLAYER()->x -= delta;
+
+	if (PLAYER()->x < cache.margin.x) {
+		VIEW()->x = PLAYER()->x - MARGIN_WIDTH;
+
+		if (VIEW()->x < 0)
+			VIEW()->x = 0;
+	}
+
+	if (PLAYER()->x < 0)
+		PLAYER()->x = 0;
+}
+
+static void
+move_down(unsigned int delta)
+{
+	PLAYER()->y += delta;
+
+	if (PLAYER()->y > (int)(cache.margin.y + cache.margin.h)) {
+		VIEW()->y = (PLAYER()->y - VIEW()->h) + MARGIN_HEIGHT;
+
+		if (VIEW()->y >= (int)(MAP()->data.real_h - VIEW()->h))
+			VIEW()->y = MAP()->data.real_h - VIEW()->h;
+	}
+
+	if (PLAYER()->y > (int)MAP()->data.real_h - 48)
+		PLAYER()->y = MAP()->data.real_h - 48;
+}
+
+static void
+move_up(unsigned int delta)
+{
+	PLAYER()->y -= delta;
+
+	if (PLAYER()->y < cache.margin.y) {
+		VIEW()->y = PLAYER()->y - MARGIN_HEIGHT;
+
+		if (VIEW()->y < 0)
+			VIEW()->y = 0;
+	}
+
+	if (PLAYER()->y < 0)
+		PLAYER()->y = 0;
+}
+
+static void
+move(unsigned int ticks)
+{
+	/* This is the amount of pixels the player must move. */
+	const int delta = SPEED * ticks / SEC;
+
+	/* This is the rectangle within the view where users must be. */
+	cache.margin.x = VIEW()->x + MARGIN_WIDTH;
+	cache.margin.y = VIEW()->y + MARGIN_HEIGHT;
+
+	int dx = 0;
+	int dy = 0;
+
+	if (cache.player.moving == 0)
+		return;
+
+	if (cache.player.moving & MOVING_UP)
+		dy = -1;
+	if (cache.player.moving & MOVING_DOWN)
+		dy = 1;
+	if (cache.player.moving & MOVING_LEFT)
+		dx = -1;
+	if (cache.player.moving & MOVING_RIGHT)
+		dx = 1;
+
+	/* Move the player and adjust view if needed. */
+	if (dx > 0)
+		move_right(delta);
+	else if (dx < 0)
+		move_left(delta);
+
+	if (dy > 0)
+		move_down(delta);
+	else if (dy < 0)
+		move_up(delta);
+
+	walksprite_update(&cache.player.ws, ticks);
+}
+
+static void
+handle(const union event *event)
+{
+	switch (event->type) {
+	case EVENT_KEYDOWN:
+		handle_keydown(event);
+		break;
+	case EVENT_KEYUP:
+		handle_keyup(event);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+update(unsigned int ticks)
+{
+	move(ticks);
+}
+
+static void
+draw(void)
+{
+	struct debug_report report = DEBUG_INIT_DEFAULTS;
+
+	map_draw(&map_state_data.map.map, VIEW()->x, VIEW()->y);
+	walksprite_draw(
+		&cache.player.ws,
+		PLAYER()->angle,
+		PLAYER()->x - VIEW()->x,
+		PLAYER()->y - VIEW()->y);
+
+	debug_printf(&report, "position: %d, %d", PLAYER()->x,
+	    PLAYER()->y);
+	debug_printf(&report, "view: %d, %d", VIEW()->x,
+	    VIEW()->y);
+}
+
+struct map_state_data map_state_data;
+
+struct state map_state = {
+	.enter = enter,
+	.leave = leave,
+	.update = update,
+	.handle = handle,
+	.draw = draw
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/map_state.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,74 @@
+/*
+ * map_state.h -- state when player is on a map
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_MAP_STATE_H
+#define MOLKO_MAP_STATE_H
+
+/**
+ * \file map_state.h
+ * \brief State when player is on a map.
+ * \ingroup states
+ */
+
+#include "map.h"
+#include "sprite.h"
+
+/**
+ * \brief Data for the state.
+ *
+ * Update this structure before switching to this state.
+ */
+extern struct map_state_data {
+	/**
+	 * Map properties.
+	 */
+	struct {
+		struct map_data data;   /*!< (RW) Map data. */
+		struct map map;         /*!< (RW) Map object. */
+	} map;
+
+	/**
+	 * Player position.
+	 *
+	 * If you adjust this structure, it is strictly encouraged to update
+	 * the view as well.
+	 */
+	struct {
+		struct sprite sprite;   /*!< (RW) The sprite to use */
+		int x;                  /*!< (RO) Player position in x */
+		int y;                  /*!< (RO) Player position in y */
+		int angle;              /*!< (RO) Player angle (see walksprite) */
+	} player;
+
+	/**
+	 * Position and size of the view.
+	 */
+	struct {
+		int x;                  /*!< (RW) Position in x */
+		int y;                  /*!< (RW) Position in y */
+		unsigned int w;         /*!< (RO) View width */
+		unsigned int h;         /*!< (RO) View height */
+	} view;
+} map_state_data; /*!< Access to data. */
+
+/**
+ * \brief State when player is on a map.
+ */
+extern struct state map_state;
+
+#endif /* !MOLKO_MAP_STATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/maths.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,44 @@
+/*
+ * maths.c -- basic maths
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "maths.h"
+
+bool
+maths_is_boxed(int x, int y, unsigned int w, unsigned int h, int px, int py)
+{
+	return px >= x &&
+	       py >= y &&
+	       px <= x + w &&
+	       py <= y + h;
+}
+
+void
+maths_centerize(int *x,
+               int *y,
+               unsigned int w,
+               unsigned int h,
+               int px,
+               int py,
+               unsigned int pw,
+               unsigned int ph)
+{
+	if (x)
+		*x = px + (pw / 2) - (w / 2);
+	if (y)
+		*y = py + (ph / 2) - (h / 2);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/maths.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,68 @@
+/*
+ * maths.h -- basic maths
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_MATHS_H
+#define MOLKO_MATHS_H
+
+#include <stdbool.h>
+
+/**
+ * \file maths.h
+ * \brief Basic maths.
+ */
+
+/**
+ * Tells if a coordinate is within a rectangle region.
+ *
+ * \param x the region start
+ * \param y the region start
+ * \param w the region width
+ * \param h the region height
+ * \param px the point to test
+ * \param py the point to test
+ * \return True if within the region
+ */
+bool
+maths_is_boxed(int x, int y, unsigned int w, unsigned int h, int px, int py);
+
+/**
+ * Update x, y to be centered into a parent region.
+ *
+ * You can select to ignore horizontal/vertical centering by passing NULL to x
+ * or y respectively.
+ *
+ * \param x the pointer to x coordinate to modify
+ * \param y the pointer yo y coordinate to modify
+ * \param w the object width
+ * \param h the object height
+ * \param px the parent region start
+ * \param py the parent region start
+ * \param pw the parent region width
+ * \param ph the parent region height
+ */
+void
+maths_centerize(int *x,
+                int *y,
+                unsigned int w,
+                unsigned int h,
+                int px,
+                int py,
+                unsigned int pw,
+                unsigned int ph);
+
+#endif /* !MOLKO_MATHS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/message.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,261 @@
+/*
+ * message.c -- message dialog
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "action.h"
+#include "event.h"
+#include "font.h"
+#include "frame.h"
+#include "label.h"
+#include "message.h"
+#include "painter.h"
+#include "panic.h"
+#include "sprite.h"
+#include "texture.h"
+#include "theme.h"
+#include "util.h"
+#include "window.h"
+
+#define MESSAGE_SPEED   100     /* Time delay for animations */
+#define MESSAGE_TIMEOUT 5000    /* Time for auto-closing */
+
+#define WIDTH   (window.w * 0.75)
+#define HEIGHT  (window.h * 0.125)
+
+#define THEME(msg) (msg->theme ? msg->theme : theme_default())
+
+static void
+action_handle(struct action *action, const union event *ev)
+{
+	assert(action);
+	assert(ev);
+
+	message_handle(action->data, ev);
+}
+
+static bool
+action_update(struct action *action, unsigned int ticks)
+{
+	assert(action);
+
+	return message_update(action->data, ticks);
+}
+
+static void
+action_draw(struct action *action)
+{
+	assert(action);
+
+	message_draw(action->data);
+}
+
+static void
+action_finish(struct action *action)
+{
+	assert(action);
+
+	free(action->data);
+}
+
+void
+message_start(struct message *msg)
+{
+	assert(msg);
+
+	msg->elapsed = 0;
+	msg->scale = 0.0;
+	msg->state = msg->flags & MESSAGE_QUICK ? MESSAGE_SHOWING : MESSAGE_OPENING;
+}
+
+void
+message_handle(struct message *msg, const union event *ev)
+{
+	assert(msg);
+	assert(ev);
+
+	/* Skip if the message animation hasn't complete. */
+	if (msg->state != MESSAGE_SHOWING)
+		return;
+
+	/* Only keyboard event are valid. */
+	if (ev->type != EVENT_KEYDOWN || msg->state == MESSAGE_NONE)
+		return;
+
+	switch (ev->key.key) {
+	case KEY_UP:
+		if (msg->index > 0)
+			msg->index--;
+		break;
+	case KEY_DOWN:
+		if (msg->index < 5 && msg->text[msg->index + 1])
+			msg->index++;
+		break;
+	case KEY_ENTER:
+		msg->state = msg->flags & MESSAGE_QUICK ? MESSAGE_NONE : MESSAGE_HIDING;
+		msg->elapsed = 0;
+		break;
+	default:
+		break;
+	}
+}
+
+bool
+message_update(struct message *msg, unsigned int ticks)
+{
+	assert(msg);
+
+	msg->elapsed += ticks;
+
+	switch (msg->state) {
+	case MESSAGE_OPENING:
+		msg->scale = (double)msg->elapsed / (double)MESSAGE_SPEED;
+
+		if (msg->scale > 1)
+			msg->scale = 1;
+
+		if (msg->elapsed >= MESSAGE_SPEED) {
+			msg->state = MESSAGE_SHOWING;
+			msg->elapsed = 0;
+		}
+
+		break;
+	case MESSAGE_SHOWING:
+		/* Do automatically switch state if requested by the user. */
+		if (msg->flags & MESSAGE_AUTOMATIC && msg->elapsed >= MESSAGE_TIMEOUT) {
+			msg->state = msg->flags & MESSAGE_QUICK ? MESSAGE_NONE : MESSAGE_HIDING;
+			msg->elapsed = 0;
+		}
+
+		break;
+	case MESSAGE_HIDING:
+		msg->scale = 1 - (double)msg->elapsed / (double)MESSAGE_SPEED;
+
+		if (msg->scale < 0)
+			msg->scale = 0;
+		if (msg->elapsed >= MESSAGE_SPEED) {
+			msg->state = MESSAGE_NONE;
+			msg->elapsed = 0;
+		}
+
+		break;
+	default:
+		break;
+	}
+
+	return msg->state == MESSAGE_NONE;
+}
+
+static void
+draw_frame(const struct message *msg)
+{
+	assert(msg);
+
+	struct frame frame = {
+		.w = WIDTH,
+		.h = HEIGHT
+	};
+
+	frame_draw(&frame);
+}
+
+static void
+draw_lines(const struct message *msg)
+{
+	struct font *font;
+	unsigned int lineh;
+
+	font = THEME(msg)->fonts[THEME_FONT_INTERFACE];
+	lineh = font_height(font);
+
+	for (int i = 0; i < 6; ++i) {
+		if (!msg->text[i])
+			continue;
+
+		struct label label = {
+			.x = 10,
+			.y = 10 + (i * lineh),
+			.h = lineh,
+			.theme = msg->theme,
+			.text = msg->text[i],
+			.flags = LABEL_NO_HCENTER
+		};
+
+		/*
+		 * The function label_draw will normally use
+		 * THEME_FONT_INTERFACE so update its color if needed.
+		 */
+		if (msg->flags & MESSAGE_QUESTION && msg->index == i)
+			label.color = THEME(msg)->colors[THEME_COLOR_SELECTED];
+
+		label_draw(&label);
+	}
+}
+
+void
+message_draw(struct message *msg)
+{
+	assert(msg);
+
+	struct texture tex;
+	int x, y, w, h;
+
+	if (!texture_new(&tex, WIDTH, HEIGHT))
+		panic();
+
+	PAINTER_BEGIN(&tex);
+	draw_frame(msg);
+	draw_lines(msg);
+	PAINTER_END();
+
+	/* Compute scaling. */
+	w = WIDTH * msg->scale;
+	h = HEIGHT * msg->scale;
+
+	/* Compute position. */
+	x = (window.w / 2) - (w / 2);
+	y = HEIGHT;
+
+	texture_scale(&tex, 0, 0, WIDTH, HEIGHT, x, y, w, h, 0.0);
+	texture_finish(&tex);
+}
+
+void
+message_hide(struct message *msg)
+{
+	assert(msg);
+
+	msg->state = MESSAGE_HIDING;
+	msg->elapsed = 0;
+}
+
+void
+message_action(const struct message *msg, struct action *action)
+{
+	assert(msg);
+	assert(action);
+
+	memset(action, 0, sizeof (struct action));
+	action->data = ememdup(msg, sizeof (struct message));
+	action->handle = action_handle;
+	action->update = action_update;
+	action->draw = action_draw;
+	action->finish = action_finish;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/message.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,179 @@
+/*
+ * message.h -- message dialog
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_MESSAGE_H
+#define MOLKO_MESSAGE_H
+
+/**
+ * \file message.h
+ * \brief Message dialog.
+ * \ingroup actions
+ * \ingroup drawing
+ *
+ * This module's purpose is to show a dialog box into the screen to show text
+ * and optionally ask the user a question.
+ *
+ * By itself, it is very low level and does not prevent other parts of the game
+ * to use the input so you probably need to inhibit input if your dialog is
+ * meant to be displayed on a map.
+ *
+ * To use it use the following procedure:
+ *
+ * 1. Create a struct message object and set required properties,
+ * 2. Call \ref message_start to reset the state,
+ * 3. Call \ref message_handle and \ref message_update with appropriate values,
+ * 4. Call \ref message_draw to render the dialog.
+ *
+ * Depending on message flags or user input, step 3 may return true in this
+ * case you should stop using the message as it has completed rendering.
+ *
+ * \note All properties must exist until the object is no longer used.
+ *
+ * \code
+ * struct message msg = {
+ * 	// You can show up to 6 lines.
+ * 	.text = {
+ * 		"Hello, what's up?"
+ * 	},
+ * 	// This image will be shown on the left as user face.
+ * 	.avatar = mysuperavatar,
+ * 	// This should point to a image that is used as background.
+ * 	.frame = mysuperframe,
+ * 	// The first color is normal text, the second is for selected text
+ * 	// in case of question.
+ * 	.colors = { 0xffffffff, 0x0000ffff },
+ * 	// This indicates this message is a question.
+ * 	.flags = MESSAGE_QUESTION
+ * };
+ * \endcode
+ */
+
+#include <stdbool.h>
+
+#include "texture.h"
+
+struct action;
+struct font;
+struct theme;
+
+union event;
+
+/**
+ * \brief Message flags.
+ */
+enum message_flags {
+	MESSAGE_AUTOMATIC       = (1 << 0),     /*!< Will automatically change state by itself. */
+	MESSAGE_QUESTION        = (1 << 1),     /*!< The message is a question. */
+	MESSAGE_QUICK           = (1 << 2),     /*!< Avoid animations. */
+};
+
+/**
+ * \brief Message state.
+ */
+enum message_state {
+	MESSAGE_NONE,           /*!< Message hasn't start yet or is finished */
+	MESSAGE_OPENING,        /*!< Message animation is opening */
+	MESSAGE_SHOWING,        /*!< Message is displaying */
+	MESSAGE_HIDING          /*!< Message animation for hiding */
+};
+
+/**
+ * \brief Message object.
+ *
+ * This structure is used to display a message into the screen. It does not own
+ * any user properties and therefore must exist while using it.
+ */
+struct message {
+	const char *text[6];            /*!< (RW) Lines of text to show. */
+	struct texture *frame;          /*!< (RW, ref) Frame to use. */
+	struct texture *avatar;         /*!< (RW, ref, optional) Avatar face. */
+	unsigned int index;             /*!< (RW) Line selected */
+	enum message_flags flags;       /*!< (RW) Message flags */
+	enum message_state state;       /*!< (RO) Current state */
+	struct theme *theme;            /*!< (RW, ref, optional) Theme to use. */
+	unsigned int elapsed;           /*!< (RO) Time elapsed. */
+	double scale;                   /*!< (RO) Current scale [0-1]. */
+};
+
+/**
+ * Start opening the message. This function will reset the message state and
+ * elapsed time.
+ *
+ * \pre msg != NULL
+ * \param msg the message
+ */
+void
+message_start(struct message *msg);
+
+/**
+ * Handle input events.
+ *
+ * This function will alter state of the message and change its selection in
+ * case of question.
+ *
+ * \pre msg != NULL
+ * \pre ev != NULL
+ * \param msg the message
+ * \param ev the event which occured
+ */
+void
+message_handle(struct message *msg, const union event *ev);
+
+/**
+ * Update the message state and elapsed time..
+ *
+ * \pre msg != NULL
+ * \param msg the message
+ * \param ticks the elapsed delay since last frame
+ * \return true if it has finished
+ */
+bool
+message_update(struct message *msg, unsigned int ticks);
+
+/**
+ * Draw the message into the screen.
+ *
+ * \pre msg != NULL
+ * \param msg the message
+ */
+void
+message_draw(struct message *msg);
+
+/**
+ * Start hiding the message.
+ *
+ * \pre msg != NULL
+ * \param msg the message
+ * \note You should still continue to draw the message as the animation is not
+ *       finished!
+ */
+void
+message_hide(struct message *msg);
+
+/**
+ * Convert message into an action.
+ *
+ * \pre msg != NULL
+ * \pre action != NULL
+ * \param msg the message to copy from
+ * \param action the action to fill
+ */
+void
+message_action(const struct message *msg, struct action *action);
+
+#endif /* !MOLKO_MESSAGE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/mouse.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,43 @@
+/*
+ * mouse.h -- mouse definitions
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_MOUSE_H
+#define MOLKO_MOUSE_H
+
+/**
+ * \file mouse.h
+ * \brief Mouse definitions.
+ * \ingroup input
+ */
+
+/**
+ * \brief Buttons from mouse.
+ *
+ * This enumeration is used as both flags or constants. For example when the
+ * user press one button on the mouse it generates one constant event. On the
+ * other hand, while moving the mouse the user may have one or more buttons
+ * pressed, thus the OR'ed combination.
+ */
+enum mouse_button {
+	MOUSE_BUTTON_UNKNOWN    = 0,            /*!< No buttons pressed */
+	MOUSE_BUTTON_LEFT       = (1 << 0),     /*!< Left button pressed */
+	MOUSE_BUTTON_MIDDLE     = (1 << 1),     /*!< Middle button pressed */
+	MOUSE_BUTTON_RIGHT      = (1 << 2)      /*!< Right button pressed */
+};
+
+#endif /* !MOLKO_MOUSE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/painter.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,119 @@
+/*
+ * painter.c -- basic drawing routines
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <math.h>
+
+#include "color.h"
+#include "painter.h"
+#include "texture.h"
+#include "window.h"
+#include "window_p.h"
+
+/* Current texture renderer. */
+static struct texture *renderer;
+
+struct texture *
+painter_get_target(void)
+{
+	return renderer;
+}
+
+void
+painter_set_target(struct texture *tex)
+{
+	renderer = tex;
+	SDL_SetRenderTarget(RENDERER(), tex ? tex->handle : NULL);
+}
+
+unsigned long
+painter_get_color(void)
+{
+	Uint8 r = 0, g = 0, b = 0, a = 0;
+
+	SDL_GetRenderDrawColor(RENDERER(), &r, &g, &b, &a);
+
+	return COLOR_HEX(r, g, b, a);
+}
+
+void
+painter_set_color(unsigned long color)
+{
+	SDL_SetRenderDrawColor(
+		RENDERER(),
+		COLOR_R(color),
+		COLOR_G(color),
+		COLOR_B(color),
+		COLOR_A(color)
+	);
+}
+
+void
+painter_draw_line(int x1, int y1, int x2, int y2)
+{
+	SDL_RenderDrawLine(RENDERER(), x1, y1, x2, y2);
+}
+
+void
+painter_draw_point(int x1, int y1)
+{
+	SDL_RenderDrawPoint(RENDERER(), x1, y1);
+}
+
+void
+painter_draw_rectangle(int x, int y, unsigned int width, unsigned int height)
+{
+	const SDL_Rect rect = {
+		.w = width,
+		.h = height,
+		.x = x,
+		.y = y
+	};
+
+	SDL_RenderFillRect(RENDERER(), &rect);
+}
+
+void
+painter_draw_circle(int x, int y, int radius)
+{
+	// Note that there is more to altering the bitrate of this 
+	// method than just changing this value.  See how pixels are
+	// altered at the following web page for tips:
+	//   http://www.libsdl.org/intro.en/usingvideo.html
+	static const int BPP = 4;
+
+	//double ra = (double)radius;
+
+	for (double dy = 1; dy <= radius; dy += 1.0) {
+		double dx = floor(sqrt((2.0 * radius * dy) - (dy * dy)));
+
+		SDL_RenderDrawLine(RENDERER(), x - dx, y + dy - radius, x + dx, y + dy - radius);
+		SDL_RenderDrawLine(RENDERER(), x - dx, y - dy + radius, x + dx, y - dy + radius);
+	}
+}
+
+void
+painter_clear(void)
+{
+	SDL_RenderClear(RENDERER());
+}
+
+void
+painter_present(void)
+{
+	SDL_RenderPresent(RENDERER());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/painter.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,150 @@
+/*
+ * painter.h -- basic drawing routines
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_PAINTER_H
+#define MOLKO_PAINTER_H
+
+/**
+ * \file painter.h
+ * \brief Basic drawing routines.
+ * \ingroup drawing
+ */
+
+#include <stdbool.h>
+
+struct texture;
+
+/**
+ * Give the current texture being used for rendering, maybe NULL if the
+ * rendering is on root.
+ *
+ * \return Texture or NULL.
+ */
+struct texture *
+painter_get_target(void);
+
+/**
+ * Set the rendering context to the given texture.
+ *
+ * Since this function change an internal global variable it is strongly
+ * encouraged to store a local backup of the current texture using \a
+ * painter_get_target and call this function with it afterwards.
+ *
+ * If texture is NULL, use default context aka the window.
+ *
+ * \param tex the texture
+ * \see \ref PAINTER_BEGIN
+ * \see \ref PAINTER_END
+ */
+void
+painter_set_target(struct texture *tex);
+
+/**
+ * Get the current drawing color.
+ *
+ * \return the color in RRGGBBAA format
+ */
+unsigned long
+painter_get_color(void);
+
+/**
+ * Set the rendering drawing color.
+ *
+ * \param color in RRGGBBAA format
+ */
+void
+painter_set_color(unsigned long color);
+
+/**
+ * Draw a line.
+ *
+ * \param x1 first X coordinate
+ * \param y1 first Y coordinate
+ * \param x2 second X coordinate
+ * \param y2 second Y coordinate
+ */
+void
+painter_draw_line(int x1, int y1, int x2, int y2);
+
+/**
+ * Draw a pixel point.
+ *
+ * \param x the X coordinate
+ * \param y the Y coordinate
+ */
+void
+painter_draw_point(int x, int y);
+
+/**
+ * Draw a rectangle
+ *
+ * \param x the X coordinate
+ * \param y the Y coordinate
+ * \param w the rectangle width
+ * \param h the rectangle height
+ */
+void
+painter_draw_rectangle(int x, int y, unsigned int w, unsigned int h);
+
+/**
+ * Draw a circle.
+ *
+ * \param x the X coordinate
+ * \param y the Y coordinate
+ * \param radius the radius size
+ */
+void
+painter_draw_circle(int x, int y, int radius);
+
+/**
+ * Clear the window.
+ */
+void
+painter_clear(void);
+
+/**
+ * Present the window, only call this function one time in the main loop.
+ */
+void
+painter_present(void);
+
+/**
+ * Use this macro to start painting on the texture to store the current
+ * rendering context and put it back afterwards.
+ *
+ * \pre tex != NULL
+ * \param tex the texture to use
+ * \see \ref PAINTER_END
+ */
+#define PAINTER_BEGIN(tex    )                                          \
+do {                                                                    \
+        struct texture *__current_texture__;                            \
+                                                                        \
+        __current_texture__ = painter_get_target();                     \
+        painter_set_target((tex))
+
+/**
+ * Use this macro at the end of rendering into a given texture.
+ *
+ * \see \ref PAINTER_BEGIN
+ */
+#define PAINTER_END()                                                   \
+        painter_set_target(__current_texture__);                        \
+} while (0)
+
+#endif /* !MOLKO_PAINTER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/panic.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,76 @@
+/*
+ * panic.c -- unrecoverable error handling
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "error.h"
+#include "panic.h"
+
+static noreturn void
+terminate(void)
+{
+	fprintf(stderr, "abort: %s", error());
+	exit(1);
+}
+
+void (*panic_handler)(void) = terminate;
+
+noreturn void
+panicf(const char *fmt, ...)
+{
+	assert(fmt);
+
+	va_list ap;
+
+	/*
+	 * Store the error before calling panic because va_end would not be
+	 * called.
+	 */
+	va_start(ap, fmt);
+	error_vprintf(fmt, ap);
+	va_end(ap);
+
+	panic();
+}
+
+noreturn void
+vpanicf(const char *fmt, va_list ap)
+{
+	assert(fmt);
+	assert(panic_handler);
+
+	error_vprintf(fmt, ap);
+	panic();
+}
+
+noreturn void
+panic(void)
+{
+	assert(panic_handler);
+
+	panic_handler();
+
+	/*
+	 * This should not happen, if it does it means the user did not fully
+	 * satisfied the constraint of panic_handler.
+	 */
+	fprintf(stderr, "abort: panic handler returned");
+	exit(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/panic.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,87 @@
+/*
+ * panic.h -- unrecoverable error handling
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_PANIC_H
+#define MOLKO_PANIC_H
+
+/**
+ * \file panic.h
+ * \brief Unrecoverable error handling.
+ * \ingroup basics
+ *
+ * This set of functions should be used to detect runtime errors that are
+ * unexpected. They should be used only when the game cannot continue because
+ * it is in a unrecoverable state.
+ *
+ * Examples of appropriate use cases:
+ *
+ * - Game saved data is corrupt,
+ * - Assets are missing,
+ * - No more memory.
+ *
+ * In other contexts, use asserts to indicates programming error and
+ * appropriate solutions to recover the game otherwise.
+ */
+
+#include <stdarg.h>
+#include <stdnoreturn.h>
+
+#include "plat.h"
+
+/**
+ * \brief Global panic handler.
+ *
+ * The default implementation shows the last error and exit with code 1. The
+ * function must not return so you have to implement a setjmp/longjmp or a
+ * exception to be thrown.
+ *
+ * If the user defined function returns, panic routines will finally exit with
+ * code 1.
+ */
+extern void (*panic_handler)(void);
+
+/**
+ * Terminate the program using the \ref panic_handler routine.
+ *
+ * This function will first set the global error with the provided format
+ * string and then call the handler.
+ *
+ * \pre fmt != NULL
+ * \param fmt the printf(3) format string
+ */
+noreturn void
+panicf(const char *fmt, ...) PLAT_PRINTF(1, 2);
+
+/**
+ * Similar to \ref panicf but with a arguments pointer.
+ *
+ * \pre fmt != NULL
+ * \param fmt the printf(3) format string
+ * \param ap the arguments pointer
+ */
+noreturn void
+vpanicf(const char *fmt, va_list ap) PLAT_PRINTF(1, 0);
+
+/**
+ * Similar to \ref panicf but use last error stored using \ref error.h
+ * routines.
+ */
+noreturn void
+panic(void);
+
+#endif /* !MOLKO_PANIC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/plat.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,49 @@
+/*
+ * plat.h -- non-portable platform specific code
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_PLAT_H
+#define MOLKO_PLAT_H
+
+/**
+ * \file plat.h
+ * \brief Non-portable platform specific code.
+ */
+
+/*
+ * This block is used for doxygen documentation, the macros here are never
+ * exposed.
+ */
+#if defined(DOXYGEN)
+
+/**
+ * Printf specifier for function supporting the printf(3) syntax. This is
+ * currently only supported on GCC/Clang
+ */
+#define PLAT_PRINTF(p1, p2)
+
+#else
+
+#if defined(__GNUC__)
+#define PLAT_PRINTF(p1, p2) __attribute__ ((format (printf, p1, p2)))
+#else
+#define PLAT_PRINTF(p1, p2)
+#endif
+
+#endif /* !DOXYGEN  */
+
+#endif /* !MOLKO_PLAT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/rbuf.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,57 @@
+/*
+ * rbuf.c -- basic utility for reading input buffers
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "rbuf.h"
+
+void
+rbuf_open(struct rbuf *rb, const void *data, size_t datasz)
+{
+	assert(rb);
+	assert(data);
+
+	rb->s = data;
+	rb->e = rb->s + datasz;
+}
+
+bool
+rbuf_readline(struct rbuf *rb, char *output, size_t outputsz)
+{
+	assert(rb);
+	assert(output);
+	assert(outputsz > 0);
+
+	if (rb->s == rb->e)
+		return false;
+
+	for (--outputsz; rb->s != rb->e && *rb->s != '\n' && outputsz; outputsz--)
+		*output++ = *rb->s++;
+
+	/* Not enough space? */
+	if (!outputsz && rb->s != rb->e && *rb->s != '\n')
+		return false;
+
+	/* Remove this '\n' if still present. */
+	if (rb->s != rb->e && *rb->s == '\n')
+		rb->s++;
+
+	*output = '\0';
+
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/rbuf.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,81 @@
+/*
+ * rbuf.h -- basic utility for reading input buffers
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_RBUF_H
+#define MOLKO_RBUF_H
+
+/**
+ * \file rbuf.h
+ * \brief Basic utility for reading input buffers.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/**
+ * \brief Input object to store progression.
+ */
+struct rbuf {
+	const char *s;  /*!< (RO) Pointer to current character. */
+	const char *e;  /*!< (RO) Pointer to end of array. */
+};
+
+/**
+ * Open this input buffer.
+ *
+ * \pre rb != NULL
+ * \pre data != NULL
+ * \param rb the input object
+ * \param data the data to read
+ * \param datasz the size of buffer
+ */
+void
+rbuf_open(struct rbuf *rb, const void *data, size_t datasz);
+
+/**
+ * Read the next line from the input.
+ *
+ * This function writes at most outputsz - 1 and is always NULL terminated
+ * unless the function returns false which indicates either end of buffer or
+ * too small output size.
+ *
+ * Example of use (`some_data` is assumed to be a buffer).
+ *
+ * \code
+ * struct rbuf rb;
+ * char line[1024];
+ *
+ * rbuf_open(&rb, some_data, sizeof (some_data));
+ *
+ * while (rbuf_readline(&rb, line, sizeof (line))) {
+ *     printf("line contents: >[%s]<\n", line);
+ * }
+ * \endcode
+ *
+ * \pre rb != NULL
+ * \pre output != NULL
+ * \pre outputsz > 0
+ * \param rb the input object
+ * \param output the output buffer
+ * \param outputsz the output buffer size
+ * \return true if a line was read correctly
+ */
+bool
+rbuf_readline(struct rbuf *rb, char *output, size_t outputsz);
+
+#endif /* !MOLKO_RBUF_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/save.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,214 @@
+/*
+ * save.c -- save functions
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sqlite3.h>
+
+#include "error.h"
+#include "save.h"
+#include "sys.h"
+
+static sqlite3 *db;
+
+static const char *sinit =
+	"BEGIN EXCLUSIVE TRANSACTION;"
+	""
+	"CREATE TABLE IF NOT EXISTS property("
+	"  id INTEGER PRIMARY KEY AUTOINCREMENT,"
+	"  key TEXT NOT NULL UNIQUE,"
+	"  value TEXT NOT NULL"
+	");"
+	""
+	"COMMIT"
+;
+
+static const char *sbegin =
+	"BEGIN EXCLUSIVE TRANSACTION"
+;
+
+static const char *scommit =
+	"COMMIT"
+;
+
+static const char *srollback =
+	"ROLLBACK"
+;
+
+static const char *sset_property =
+	"INSERT OR REPLACE INTO property("
+	"  key,"
+	"  value"
+	")"
+	"VALUES("
+	"  ?,"
+	"  ?"
+	");"
+;
+
+static const char *sget_property =
+	"SELECT value"
+	"  FROM property"
+	" WHERE key = ?"
+;
+
+static const char *sremove_property =
+	"DELETE"
+	"  FROM property"
+	" WHERE key = ?"
+;
+
+static bool
+exec(const char *sql)
+{
+	if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK)
+		return error_printf("%s", sqlite3_errmsg(db));
+
+	return true;
+}
+
+bool
+save_open(unsigned int idx)
+{
+	return save_open_path(sys_savepath(idx));
+}
+
+bool
+save_open_path(const char *path)
+{
+	assert(path);
+
+	if (sqlite3_open(path, &db) != SQLITE_OK)
+		return error_printf("database open error: %s", sqlite3_errmsg(db));
+	if (sqlite3_exec(db, sinit, NULL, NULL, NULL) != SQLITE_OK)
+		return error_printf("database init error: %s", sqlite3_errmsg(db));
+
+	return true;
+}
+
+bool
+save_set_property(const char *key, const char *value)
+{
+	assert(key);
+	assert(value && strlen(value) <= SAVE_PROPERTY_VALUE_MAX);
+
+	sqlite3_stmt *stmt = NULL;
+
+	if (!exec(sbegin))
+		return false;
+	if (sqlite3_prepare(db, sset_property, -1, &stmt, NULL) != SQLITE_OK)
+		goto sqlite3_err;
+	if (sqlite3_bind_text(stmt, 1, key, -1, NULL) != SQLITE_OK ||
+	    sqlite3_bind_text(stmt, 2, value, -1, NULL) != SQLITE_OK)
+		goto sqlite3_err;
+	if (sqlite3_step(stmt) != SQLITE_DONE)
+		goto sqlite3_err;
+
+	sqlite3_finalize(stmt);
+
+	return exec(scommit);
+
+sqlite3_err:
+	if (stmt) {
+		sqlite3_finalize(stmt);
+		exec(srollback);
+	}
+
+	return error_printf("%s", sqlite3_errmsg(db));
+}
+
+const char *
+save_get_property(const char *key)
+{
+	assert(key);
+
+	static char value[SAVE_PROPERTY_VALUE_MAX + 1];
+	const char *ret = value;
+	sqlite3_stmt *stmt = NULL;
+
+	memset(value, 0, sizeof (value));
+
+	if (sqlite3_prepare(db, sget_property, -1, &stmt, NULL) != SQLITE_OK)
+		goto sqlite3_err;
+	if (sqlite3_bind_text(stmt, 1, key, -1, NULL) != SQLITE_OK)
+		goto sqlite3_err;
+
+	switch (sqlite3_step(stmt)) {
+	case SQLITE_DONE:
+		/* Not found. */
+		ret = NULL;
+		break;
+	case SQLITE_ROW:
+		/* Found. */
+		snprintf(value, sizeof (value), "%s", sqlite3_column_text(stmt, 0));
+		break;
+	default:
+		/* Error. */
+		goto sqlite3_err;
+	}
+
+	sqlite3_finalize(stmt);
+
+	return ret;
+
+sqlite3_err:
+	if (stmt)
+		sqlite3_finalize(stmt);
+
+	error_printf("%s", sqlite3_errmsg(db));
+
+	return NULL;
+}
+
+bool
+save_remove_property(const char *key)
+{
+	assert(key);
+
+	sqlite3_stmt *stmt = NULL;
+
+	if (!exec(sbegin))
+		return false;
+	if (sqlite3_prepare(db, sremove_property, -1, &stmt, NULL) != SQLITE_OK)
+		goto sqlite3_err;
+	if (sqlite3_bind_text(stmt, 1, key, -1, NULL) != SQLITE_OK)
+		goto sqlite3_err;
+	if (sqlite3_step(stmt) != SQLITE_DONE)
+		goto sqlite3_err;
+
+	sqlite3_finalize(stmt);
+
+	return exec(scommit);
+
+sqlite3_err:
+	if (stmt)
+		sqlite3_finalize(stmt);
+
+	error_printf("%s", sqlite3_errmsg(db));
+
+	return false;
+}
+
+void
+save_finish(void)
+{
+	if (db)
+		sqlite3_close(db);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/save.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,95 @@
+/*
+ * save.h -- save functions
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_SAVE_H
+#define MOLKO_SAVE_H
+
+/**
+ * \file save.h
+ * \brief Save functions.
+ */
+
+#include <stdbool.h>
+
+/**
+ * \brief Max property value.
+ */
+#define SAVE_PROPERTY_VALUE_MAX 1024
+
+/**
+ * Open a database by index.
+ *
+ * This function use the preferred path to store local files under the user
+ * home directory. The parameter idx specifies the save slot to use.
+ *
+ * \param idx the save slot
+ * \return false on error
+ */
+bool
+save_open(unsigned int idx);
+
+/**
+ * Open the save slot specified by path.
+ *
+ * \pre path != NULL
+ * \param path the path to the save slot
+ * \return false on error
+ */
+bool
+save_open_path(const char *path);
+
+/**
+ * Sets an arbitrary property.
+ *
+ * If the property already exists, replace it.
+ *
+ * \pre key != NULL
+ * \pre value != NULL && strlen(value) <= SAVE_PROPERTY_VALUE_MAX
+ * \param key the property key
+ * \param value the property value
+ */
+bool
+save_set_property(const char *key, const char *value);
+
+/**
+ * Get a property.
+ *
+ * \pre key != NULL
+ * \param key the property key
+ * \return the key or NULL if not found
+ */
+const char *
+save_get_property(const char *key);
+
+/**
+ * Remove a property.
+ *
+ * \pre key != NULL
+ * \param key the property key
+ * \return false on error
+ */
+bool
+save_remove_property(const char *key);
+
+/**
+ * Close the save slot.
+ */
+void
+save_finish(void);
+
+#endif /* !MOLKO_SAVE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/script.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,159 @@
+/*
+ * script.c -- convenient sequence of actions
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "script.h"
+#include "util.h"
+
+static void
+script_action_finish(struct action *a)
+{
+	assert(a);
+
+	script_finish(a->data);
+	free(a->data);
+}
+
+static void
+script_action_handle(struct action *a, const union event *ev)
+{
+	assert(a);
+	assert(ev);
+
+	script_handle(a->data, ev);
+}
+
+static bool
+script_action_update(struct action *a, unsigned int ticks)
+{
+	assert(a);
+
+	return script_update(a->data, ticks);
+}
+
+static void
+script_action_draw(struct action *a)
+{
+	assert(a);
+
+	script_draw(a->data);
+}
+
+void
+script_init(struct script *s)
+{
+	assert(s);
+
+	memset(s, 0, sizeof (struct script));
+	s->tail = &s->head;
+}
+
+void
+script_start(struct script *s)
+{
+	assert(s);
+
+	s->iter = s->head;
+}
+
+void
+script_append(struct script *s, const struct action *a)
+{
+	assert(s);
+	assert(a);
+	assert(a->update);
+
+	struct script_action *iter = ecalloc(1, sizeof (struct script_action));
+
+	memcpy(&iter->action, a, sizeof (struct action));
+	*s->tail = iter;
+	s->tail = &iter->next;
+}
+
+void
+script_handle(struct script *s, const union event *ev)
+{
+	assert(s);
+	assert(ev);
+
+	if (s->iter && s->iter->action.handle)
+		s->iter->action.handle(&s->iter->action, ev);
+}
+
+bool
+script_update(struct script *s, unsigned int ticks)
+{
+	assert(s);
+
+	if (!s->iter)
+		return true;
+
+	struct action *a = &s->iter->action;
+
+	if (a->update(a, ticks)) {
+		if (a->end)
+			a->end(a);
+		if (a->finish)
+			a->finish(a);
+
+		s->iter = s->iter->next;
+	}
+
+	return s->iter == NULL;
+}
+
+void
+script_draw(struct script *s)
+{
+	assert(s);
+
+	if (s->iter && s->iter->action.draw)
+		s->iter->action.draw(&s->iter->action);
+}
+
+void
+script_action(const struct script *s, struct action *action)
+{
+	assert(s);
+	assert(action);
+
+	memset(action, 0, sizeof (struct action));
+	action->data = ememdup(s, sizeof (struct script));
+	action->handle = script_action_handle;
+	action->update = script_action_update;
+	action->draw = script_action_draw;
+	action->finish = script_action_finish;
+}
+
+void
+script_finish(struct script *s)
+{
+	assert(s);
+
+	struct script_action *iter, *next;
+
+	for (iter = s->head; iter; iter = next) {
+		next = iter->next;
+		free(iter);
+	}
+
+	memset(s, 0, sizeof (struct script));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/script.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,160 @@
+/*
+ * script.h -- convenient sequence of actions
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_SCRIPT_H
+#define MOLKO_SCRIPT_H
+
+/**
+ * \file script.h
+ * \brief Convenient sequence of actions.
+ * \ingroup actions
+ *
+ * Those routines wrap individual actions into a sequence of actions into an
+ * action itself.
+ *
+ * This is convenient for scenarios where you need to specify several
+ * sequential actions that neet to wait before continuing.
+ *
+ * In a nutshell, to write a scenario you should:
+ *
+ * 1. Create a script with see \ref script_init,
+ * 2. Create one or more actions and append with \ref script_append,
+ * 3. Start the action using \ref script_start,
+ * 4. Put the script into the game using \ref game_add_action.
+ *
+ * \warning You must always call \ref script_init before using this object.
+ */
+
+#include <stdbool.h>
+
+#include "action.h"
+
+union event;
+
+/**
+ * \brief Single-linked list of actions.
+ */
+struct script_action {
+	struct action action;           /*!< (RW) Action to use */
+	struct script_action *next;     /*!< (RO) Pointer to next action */
+};
+
+/**
+ * \brief Sequence of actions and state holder.
+ */
+struct script {
+	struct script_action *iter;     /*!< (RO) Current action */
+	struct script_action *head;     /*!< (RO) Beginning */
+	struct script_action **tail;    /*!< (RO) Pointer to add to tail */
+};
+
+/**
+ * Initialize a script.
+ *
+ * This is mandatory before using any functions, do not zero-initialize the
+ * structure yourself.
+ *
+ * \pre s != NULL
+ * \param s the script
+ */
+void
+script_init(struct script *s);
+
+/**
+ * Call this function before putting the script in the game.
+ *
+ * \pre s != NULL
+ * \param s the script
+ */
+void
+script_start(struct script *s);
+
+/**
+ * Append a new action to the script.
+ *
+ * The action is copied into the script and does not need to be allocated on
+ * the heap.
+ *
+ * The action can be empty but must have at least update member set.
+ *
+ * \pre s != NULL
+ * \pre a != NULL && a->update
+ * \param s the script
+ * \param a the action to copy
+ */
+void
+script_append(struct script *s, const struct action *a);
+
+/**
+ * Handle the event into the current action.
+ *
+ * \pre s != NULL
+ * \pre ev != NULL
+ * \param s the script
+ * \param ev the event
+ * \note You usually don't need to call this yourself.
+ */
+void
+script_handle(struct script *s, const union event *ev);
+
+/**
+ * Update the current action.
+ *
+ * \pre s != NULL
+ * \param s the script
+ * \param ticks the number of milliseconds since last frame
+ * \note You usually don't need to call this yourself.
+ */
+bool
+script_update(struct script *s, unsigned int ticks);
+
+/**
+ * Draw the current action.
+ *
+ * \pre s != NULL
+ * \param s the script
+ * \note You usually don't need to call this yourself.
+ */
+void
+script_draw(struct script *s);
+
+/**
+ * Create an action from the script for use into the game.
+ *
+ * This function is meant to transform the script into an action itself and be
+ * added to the game using \ref game_add_action.
+ *
+ * \pre s != NULL
+ * \pre dst != NULL
+ * \param s the script
+ * \param dst the action to build with the script
+ */
+void
+script_action(const struct script *s, struct action *dst);
+
+/**
+ * Destroy all the actions into the script.
+ *
+ * \pre s != NULL
+ * \param s the script
+ * \note You usually don't need to call this yourself.
+ */
+void
+script_finish(struct script *s);
+
+#endif /* !MOLKO_SCRIPT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/sound.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,107 @@
+/*
+ * sound.c -- sound support
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <SDL_mixer.h>
+
+#include "sound.h"
+#include "error_p.h"
+
+bool
+sound_open(struct sound *snd, const char *path)
+{
+	assert(snd);
+	assert(path);
+
+	if (!(snd->handle = Mix_LoadMUS(path)))
+		return error_sdl();
+
+	return true;
+}
+
+bool
+sound_openmem(struct sound *snd, const void *buffer, size_t buffersz)
+{
+	assert(snd);
+	assert(buffer);
+
+	SDL_RWops *ops;
+
+	if (!(ops = SDL_RWFromConstMem(buffer, buffersz)) ||
+	    !(snd->handle = Mix_LoadMUS_RW(ops, true)))
+		return error_sdl();
+
+	return true;
+}
+
+bool
+sound_play(struct sound *snd)
+{
+	assert(snd);
+
+	int n = 1;
+
+	if (snd->flags & SOUND_LOOP)
+		n = -1;
+	if (Mix_PlayMusic(snd->handle, n) < 0)
+		return error_sdl();
+
+	return true;
+}
+
+void
+sound_pause(struct sound *snd)
+{
+	/* Not needed yet. */
+	(void)snd;
+
+	Mix_PauseMusic();
+}
+
+void
+sound_resume(struct sound *snd)
+{
+	/* Not needed yet. */
+	(void)snd;
+
+	Mix_ResumeMusic();
+}
+
+void
+sound_stop(struct sound *snd)
+{
+	/* Not needed yet. */
+	(void)snd;
+
+	Mix_HaltMusic();
+}
+
+void
+sound_finish(struct sound *snd)
+{
+	assert(snd);
+
+	if (snd->handle) {
+		Mix_HaltMusic();
+		Mix_FreeMusic(snd->handle);
+	}
+
+	memset(snd, 0, sizeof (*snd));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/sound.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,120 @@
+/*
+ * sound.h -- sound support
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_SOUND_H
+#define MOLKO_SOUND_H
+
+/**
+ * \file sound.h
+ * \brief Sound support.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/**
+ * \brief Sound flags.
+ */
+enum sound_flags {
+	SOUND_NONE,                     /*!< No flags. */
+	SOUND_LOOP      = (1 << 0)      /*!< Loop the music. */
+};
+
+/**
+ * \brief Sound chunk.
+ */
+struct sound {
+	enum sound_flags flags;         /*!< (RW) Flags. */
+	void *handle;                   /*!< (RO) Native handle. */
+};
+
+/**
+ * Open a sound audio file.
+ *
+ * \pre snd != NULL
+ * \pre path != NULL
+ * \param snd the sound object to initialize
+ * \param path the path to the audio file
+ * \return False on errors.
+ */
+bool
+sound_open(struct sound *snd, const char *path);
+
+/**
+ * Open a sound audio from a buffer.
+ *
+ * \pre snd != NULL
+ * \pre buffer != NULL
+ * \param snd the sound object to initialize
+ * \param buffer the buffer
+ * \param buffersz the buffer size
+ * \return False on errors.
+ * \warning The buffer must exists until the sound object is closed.
+ */
+bool
+sound_openmem(struct sound *snd, const void *buffer, size_t buffersz);
+
+/**
+ * Start playing the sound.
+ *
+ * This function will resume the playback since the beginning.
+ *
+ * \pre snd != NULL
+ * \param snd the sound object
+ * \return False on errors.
+ */
+bool
+sound_play(struct sound *snd);
+
+/**
+ * Pause the sound music.
+ *
+ * \pre snd != NULL
+ * \param snd the sound object
+ */
+void
+sound_pause(struct sound *snd);
+
+/**
+ * Resume the sound music.
+ *
+ * \pre snd != NULL
+ * \param snd the sound object
+ */
+void
+sound_resume(struct sound *snd);
+
+/**
+ * Stop the sound music.
+ *
+ * \pre snd != NULL
+ * \param snd the sound object
+ */
+void
+sound_stop(struct sound *snd);
+
+/**
+ * Close the associated resources.
+ *
+ * \pre snd != NULL
+ * \param snd the sound object
+ */
+void
+sound_finish(struct sound *snd);
+
+#endif /* !MOLKO_SOUND_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/sprite.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,57 @@
+/*
+ * sprite.c -- image sprites
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "sprite.h"
+#include "texture.h"
+
+void
+sprite_init(struct sprite *sprite,
+            struct texture *tex,
+            unsigned int cellw,
+            unsigned int cellh)
+{
+	assert(sprite);
+	assert(tex && texture_ok(tex));
+
+	sprite->texture = tex;
+	sprite->cellw = cellw;
+	sprite->cellh = cellh;
+	sprite->nrows = tex->h / cellh;
+	sprite->ncols = tex->w / cellw;
+}
+
+void
+sprite_draw(struct sprite *sprite, unsigned int r, unsigned int c, int x, int y)
+{
+	assert(sprite);
+
+	texture_scale(
+		sprite->texture,
+		c * sprite->cellw,      /* src y */
+		r * sprite->cellh,      /* src x */
+		sprite->cellw,          /* src width */
+		sprite->cellh,          /* src height */
+		x,                      /* dst x */
+		y,                      /* dst y */
+		sprite->cellw,          /* dst width */
+		sprite->cellh,          /* dst height */
+		0.0                     /* angle */
+	);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/sprite.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,80 @@
+/*
+ * sprite.h -- image sprites
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_SPRITE_H
+#define MOLKO_SPRITE_H
+
+/**
+ * \file sprite.h
+ * \brief Image sprites.
+ * \ingroup drawing
+ */
+
+struct texture;
+
+/**
+ * \brief Sprite structure.
+ */
+struct sprite {
+	struct texture *texture;        /*!< Texture to access (RO) */
+	unsigned int cellw;             /*!< Width per cell (RW) */
+	unsigned int cellh;             /*!< Height per cell (RW) */
+	unsigned int nrows;             /*!< Number of rows (RW) */
+	unsigned int ncols;             /*!< Number of columns (RW) */
+};
+
+/**
+ * Initialize a sprite.
+ *
+ * The sprite does not take ownership of texture and must be valid until the
+ * sprite is no longer used.
+ *
+ * This function is only provided as convenience, user may initialize the
+ * sprite by itself if wanted.
+ *
+ * The fields `nrows' and `ncols' will be determined automatically from the
+ * texture size.
+ *
+ * \pre sprite != NULL
+ * \pre tex != NULL && texture_ok(tex)
+ * \param sprite the sprite to initialize
+ * \param tex the texture
+ * \param cellw the width per cell in pixels
+ * \param cellh the height per cell in pixels
+ */
+void
+sprite_init(struct sprite *sprite,
+            struct texture *tex,
+            unsigned int cellw,
+            unsigned int cellh);
+
+/**
+ * Draw the sprite component from row `r' and column `c'.
+ *
+ * \pre sprite != NULL
+ * \param sprite the sprite to draw
+ * \param r the row number
+ * \param c the column number
+ * \param x the X destination
+ * \param y the Y destination
+ * \warning No bounds checking
+ */
+void
+sprite_draw(struct sprite *sprite, unsigned int r, unsigned int c, int x, int y);
+
+#endif /* !MOLKO_SPRITE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/state.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,61 @@
+/*
+ * state.h -- abstract state
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_STATE_H
+#define MOLKO_STATE_H
+
+/**
+ * \file state.h
+ * \brief Abstract state.
+ * \ingroup states
+ */
+
+union event;
+
+/**
+ * \brief Abstract state.
+ */
+struct state {
+	/**
+	 * This function is called when the state is entered.
+	 */
+	void (*enter)(void);
+
+	/**
+	 * This function is called when the state is about to be left.
+	 */
+	void (*leave)(void);
+
+	/**
+	 * This function is called for each event that happened.
+	 */
+	void (*handle)(const union event *);
+
+	/**
+	 * This function is called to update the game, with the number of
+	 * milliseconds since the last frame.
+	 */
+	void (*update)(unsigned int ticks);
+
+	/**
+	 * This function is supposed to draw the game.
+	 */
+	void (*draw)(void);
+};
+
+#endif /* !MOLKO_STATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/sys.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,181 @@
+/*
+ * sys.c -- system routines
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <SDL.h>
+#include <SDL_image.h>
+#include <SDL_mixer.h>
+#include <SDL_ttf.h>
+
+#if !defined(_WIN32)            /* Assuming POSIX */
+#	include <sys/types.h>
+#	include <dirent.h>
+#endif
+
+#include "error.h"
+#include "error_p.h"
+#include "sys.h"
+
+#if defined(_WIN32)
+
+static void
+determine(char path[], size_t pathlen)
+{
+	char *base = SDL_GetBasePath();
+
+	/* On Windows, the data hierarchy is the same as the project. */
+	snprintf(path, pathlen, "%sassets", base);
+	SDL_free(base);
+}
+
+#else                           /* Assuming POSIX */
+
+static bool
+is_absolute(const char *path)
+{
+	assert(path);
+
+	return path[0] == '/';
+}
+
+static void
+determine(char path[], size_t pathlen)
+{
+	char localassets[PATH_MAX];
+	char *base = SDL_GetBasePath();
+	DIR *dp;
+
+	/* Try assets directory where executable lives. */
+	snprintf(localassets, sizeof (localassets), "%sassets", base);
+
+	if ((dp = opendir(localassets))) {
+		snprintf(path, pathlen, "%sassets", base);
+		closedir(dp);
+	} else {
+		/* We are not in the project source directory. */
+		if (is_absolute(SHAREDIR)) {
+			/* SHAREDIR is absolute */
+			snprintf(path, pathlen, "%s/molko", SHAREDIR);
+		} else if (is_absolute(BINDIR)) {
+			/* SHAREDIR is relative but BINDIR is absolute */
+			snprintf(path, pathlen, "%s/%s/molko", PREFIX, SHAREDIR);
+		} else {
+			/* SHAREDIR, BINDIR are both relative */
+			char *ptr = strstr(base, BINDIR);
+
+			if (ptr) {
+				*ptr = '\0';
+				snprintf(path, pathlen, "%s%s/molko", base, SHAREDIR);
+			} else {
+				/* Unable to determine. */
+				snprintf(path, pathlen, ".");
+			}
+		}
+	}
+
+	SDL_free(base);
+}
+
+#endif
+
+bool
+sys_init(void)
+{
+#if defined(__MINGW64__)
+	/* On MinGW buffering leads to painful debugging. */
+	setbuf(stderr, NULL);
+	setbuf(stdout, NULL);
+#endif
+
+	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
+		return error_sdl();
+	if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG)
+		return error_sdl();
+	if (TTF_Init() < 0)
+		return error_sdl();
+	if (Mix_Init(MIX_INIT_OGG) != MIX_INIT_OGG)
+		return error_sdl();
+	if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0)
+		return error_sdl();
+
+	return true;
+}
+
+const char *
+sys_datadir(void)
+{
+	static char path[PATH_MAX];
+
+	if (path[0] == '\0')
+		determine(path, sizeof (path));
+
+	return path;
+}
+
+const char *
+sys_datapath(const char *fmt, ...)
+{
+	const char *ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = sys_datapathv(fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+const char *
+sys_datapathv(const char *fmt, va_list ap)
+{
+	static char path[PATH_MAX];
+	char filename[FILENAME_MAX];
+
+	vsnprintf(filename, sizeof (filename), fmt, ap);
+	snprintf(path, sizeof (path), "%s/%s", sys_datadir(), filename);
+
+	return path;
+}
+
+const char *
+sys_savepath(unsigned int idx)
+{
+	static char path[PATH_MAX];
+	char *pref;
+
+	if ((pref = SDL_GetPrefPath("malikania", "molko"))) {
+		snprintf(path, sizeof (path), "%ssave-%u", pref, idx);
+		SDL_free(pref);
+	} else
+		snprintf(path, sizeof (path), "save-%u", idx);
+
+	return path;
+}
+
+void
+sys_finish(void)
+{
+	Mix_Quit();
+	TTF_Quit();
+	IMG_Quit();
+	SDL_Quit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/sys.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,83 @@
+/*
+ * sys.h -- system routines
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_SYS_H
+#define MOLKO_SYS_H
+
+/**
+ * \file sys.h
+ * \brief System routines.
+ * \ingroup basics
+ */
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+/**
+ * Initialize the system, should be called in the beginning of the main.
+ */
+bool
+sys_init(void);
+
+/**
+ * Get the base system directory path.
+ *
+ * \return the path where the executable lives
+ */
+const char *
+sys_datadir(void);
+
+/**
+ * Construct path to assets directory using printf-like format.
+ *
+ * \param fmt the format string
+ * \return the path to the file
+ * \note This function returns pointer to static string.
+ */
+const char *
+sys_datapath(const char *fmt, ...);
+
+/**
+ * Similar to \a sys_datapath.
+ *
+ * \param fmt the format string
+ * \param ap the variadic arguments pointer
+ * \return the path to the file
+ * \note This function returns pointer to static string.
+ */
+const char *
+sys_datapathv(const char *fmt, va_list ap);
+
+/**
+ * Compute the path to the save file for the given game state.
+ *
+ * \param idx the save number
+ * \return the path to the database file
+ * \note This only compute the path, it does not check the presence of the file
+ * \post The returned value will never be NULL
+ */
+const char *
+sys_savepath(unsigned int idx);
+
+/**
+ * Close the system.
+ */
+void
+sys_finish(void);
+
+#endif /* !MOLKO_SYS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/texture.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,127 @@
+/*
+ * texture.c -- basic texture management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "error.h"
+#include "error_p.h"
+#include "texture.h"
+#include "texture_p.h"
+#include "util.h"
+#include "window.h"
+#include "window_p.h"
+
+bool
+texture_new(struct texture *tex, unsigned int w, unsigned int h)
+{
+	assert(tex);
+
+	tex->handle = SDL_CreateTexture(RENDERER(),
+	    SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, w, h);
+
+	if (!tex->handle) {
+		tex->w = tex->h = 0;
+		return error_sdl();
+	}
+
+	tex->w = w;
+	tex->h = h;
+
+	return true;
+}
+
+bool
+texture_ok(const struct texture *tex)
+{
+	assert(tex);
+
+	return tex->handle && tex->w && tex->h;
+}
+
+void
+texture_draw(struct texture *tex, int x, int y)
+{
+	assert(tex);
+
+	SDL_Rect dst = {
+		.x = x,
+		.y = y,
+		.w = tex->w,
+		.h = tex->h
+	};
+
+	SDL_RenderCopy(RENDERER(), tex->handle, NULL, &dst);
+}
+
+void
+texture_scale(struct texture *tex,
+              int src_x,
+              int src_y,
+              unsigned src_w,
+              unsigned src_h,
+              int dst_x,
+              int dst_y,
+              unsigned dst_w,
+              unsigned dst_h,
+              double angle)
+{
+	const SDL_Rect src = {
+		.x = src_x,
+		.y = src_y,
+		.w = src_w,
+		.h = src_h
+	};
+	const SDL_Rect dst = {
+		.x = dst_x,
+		.y = dst_y,
+		.w = dst_w,
+		.h = dst_h
+	};
+
+	SDL_RenderCopyEx(RENDERER(), tex->handle, &src, &dst, angle, NULL, SDL_FLIP_NONE);
+}
+
+void
+texture_finish(struct texture *tex)
+{
+	assert(tex);
+
+	if (tex->handle)
+		SDL_DestroyTexture(tex->handle);
+
+	memset(tex, 0, sizeof (*tex));
+}
+
+/* private */
+
+bool
+texture_from_surface(struct texture *tex, SDL_Surface *surface)
+{
+	assert(tex);
+	assert(surface);
+
+	if (!(tex->handle = SDL_CreateTextureFromSurface(RENDERER(), surface))) {
+		tex->w = tex->h = 0;
+		return error_sdl();
+	}
+
+	tex->w = surface->w;
+	tex->h = surface->h;
+
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/texture.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,113 @@
+/*
+ * texture.h -- basic texture management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_TEXTURE_H
+#define MOLKO_TEXTURE_H
+
+/**
+ * \file texture.h
+ * \brief Basic texture management.
+ * \ingroup drawing
+ *
+ * See also \a image.h for usage of textures.
+ */
+
+#include <stdbool.h>
+
+/**
+ * \brief Texture object.
+ */
+struct texture {
+	unsigned int w;         /*!< (RO) Texture width. */
+	unsigned int h;         /*!< (RO) Texture height. */
+	void *handle;           /*!< (RO) Native handle. */
+};
+
+/**
+ * Create a new texture.
+ *
+ * \pre tex != NULL
+ * \param tex the texture to initialize
+ * \param w the width
+ * \param h the height
+ * \return False on error.
+ */
+bool
+texture_new(struct texture *tex, unsigned int w, unsigned int h);
+
+/**
+ * Check if the texture is valid.
+ *
+ * This function simply checks if the texture is initialized and has non-null
+ * dimensions.
+ *
+ * \pre tex != NULL
+ * \param tex the texture to check
+ * \return True if the texture is initialized
+ */
+bool
+texture_ok(const struct texture *tex);
+
+/**
+ * Simple texture drawing.
+ *
+ * \pre tex != NULL
+ * \param tex the texture
+ * \param x the X coordinate
+ * \param y the Y coordinate
+ */
+void
+texture_draw(struct texture *tex, int x, int y);
+
+/**
+ * Advanced texture drawing.
+ *
+ * \pre tex != NULL
+ * \param tex the texture
+ * \param src_x the source rectangle X coordinate
+ * \param src_y the source rectangle Y coordinate
+ * \param src_w the source rectangle width
+ * \param src_h the source rectangle height
+ * \param dst_x the destination rectangle X coordinate
+ * \param dst_y the destination rectangle Y coordinate
+ * \param dst_w the destination rectangle width
+ * \param dst_h the destination rectangle height
+ * \param angle the angle
+ */
+void
+texture_scale(struct texture *tex,
+              int src_x,
+              int src_y,
+              unsigned src_w,
+              unsigned src_h,
+              int dst_x,
+              int dst_y,
+              unsigned dst_w,
+              unsigned dst_h,
+              double angle);
+
+/**
+ * Close the texture, do not use afterwards.
+ *
+ * \pre tex != NULL
+ * \param tex the texture
+ */
+void
+texture_finish(struct texture *tex);
+
+#endif /* !MOLKO_TEXTURE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/texture_p.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,31 @@
+/*
+ * texture_p.h -- (PRIVATE) basic texture management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_TEXTURE_P_H
+#define MOLKO_TEXTURE_P_H
+
+#include <stdbool.h>
+
+#include <SDL.h>
+
+struct texture;
+
+bool
+texture_from_surface(struct texture *tex, SDL_Surface *surface);
+
+#endif /* !MOLKO_TEXTURE_P_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/theme.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,254 @@
+/*
+ * theme.c -- abstract theming
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include "button.h"
+#include "checkbox.h"
+#include "font.h"
+#include "frame.h"
+#include "label.h"
+#include "maths.h"
+#include "painter.h"
+#include "panic.h"
+#include "texture.h"
+#include "theme.h"
+#include "util.h"
+
+#include "core/assets/fonts/ComicNeue-Regular.h"
+
+#define THEME(t) (t ? t : &default_theme)
+
+#define CHECKBOX_W 16
+#define CHECKBOX_H 16
+#define CHECKBOX_RAD 6
+
+static struct font default_font;
+
+static void
+box(int x, int y, unsigned int w, unsigned int h)
+{
+	/* Some basic outlines. */
+	painter_set_color(0x4d3533ff);
+
+	painter_draw_line(x, y, x + w, y);
+	painter_draw_line(x, y + h, x + w, y + h);
+	painter_draw_line(x, y, x, y + h);
+	painter_draw_line(x + w, y, x + w, y + h);
+}
+
+static void
+draw_frame(struct theme *t, const struct frame *frame)
+{
+	if (frame->style == FRAME_STYLE_BOX)
+		painter_set_color(0x6e4c30ff);
+	else
+		painter_set_color(0xce9248ff);
+
+	painter_draw_rectangle(frame->x, frame->y, frame->w, frame->h);
+	box(frame->x, frame->y, frame->w, frame->h);
+}
+
+static void
+draw_label(struct theme *t, const struct label *label)
+{
+	struct texture tex;
+	int x = label->x, y = label->y;
+	int *px = &x, *py = &y;
+
+	if (label->flags & LABEL_NO_HCENTER)
+		px = NULL;
+	if (label->flags & LABEL_NO_VCENTER)
+		py = NULL;
+
+	/* Shadow text, only if enabled. */
+	if (!(label->flags & LABEL_NO_SHADOW)) {
+		t->fonts[THEME_FONT_INTERFACE]->color = t->colors[THEME_COLOR_SHADOW];
+
+		if (!font_render(t->fonts[THEME_FONT_INTERFACE], &tex, label->text))
+			panic();
+
+		maths_centerize(px, py, tex.w, tex.h,
+		    label->x, label->y, label->w, label->h);
+
+		texture_draw(&tex, x + 1, y + 1);
+		texture_finish(&tex);
+	}
+
+	/* Normal text. */
+	t->fonts[THEME_FONT_INTERFACE]->color = label->color
+		? label->color
+		: t->colors[THEME_COLOR_NORMAL];
+
+	if (!font_render(t->fonts[THEME_FONT_INTERFACE], &tex, label->text))
+		panic();
+
+	maths_centerize(px, py, tex.w, tex.h,
+	    label->x, label->y, label->w, label->h);
+
+	texture_draw(&tex, x, y);
+	texture_finish(&tex);
+}
+
+static void
+draw_button(struct theme *t, const struct button *button)
+{
+	struct label label = {
+		.text = button->text,
+		.x = button->x,
+		.y = button->y,
+		.w = button->w,
+		.h = button->h
+	};
+
+	painter_set_color(0xabcdefff);
+	painter_draw_rectangle(button->x, button->y, button->w, button->h);
+
+	label_draw(&label);
+
+	box(button->x, button->y, button->w, button->h);
+}
+
+static void
+draw_checkbox(struct theme *t, const struct checkbox *cb)
+{
+	box(cb->x, cb->y, CHECKBOX_W, CHECKBOX_H);
+
+	if (cb->checked)
+		painter_draw_rectangle(cb->x + 5, cb->y + 5, CHECKBOX_W - 9, CHECKBOX_H - 9);
+
+	if (cb->label) {
+		const unsigned int w = cb->w - (t->padding * 2) - CHECKBOX_W;
+		const int x = cb->x + (t->padding * 2) + CHECKBOX_W;
+
+		struct label label = {
+			.text = cb->label,
+			.flags = LABEL_NO_HCENTER,
+			.x = x,
+			.y = cb->y,
+			.w = w,
+			.h = cb->h
+		};
+
+		draw_label(t, &label);
+	}
+}
+
+/* Default theme. */
+static struct theme default_theme = {
+	.colors = {
+		[THEME_COLOR_NORMAL]    = 0xffffffff,
+		[THEME_COLOR_SELECTED]  = 0x006554ff,
+		[THEME_COLOR_SHADOW]    = 0x000000ff
+	},
+	.padding = 10,
+	.draw_frame = draw_frame,
+	.draw_label = draw_label,
+	.draw_button = draw_button,
+	.draw_checkbox = draw_checkbox
+};
+
+/* Default font catalog. */
+#define FONT(bin, size, index)                                          \
+        { bin, sizeof (bin), size, &default_theme.fonts[index] }
+
+static struct font_catalog {
+	const unsigned char *data;
+	const size_t datasz;
+	unsigned int size;
+	struct font **dest;
+	struct font font;
+} default_fonts[] = {
+	FONT(ComicNeue_Regular, 20, THEME_FONT_INTERFACE)
+};
+
+bool
+theme_init(void)
+{
+	/* Open all fonts. */
+	for (size_t i = 0; i < NELEM(default_fonts); ++i) {
+		struct font_catalog *fc = &default_fonts[i];
+
+		if (!font_openmem(&fc->font, fc->data, fc->datasz, fc->size))
+			goto failed;
+
+		/* Reference this font into the catalog. */
+		*default_fonts[i].dest = &default_fonts[i].font;
+	}
+
+	return true;
+
+failed:
+	theme_finish();
+
+	return false;
+}
+
+struct theme *
+theme_default(void)
+{
+	return &default_theme;
+}
+
+unsigned int
+theme_padding(const struct theme *t)
+{
+	return THEME(t)->padding;
+}
+
+void
+theme_draw_frame(struct theme *t, const struct frame *frame)
+{
+	assert(frame);
+
+	THEME(t)->draw_frame(THEME(t), frame);
+}
+
+void
+theme_draw_label(struct theme *t, const struct label *label)
+{
+	assert(label);
+
+	THEME(t)->draw_label(THEME(t), label);
+}
+
+void
+theme_draw_button(struct theme *t, const struct button *button)
+{
+	assert(button);
+
+	THEME(t)->draw_button(THEME(t), button);
+}
+
+void
+theme_draw_checkbox(struct theme *t, const struct checkbox *cb)
+{
+	assert(cb);
+
+	THEME(t)->draw_checkbox(THEME(t), cb);
+}
+
+void
+theme_finish(void)
+{
+	for (size_t i = 0; i < NELEM(default_fonts); ++i) {
+		font_finish(&default_fonts[i].font);
+		*default_fonts[i].dest = NULL;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/theme.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,175 @@
+/*
+ * theme.h -- abstract theming
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_THEME_H
+#define MOLKO_THEME_H
+
+/**
+ * \file theme.h
+ * \brief Abstract theming.
+ */
+
+#include <stdbool.h>
+
+struct checkbox;
+struct button;
+struct font;
+struct frame;
+struct label;
+
+/**
+ * \brief Font component.
+ */
+enum theme_font {
+	THEME_FONT_INTERFACE,   /*!< Font for interface elements. */
+	THEME_FONT_LAST         /*!< Unused. */
+};
+
+/**
+ * \brief Theme colors.
+ */
+enum theme_color {
+	THEME_COLOR_NORMAL,     /*!< Normal font color. */
+	THEME_COLOR_SELECTED,   /*!< Font color for selected elements. */
+	THEME_COLOR_SHADOW,     /*!< Shadow color. */
+	THEME_COLOR_LAST        /*!< Unused. */
+};
+
+/**
+ * \brief Abstract theme structure.
+ */
+struct theme {
+	/**
+	 * (RW, ref) Fonts catalog.
+	 */
+	struct font *fonts[THEME_FONT_LAST];
+
+	/**
+	 * (RW) Miscellaneous colors.
+	 */
+	unsigned long colors[THEME_COLOR_LAST];
+
+	/**
+	 * (RW) Padding between GUI elements.
+	 */
+	unsigned int padding;
+
+	/**
+	 * Draw a frame.
+	 *
+	 * This function is used to draw a box usually as a container where UI
+	 * elements will be put.
+	 *
+	 * \see \ref theme_draw_frame
+	 */
+	void (*draw_frame)(struct theme *, const struct frame *);
+
+	/**
+	 * Draw a label.
+	 *
+	 * \see \ref theme_draw_label
+	 */
+	void (*draw_label)(struct theme *, const struct label *);
+
+	/**
+	 * Draw a button.
+	 *
+	 * \see \ref theme_draw_button
+	 */
+	void (*draw_button)(struct theme *, const struct button *);
+
+	/**
+	 * Draw a checkbox.
+	 *
+	 * \see \ref theme_draw_button
+	 */
+	void (*draw_checkbox)(struct theme *t, const struct checkbox *);
+};
+
+/**
+ * Initialize the theming system.
+ *
+ * \return false on errors
+ * \warning This function must be called before any other theme functions.
+ */
+bool
+theme_init(void);
+
+/**
+ * Get a reference to the default theme.
+ *
+ * \return A non-owning pointer to a static storage for the default theme
+ */
+struct theme *
+theme_default(void);
+
+/**
+ * Get the desired padding between GUI elements.
+ *
+ * \param t the theme to use (may be NULL)
+ * \return the padding in pixels
+ */
+unsigned int
+theme_padding(const struct theme *t);
+
+/**
+ * Draw a frame.
+ *
+ * \pre frame != NULL
+ * \param t the theme to use (may be NULL)
+ * \param frame the frame
+ */
+void
+theme_draw_frame(struct theme *t, const struct frame *frame);
+
+/**
+ * Draw a label.
+ *
+ * \pre label != NULL
+ * \param t the theme to use (may be NULL)
+ * \param label the label
+ */
+void
+theme_draw_label(struct theme *t, const struct label *label);
+
+/**
+ * Draw a button.
+ *
+ * \pre button != NULL
+ * \param t the theme to use (may be NULL)
+ * \param button the button
+ */
+void
+theme_draw_button(struct theme *t, const struct button *button);
+
+/**
+ * Draw a checkbox.
+ *
+ * \param t the theme to use (may be NULL)
+ * \param cb the checkbox
+ */
+void
+theme_draw_checkbox(struct theme *t, const struct checkbox *cb);
+
+/**
+ * Close associated resources.
+ */
+void
+theme_finish(void);
+
+#endif /* !MOLKO_THEME_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/util.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,108 @@
+/*
+ * util.c -- utilities
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <SDL.h>
+
+#include "panic.h"
+#include "util.h"
+
+void *
+emalloc(size_t size)
+{
+	void *mem;
+
+	if (!(mem = malloc(size)))
+		panicf("%s", strerror(errno));
+
+	return mem;
+}
+
+void *
+ecalloc(size_t n, size_t size)
+{
+	void *mem;
+
+	if (!(mem = calloc(n, size)))
+		panicf("%s", strerror(errno));
+
+	return mem;
+}
+
+void *
+ememdup(const void *ptr, size_t size)
+{
+	void *mem;
+
+	if (!(mem = malloc(size)))
+		panicf("%s", strerror(errno));
+
+	return memcpy(mem, ptr, size);
+}
+
+char *
+eprintf(const char *fmt, ...)
+{
+	assert(fmt);
+
+	va_list ap;
+	char *ret;
+
+	va_start(ap, fmt);
+	ret = evprintf(fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+char *
+evprintf(const char *fmt, va_list args)
+{
+	assert(fmt);
+
+	va_list ap;
+	int size;
+	char *ret;
+
+	/* Count number of bytes required. */
+	va_copy(ap, args);
+
+	if ((size = vsnprintf(NULL, 0, fmt, ap)) < 0)
+		panicf("%s", strerror(errno));
+
+	/* Do actual copy. */
+	ret = emalloc(size + 1);
+	va_copy(ap, args);
+
+	if (vsnprintf(ret, size, fmt, ap) != size) {
+		free(ret);
+		panicf("%s", strerror(errno));
+	}
+
+	return ret;
+}
+
+void
+delay(unsigned int ms)
+{
+	SDL_Delay(ms);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/util.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,105 @@
+/*
+ * util.h -- utilities
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_UTIL_H
+#define MOLKO_UTIL_H
+
+/**
+ * \file util.h
+ * \brief Utilities.
+ * \ingroup basics
+ *
+ * This file contains several utilities.
+ *
+ * \note In contrast to other files, identifiers are not prefixed with `util_`
+ *       for convenience.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#include "plat.h"
+
+/**
+ * Get the number of elements in a static array.
+ *
+ * \param x the array
+ * \return the number of elements
+ */
+#define NELEM(x) sizeof ((x)) / sizeof ((x)[0])
+
+/**
+ * Wrapper around malloc(3) that exits on allocation failure.
+ *
+ * \param size the size
+ * \return a pointer
+ * \post returned pointer will never be NULL
+ */
+void *
+emalloc(size_t size);
+
+/**
+ * Wrapper around calloc(3) that exits on allocation failure.
+ *
+ * \param n the number of objects to allocate
+ * \param size the size per n
+ * \return a pointer
+ * \post returned pointer will never be NULL
+ */
+void *
+ecalloc(size_t n, size_t size);
+
+/**
+ * Copy the region specified by ptr.
+ *
+ * \pre ptr != NULL
+ * \param ptr the pointer
+ * \param size the size of the memory to copy
+ * \return a pointer
+ * \post returned pointer will never be NULL
+ */
+void *
+ememdup(const void *ptr, size_t size);
+
+/**
+ * Create a dynamically allocated string in the printf(3) format string.
+ *
+ * \pre fmt != NULL
+ * \return The heap allocated string.
+ * \post Returned string will never be NULL.
+ */
+char *
+eprintf(const char *fmt, ...) PLAT_PRINTF(1, 2);
+
+/**
+ * Similar to \ref eprintf with arguments pointer.
+ *
+ * \copydoc eprintf
+ */
+char *
+evprintf(const char *fmt, va_list ap) PLAT_PRINTF(1, 0);
+
+/**
+ * Put the thread to sleep for a given amount of milliseconds.
+ *
+ * \param ms the number of milliseconds to wait
+ */
+void
+delay(unsigned int ms);
+
+#endif /* !MOLKO_UTIL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/wait.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,73 @@
+/*
+ * wait.c -- wait action
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "action.h"
+#include "wait.h"
+#include "util.h"
+
+static bool
+action_update(struct action *a, unsigned int ticks)
+{
+	assert(a);
+
+	return wait_update(a->data, ticks);
+}
+
+static void
+action_finish(struct action *a)
+{
+	assert(a);
+
+	free(a->data);
+}
+
+void
+wait_start(struct wait *w)
+{
+	assert(w);
+	w->elapsed = 0u;
+}
+
+bool
+wait_update(struct wait *w, unsigned int ticks)
+{
+	assert(w);
+
+	w->elapsed += ticks;
+
+	if (w->elapsed >= w->delay)
+		w->elapsed = w->delay;
+
+	return w->elapsed >= w->delay;
+}
+
+void
+wait_action(const struct wait *w, struct action *a)
+{
+	assert(w);
+	assert(a);
+
+	memset(a, 0, sizeof (struct action));
+	a->data = ememdup(w, sizeof (struct wait));
+	a->update = action_update;
+	a->finish = action_finish;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/wait.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,96 @@
+/*
+ * wait.h -- wait action
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_WAIT_H
+#define MOLKO_WAIT_H
+
+/**
+ * \file wait.h
+ * \brief Wait action.
+ * \ingroup actions
+ *
+ * This module is meant to create a delayed action.
+ *
+ * Combined with \ref script.h, you can create a sequence of actions with
+ * delays between each.
+ *
+ * \code
+ * struct script script;
+ * struct action action;
+ *
+ * // Prepare the script.
+ * script_init(&script);
+ *
+ * // Add some actions to script using script_append.
+ * // ...
+ *
+ * // Wait one second delay before next action.
+ * wait_action(&(struct wait) { .delay = 1000 }, &action);
+ * script_append(&script, &action);
+ *
+ * // Add more actions after this delay.
+ * // ...
+ * \endcode
+ */
+
+#include <stdbool.h>
+
+struct action;
+
+/**
+ * \brief Wait action.
+ */
+struct wait {
+	unsigned int delay;             /*!< (RW) Time to wait in milliseconds */
+	unsigned int elapsed;           /*!< (RO) Elapsed time */
+};
+
+/**
+ * Start the wait action.
+ *
+ * This function is equivalent to `w->elapsed = 0`;
+ *
+ * \pre w != NULL
+ * \param w the wait object
+ */
+void
+wait_start(struct wait *w);
+
+/**
+ * Update the wait object.
+ *
+ * \pre w != NULL
+ * \param w the wait object
+ * \param ticks the number of milliseconds since last frame
+ * \return true if complete
+ */
+bool
+wait_update(struct wait *w, unsigned int ticks);
+
+/**
+ * Create an action from the wait object.
+ *
+ * \pre w != NULL
+ * \pre a != NULL
+ * \param w the wait object to copy from
+ * \param a the action to fill
+ */
+void
+wait_action(const struct wait *w, struct action *a);
+
+#endif /* !MOLKO_WAIT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/walksprite.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,60 @@
+/*
+ * walksprite.c -- sprite designed for walking entities
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "walksprite.h"
+#include "sprite.h"
+
+void
+walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay)
+{
+	assert(ws);
+	assert(sprite);
+
+	memset(ws, 0, sizeof (struct walksprite));
+	ws->sprite = sprite;
+	ws->delay = delay;
+}
+
+void
+walksprite_update(struct walksprite *ws, unsigned int ticks)
+{
+	assert(ws);
+
+	ws->elapsed += ticks;
+
+	if (ws->elapsed >= ws->delay) {
+		ws->index += 1;
+
+		if (ws->index >= ws->sprite->ncols)
+			ws->index = 0;
+
+		ws->elapsed = 0;
+	}
+}
+
+void
+walksprite_draw(struct walksprite *ws, unsigned int orientation, int x, int y)
+{
+	assert(ws);
+	assert(orientation < 8);
+
+	sprite_draw(ws->sprite, orientation, ws->index, x, y);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/walksprite.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,103 @@
+/*
+ * walksprite.h -- sprite designed for walking entities
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_WALKSPRITE_H
+#define MOLKO_WALKSPRITE_H
+
+/**
+ * \file walksprite.h
+ * \brief Sprite designed for walking entities.
+ * \ingroup drawing
+ */
+
+struct sprite;
+
+/**
+ * \brief Sprite designed for walking entities.
+ *
+ * This structure works with sprite images that are defined as using the
+ * following conventions:
+ *
+ * ```
+ * 7   0   1
+ *   ↖ ↑ ↗
+ * 6 ←   → 2
+ *   ↙ ↓ ↘
+ * 5   4   3
+ * ```
+ *
+ * Where numbers define row in the sprite according to the character
+ * orientation. In other terms, your image sprite should look like this:
+ *
+ * ```
+ * row columns in your image
+ * ---|---------------------
+ *  0 | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
+ *  1 | ↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗
+ *  2 | →→→→→→→→→→→→→→→→→→→→
+ *  3 | ↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘
+ *  4 | ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
+ *  5 | ↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙
+ *  6 | ←←←←←←←←←←←←←←←←←←←←
+ *  7 | ↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖
+ * ```
+ */
+struct walksprite {
+	struct sprite *sprite;  /*!< (RW) The sprite to use */
+	unsigned int delay;     /*!< (RW) The delay between frames */
+	unsigned int index;     /*!< (RO) Current column index */
+	unsigned int elapsed;   /*!< (RO) Elapsed time since last frame */
+};
+
+/**
+ * Initialize the walking sprite.
+ *
+ * \pre ws != NULL
+ * \pre sprite != NULL
+ * \param ws the walking sprite
+ * \param sprite the sprite to use
+ * \param delay the delay between sprites
+ */
+void
+walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay);
+
+/**
+ * Update the walking sprite
+ *
+ * \pre ws != NULL
+ * \param ws the walking sprite
+ * \param ticks the number of milliseconds between last frame
+ */
+void
+walksprite_update(struct walksprite *ws, unsigned int ticks);
+
+/**
+ * Draw the appropriate sprite cell to the screen according to the orientation
+ * given.
+ *
+ * \pre ws != NULL
+ * \pre orientation < 8
+ * \param ws the walking sprite
+ * \param orientation the orientation (or the row between 0 and 7)
+ * \param x the x coordinate
+ * \param y the y coordinate
+ */
+void
+walksprite_draw(struct walksprite *ws, unsigned int orientation, int x, int y);
+
+#endif /* !MOLKO_WALKSPRITE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/window.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,60 @@
+/*
+ * window.c -- basic window management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include <SDL.h>
+
+#include "error_p.h"
+#include "window.h"
+#include "window_p.h"
+
+static struct window_handle handle = {
+	.win = NULL,
+	.renderer = NULL
+};
+
+struct window window = {
+	.handle = &handle
+};
+
+bool
+window_init(const char *title, unsigned int w, unsigned int h)
+{
+	assert(title);
+
+	if (SDL_CreateWindowAndRenderer(w, h, SDL_WINDOW_OPENGL,
+	    &handle.win, &handle.renderer) < 0)
+		return error_sdl();
+
+	SDL_SetWindowTitle(handle.win, title);
+
+	window.w = w;
+	window.h = h;
+
+	return true;
+}
+
+void
+window_finish(void)
+{
+	if (handle.renderer)
+		SDL_DestroyRenderer(handle.renderer);
+	if (handle.win)
+		SDL_DestroyWindow(handle.win);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/window.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,62 @@
+/*
+ * window.h -- basic window management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_WINDOW_H
+#define MOLKO_WINDOW_H
+
+/**
+ * \file window.h
+ * \brief Basic window management.
+ * \ingroup drawing
+ */
+
+#include <stdbool.h>
+
+/**
+ * \brief Global exposed window structure.
+ */
+struct window {
+	unsigned int w;         /*!< (RO) Window width. */
+	unsigned int h;         /*!< (RO) Window height. */
+	void *handle;           /*!< (RO) Native handle. */
+};
+
+/**
+ * \brief Access to global window structure.
+ */
+extern struct window window;
+
+/**
+ * Initialize window.
+ *
+ * \pre title != NULL
+ * \param title the window title
+ * \param width the desired width
+ * \param height the desired height
+ * \return true on success
+ */
+bool
+window_init(const char *title, unsigned int width, unsigned int height);
+
+/**
+ * Close the window and destroy associated resources.
+ */
+void
+window_finish(void);
+
+#endif /* !MOLKO_WINDOW_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/window_p.h	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,33 @@
+/*
+ * window.c -- (PRIVATE) basic window management
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_WINDOW_P_H
+#define MOLKO_WINDOW_P_H
+
+#include <SDL.h>
+
+struct window_handle {
+	SDL_Window *win;
+	SDL_Renderer *renderer;
+};
+
+/* Convenient macros to access the native handle from global window object. */
+#define WINDOW()        (((struct window_handle *)window.handle)->win)
+#define RENDERER()      (((struct window_handle *)window.handle)->renderer)
+
+#endif /* !MOLKO_WINDOW_P_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/molko/CMakeLists.txt	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,21 @@
+#
+# CMakeLists.txt -- CMake build system for molko
+#
+# Copyright (c) 2020 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(molko)
+add_executable(molko main.c)
+target_link_libraries(molko libadventure)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/molko/main.c	Mon Oct 05 13:25:06 2020 +0200
@@ -0,0 +1,126 @@
+/*
+ * main.c -- Molko's Adventure
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <setjmp.h>
+#include <stdnoreturn.h>
+
+#include <core/clock.h>
+#include <core/event.h>
+#include <core/game.h>
+#include <core/panic.h>
+#include <core/sys.h>
+#include <core/theme.h>
+#include <core/util.h>
+#include <core/window.h>
+
+#include <adventure/panic_state.h>
+#include <adventure/splashscreen_state.h>
+
+#define WINDOW_WIDTH 1280
+#define WINDOW_HEIGHT 720
+
+static jmp_buf panic_buf;
+
+static noreturn void
+unrecoverable(void)
+{
+	longjmp(panic_buf, 1);
+}
+
+static void
+init(void)
+{
+	if (!sys_init())
+		panic();
+	if (!window_init("Molko's Adventure", WINDOW_WIDTH, WINDOW_HEIGHT))
+		panic();
+
+	/*
+	 * From here, we can setup our panic state which requires a window
+	 * to be running.
+	 */
+
+	/* Init unrecoverable panic state. */
+	panic_state_init();
+	panic_handler = unrecoverable;
+
+	if (!theme_init())
+		panic();
+
+	/* Default state is splash screen */
+	game_switch(&splashscreen_state, true);
+}
+
+static void
+run(void)
+{
+	struct clock clock = { 0 };
+
+	while (game.state) {
+		unsigned int elapsed = clock_elapsed(&clock);
+
+		clock_start(&clock);
+
+		for (union event ev; event_poll(&ev); ) {
+			switch (ev.type) {
+			case EVENT_QUIT:
+				return;
+			default:
+				game_handle(&ev);
+				break;
+			}
+		}
+
+		game_update(elapsed);
+		game_draw();
+
+		if ((elapsed = clock_elapsed(&clock)) < 20)
+			delay(20 - elapsed);
+	}
+}
+
+static void
+close(void)
+{
+	window_finish();
+	sys_finish();
+}
+
+int
+main(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+
+	if (setjmp(panic_buf) == 0) {
+		/* Initial game run. */
+		init();
+		run();
+	} else {
+		/* Clear event queue to avoid accidental key presses. */
+		for (union event ev; event_poll(&ev); )
+			continue;
+
+		game_switch(&panic_state, true);
+		run();
+	}
+
+	close();
+
+	return 0;
+}
--- a/src/adventure/CMakeLists.txt	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for libadventure
-#
-# Copyright (c) 2020 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(libadventure)
-
-set(
-	SOURCES
-	${libadventure_SOURCE_DIR}/mainmenu_state.c
-	${libadventure_SOURCE_DIR}/mainmenu_state.h
-	${libadventure_SOURCE_DIR}/panic_state.c
-	${libadventure_SOURCE_DIR}/panic_state.h
-	${libadventure_SOURCE_DIR}/splashscreen_state.c
-	${libadventure_SOURCE_DIR}/splashscreen_state.h
-)
-
-molko_define_library(
-	TARGET libadventure
-	SOURCES ${SOURCES}
-	LIBRARIES libcore
-	PUBLIC_INCLUDES
-		$<BUILD_INTERFACE:${libadventure_SOURCE_DIR}>
-)
--- a/src/adventure/mainmenu_state.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,212 +0,0 @@
-/*
- * mainmenu_state.c -- game main menu
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <event.h>
-#include <font.h>
-#include <game.h>
-#include <image.h>
-#include <map_state.h>
-#include <painter.h>
-#include <panic.h>
-#include <state.h>
-#include <sys.h>
-#include <texture.h>
-#include <window.h>
-
-#include "mainmenu_state.h"
-#include "splashscreen_state.h"
-
-#define SPEED 120
-#define SEC   1000
-
-enum substate {
-	SUBSTATE_MOVING,
-	SUBSTATE_WAITING
-};
-
-static int x;
-static int y;
-static unsigned int selection;
-static int destination;
-static enum substate substate;
-static struct texture image;
-
-/* Menu items. */
-static struct {
-	struct texture texture;
-	int x;
-	int y;
-} items[3];
-
-static void
-enter(void)
-{
-	struct font font = { 0 };
-
-	if (!font_open(&font, sys_datapath("fonts/pirata-one.ttf"), 30))
-		panic();
-
-	substate = SUBSTATE_MOVING;
-	x = splashscreen_state_data.x;
-	y = splashscreen_state_data.y;
-	destination = window.h / 4;
-
-	/* TODO: change continue color if no game exists. */
-	font_render(&font, &items[0].texture, "New game");
-	items[0].x = (window.w / 2) - (items[0].texture.w / 2);
-	items[0].y = window.h * 0.75;
-
-	font_render(&font, &items[1].texture, "Continue");
-	items[1].x = items[0].x;
-	items[1].y = items[0].y + items[0].texture.h;
-
-	font_render(&font, &items[2].texture, "Quit");
-	items[2].x = items[0].x;
-	items[2].y = items[1].y + items[1].texture.h;
-
-	font_finish(&font);
-}
-
-static void
-new(void)
-{
-	/* TODO: convenient map_state_start function? */
-
-	/* Prepare map. */
-	if (!map_data_open(&map_state_data.map.data, sys_datapath("maps/test.map")))
-		panic();
-	if (!map_init(&map_state_data.map.map, &map_state_data.map.data))
-		panic();
-
-	/* Prepare image and sprite. */
-	if (!(image_open(&image, sys_datapath("sprites/test-walk.png"))))
-		panic();
-
-	sprite_init(&map_state_data.player.sprite, &image, 48, 48);
-	game_switch(&map_state, false);
-}
-
-static void
-resume(void)
-{
-}
-
-static void
-quit(void)
-{
-	game_quit();
-}
-
-static void
-perform(void)
-{
-	assert(selection < 3);
-
-	static void (*handlers[])(void) = {
-		[0] = new,
-		[1] = resume,
-		[2] = quit
-	};
-
-	handlers[selection]();
-}
-
-static void
-handle(const union event *event)
-{
-	if (substate != SUBSTATE_WAITING)
-		return;
-
-	switch (event->type) {
-	case EVENT_KEYDOWN:
-		switch (event->key.key) {
-		case KEY_UP:
-			selection = selection == 0 ? 2 : selection - 1;
-			break;
-		case KEY_DOWN:
-			selection = (selection + 1) % 3;
-			break;
-		case KEY_ENTER:
-			perform();
-		default:
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-update(unsigned int ticks)
-{
-	switch (substate) {
-	case SUBSTATE_MOVING:
-		y -= SPEED * ticks / SEC;
-
-		if (y <= destination) {
-			y = destination;
-			substate = SUBSTATE_WAITING;
-		}
-
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-draw(void)
-{
-	painter_set_color(0xffffffff);
-	painter_clear();
-	texture_draw(&splashscreen_state_data.text, x, y);
-
-	if (substate == SUBSTATE_WAITING) {
-		texture_draw(&items[0].texture, items[0].x, items[0].y);
-		texture_draw(&items[1].texture, items[1].x, items[1].y);
-		texture_draw(&items[2].texture, items[2].x, items[2].y);
-
-		/* Selection cursor. */
-
-		/* TODO: a sword here. */
-		painter_set_color(0x000000ff);
-		painter_draw_rectangle(items[selection].x - 30,
-		    items[selection].y + 11, 15, 15);
-	}
-}
-
-static void
-leave(void)
-{
-	texture_finish(&items[0].texture);
-	texture_finish(&items[1].texture);
-	memset(items, 0, sizeof (items));
-}
-
-struct state mainmenu_state = {
-	.enter = enter,
-	.handle = handle,
-	.update = update,
-	.draw = draw,
-	.leave = leave
-};
--- a/src/adventure/mainmenu_state.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * mainmenu_state.h -- game main menu
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_MAINMENU_STATE_H
-#define MOLKO_MAINMENU_STATE_H
-
-/**
- * \file mainmenu_state.h
- * \brief Game main menu.
- */
-
-/**
- * \brief Main menu state.
- */
-extern struct state mainmenu_state;
-
-#endif /* !MOLKO_MAINMENU_STATE_H */
--- a/src/adventure/panic_state.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-/*
- * panic_state.c -- panic state
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <error.h>
-#include <event.h>
-#include <font.h>
-#include <game.h>
-#include <painter.h>
-#include <sys.h>
-#include <texture.h>
-#include <util.h>
-#include <window.h>
-#include <map_state.h>
-
-#include <assets/fonts/Lato-Regular.h>
-
-#include "panic_state.h"
-
-#define BACKGROUND 0x4f5070ff
-#define FOREGROUND 0xffffffff
-
-#define SIZE 16
-#define PADDING 20
-
-#define OUT "molko-adventure.txt"
-
-struct label {
-	const char *text;
-	struct texture texture;
-};
-
-static struct {
-	struct font font;
-} data;
-
-static struct label headers[] = {
-	{ "An unrecoverable error occured and the game cannot continue.", 0 },
-	{ "Please report the detailed error as provided below.", 0 },
-};
-
-static struct label bottom[] = {
-	{ "Press <s> to save information and generate a core dump.", 0 },
-	{ "Press <q> to quit without saving information.", 0 }
-};
-
-static struct label lerror;
-
-static void
-die(const char *fmt, ...)
-{
-	assert(fmt);
-
-	va_list ap;
-
-	va_start(ap, fmt);
-	fprintf(stderr, "abort: ");
-	vfprintf(stderr, fmt, ap);
-	va_end(ap);
-	exit(1);
-}
-
-static void
-enter(void)
-{
-}
-
-static void
-dump(void)
-{
-	FILE *fp;
-
-	if (!(fp = fopen(OUT, "w")))
-		goto dump;
-
-	/* Print various information. */
-	fprintf(fp, "Molko's Adventure crash dump report\n");
-	fprintf(fp, "== state map dump ==\n");
-	fprintf(fp, "map:\n");
-	fprintf(fp, "  w     %u\n", map_state_data.map.data.w);
-	fprintf(fp, "  h     %u\n", map_state_data.map.data.h);
-	fprintf(fp, "player:\n");
-	fprintf(fp, "  x:    %u\n", map_state_data.player.x);
-	fprintf(fp, "  y:    %u\n", map_state_data.player.y);
-	fprintf(fp, "view:\n");
-	fprintf(fp, "  w:    %u\n", map_state_data.view.w);
-	fprintf(fp, "  h:    %u\n", map_state_data.view.h);
-	fprintf(fp, "  x:    %u\n", map_state_data.view.x);
-	fprintf(fp, "  y:    %u\n", map_state_data.view.y);
-
-dump:
-	if (fp)
-		fclose(fp);
-
-	abort();
-}
-
-static void
-handle_keydown(const struct event_key *ev)
-{
-	assert(ev);
-
-	switch (ev->key) {
-	case KEY_q:
-		game_quit();
-		break;
-	case KEY_s:
-		dump();
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-handle(const union event *ev)
-{
-	assert(ev);
-
-	switch (ev->type) {
-	case EVENT_KEYDOWN:
-		handle_keydown(&ev->key);
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-generate(struct label labels[], size_t labelsz)
-{
-	assert(labels);
-
-	for (size_t i = 0; i < labelsz; ++i) {
-		if (texture_ok(&labels[i].texture))
-			continue;
-
-		data.font.color = FOREGROUND;
-		font_render(&data.font, &labels[i].texture, labels[i].text);
-
-		if (!texture_ok(&labels[i].texture))
-			die("%s\n", error());
-	}
-}
-
-static void
-update(unsigned int ticks)
-{
-	(void)ticks;
-
-	lerror.text = error();
-
-	generate(headers, NELEM(headers));
-	generate(&lerror, 1);
-	generate(bottom, NELEM(bottom));
-}
-
-static void
-draw(void)
-{
-	int y = PADDING;
-
-	painter_set_target(NULL);
-	painter_set_color(BACKGROUND);
-	painter_clear();
-
-	/* Header. */
-	for (size_t i = 0; i < NELEM(headers); ++i) {
-		texture_draw(&headers[i].texture, PADDING, y);
-		y += headers[i].texture.h + 2;
-	}
-
-	/* Error message. */
-	texture_draw(&lerror.texture, PADDING, y + PADDING);
-
-	/* Bottom. */
-	y = window.h - PADDING;
-	y -= bottom[0].texture.h;
-
-	for (size_t i = 0; i < NELEM(bottom); ++i) {
-		texture_draw(&bottom[i].texture, PADDING, y);
-		y -= bottom[i].texture.h + 2;
-	}
-}
-
-static void
-leave(void)
-{
-}
-
-struct state panic_state = {
-	.enter = enter,
-	.handle = handle,
-	.update = update,
-	.draw = draw,
-	.leave = leave
-};
-
-void
-panic_state_init(void)
-{
-	/*
-	 * If the panic state can not be loaded we're unable to show any
-	 * useful information to the screen so as last resort print them
-	 * on the console.
-	 */
-	if (!(font_openmem(&data.font, Lato_Regular, sizeof (Lato_Regular), SIZE)))
-		die("%s", error());
-}
--- a/src/adventure/panic_state.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * panic_state.h -- panic state
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_PANIC_STATE_H
-#define MOLKO_PANIC_STATE_H
-
-/**
- * \file panic_state.h
- * \brief Panic state.
- */
-
-#include "state.h"
-
-/**
- * \brief Global panic state structure.
- */
-extern struct state panic_state;
-
-/**
- * Call this function as early as possible to be able to use this state even on
- * memory allocation errors.
- *
- * \note You must still initialize the system before.
- * \see \ref sys_init
- * \see \ref window_init
- */
-void
-panic_state_init(void);
-
-#endif /* !MOLKO_PANIC_STATE_H */
--- a/src/adventure/splashscreen_state.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * splashscreen_state.c -- splash screen state
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <font.h>
-#include <game.h>
-#include <image.h>
-#include <map.h>
-#include <map_state.h>
-#include <painter.h>
-#include <panic.h>
-#include <state.h>
-#include <sys.h>
-#include <texture.h>
-#include <window.h>
-
-#include "splashscreen_state.h"
-#include "mainmenu_state.h"
-
-#define DELAY 2000
-
-struct splashscreen_state_data splashscreen_state_data;
-
-static void
-enter(void)
-{
-	struct font font = {
-		.color = 0x000000ff
-	};
-
-	if (!(font_open(&font, sys_datapath("fonts/teutonic1.ttf"), 130)))
-		panic();
-	if (!(font_render(&font, &splashscreen_state_data.text, "Molko's Adventure")))
-		panic();
-
-	/* Compute position. */
-	const unsigned int w = splashscreen_state_data.text.w;
-	const unsigned int h = splashscreen_state_data.text.h;
-
-	splashscreen_state_data.x = (window.w / 2) - (w / 2);
-	splashscreen_state_data.y = (window.h / 2) - (h / 2);
-
-	font_finish(&font);
-}
-
-static void
-leave(void)
-{
-	/* We don't delete the texture because it is used by mainmenu_state. */
-}
-
-static void
-handle(const union event *event)
-{
-	(void)event;
-}
-
-static void
-update(unsigned int ticks)
-{
-	splashscreen_state_data.elapsed += ticks;
-
-	if (splashscreen_state_data.elapsed >= DELAY)
-		game_switch(&mainmenu_state, false);
-}
-
-static void
-draw(void)
-{
-	painter_set_color(0xffffffff);
-	painter_clear();
-	texture_draw(&splashscreen_state_data.text,
-		splashscreen_state_data.x,
-		splashscreen_state_data.y);
-}
-
-struct state splashscreen_state = {
-	.enter = enter,
-	.leave = leave,
-	.handle = handle,
-	.update = update,
-	.draw = draw
-};
--- a/src/adventure/splashscreen_state.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * splashscreen_state.h -- splash screen state
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_SPLASHSCREEN_ADVENTURE_H
-#define MOLKO_SPLASHSCREEN_ADVENTURE_H
-
-/**
- * \file splashscreen_state.h
- * \brief Splash screen state.
- */
-
-#include "texture.h"
-
-/**
- * \brief Data for splashscreen.
- */
-extern struct splashscreen_state_data {
-	struct texture text;            /*!< (RW) Texture for the text. */
-	int x;                          /*!< (RW) Position in x. */
-	int y;                          /*!< (RW) Position in y. */
-	unsigned int elapsed;           /*!< (RW) Time elapsed. */
-} splashscreen_state_data;              /*!< (RW) Global state data. */
-
-/**
- * \brief Splash screen state.
- */
-extern struct state splashscreen_state;
-
-#endif /* !MOLKO_SPLASHSCREEN_ADVENTURE_H */
--- a/src/core/CMakeLists.txt	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for libcore
-#
-# Copyright (c) 2020 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(libcore)
-
-set(
-	ASSETS
-	${libcore_SOURCE_DIR}/assets/maps/test.map
-	${libcore_SOURCE_DIR}/assets/images/message.png
-	${libcore_SOURCE_DIR}/assets/sprites/test-walk.png
-	${libcore_SOURCE_DIR}/assets/fonts/DejaVuSansCondensed.ttf
-	${libcore_SOURCE_DIR}/assets/fonts/DejaVuSans.ttf
-	${libcore_SOURCE_DIR}/assets/fonts/Lato-Regular.ttf
-	${libcore_SOURCE_DIR}/assets/fonts/ComicNeue-Regular.ttf
-	${libcore_SOURCE_DIR}/assets/fonts/pirata-one.ttf
-	${libcore_SOURCE_DIR}/assets/fonts/teutonic1.ttf
-	${libcore_SOURCE_DIR}/assets/fonts/knights-quest.ttf
-	${libcore_SOURCE_DIR}/assets/tilesets/test.png
-)
-
-set(
-	SOURCES
-	${libcore_SOURCE_DIR}/action.h
-	${libcore_SOURCE_DIR}/animation.c
-	${libcore_SOURCE_DIR}/animation.h
-	${libcore_SOURCE_DIR}/button.c
-	${libcore_SOURCE_DIR}/button.h
-	${libcore_SOURCE_DIR}/checkbox.c
-	${libcore_SOURCE_DIR}/checkbox.h
-	${libcore_SOURCE_DIR}/clock.c
-	${libcore_SOURCE_DIR}/clock.h
-	${libcore_SOURCE_DIR}/color.h
-	${libcore_SOURCE_DIR}/debug.c
-	${libcore_SOURCE_DIR}/debug.h
-	${libcore_SOURCE_DIR}/error.c
-	${libcore_SOURCE_DIR}/error.h
-	${libcore_SOURCE_DIR}/error_p.h
-	${libcore_SOURCE_DIR}/event.c
-	${libcore_SOURCE_DIR}/event.h
-	${libcore_SOURCE_DIR}/font.c
-	${libcore_SOURCE_DIR}/font.h
-	${libcore_SOURCE_DIR}/frame.c
-	${libcore_SOURCE_DIR}/frame.h
-	${libcore_SOURCE_DIR}/game.c
-	${libcore_SOURCE_DIR}/game.h
-	${libcore_SOURCE_DIR}/image.c
-	${libcore_SOURCE_DIR}/image.h
-	${libcore_SOURCE_DIR}/inhibit.c
-	${libcore_SOURCE_DIR}/inhibit.h
-	${libcore_SOURCE_DIR}/inventory.c
-	${libcore_SOURCE_DIR}/inventory.h
-	${libcore_SOURCE_DIR}/inventory_dialog.c
-	${libcore_SOURCE_DIR}/inventory_dialog.h
-	${libcore_SOURCE_DIR}/item.h
-	${libcore_SOURCE_DIR}/key.h
-	${libcore_SOURCE_DIR}/label.c
-	${libcore_SOURCE_DIR}/label.h
-	${libcore_SOURCE_DIR}/map.c
-	${libcore_SOURCE_DIR}/map.h
-	${libcore_SOURCE_DIR}/map_state.c
-	${libcore_SOURCE_DIR}/map_state.h
-	${libcore_SOURCE_DIR}/maths.c
-	${libcore_SOURCE_DIR}/maths.h
-	${libcore_SOURCE_DIR}/message.c
-	${libcore_SOURCE_DIR}/message.h
-	${libcore_SOURCE_DIR}/mouse.h
-	${libcore_SOURCE_DIR}/painter.c
-	${libcore_SOURCE_DIR}/painter.h
-	${libcore_SOURCE_DIR}/panic.c
-	${libcore_SOURCE_DIR}/panic.h
-	${libcore_SOURCE_DIR}/plat.h
-	${libcore_SOURCE_DIR}/rbuf.c
-	${libcore_SOURCE_DIR}/rbuf.h
-	${libcore_SOURCE_DIR}/save.c
-	${libcore_SOURCE_DIR}/save.h
-	${libcore_SOURCE_DIR}/script.c
-	${libcore_SOURCE_DIR}/script.h
-	${libcore_SOURCE_DIR}/sound.c
-	${libcore_SOURCE_DIR}/sound.h
-	${libcore_SOURCE_DIR}/sprite.c
-	${libcore_SOURCE_DIR}/sprite.h
-	${libcore_SOURCE_DIR}/state.h
-	${libcore_SOURCE_DIR}/sys.c
-	${libcore_SOURCE_DIR}/sys.h
-	${libcore_SOURCE_DIR}/texture.c
-	${libcore_SOURCE_DIR}/texture.h
-	${libcore_SOURCE_DIR}/texture_p.h
-	${libcore_SOURCE_DIR}/theme.c
-	${libcore_SOURCE_DIR}/theme.h
-	${libcore_SOURCE_DIR}/util.c
-	${libcore_SOURCE_DIR}/util.h
-	${libcore_SOURCE_DIR}/wait.c
-	${libcore_SOURCE_DIR}/wait.h
-	${libcore_SOURCE_DIR}/walksprite.c
-	${libcore_SOURCE_DIR}/walksprite.h
-	${libcore_SOURCE_DIR}/window.c
-	${libcore_SOURCE_DIR}/window.h
-	${libcore_SOURCE_DIR}/window_p.h
-)
-
-molko_define_library(
-	TARGET libcore
-	SOURCES ${SOURCES}
-	ASSETS ${ASSETS}
-	LIBRARIES
-		libsqlite
-		SDL2::SDL2
-		SDL2::image
-		SDL2::mixer
-		SDL2::ttf
-	PRIVATE_FLAGS
-		BINDIR="${CMAKE_INSTALL_BINDIR}"
-		PREFIX="${CMAKE_INSTALL_PREFIX}"
-		SHAREDIR="${CMAKE_INSTALL_DATADIR}"
-	PUBLIC_FLAGS
-		_XOPEN_SOURCE=700
-	PUBLIC_INCLUDES
-		$<BUILD_INTERFACE:${libcore_SOURCE_DIR}>
-)
--- a/src/core/action.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * action.h -- action states
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef ACTION_H
-#define ACTION_H
-
-/**
- * \file action.h
- * \brief Action states.
- * \ingroup actions
- */
-
-#include <stdbool.h>
-
-union event;
-
-/**
- * \brief Action flags.
- */
-enum action_flags {
-	ACTION_NONE,                            /*!< No flags */
-	ACTION_AUTO_LEAVE       = (1 << 0)      /*!< Action is removed on state change */
-};
-
-/**
- * \brief Action structure.
- */
-struct action {
-	/**
-	 * (RW)
-	 *
-	 * Optional flags.
-	 */
-	enum action_flags flags;
-
-	/**
-	 * (RW)
-	 *
-	 * Arbitrary user data.
-	 */
-	void *data;
-
-	/**
-	 * (RW)
-	 *
-	 * Handle event.
-	 */
-	void (*handle)(struct action *, const union event *event);
-
-	/**
-	 * (RW)
-	 *
-	 * Update the action.
-	 *
-	 * If returns true, the action is removed.
-	 */
-	bool (*update)(struct action *, unsigned int);
-
-	/**
-	 * (RW)
-	 *
-	 * Draw the aciton.
-	 */
-	void (*draw)(struct action *);
-
-	/**
-	 * (RW)
-	 *
-	 * Called when the action was completed.
-	 *
-	 * This callback is mostly provided to allow the user doing something
-	 * else once an action is complete. Predefined actions should not use
-	 * this callback by themselves.
-	 */
-	void (*end)(struct action *a);
-
-	/**
-	 * (RW)
-	 *
-	 * Close the action before removal.
-	 */
-	void (*finish)(struct action *);
-};
-
-#endif /* !ACTION_H */
--- a/src/core/animation.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * animation.c -- basic animations
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include "animation.h"
-#include "sprite.h"
-
-void
-animation_init(struct animation *an, struct sprite *sprite, unsigned int delay)
-{
-	assert(an);
-	assert(sprite);
-
-	an->sprite = sprite;
-	an->row = 0;
-	an->column = 0;
-	an->delay = delay;
-	an->elapsed = 0;
-}
-
-bool
-animation_is_complete(const struct animation *an)
-{
-	assert(an);
-
-	return an->row == an->sprite->nrows &&
-	       an->column == an->sprite->ncols &&
-	       an->elapsed >= an->delay;
-}
-
-void
-animation_start(struct animation *an)
-{
-	assert(an);
-
-	an->row = 0;
-	an->column = 0;
-	an->elapsed = 0;
-}
-
-void
-animation_update(struct animation *an, unsigned int ticks)
-{
-	assert(an);
-
-	an->elapsed += ticks;
-
-	if (an->elapsed < an->delay)
-		return;
-
-	/* Increment column first */
-	if (++an->column >= an->sprite->ncols) {
-		/*
-		 * Increment row, if we reach the last row it means we are
-		 * at the last frame.
-		 */
-		if (++an->row >= an->sprite->nrows)
-			an->row = an->sprite->nrows;
-		else
-			an->column = 0;
-	}
-}
-
-void
-animation_draw(struct animation *an, int x, int y)
-{
-	sprite_draw(an->sprite, an->row, an->column, x, y);
-}
--- a/src/core/animation.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * animation.h -- basic animations
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_ANIMATION_H
-#define MOLKO_ANIMATION_H
-
-/**
- * \file animation.h
- * \brief Basic animations.
- * \ingroup drawing
- */
-
-#include <stdbool.h>
-
-struct sprite;
-
-/**
- * \brief Animation object
- */
-struct animation {
-	struct sprite *sprite;  /*!< Sprite to use (RW) */
-	unsigned int row;       /*!< current row (RO) */
-	unsigned int column;    /*!< current column (RO) */
-	unsigned int delay;     /*!< delay between frames (RW) */
-	unsigned int elapsed;   /*!< elapsed time since last frame (RO) */
-};
-
-/**
- * Initialize the animation.
- *
- * The animation does not take sprite ownership, it must be valid until
- * animation is no longer used.
- *
- * \pre an != NULL
- * \pre sprite != NULL
- * \param an the animation
- * \param sprite the sprite to use
- * \param delay the delay between frames in milliseconds
- */
-void
-animation_init(struct animation *an, struct sprite *sprite, unsigned int delay);
-
-/**
- * Start an animation.
- *
- * \pre an != NULL
- * \param an the animation
- */
-void
-animation_start(struct animation *an);
-
-/**
- * Update the animation.
- *
- * You must call this function at each loop iteration to update the animation
- * frame depending on its delay.
- *
- * \pre an != NULL
- * \param an the animation
- * \param ticks the elapsed ticks since the last call
- */
-void
-animation_update(struct animation *an, unsigned int ticks);
-
-/**
- * Draw the animation.
- *
- * \pre an != NULL
- * \param an the animation
- * \param x the X coordinate
- * \param y the Y coordinate
- */
-void
-animation_draw(struct animation *an, int x, int y);
-
-#endif /* !MOLKO_ANIMATION_H */
Binary file src/core/assets/fonts/ComicNeue-Regular.ttf has changed
Binary file src/core/assets/fonts/DejaVuSans.ttf has changed
Binary file src/core/assets/fonts/DejaVuSansCondensed.ttf has changed
Binary file src/core/assets/fonts/Lato-Regular.ttf has changed
Binary file src/core/assets/fonts/knights-quest.ttf has changed
Binary file src/core/assets/fonts/pirata-one.ttf has changed
Binary file src/core/assets/fonts/teutonic1.ttf has changed
Binary file src/core/assets/images/message.png has changed
Binary file src/core/assets/images/message.xcf has changed
--- a/src/core/assets/maps/test.map	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20009 +0,0 @@
-title|World
-origin|700|400
-width|100
-height|100
-tilewidth|32
-tileheight|32
-layer|background
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-111
-112
-112
-112
-112
-112
-112
-112
-112
-113
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-141
-142
-142
-142
-142
-142
-142
-142
-142
-143
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-141
-142
-142
-142
-142
-142
-142
-142
-142
-143
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-141
-142
-142
-142
-142
-142
-142
-142
-142
-143
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-141
-142
-142
-142
-142
-142
-142
-142
-142
-143
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-141
-142
-142
-142
-142
-142
-142
-142
-142
-143
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-141
-142
-142
-142
-142
-142
-142
-142
-142
-143
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-171
-172
-172
-172
-172
-172
-172
-172
-172
-173
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-21
-layer|foreground
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-407
-408
-409
-410
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-437
-438
-439
-440
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-467
-468
-469
-470
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-497
-498
-499
-500
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-527
-528
-529
-530
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-557
-558
-559
-560
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-587
-588
-589
-590
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-893
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-893
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-893
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-893
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-893
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-tileset|test.png
Binary file src/core/assets/sprites/test-walk.png has changed
Binary file src/core/assets/sprites/test-walk.xcf has changed
Binary file src/core/assets/tilesets/test.png has changed
--- a/src/core/button.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * button.c -- GUI button
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include "button.h"
-#include "event.h"
-#include "maths.h"
-#include "theme.h"
-
-static bool
-is_boxed(const struct button *button, const struct event_click *click)
-{
-	assert(button);
-	assert(click);
-	assert(click->type == EVENT_CLICKDOWN || click->type == EVENT_CLICKUP);
-
-	return maths_is_boxed(button->x, button->y, button->w, button->h,
-	    click->x, click->y);
-}
-
-void
-button_handle(struct button *button, const union event *ev)
-{
-	assert(button);
-	assert(ev);
-
-	switch (ev->type) {
-	case EVENT_CLICKDOWN:
-		if (is_boxed(button, &ev->click))
-			button->state = BUTTON_STATE_PRESSED;
-		break;
-	case EVENT_CLICKUP:
-		/*
-		 * If the button was pressed, indicate that the button is
-		 * finally activated. This let the user to move the cursor
-		 * outside the button to "forget" the press.
-		 */
-		if (!is_boxed(button, &ev->click))
-			button->state = BUTTON_STATE_NONE;
-		else if (button->state == BUTTON_STATE_PRESSED)
-			button->state = BUTTON_STATE_ACTIVATED;
-		break;
-	default:
-		break;
-	}
-}
-
-void
-button_reset(struct button *button)
-{
-	assert(button);
-
-	button->state = BUTTON_STATE_NONE;
-}
-
-void
-button_draw(struct button *button)
-{
-	assert(button);
-
-	theme_draw_button(button->theme, button);
-}
--- a/src/core/button.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * button.h -- GUI button
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_BUTTON_H
-#define MOLKO_BUTTON_H
-
-/**
- * \file button.h
- * \brief GUI button.
- */
-
-union event;
-
-struct theme;
-
-/**
- * \brief Button state.
- */
-enum button_state {
-	BUTTON_STATE_NONE,              /*!< Button is inactive. */
-	BUTTON_STATE_PRESSED,           /*!< Button is currently pressed. */
-	BUTTON_STATE_ACTIVATED          /*!< Button is considered activated. */
-};
-
-/**
- * \brief GUI button.
- */
-struct button {
-	int x;                          /*!< (RW) Position in x. */
-	int y;                          /*!< (RW) Position in y. */
-	unsigned int w;                 /*!< (RW) Width. */
-	unsigned int h;                 /*!< (RW) Height. */
-	const char *text;               /*!< (RW, ref) Text to draw. */
-	enum button_state state;        /*!< (RW) Button state. */
-	struct theme *theme;            /*!< (RW, ref, optional) Theme to use. */
-};
-
-/**
- * Handle the event.
- *
- * You should always call this function even if the event is completely
- * unrelated.
- *
- * \pre button != NULL
- * \pre ev != NULL
- * \param button the button
- * \param ev the event
- */
-void
-button_handle(struct button *button, const union event *ev);
-
-/**
- * Use this function once the button has been considered activated.
- *
- * \pre button != NULL
- * \param button the button
- */
-void
-button_reset(struct button *button);
-
-/**
- * Draw the button.
- *
- * \pre button != NULL
- * \param button the button
- */
-void
-button_draw(struct button *button);
-
-#endif /* !MOLKO_BUTTON_H */
--- a/src/core/checkbox.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * checkbox.c -- GUI checkbox
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include "checkbox.h"
-#include "theme.h"
-#include "event.h"
-#include "maths.h"
-
-static bool
-is_boxed(const struct checkbox *cb, const struct event_click *click)
-{
-	assert(cb);
-	assert(click && click->type == EVENT_CLICKDOWN);
-
-	return maths_is_boxed(cb->x, cb->y, cb->w, cb->h, click->x, click->y);
-}
-
-void
-checkbox_handle(struct checkbox *cb, const union event *ev)
-{
-	assert(cb);
-	assert(ev);
-
-	switch (ev->type) {
-	case EVENT_CLICKDOWN:
-		if (is_boxed(cb, &ev->click))
-			cb->checked = !cb->checked;
-		break;
-	default:
-		break;
-	}
-}
-
-void
-checkbox_draw(const struct checkbox *cb)
-{
-	theme_draw_checkbox(cb->theme, cb);
-}
--- a/src/core/checkbox.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * checkbox.h -- GUI checkbox
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_CHECKBOX_H
-#define MOLKO_CHECKBOX_H
-
-/**
- * \file checkbox.h
- * \brief GUI checkbox.
- */
-
-#include <stdbool.h>
-
-union event;
-
-/**
- * \brief GUI checkbox.
- */
-struct checkbox {
-	int x;                  /*!< (RW) Position in x. */
-	int y;                  /*!< (RW) Position in y. */
-	unsigned int w;         /*!< (RW) Width. */
-	unsigned int h;         /*!< (RW) Height. */
-	const char *label;      /*!< (RW, ref) Text to show. */
-	bool checked;           /*!< (RW) Is activated? */
-	struct theme *theme;    /*!< (RW, ref, optional) Theme to use. */
-};
-
-/**
- * Draw the checkbox.
- *
- * \pre cb != NULL
- * \pre ev != NULL
- * \param cb the checkbox
- * \param ev the event
- */
-void
-checkbox_handle(struct checkbox *cb, const union event *ev);
-
-/**
- * Draw the checkbox.
- *
- * \pre cb != NULL
- * \param cb the checkbox
- */
-void
-checkbox_draw(const struct checkbox *cb);
-
-#endif /* !MOLKO_CHECKBOX_H */
--- a/src/core/clock.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * clock.c -- track elapsed time
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <SDL.h>
-
-#include "clock.h"
-
-void
-clock_start(struct clock *clock)
-{
-	clock->ticks = SDL_GetTicks();
-}
-
-unsigned int
-clock_elapsed(const struct clock *clock)
-{
-	return SDL_GetTicks() - clock->ticks;
-}
--- a/src/core/clock.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * clock.h -- track elapsed time
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_CLOCK_H
-#define MOLKO_CLOCK_H
-
-/**
- * \file clock.h
- * \brief Track elapsed time.
- * \ingroup basics
- */
-
-/**
- * \brief Clock structure.
- */
-struct clock {
-	unsigned int ticks;     /*!< time point on initialization */
-};
-
-/**
- * Start the clock and track elapsed time.
- *
- * \pre clock != NULL
- * \param clock the clock
- */
-void
-clock_start(struct clock *clock);
-
-/**
- * Tell the measured time.
- *
- * \pre clock != NULL
- * \param clock the clock
- * \return the elapsed time in milliseconds
- */
-unsigned int
-clock_elapsed(const struct clock *clock);
-
-#endif /* !MOLKO_CLOCK_H */
--- a/src/core/color.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * color.h -- basic color routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_COLOR_H
-#define MOLKO_COLOR_H
-
-/**
- * \file color.h
- * \brief Basic color routines.
- */
-
-/**
- * Get red component of hexadecimal color.
- *
- * \param c the hexadecimal color
- * \return the red component
- */
-#define COLOR_R(c)              (c >> 24 & 0xff)
-
-/**
- * Get green component of hexadecimal color.
- *
- * \param c the hexadecimal color
- * \return the green component
- */
-#define COLOR_G(c)              (c >> 16 & 0xff)
-
-/**
- * Get blue component of hexadecimal color.
- *
- * \param c the hexadecimal color
- * \return the blue component
- */
-#define COLOR_B(c)              (c >> 8  & 0xff)
-
-/**
- * Get alpha component of hexadecimal color.
- *
- * \param c the hexadecimal color
- * \return the alpha component
- */
-#define COLOR_A(c)              (c       & 0xff)
-
-/**
- * Convert individual RGBA components into a hexadecimal color.
- *
- * \param r the red component
- * \param g the green component
- * \param b the blue component
- * \param a the alpha component
- * \return the hexadecimal color
- */
-#define COLOR_HEX(r, g, b, a)   \
-        ((r << 24 & 0xff000000) | \
-         (g << 16 & 0x00ff0000) | \
-         (b << 8  & 0x0000ff00) | \
-         (a       & 0x000000ff))
-
-#endif /* !MOLKO_COLOR_H */
--- a/src/core/debug.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * debug.c -- debugging interfaces
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdio.h>
-
-#include "debug.h"
-#include "font.h"
-#include "texture.h"
-
-#define PADDING_X 5
-#define PADDING_Y 5
-
-struct debug_options debug_options = {
-	.default_color = 0x0000ffff,
-	.default_style = FONT_STYLE_ANTIALIASED
-};
-
-void
-debug_printf(struct debug_report *report, const char *fmt, ...)
-{
-	assert(report);
-	assert(fmt);
-
-	va_list ap;
-
-	va_start(ap, fmt);
-	debug_vprintf(report, fmt, ap);
-	va_end(ap);
-}
-
-void
-debug_vprintf(struct debug_report *report, const char *fmt, va_list ap)
-{
-	assert(report);
-	assert(fmt);
-
-	char line[DEBUG_LINE_MAX];
-	struct texture tex;
-	struct font *font;
-	unsigned int gapy;
-
-	vsnprintf(line, sizeof (line), fmt, ap);
-
-	font = report->font ? report->font : debug_options.default_font;
-	font->color = report->color;
-	font->style = report->style;
-
-	if (!font_render(font, &tex, line))
-		return;
-
-	gapy = (PADDING_Y * (report->count)) +
-	    (font_height(font) * (report->count));
-	report->count++;
-
-	texture_draw(&tex, PADDING_X, gapy);
-	texture_finish(&tex);
-}
--- a/src/core/debug.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/*
- * debug.h -- debugging interfaces
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_DEBUG_H
-#define MOLKO_DEBUG_H
-
-/**
- * \file debug.h
- * \brief Debugging interfaces.
- *
- * This module provides functions to draw debugging information within the game
- * window. It is mostly used for information only when state of the game is
- * better inspected via direct window information rather than writing in the
- * console.
- *
- * Predefined core states may print debugging information if
- * debug_options.enabled variable is set to true. However, you need to specify
- * the font to use in order to work.
- *
- * Each call to \ref debug_printf or \ref debug_vprintf automatically adjust
- * next coordinate for rendering the text. As such, user may simply print
- * several lines of text without having to deal with that manually.
- *
- * Example, activate global debugging.
- *
- * \code
- * struct font *f = font_openf("foo.ttf", 10);
- *
- * if (!f)
- * 	error_fatal();
- *
- * debug_options.default_font = f;
- * debug_options.enabled = true;
- * \endcode
- *
- * Example, print debugging information manually.
- *
- * \code
- * struct debug_report report = {
- * 	.color = 0x00ff00ff,
- * 	.font = myfont          // Optional if debug_options.default_font is set.
- * };
- *
- * debug_printf("current position: %d, %d\n", x, y);
- * \endcode
- */
-
-#include <stdbool.h>
-#include <stdarg.h>
-
-#include "font.h"
-
-/**
- * Maximum content length per report.
- */
-#define DEBUG_LINE_MAX 1024
-
-/**
- * \brief Debugging options.
- *
- * Fill this structure with appropriate values to change debugging behavior
- * in core API.
- */
-struct debug_options {
-	struct font *default_font;      /*!< (RW) Default font for reports. */
-	enum font_style default_style;  /*!< (RW) Default font style. */
-	unsigned long default_color;    /*!< (RW) Default font color. */
-	bool enable;                    /*!< (RW) Enable core API debugging. */
-};
-
-/**
- * \brief Debug context.
- *
- * Use this structure each time you need to print one or more messages.
- */
-struct debug_report {
-	struct font *font;              /*!< (RW) Font to use. */
-	enum font_style style;          /*!< (RW) Font style to use. */
-	unsigned long color;            /*!< (RW) Font foreground color to use. */
-	unsigned int count;             /*!< (PV) Number of messages already printed. */
-};
-
-/**
- * Global debugging options.
- */
-extern struct debug_options debug_options;
-
-/**
- * Convenient macro to initialize \ref debug_report with default values.
- */
-#define DEBUG_INIT_DEFAULTS {                   \
-        .font = debug_options.default_font,     \
-        .color = debug_options.default_color,   \
-        .style = debug_options.default_style    \
-}
-
-/**
- * Print debugging information into the screen.
- *
- * \pre report != NULL
- * \pre fmt != NULL
- * \param report the reporting context
- * \param fmt the printf(3) format string
- * \note The message length must not exceed DEBUG_LINE_MAX, otherwise its
- *       result is truncated.
- */
-void
-debug_printf(struct debug_report *report, const char *fmt, ...);
-
-/**
- * Similar to \ref debug_printf but with a va_list object.
- *
- * \see \ref debug_printf
- */
-void
-debug_vprintf(struct debug_report *report, const char *fmt, va_list ap);
-
-#endif /* !MOLKO_DEBUG_H */
--- a/src/core/error.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * error.c -- error routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "error.h"
-#include "error_p.h"
-
-#include <SDL.h>
-
-static char buffer[2048];
-
-const char *
-error(void)
-{
-	return buffer;
-}
-
-bool
-error_errno(void)
-{
-	error_printf("%s", strerror(errno));
-
-	return false;
-}
-
-bool
-error_printf(const char *fmt, ...)
-{
-	assert(fmt);
-
-	va_list ap;
-
-	va_start(ap, fmt);
-	error_vprintf(fmt, ap);
-	va_end(ap);
-
-	return false;
-}
-
-bool
-error_vprintf(const char *fmt, va_list ap)
-{
-	assert(fmt);
-
-	vsnprintf(buffer, sizeof (buffer), fmt, ap);
-
-	return false;
-}
-
-/* private: error_p.h */
-
-bool
-error_sdl(void)
-{
-	error_printf("%s", SDL_GetError());
-
-	return false;
-}
--- a/src/core/error.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * error.h -- error routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_ERROR_H
-#define MOLKO_ERROR_H
-
-/**
- * \file error.h
- * \brief Error routines.
- * \ingroup basics
- */
-
-#include <stdarg.h>
-#include <stdbool.h>
-
-#include "plat.h"
-
-/**
- * Get the last error returned.
- *
- * \return The error string.
- */
-const char *
-error(void);
-
-/**
- * Convenient helper that sets last error from global C errno and then return
- * false.
- *
- * \return Always false.
- */
-bool
-error_errno(void);
-
-/**
- * Set the game error with a printf-like format.
- *
- * \pre fmt != NULL
- * \param fmt the format string
- * \return Always false.
- */
-bool
-error_printf(const char *fmt, ...) PLAT_PRINTF(1, 2);
-
-/**
- * Similar to \ref error_printf.
- *
- * \pre fmt != NULL
- * \param fmt the format stinrg
- * \param ap the variadic arguments pointer
- * \return Always false.
- */
-bool
-error_vprintf(const char *fmt, va_list ap) PLAT_PRINTF(1, 0);
-
-#endif /* !MOLKO_ERROR_H */
--- a/src/core/error_p.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * error.h -- (PRIVATE) error routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_ERROR_P_H
-#define MOLKO_ERROR_P_H
-
-#include <stdbool.h>
-
-/**
- * Convenient handler that sets the game error to the last SDL error and then
- * return false.
- *
- * \return false
- */
-bool
-error_sdl(void);
-
-#endif /* !MOLKO_ERROR_P_H */
--- a/src/core/event.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,255 +0,0 @@
-/*
- * event.c -- event management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <SDL.h>
-
-#include "event.h"
-
-/* Maintain with enum key constants in key.h */
-static const struct {
-	SDL_Keycode key;
-	enum key value;
-} keymap[] = {
-	{ SDLK_RETURN,          KEY_ENTER               },
-	{ SDLK_ESCAPE,          KEY_ESCAPE              },
-	{ SDLK_BACKSPACE,       KEY_BACKSPACE           },
-	{ SDLK_TAB,             KEY_TAB                 },
-	{ SDLK_SPACE,           KEY_SPACE               },
-	{ SDLK_EXCLAIM,         KEY_EXCLAIM             },
-	{ SDLK_QUOTEDBL,        KEY_DOUBLE_QUOTE        },
-	{ SDLK_HASH,            KEY_HASH                },
-	{ SDLK_PERCENT,         KEY_PERCENT             },
-	{ SDLK_DOLLAR,          KEY_DOLLAR              },
-	{ SDLK_AMPERSAND,       KEY_AMPERSAND           },
-	{ SDLK_QUOTE,           KEY_QUOTE               },
-	{ SDLK_LEFTPAREN,       KEY_LEFT_PAREN          },
-	{ SDLK_RIGHTPAREN,      KEY_RIGHT_PAREN         },
-	{ SDLK_ASTERISK,        KEY_ASTERISK            },
-	{ SDLK_PLUS,            KEY_PLUS                },
-	{ SDLK_COMMA,           KEY_COMMA               },
-	{ SDLK_MINUS,           KEY_MINUS               },
-	{ SDLK_PERIOD,          KEY_PERIOD              },
-	{ SDLK_SLASH,           KEY_SLASH               },
-	{ SDLK_0,               KEY_0                   },
-	{ SDLK_1,               KEY_1                   },
-	{ SDLK_2,               KEY_2                   },
-	{ SDLK_3,               KEY_3                   },
-	{ SDLK_4,               KEY_4                   },
-	{ SDLK_5,               KEY_5                   },
-	{ SDLK_6,               KEY_6                   },
-	{ SDLK_7,               KEY_7                   },
-	{ SDLK_8,               KEY_8                   },
-	{ SDLK_9,               KEY_9                   },
-	{ SDLK_COLON,           KEY_COLON               },
-	{ SDLK_SEMICOLON,       KEY_SEMICOLON           },
-	{ SDLK_LESS,            KEY_LESS                },
-	{ SDLK_EQUALS,          KEY_EQUALS              },
-	{ SDLK_GREATER,         KEY_GREATER             },
-	{ SDLK_QUESTION,        KEY_QUESTION            },
-	{ SDLK_AT,              KEY_AT                  },
-	{ SDLK_LEFTBRACKET,     KEY_LEFT_BRACKET        },
-	{ SDLK_BACKSLASH,       KEY_BACKSLASH           },
-	{ SDLK_RIGHTBRACKET,    KEY_RIGHT_BRACKET       },
-	{ SDLK_CARET,           KEY_CARET               },
-	{ SDLK_UNDERSCORE,      KEY_UNDERSCORE          },
-	{ SDLK_BACKQUOTE,       KEY_BACKQUOTE           },
-	{ SDLK_a,               KEY_a                   },
-	{ SDLK_b,               KEY_b                   },
-	{ SDLK_c,               KEY_c                   },
-	{ SDLK_d,               KEY_d                   },
-	{ SDLK_e,               KEY_e                   },
-	{ SDLK_f,               KEY_f                   },
-	{ SDLK_g,               KEY_g                   },
-	{ SDLK_h,               KEY_h                   },
-	{ SDLK_i,               KEY_i                   },
-	{ SDLK_j,               KEY_j                   },
-	{ SDLK_k,               KEY_k                   },
-	{ SDLK_l,               KEY_l                   },
-	{ SDLK_m,               KEY_m                   },
-	{ SDLK_n,               KEY_n                   },
-	{ SDLK_o,               KEY_o                   },
-	{ SDLK_p,               KEY_p                   },
-	{ SDLK_q,               KEY_q                   },
-	{ SDLK_r,               KEY_r                   },
-	{ SDLK_s,               KEY_s                   },
-	{ SDLK_t,               KEY_t                   },
-	{ SDLK_u,               KEY_u                   },
-	{ SDLK_v,               KEY_v                   },
-	{ SDLK_w,               KEY_w                   },
-	{ SDLK_x,               KEY_x                   },
-	{ SDLK_y,               KEY_y                   },
-	{ SDLK_z,               KEY_z                   },
-	{ SDLK_CAPSLOCK,        KEY_CAPSLOCK            },
-	{ SDLK_F1,              KEY_F1                  },
-	{ SDLK_F2,              KEY_F2                  },
-	{ SDLK_F3,              KEY_F3                  },
-	{ SDLK_F4,              KEY_F4                  },
-	{ SDLK_F5,              KEY_F5                  },
-	{ SDLK_F6,              KEY_F6                  },
-	{ SDLK_F7,              KEY_F7                  },
-	{ SDLK_F8,              KEY_F8                  },
-	{ SDLK_F9,              KEY_F9                  },
-	{ SDLK_F10,             KEY_F10                 },
-	{ SDLK_F11,             KEY_F11                 },
-	{ SDLK_F12,             KEY_F12                 },
-	{ SDLK_F13,             KEY_F13                 },
-	{ SDLK_F14,             KEY_F14                 },
-	{ SDLK_F15,             KEY_F15                 },
-	{ SDLK_F16,             KEY_F16                 },
-	{ SDLK_F17,             KEY_F17                 },
-	{ SDLK_F18,             KEY_F18                 },
-	{ SDLK_F19,             KEY_F19                 },
-	{ SDLK_F20,             KEY_F20                 },
-	{ SDLK_F21,             KEY_F21                 },
-	{ SDLK_F22,             KEY_F22                 },
-	{ SDLK_F23,             KEY_F23                 },
-	{ SDLK_F24,             KEY_F24                 },
-	{ SDLK_PRINTSCREEN,     KEY_PRINTSCREEN         },
-	{ SDLK_SCROLLLOCK,      KEY_SCROLLLOCK          },
-	{ SDLK_PAUSE,           KEY_PAUSE               },
-	{ SDLK_INSERT,          KEY_INSERT              },
-	{ SDLK_HOME,            KEY_HOME                },
-	{ SDLK_PAGEUP,          KEY_PAGEUP              },
-	{ SDLK_DELETE,          KEY_DELETE              },
-	{ SDLK_END,             KEY_END                 },
-	{ SDLK_PAGEDOWN,        KEY_PAGEDOWN            },
-	{ SDLK_RIGHT,           KEY_RIGHT               },
-	{ SDLK_LEFT,            KEY_LEFT                },
-	{ SDLK_DOWN,            KEY_DOWN                },
-	{ SDLK_UP,              KEY_UP                  },
-	{ SDLK_KP_DIVIDE,       KEY_KP_DIVIDE           },
-	{ SDLK_KP_MULTIPLY,     KEY_KP_MULTIPLY         },
-	{ SDLK_KP_MINUS,        KEY_KP_MINUS            },
-	{ SDLK_KP_PLUS,         KEY_KP_PLUS             },
-	{ SDLK_KP_ENTER,        KEY_KP_ENTER            },
-	{ SDLK_KP_1,            KEY_KP_1                },
-	{ SDLK_KP_2,            KEY_KP_2                },
-	{ SDLK_KP_3,            KEY_KP_3                },
-	{ SDLK_KP_4,            KEY_KP_4                },
-	{ SDLK_KP_5,            KEY_KP_5                },
-	{ SDLK_KP_6,            KEY_KP_6                },
-	{ SDLK_KP_7,            KEY_KP_7                },
-	{ SDLK_KP_8,            KEY_KP_8                },
-	{ SDLK_KP_9,            KEY_KP_9                },
-	{ SDLK_KP_0,            KEY_KP_0                },
-	{ SDLK_KP_PERIOD,       KEY_KP_PERIOD           },
-	{ SDLK_KP_COMMA,        KEY_KP_COMMA            },
-	{ SDLK_MENU,            KEY_MENU                },
-	{ SDLK_MUTE,            KEY_MUTE                },
-	{ SDLK_VOLUMEUP,        KEY_VOLUME_UP           },
-	{ SDLK_VOLUMEDOWN,      KEY_VOLUME_DOWN         },
-	{ SDLK_LCTRL,           KEY_LCTRL               },
-	{ SDLK_LSHIFT,          KEY_LSHIFT              },
-	{ SDLK_LALT,            KEY_LALT                },
-	{ SDLK_LGUI,            KEY_LSUPER              },
-	{ SDLK_RCTRL,           KEY_RCTRL               },
-	{ SDLK_RSHIFT,          KEY_RSHIFT              },
-	{ SDLK_RALT,            KEY_RALT                },
-	{ SDLK_RGUI,            KEY_RSUPER              },
-	{ 0,                    -1                      }
-};
-
-/* Maintain with enum mouse_button constants in mouse.h */
-static const struct {
-	int key;
-	enum mouse_button value;
-} buttons[] = {
-	{ SDL_BUTTON_LEFT,      MOUSE_BUTTON_LEFT       },
-	{ SDL_BUTTON_MIDDLE,    MOUSE_BUTTON_MIDDLE     },
-	{ SDL_BUTTON_RIGHT,     MOUSE_BUTTON_RIGHT      },
-	{ -1,                   MOUSE_BUTTON_UNKNOWN    }
-};
-
-static void
-convert_key(const SDL_Event *event, union event *ev)
-{
-	ev->type = event->type == SDL_KEYDOWN ? EVENT_KEYDOWN : EVENT_KEYUP;
-	ev->key.key = KEY_UNKNOWN;
-
-	for (size_t i = 0; keymap[i].key != 0; ++i) {
-		if (keymap[i].key == event->key.keysym.sym) {
-			ev->key.key = keymap[i].value;
-			break;
-		}
-	}
-}
-
-static void
-convert_mouse(const SDL_Event *event, union event *ev)
-{
-	ev->type = EVENT_MOUSE;
-	ev->mouse.buttons = 0;
-	ev->mouse.x = event->motion.x;
-	ev->mouse.y = event->motion.y;
-
-	if (event->motion.state & SDL_BUTTON_LMASK)
-		ev->mouse.buttons |= MOUSE_BUTTON_LEFT;
-	if (event->motion.state & SDL_BUTTON_MMASK)
-		ev->mouse.buttons |= MOUSE_BUTTON_MIDDLE;
-	if (event->motion.state & SDL_BUTTON_RMASK)
-		ev->mouse.buttons |= MOUSE_BUTTON_RIGHT;
-}
-
-static void
-convert_click(const SDL_Event *event, union event *ev)
-{
-	ev->type = event->type == SDL_MOUSEBUTTONDOWN ? EVENT_CLICKDOWN : EVENT_CLICKUP;
-	ev->click.button = MOUSE_BUTTON_UNKNOWN;
-	ev->click.x = event->button.x;
-	ev->click.y = event->button.y;
-
-	for (size_t i = 0; buttons[i].value != MOUSE_BUTTON_UNKNOWN; ++i) {
-		if (buttons[i].key == event->button.button) {
-			ev->click.button = buttons[i].value;
-			break;
-		}
-	}
-}
-
-bool
-event_poll(union event *ev)
-{
-	SDL_Event event;
-
-	/*
-	 * Loop until we find an event we want to report, we skip unneeded
-	 * ones.
-	 */
-	while (SDL_PollEvent(&event)) {
-		switch (event.type) {
-		case SDL_QUIT:
-			ev->type = EVENT_QUIT;
-			return true;
-		case SDL_KEYDOWN:
-		case SDL_KEYUP:
-			convert_key(&event, ev);
-			return true;
-		case SDL_MOUSEMOTION:
-			convert_mouse(&event, ev);
-			return true;
-		case SDL_MOUSEBUTTONDOWN:
-		case SDL_MOUSEBUTTONUP:
-			convert_click(&event, ev);
-			return true;
-		default:
-			continue;
-		}
-	}
-
-	return false;
-}
--- a/src/core/event.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * event.h -- event management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_EVENT_H
-#define MOLKO_EVENT_H
-
-/**
- * \file event.h
- * \brief Event management.
- * \ingroup input
- */
-
-#include <stdbool.h>
-
-#include "key.h"
-#include "mouse.h"
-
-/**
- * \brief Kind of event.
- */
-enum event_type {
-	EVENT_CLICKDOWN,        /*!< Mouse click down (\ref event_click) */
-	EVENT_CLICKUP,          /*!< Mouse click released (\ref event_click) */
-	EVENT_KEYDOWN,          /*!< Single key down (\ref event_key) */
-	EVENT_KEYUP,            /*!< Single key released (\ref event_key) */
-	EVENT_MOUSE,            /*!< Mouse moved (\ref event_mouse) */
-	EVENT_QUIT,             /*!< Quit request */
-};
-
-/**
- * \brief Key event.
- */
-struct event_key {
-	enum event_type type;           /*!< EVENT_KEYDOWN or EVENT_KEYUP */
-	enum key key;                   /*!< Which key */
-};
-
-/**
- * \brief Mouse motion event.
- */
-struct event_mouse {
-	enum event_type type;           /*!< EVENT_MOUSE */
-	enum mouse_button buttons;      /*!< OR'ed buttons that are pressed */
-	int x;                          /*!< Mouse position in x */
-	int y;                          /*!< Mouse position in y */
-};
-
-/**
- * \brief Mouse click event.
- */
-struct event_click {
-	enum event_type type;           /*!< EVENT_CLICKDOWN or EVENT_CLICKUP */
-	enum mouse_button button;       /*!< Unique button that was pressed */
-	int x;                          /*!< Mouse position in x */
-	int y;                          /*!< Mouse position in y */
-};
-
-/**
- * \brief Store events.
- */
-union event {
-	enum event_type type;           /*!< Which kind of event */
-	struct event_key key;           /*!< Key event */
-	struct event_mouse mouse;       /*!< Mouse motion event */
-	struct event_click click;       /*!< Mouse click event */
-};
-
-/**
- * Fetch the next event or return false if there are not.
- *
- * \param ev the event
- * \return true if the event was filled or false otherwise
- */
-bool
-event_poll(union event *ev);
-
-#endif /* !MOLKO_EVENT_H */
--- a/src/core/font.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-/*
- * font.c -- basic font management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdio.h>
-
-#include <SDL_ttf.h>
-
-#include "color.h"
-#include "error.h"
-#include "error_p.h"
-#include "font.h"
-#include "texture_p.h"
-#include "util.h"
-
-bool
-font_open(struct font *font, const char *path, unsigned int size)
-{
-	assert(font);
-	assert(path);
-
-	if (!(font->handle = TTF_OpenFont(path, size)))
-		return error_sdl();
-
-	return true;
-}
-
-bool
-font_openmem(struct font *font, const void *buffer, size_t buflen, unsigned int size)
-{
-	assert(font);
-	assert(buffer);
-
-	SDL_RWops *ops;
-
-	if (!(ops = SDL_RWFromConstMem(buffer, buflen)) ||
-	   (!(font->handle = TTF_OpenFontRW(ops, true, size))))
-		return error_sdl();
-
-	return true;
-}
-
-bool
-font_ok(const struct font *font)
-{
-	assert(font);
-
-	return font->handle;
-}
-
-bool
-font_render(struct font *font, struct texture *tex, const char *text)
-{
-	assert(font);
-	assert(text);
-
-	SDL_Color fg = {
-		.r = COLOR_R(font->color),
-		.g = COLOR_G(font->color),
-		.b = COLOR_B(font->color),
-		.a = COLOR_A(font->color)
-	};
-	SDL_Surface *surface;
-	SDL_Surface *(*func)(TTF_Font *, const char *, SDL_Color);
-
-	switch (font->style) {
-	case FONT_STYLE_ANTIALIASED:
-		func = TTF_RenderUTF8_Blended;
-		break;
-	default:
-		func = TTF_RenderUTF8_Solid;
-		break;
-	}
-
-	if (!(surface = func(font->handle, text, fg)))
-		return error_sdl();
-
-	return texture_from_surface(tex, surface);
-}
-
-unsigned int
-font_height(const struct font *font)
-{
-	assert(font);
-
-	return TTF_FontHeight(font->handle);
-}
-
-void
-font_finish(struct font *font)
-{
-	assert(font);
-
-	if (font->handle)
-		TTF_CloseFont(font->handle);
-}
--- a/src/core/font.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- * font.h -- basic font management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_FONT_H
-#define MOLKO_FONT_H
-
-/**
- * \file font.h
- * \brief Basic font management.
- * \ingroup drawing
- */
-
-#include <stdbool.h>
-#include <stddef.h>
-
-struct texture;
-
-/**
- * \brief Font style for rendering.
- */
-enum font_style {
-	FONT_STYLE_ANTIALIASED,         /*!< Pretty antialiasing looking. */
-	FONT_STYLE_NONE                 /*!< No antialiasing. */
-};
-
-/**
- * \brief Font object.
- */
-struct font {
-	enum font_style style;          /*!< (RW) Style for rendering. */
-	unsigned long color;            /*!< (RW) Color for rendering. */
-	void *handle;                   /*!< (RO) Native handle. */
-};
-
-/**
- * Open font from path file.
- *
- * \pre font != NULL
- * \pre path != NULL
- * \param font the font to initialize
- * \param path the path to the font
- * \param size the desired size
- * \return False on errors.
- */
-bool
-font_open(struct font *font, const char *path, unsigned int size);
-
-/**
- * Open font from memory buffer.
- *
- * \pre font != NULL
- * \pre buffer != NULL
- * \param font the font to initialize
- * \param buffer the memory buffer
- * \param buflen the memory buffer length
- * \param size the desired size
- * \warning The buffer must remain valid until font is closed
- * \return False on errors.
- */
-bool
-font_openmem(struct font *font, const void *buffer, size_t buflen, unsigned int size);
-
-/**
- * Tells if the font was properly opened.
- *
- * \pre font != NULL
- * \param font the font to check
- * \return True if the native handle was opened.
- */
-bool
-font_ok(const struct font *font);
-
-/**
- * Render some text into the texture.
- *
- * This function use the current color/style and other properties in the font
- * to render the texture.
- *
- * \pre font != NULL
- * \pre tex != NULL
- * \param font the font to use
- * \param tex the texture to generate
- * \param text the UTF-8 text
- * \return False on errors.
- */
-bool
-font_render(struct font *font, struct texture *tex, const char *text);
-
-/**
- * Get the maximum height for all glyphs.
- *
- * \pre font != NULL
- * \param font the font handle
- * \return the height in pixels
- */
-unsigned int
-font_height(const struct font *font);
-
-/**
- * Close the font.
- *
- * \pre font != NULL
- * \param font the font handle
- */
-void
-font_finish(struct font *font);
-
-#endif /* !MOLKO_FONT_H */
--- a/src/core/frame.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * frame.h -- GUI frame
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include "frame.h"
-#include "theme.h"
-
-void
-frame_draw(const struct frame *frame)
-{
-	assert(frame);
-
-	theme_draw_frame(frame->theme, frame);
-}
--- a/src/core/frame.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * frame.h -- GUI frame
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_FRAME_H
-#define MOLKO_FRAME_H
-
-/**
- * \file frame.h
- * \brief GUI frame.
- */
-
-struct theme;
-
-/**
- * \brief Frame style.
- */
-enum frame_style {
-	FRAME_STYLE_NORMAL,
-	FRAME_STYLE_BOX
-};
-
-/**
- * \brief GUI frame.
- */
-struct frame {
-	int x;                  /*!< (RW) Position in x. */
-	int y;                  /*!< (RW) Position in y. */
-	unsigned int w;         /*!< (RW) Width. */
-	unsigned int h;         /*!< (RW) Height. */
-	enum frame_style style; /*!< (RW) Frame style. */
-	struct theme *theme;    /*!< (RW, ref, optional) Theme to use. */
-};
-
-/**
- * Draw the frame.
- *
- * \pre frame != NULL
- * \param frame the frame to draw
- */
-void
-frame_draw(const struct frame *frame);
-
-#endif /* !MOLKO_FRAME_H */
--- a/src/core/game.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/*
- * game.c -- main game object
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "game.h"
-#include "state.h"
-#include "painter.h"
-
-struct game game;
-
-static struct action *
-find_empty_action(void)
-{
-	static struct action null;
-
-	for (struct action *a = game.actions; a != &game.actions[GAME_ACTIONS_MAX]; ++a)
-		if (memcmp(a, &null, sizeof (struct action)) == 0)
-			return a;
-
-	return NULL;
-}
-
-static void
-clear_actions(void)
-{
-	for (struct action *a = game.actions; a != &game.actions[GAME_ACTIONS_MAX]; ++a) {
-		/* These actions are removed on state change. */
-		if (a->flags & ACTION_AUTO_LEAVE) {
-			if (a->finish)
-				a->finish(a);
-
-			memset(a, 0, sizeof (struct action));
-		}
-	}
-}
-
-static void
-handle_actions(const union event *event)
-{
-	for (struct action *a = game.actions; a != &game.actions[GAME_ACTIONS_MAX]; ++a)
-		if (a->handle)
-			a->handle(a, event);
-}
-
-static void
-update_actions(unsigned int ticks)
-{
-	for (size_t i = 0; i < GAME_ACTIONS_MAX; ++i) {
-		struct action *a = &game.actions[i];
-
-		if (!a->update)
-			continue;
-
-		if (a->update(a, ticks)) {
-			if (a->end)
-				a->end(a);
-			if (a->finish)
-				a->finish(a);
-
-			memset(&game.actions[i], 0, sizeof (struct action));
-		}
-	}
-}
-
-static void
-draw_actions(void)
-{
-	for (size_t i = 0; i < GAME_ACTIONS_MAX; ++i)
-		if (game.actions[i].draw)
-			game.actions[i].draw(&game.actions[i]);
-}
-
-void
-game_switch(struct state *state, bool quick)
-{
-	assert(state);
-
-	if (quick) {
-		game.state = state;
-		game.state->enter();
-	} else
-		game.state_next = state;
-}
-
-void
-game_handle(const union event *event)
-{
-	assert(event);
-
-	if (game.state && !(game.inhibit & INHIBIT_STATE_INPUT))
-		game.state->handle(event);
-
-	handle_actions(event);
-}
-
-void
-game_update(unsigned int ticks)
-{
-	if (!(game.inhibit & INHIBIT_STATE_UPDATE)) {
-		/* Change state if any. */
-		if (game.state_next) {
-			/* Inform the current state we're gonna leave it. */
-			if (game.state)
-				game.state->leave();
-
-			game.state = game.state_next;
-			game.state->enter();
-			game.state_next = NULL;
-
-			/* Remove any actions that must be deleted. */
-			clear_actions();
-		}
-
-		if (game.state)
-			game.state->update(ticks);
-	}
-
-	update_actions(ticks);
-}
-
-void
-game_draw(void)
-{
-	if (game.state && !(game.inhibit & INHIBIT_STATE_DRAW))
-		game.state->draw();
-
-	draw_actions();
-	painter_present();
-}
-
-void
-game_add_action(const struct action *action)
-{
-	assert(action);
-
-	struct action *pos;
-
-	if ((pos = find_empty_action()))
-		memcpy(pos, action, sizeof (struct action));
-}
-
-void
-game_quit(void)
-{
-	if (game.state && game.state->leave)
-		game.state->leave();
-
-	game.state = NULL;
-}
--- a/src/core/game.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*
- * game.h -- main game object
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_GAME_H
-#define MOLKO_GAME_H
-
-/**
- * \file game.h
- * \brief Main game object.
- */
-
-#include <stdbool.h>
-
-#include "action.h"
-#include "inhibit.h"
-
-/**
- * \brief Max number of actions allowed at the same time.
- */
-#define GAME_ACTIONS_MAX 128
-
-struct state;
-
-union event;
-
-/**
- * \brief Main game object.
- */
-struct game {
-	/* Inhibition */
-	enum inhibit inhibit;           /*!< (RW) What to disable. */
-
-	/* Game states. */
-	struct state *state;            /*!< (RO) Current state  */
-	struct state *state_next;       /*!< (RO) Next state */
-
-	/** Array of actions. */
-	struct action actions[GAME_ACTIONS_MAX];
-};
-
-/**
- * Global game object.
- */
-extern struct game game;
-
-/**
- * Request to change state.
- *
- * This function will only update state after the next \ref  game_update call
- * unless quick is set to true.
- *
- * \pre state != NULL
- * \param state the new state
- * \param quick quickly change the state
- */
-void
-game_switch(struct state *state, bool quick);
-
-/**
- * Handle input event.
- *
- * \param event the event
- */
-void
-game_handle(const union event *event);
-
-/**
- * Update the game state.
- *
- * \param ticks the number of milliseconds between last frame
- */
-void
-game_update(unsigned int ticks);
-
-/**
- * Draw the game using the current state.
- */
-void
-game_draw(void);
-
-/**
- * Add an action to the game.
- *
- * If there are no room for the action, action is discarded. Make sure to not
- * exceed the limit GAME_ACTIONS_MAX.
- *
- * \pre action != NULL
- * \param action the action to copy
- * \note The core API **never** add actions by itself.
- */
-void
-game_add_action(const struct action *action);
-
-/**
- * Stop the game.
- *
- * This will effectively stop the current state but the main loop may continue
- * until it has completed.
- */
-void
-game_quit(void);
-
-#endif /* !MOLKO_GAME_H */
--- a/src/core/image.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * image.c -- basic image management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdbool.h>
-
-#include <SDL_image.h>
-
-#include "error_p.h"
-#include "texture.h"
-#include "window.h"
-#include "window_p.h"
-
-static void
-dimensions(struct texture *tex)
-{
-	int w, h;
-
-	if (SDL_QueryTexture(tex->handle, NULL, NULL, &w, &h) < 0)
-		tex->w = tex->h = 0;
-	else {
-		tex->w = w;
-		tex->h = h;
-	}
-}
-
-bool
-image_open(struct texture *tex, const char *path)
-{
-	assert(tex);
-	assert(path);
-
-	if (!(tex->handle = IMG_LoadTexture(RENDERER(), path)))
-		return error_sdl();
-
-	dimensions(tex);
-
-	return true;
-}
-
-bool
-image_openmem(struct texture *tex, const void *buffer, size_t size)
-{
-	assert(buffer);
-
-	SDL_RWops *ops = SDL_RWFromConstMem(buffer, size);
-
-	if (!ops || !(tex->handle = IMG_LoadTexture_RW(RENDERER(), ops, true)))
-		return error_sdl();
-
-	dimensions(tex);
-
-	return true;
-}
--- a/src/core/image.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * image.h -- basic image management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_IMAGE_H
-#define MOLKO_IMAGE_H
-
-/**
- * \file image.h
- * \brief Basic image management.
- * \ingroup drawing
- */
-
-#include <stdbool.h>
-#include <stddef.h>
-
-struct texture;
-
-/**
- * Open a file from a path.
- *
- * \pre tex != NULL
- * \pre path != NULL
- * \param tex the texture to initialize
- * \param path the path to the file
- * \return False on errors.
- */
-bool
-image_open(struct texture *tex, const char *path);
-
-/**
- * Open a file from a memory buffer.
- *
- * The buffer must be valid until the image is no longer used.
- *
- * \pre tex != NULL
- * \pre buffer != NULL
- * \param tex the texture to initialize
- * \param buffer the memory buffer
- * \param size the memory size
- * \return False on errors.
- */
-bool
-image_openmem(struct texture *tex, const void *buffer, size_t size);
-
-#endif /* !MOLKO_IMAGE_H */
--- a/src/core/inhibit.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * inhibit.c -- disable specific game behavior
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "action.h"
-#include "inhibit.h"
-#include "game.h"
-#include "util.h"
-
-static bool
-update(struct action *a, unsigned int ticks)
-{
-	(void)ticks;
-
-	game.inhibit = *((enum inhibit *)a->data);
-
-	return true;
-}
-
-static void
-finish(struct action *a)
-{
-	free(a->data);
-}
-
-void
-inhibit_action(enum inhibit mode, struct action *a)
-{
-	assert(a);
-
-	memset(a, 0, sizeof (struct action));
-	a->data = ememdup(&mode, sizeof (enum inhibit));
-	a->update = update;
-	a->finish = finish;
-}
--- a/src/core/inhibit.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * inhibit.h -- disable specific game behavior
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_INHIBIT_H
-#define MOLKO_INHIBIT_H
-
-/**
- * \file inhibit.h
- * \brief Disable specific game behavior.
- */
-
-struct action;
-
-/**
- * \brief Game inhibition.
- *
- * This enum is used to alter the game behavior.
- */
-enum inhibit {
-	/**
-	 * Nothing.
-	 */
-	INHIBIT_NONE,
-
-	/**
-	 * Disable input handling in current state.
-	 */
-	INHIBIT_STATE_INPUT        = (1 << 0),
-
-	/**
-	 * Disable current state updates.
-	 */
-	INHIBIT_STATE_UPDATE       = (1 << 1),
-
-	/**
-	 * Disable current state rendering.
-	 */
-	INHIBIT_STATE_DRAW         = (1 << 2)
-};
-
-/**
- * Create an action to inhibit the system.
- *
- * The mode will replace the actual inhibit modes rather than adding new flags.
- *
- * \pre a != NULL
- * \param mode the new mode
- * \param a the action to fill
- */
-void
-inhibit_action(enum inhibit mode, struct action *a);
-
-#endif /* !MOLKO_INHIBIT_H */
--- a/src/core/inventory.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,210 +0,0 @@
-/*
- * inventory.c -- inventory of items
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "inventory.h"
-#include "item.h"
-
-#define INVENTORY_TOTAL (INVENTORY_ROWS_MAX * INVENTORY_COLS_MAX)
-
-static bool
-can_be_used(struct inventory_slot *slot, const struct item *item)
-{
-	assert(item);
-
-	/* Empty slot. */
-	if (!slot->item)
-		return false;
-
-	/* Not same object. */
-	if (strcmp(slot->item->name, item->name) != 0)
-		return false;
-
-	/* No space in this slot. */
-	if (slot->amount >= slot->item->stackable)
-		return false;
-
-	return true;
-}
-
-static struct inventory_slot *
-find(struct inventory *iv, const struct item *item)
-{
-	assert(iv);
-	assert(item);
-
-	/* First pass: find an entry with the same item. */
-	for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r)
-		for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c)
-			if (can_be_used(&iv->items[r][c], item))
-				return &iv->items[r][c];
-
-	/* Second pass: try to find an empty slot. */
-	for (unsigned int r = 0; r < INVENTORY_ROWS_MAX; ++r)
-		for (unsigned int c = 0; c < INVENTORY_COLS_MAX; ++c)
-			if (!iv->items[r][c].item)
-				return &iv->items[r][c];
-
-	return NULL;
-}
-
-static unsigned
-provide(struct inventory_slot *slot, struct item *item, unsigned int amount)
-{
-	assert(slot);
-
-	unsigned int avail;
-
-	/* The slot may be empty, make sure it contains this item. */
-	slot->item = item;
-
-	/*
-	 * Example:
-	 *
-	 * The slot has already 10 items.
-	 * The slot item is stackble up to 64 items.
-	 *
-	 * When pushing:
-	 *
-	 * 80: 54 pushed, 26 left
-	 * 30: 30 pushed, 0 left.
-	 */
-	avail = slot->item->stackable - slot->amount;
-
-	if (amount > avail) {
-		slot->amount += avail;
-		amount -= avail;
-	} else {
-		slot->amount += amount;
-		amount = 0;
-	}
-
-	return amount;
-}
-
-static bool
-merge(struct inventory_slot *slot, struct inventory_slot *other)
-{
-	assert(slot);
-	assert(slot->item);
-	assert(other);
-
-	/* Not compatible, return false to let the sorting continue. */
-	if (slot->item != other->item)
-		return false;
-
-	while (slot->amount < slot->item->stackable && other->amount) {
-		slot->amount++;
-		other->amount--;
-	}
-
-	/* No more amount in the other slot, empty it. */
-	if (other->amount == 0U)
-		memset(other, 0, sizeof (*other));
-
-	return slot->amount >= slot->item->stackable;
-}
-
-static void
-sort(struct inventory *iv, struct inventory_slot *slot, int r, int c)
-{
-	assert(slot);
-	assert(slot->item);
-
-	/* Merge until the end of thiw row. */
-	for (c = c + 1; c < INVENTORY_COLS_MAX; ++c)
-		if (merge(slot, &iv->items[r][c]))
-			return;
-
-	/* Merge the next rows. */
-	for (r = r + 1; r < INVENTORY_ROWS_MAX; ++r)
-		for (c = 0; c < INVENTORY_COLS_MAX; ++c)
-			if (merge(slot, &iv->items[r][c]))
-				return;
-}
-
-unsigned int
-inventory_push(struct inventory *iv, struct item *item, unsigned int amount)
-{
-	assert(iv);
-	assert(item);
-
-	while (amount) {
-		struct inventory_slot *slot;
-
-		if (!(slot = find(iv, item)))
-			break;
-
-		/* Add as much as we can in this slot. */
-		amount = provide(slot, item, amount);
-	}
-
-	return amount;
-}
-
-static int
-compare_slot(const void *v1, const void *v2)
-{
-	const struct inventory_slot *slot1 = v1;
-	const struct inventory_slot *slot2 = v2;
-	int cmp;
-
-	/* Two null slots compare equal. */
-	if (!slot1->item && !slot2->item)
-		return 0;
-
-	/* Null left should be moved after. */
-	if (!slot1->item)
-		return 1;
-
-	/* Null right slots should be moved after. */
-	if (!slot2->item)
-		return -1;
-
-	/* If they are identical, use amount to sort. */
-	if ((cmp = strcmp(slot1->item->name, slot2->item->name)) == 0)
-		return (long long int)slot2->amount - (long long int)slot1->amount;
-
-	return cmp;
-}
-
-void
-inventory_sort(struct inventory *iv)
-{
-	assert(iv);
-
-	for (int r = 0; r < INVENTORY_ROWS_MAX; ++r)
-		for (int c = 0; c < INVENTORY_COLS_MAX; ++c)
-			if (iv->items[r][c].item)
-				sort(iv, &iv->items[r][c], r, c);
-
-	/* Sort by names AND by amount. */
-	qsort(iv->items, INVENTORY_TOTAL, sizeof (struct inventory_slot), compare_slot);
-}
-
-void
-inventory_clear(struct inventory *iv)
-{
-	assert(iv);
-
-	memset(iv, 0, sizeof (*iv));
-}
--- a/src/core/inventory.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/*
- * inventory.h -- inventory of items
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_INVENTORY_H
-#define MOLKO_INVENTORY_H
-
-/**
- * \file inventory.h
- * \brief Inventory of items.
- */
-
-/**
- * \brief Maximum number of rows.
- */
-#define INVENTORY_ROWS_MAX      3
-
-/**
- * \brief Maximum number of columns.
- */
-#define INVENTORY_COLS_MAX      10
-
-struct item;
-
-/**
- * \brief Inventory slot.
- *
- * This structure describe a 'cell' into the inventory. It references a item
- * and has a given amount of it.
- */
-struct inventory_slot {
-	struct item *item;      /*!< (RO, ref) Pointer to the item. */
-	unsigned int amount;    /*!< (RO) Number of items in this slot. */
-};
-
-/**
- * \brief Inventory structure.
- */
-struct inventory {
-	/**
-	 * (RW)
-	 *
-	 * Grid of objects.
-	 */
-	struct inventory_slot items[INVENTORY_ROWS_MAX][INVENTORY_COLS_MAX];
-};
-
-/**
- * Try to push as much as possible the given item.
- *
- * \pre iv != NULL
- * \pre item != NULL
- * \param iv the inventory
- * \param item the item to reference
- * \param amount the desired amount
- * \return 0 if all items were pushed or the number left otherwise
- */
-unsigned int
-inventory_push(struct inventory *iv, struct item *item, unsigned int amount);
-
-/**
- * Sort the inventory.
- *
- * \pre iv != NULL
- * \pre item != NULL
- * \param iv the inventory
- */
-void
-inventory_sort(struct inventory *iv);
-
-/**
- * Clears the inventory.
- *
- * \pre iv != NULL
- * \param iv the inventory
- */
-void
-inventory_clear(struct inventory *iv);
-
-#endif /* !MOLKO_INVENTORY_H */
--- a/src/core/inventory_dialog.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,321 +0,0 @@
-/*
- * inventory_dialog.h -- dialog for items
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdio.h>
-
-#include "button.h"
-#include "event.h"
-#include "frame.h"
-#include "game.h"
-#include "inventory.h"
-#include "inventory_dialog.h"
-#include "item.h"
-#include "maths.h"
-#include "painter.h"
-#include "texture.h"
-#include "window.h"
-
-#define ITEM_SIZE       64
-#define ITEM_PADDING    32
-
-#define GRID_WIDTH      ((INVENTORY_COLS_MAX * ITEM_SIZE) +             \
-                        ((INVENTORY_COLS_MAX + 1) * ITEM_PADDING))
-#define GRID_HEIGHT     ((INVENTORY_ROWS_MAX * ITEM_SIZE) +             \
-                        ((INVENTORY_ROWS_MAX + 1) * ITEM_PADDING))
-
-#define LABEL_WIDTH     (GRID_WIDTH)
-#define LABEL_HEIGHT    (64)
-
-#define BUTTON_HEIGHT   (32)
-#define BUTTON_WIDTH    ((GRID_WIDTH) / 4)
-
-/*
- * The frame looks like this:
- *
- * +----------------------------+
- * | [] [] [] [] [] [] [] [] [] |
- * | [] [] [] [] [] [] [] [] [] |
- * | [] [] [] [] [] [] [] [] [] |
- * +----------------------------+
- * | Item name                  |
- * | Item description           |
- * +----------------------------+
- *                       [ Sort ]
- *
- * Where space between cells is determined with ITEM_PADDING macro.
- */
-
-static unsigned int
-total_width(void)
-{
-	return GRID_WIDTH;
-}
-
-static unsigned int
-total_height(void)
-{
-	return GRID_HEIGHT + LABEL_HEIGHT + BUTTON_HEIGHT;
-}
-
-static void
-compute_box_position(const struct inventory_dialog *dlg, int r, int c, int *x, int *y)
-{
-	assert(dlg);
-	assert(x);
-	assert(y);
-
-	*x = dlg->fgrid.x + ((c * ITEM_SIZE) + ((c + 1) * ITEM_PADDING));
-	*y = dlg->fgrid.y + ((r * ITEM_SIZE) + ((r + 1) * ITEM_PADDING));
-}
-
-static void
-draw_grid_item_frame(int x, int y)
-{
-	struct frame frame = {
-		.x = x,
-		.y = y,
-		.w = ITEM_SIZE,
-		.h = ITEM_SIZE,
-		.style = FRAME_STYLE_BOX
-	};
-
-	frame_draw(&frame);
-}
-
-static void
-draw_grid_item_icon(struct item *item, int x, int y)
-{
-	struct texture *icon = item->icon;
-
-	texture_scale(icon, 0, 0, icon->w, icon->h, x, y, ITEM_SIZE, ITEM_SIZE, 0.0);
-}
-
-static void
-draw_grid_item_amount(struct inventory_slot *slot, int x, int y)
-{
-	char nstr[16];
-	struct label label = {
-		.text = nstr,
-		.x = x,
-		.y = y
-	};
-
-	/* Draw the number of item in this slot. */
-	snprintf(nstr, sizeof (nstr), "%d", slot->amount);
-	label_draw(&label);
-}
-
-static void
-draw_grid_item(struct inventory_slot *slot, int x, int y, bool selected)
-{
-	draw_grid_item_frame(x, y);
-
-	if (slot->item) {
-		draw_grid_item_icon(slot->item, x, y);
-		draw_grid_item_amount(slot, x, y);
-	}
-
-	if (selected) {
-		x -= 16;
-		y += (ITEM_SIZE / 2) - 4;
-		painter_draw_circle(x, y, 8);
-	}
-}
-
-static void
-draw_grid_items(const struct inventory_dialog *dlg)
-{
-	int x, y;
-	bool selected;
-
-	for (int r = 0; r < INVENTORY_ROWS_MAX; ++r) {
-		for (int c = 0; c < INVENTORY_COLS_MAX; ++c) {
-			selected = r == dlg->selrow && c == dlg->selcol;
-			compute_box_position(dlg, r, c, &x, &y);
-			draw_grid_item(&dlg->inv->items[r][c], x, y, selected);
-		}
-	}
-}
-
-static void
-draw_label(struct inventory_dialog *dlg)
-{
-	assert(dlg);
-
-	struct item *item = dlg->inv->items[dlg->selrow][dlg->selcol].item;
-
-	frame_draw(&dlg->fname);
-	frame_draw(&dlg->fdesc);
-
-	if (item) {
-		dlg->lname.text = item->name;
-		dlg->ldesc.text = item->summary;
-		label_draw(&dlg->lname);
-		label_draw(&dlg->ldesc);
-	}
-}
-
-void
-inventory_dialog_open(struct inventory_dialog *dlg)
-{
-	assert(dlg);
-	assert(dlg->inv);
-
-	int tw, th;
-
-	dlg->state = INVENTORY_DIALOG_SHOWING;
-
-	tw = total_width();
-	th = total_height();
-
-	/* Grid frame position. */
-	dlg->fgrid.w = GRID_WIDTH;
-	dlg->fgrid.h = GRID_HEIGHT;
-	dlg->fgrid.x = dlg->x;
-	dlg->fgrid.y = dlg->y;
-
-	/* Name label. */
-	dlg->fname.w = dlg->lname.w = LABEL_WIDTH;
-	dlg->fname.h = dlg->lname.h = LABEL_HEIGHT / 2;
-	dlg->fname.x = dlg->lname.x = dlg->x;
-	dlg->fname.y = dlg->lname.y = dlg->y + GRID_HEIGHT;
-	dlg->lname.x += ITEM_PADDING;
-	dlg->lname.flags = LABEL_NO_HCENTER;
-
-	/* Description label. */
-	dlg->fdesc.w = dlg->ldesc.w = LABEL_WIDTH;
-	dlg->fdesc.h = dlg->ldesc.h = LABEL_HEIGHT / 2;
-	dlg->fdesc.x = dlg->ldesc.x = dlg->y;
-	dlg->fdesc.y = dlg->ldesc.y = dlg->y + GRID_HEIGHT + (LABEL_HEIGHT / 2);
-	dlg->ldesc.x += ITEM_PADDING;
-	dlg->ldesc.flags = LABEL_NO_HCENTER;
-
-	/* Button sort. */
-	dlg->bsort.x = dlg->x;
-	dlg->bsort.y = dlg->y + GRID_HEIGHT + LABEL_HEIGHT;
-	dlg->bsort.w = BUTTON_WIDTH;
-	dlg->bsort.h = BUTTON_HEIGHT;
-	dlg->bsort.text = "Sort";
-}
-
-static void
-handle_keydown(struct inventory_dialog *dlg, const struct event_key *ev)
-{
-	assert(ev && ev->type == EVENT_KEYDOWN);
-
-	switch (ev->key) {
-	case KEY_LEFT:
-		if (dlg->selcol == 0)
-			dlg->selcol = INVENTORY_COLS_MAX - 1;
-		else
-			dlg->selcol--;
-		break;
-	case KEY_RIGHT:
-		dlg->selcol = (dlg->selcol + 1) % INVENTORY_COLS_MAX;
-		break;
-	case KEY_UP:
-		if (dlg->selrow == 0)
-			dlg->selrow = INVENTORY_ROWS_MAX - 1;
-		else
-			dlg->selrow--;
-		break;
-	case KEY_DOWN:
-		dlg->selrow = (dlg->selrow + 1) % INVENTORY_ROWS_MAX;
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-handle_clickdown(struct inventory_dialog *dlg, const struct event_click *ev)
-{
-	assert(dlg);
-	assert(ev && ev->type == EVENT_CLICKDOWN);
-
-	int x, y;
-
-	for (int r = 0; r < INVENTORY_ROWS_MAX; ++r) {
-		for (int c = 0; c < INVENTORY_COLS_MAX; ++c) {
-			compute_box_position(dlg, r, c, &x, &y);
-
-			if (maths_is_boxed(x, y, ITEM_SIZE, ITEM_SIZE, ev->x, ev->y)) {
-				dlg->selrow = r;
-				dlg->selcol = c;
-			}
-		}
-	}
-}
-
-void
-inventory_dialog_handle(struct inventory_dialog *dlg, const union event *event)
-{
-	assert(event);
-
-	switch (event->type) {
-	case EVENT_KEYDOWN:
-		handle_keydown(dlg, &event->key);
-		break;
-	case EVENT_CLICKDOWN:
-		handle_clickdown(dlg, &event->click);
-		break;
-	default:
-		break;
-	}
-
-	button_handle(&dlg->bsort, event);
-
-	if (dlg->bsort.state == BUTTON_STATE_ACTIVATED) {
-		inventory_sort(dlg->inv);
-		button_reset(&dlg->bsort);
-	}
-}
-
-void
-inventory_dialog_update(struct inventory_dialog *dlg, unsigned int ticks)
-{
-	assert(dlg);
-
-	(void)ticks;
-}
-
-void
-inventory_dialog_move(struct inventory_dialog *dlg, int x, int y)
-{
-	assert(dlg);
-}
-
-void
-inventory_dialog_draw(struct inventory_dialog *dlg)
-{
-	assert(dlg);
-
-	frame_draw(&dlg->fgrid);
-	draw_grid_items(dlg);
-	draw_label(dlg);
-	button_draw(&dlg->bsort);
-}
-
-void
-inventory_dialog_finish(struct inventory_dialog *dlg)
-{
-	assert(dlg);
-
-	dlg->state = INVENTORY_DIALOG_NONE;
-}
--- a/src/core/inventory_dialog.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * inventory_dialog.h -- dialog for items
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef INVENTORY_DIALOG_H
-#define INVENTORY_DIALOG_H
-
-#include "button.h"
-#include "label.h"
-#include "frame.h"
-
-union event;
-
-struct inventory;
-struct theme;
-
-enum inventory_dialog_state {
-	INVENTORY_DIALOG_NONE,
-	INVENTORY_DIALOG_SHOWING
-};
-
-struct inventory_dialog {
-	int x;                                  /*!< (RO) Position in x. */
-	int y;                                  /*!< (RO) Position in y. */
-	struct inventory *inv;                  /*!< (RW, ref) Inventory to use. */
-	struct theme *theme;                    /*!< (RW, ref, optional) Theme to use. */
-	struct button bsort;                    /*!< (RO) Button sort. */
-	struct frame fgrid;                     /*!< (RO) Grid frame. */
-	struct frame fname;                     /*!< (RO) Frame for name. */
-	struct frame fdesc;                     /*!< (RO) Frame for description. */
-	struct label lname;                     /*!< (RO) Label for name. */
-	struct label ldesc;                     /*!< (RO) Label for description. */
-	enum inventory_dialog_state state;      /*!< (RO) Current dialog state. */
-	unsigned int selrow;                    /*!< (RO) Current selected row. */
-	unsigned int selcol;                    /*!< (RO) Current selected column. */
-};
-
-void
-inventory_dialog_open(struct inventory_dialog *dlg);
-
-void
-inventory_dialog_handle(struct inventory_dialog *dlg, const union event *event);
-
-void
-inventory_dialog_update(struct inventory_dialog *dlg, unsigned int ticks);
-
-void
-inventory_dialog_move(struct inventory_dialog *dlg, int x, int y);
-
-void
-inventory_dialog_draw(struct inventory_dialog *dlg);
-
-void
-inventory_dialog_finish(struct inventory_dialog *dlg);
-
-#endif /* !INVENTORY_DIALOG_H */
--- a/src/core/item.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * item.h -- inventory items
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_ITEM_H
-#define MOLKO_ITEM_H
-
-/**
- * \file item.h
- * \brief Inventory items.
- */
-
-#include <stdbool.h>
-
-/**
- * \brief Maximum count of an item into a stack.
- */
-#define ITEM_STACK_MAX  64
-
-struct character;
-struct texture;
-
-/**
- * \brief Inventory items.
- */
-struct item {
-	const char *name;               /*!< (RW) Name of item. */
-	const char *summary;            /*!< (RW) Summary description. */
-	struct texture *icon;           /*!< (RW, ref) Icon to show. */
-	unsigned int stackable;         /*!< (RW) Stack count allowed. */
-
-	/**
-	 * (RW)
-	 *
-	 * Execute the action for this character.
-	 */
-	void (*exec)(const struct item *, struct character *);
-
-	/**
-	 * (RW, optional)
-	 *
-	 * Tells if the item can be used in this context.
-	 */
-	bool (*allowed)(const struct item *, const struct character *);
-};
-
-#endif /* !MOLKO_ITEM_H */
--- a/src/core/key.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-/*
- * key.h -- keyboard definitions
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_KEY_H
-#define MOLKO_KEY_H
-
-/**
- * \file key.h
- * \brief Keyboard definitions.
- * \ingroup input
- */
-
-/**
- * \brief Key codes.
- */
-enum key {
-	KEY_UNKNOWN,
-	KEY_ENTER,
-	KEY_ESCAPE,
-	KEY_BACKSPACE,
-	KEY_TAB,
-	KEY_SPACE,
-	KEY_EXCLAIM,
-	KEY_DOUBLE_QUOTE,
-	KEY_HASH,
-	KEY_PERCENT,
-	KEY_DOLLAR,
-	KEY_AMPERSAND,
-	KEY_QUOTE,
-	KEY_LEFT_PAREN,
-	KEY_RIGHT_PAREN,
-	KEY_ASTERISK,
-	KEY_PLUS,
-	KEY_COMMA,
-	KEY_MINUS,
-	KEY_PERIOD,
-	KEY_SLASH,
-	KEY_0,
-	KEY_1,
-	KEY_2,
-	KEY_3,
-	KEY_4,
-	KEY_5,
-	KEY_6,
-	KEY_7,
-	KEY_8,
-	KEY_9,
-	KEY_COLON,
-	KEY_SEMICOLON,
-	KEY_LESS,
-	KEY_EQUALS,
-	KEY_GREATER,
-	KEY_QUESTION,
-	KEY_AT,
-	KEY_LEFT_BRACKET,
-	KEY_BACKSLASH,
-	KEY_RIGHT_BRACKET,
-	KEY_CARET,
-	KEY_UNDERSCORE,
-	KEY_BACKQUOTE,
-	KEY_a,
-	KEY_b,
-	KEY_c,
-	KEY_d,
-	KEY_e,
-	KEY_f,
-	KEY_g,
-	KEY_h,
-	KEY_i,
-	KEY_j,
-	KEY_k,
-	KEY_l,
-	KEY_m,
-	KEY_n,
-	KEY_o,
-	KEY_p,
-	KEY_q,
-	KEY_r,
-	KEY_s,
-	KEY_t,
-	KEY_u,
-	KEY_v,
-	KEY_w,
-	KEY_x,
-	KEY_y,
-	KEY_z,
-	KEY_CAPSLOCK,
-	KEY_F1,
-	KEY_F2,
-	KEY_F3,
-	KEY_F4,
-	KEY_F5,
-	KEY_F6,
-	KEY_F7,
-	KEY_F8,
-	KEY_F9,
-	KEY_F10,
-	KEY_F11,
-	KEY_F12,
-	KEY_F13,
-	KEY_F14,
-	KEY_F15,
-	KEY_F16,
-	KEY_F17,
-	KEY_F18,
-	KEY_F19,
-	KEY_F20,
-	KEY_F21,
-	KEY_F22,
-	KEY_F23,
-	KEY_F24,
-	KEY_PRINTSCREEN,
-	KEY_SCROLLLOCK,
-	KEY_PAUSE,
-	KEY_INSERT,
-	KEY_HOME,
-	KEY_PAGEUP,
-	KEY_DELETE,
-	KEY_END,
-	KEY_PAGEDOWN,
-	KEY_RIGHT,
-	KEY_LEFT,
-	KEY_DOWN,
-	KEY_UP,
-	KEY_NUMLOCKCLEAR,
-	KEY_KP_DIVIDE,
-	KEY_KP_MULTIPLY,
-	KEY_KP_MINUS,
-	KEY_KP_PLUS,
-	KEY_KP_ENTER,
-	KEY_KP_00,
-	KEY_KP_000,
-	KEY_KP_1,
-	KEY_KP_2,
-	KEY_KP_3,
-	KEY_KP_4,
-	KEY_KP_5,
-	KEY_KP_6,
-	KEY_KP_7,
-	KEY_KP_8,
-	KEY_KP_9,
-	KEY_KP_0,
-	KEY_KP_PERIOD,
-	KEY_KP_COMMA,
-	KEY_MENU,
-	KEY_MUTE,
-	KEY_VOLUME_UP,
-	KEY_VOLUME_DOWN,
-	KEY_LCTRL,
-	KEY_LSHIFT,
-	KEY_LALT,
-	KEY_LSUPER,
-	KEY_RCTRL,
-	KEY_RSHIFT,
-	KEY_RALT,
-	KEY_RSUPER,
-};
-
-/**
- * \brief Keybord modifiers.
- *
- * This enumeration is usually stored as OR'ed flags as several modifiers can
- * be pressed at a time.
- */
-enum keymod {
-	KEYMOD_LSHIFT   = 1 << 0,       /*!< Left shift */
-	KEYMOD_LCTRL    = 1 << 1,       /*!< Left control */
-	KEYMOD_LALT     = 1 << 2,       /*!< Left alt */
-	KEYMOD_LSUPER   = 1 << 3,       /*!< Left super (logo) */
-	KEYMOD_RSHIFT   = 1 << 4,       /*!< Right shift */
-	KEYMOD_RCTRL    = 1 << 5,       /*!< Right control */
-	KEYMOD_RALT     = 1 << 6,       /*!< Right alt */
-	KEYMOD_RSUPER   = 1 << 7        /*!< Right super (logo) */
-};
-
-#endif /* !MOLKO_KEY_H */
--- a/src/core/label.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * label.c -- GUI label
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include "label.h"
-#include "theme.h"
-
-void
-label_draw(const struct label *label)
-{
-	assert(label);
-
-	theme_draw_label(label->theme, label);
-}
--- a/src/core/label.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * label.h -- GUI label
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_LABEL_H
-#define MOLKO_LABEL_H
-
-/**
- * \file label.h
- * \brief GUI label.
- */
-
-struct theme;
-
-/**
- * \brief Label flags.
- */
-enum label_flags {
-	LABEL_NONE,                             /*!< No flags. */
-	LABEL_NO_SHADOW         = (1 << 0),     /*!< Disable shadow. */
-	LABEL_NO_VCENTER        = (1 << 1),     /*!< Disable vertical centering. */
-	LABEL_NO_HCENTER        = (1 << 2)      /*!< Disable horizontal centering. */
-};
-
-/**
- * \brief GUI label.
- */
-struct label {
-	int x;                  /*!< (RW) Position in x. */
-	int y;                  /*!< (RW) Position in y. */
-	unsigned int w;         /*!< (RW) Width. */
-	unsigned int h;         /*!< (RW) Height. */
-	const char *text;       /*!< (RW, ref) Text to show. */
-	enum label_flags flags; /*!< (RW) Optional flags. */
-	unsigned long color;    /*!< (RW) Color to use (0 = use theme). */
-	struct theme *theme;    /*!< (RW, ref, optional) Theme to use. */
-};
-
-/**
- * Draw the label.
- *
- * \pre label != NULL
- * \param label the label to draw
- */
-void
-label_draw(const struct label *label);
-
-#endif /* !MOLKO_LABEL_H */
--- a/src/core/map.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-/*
- * map.c -- game map
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "error.h"
-#include "error_p.h"
-#include "image.h"
-#include "map.h"
-#include "painter.h"
-#include "sprite.h"
-#include "sys.h"
-#include "texture.h"
-#include "window.h"
-
-/* Create %<v>c string literal for scanf */
-#define MAX_F(v) MAX_F_(v)
-#define MAX_F_(v) "%" #v "c"
-
-static void
-parse_layer(struct map_data *data, const char *line, FILE *fp)
-{
-	char layer_name[32 + 1] = { 0 };
-	struct map_layer *layer;
-	size_t amount, current;
-
-	/* Determine layer. */
-	if (sscanf(line, "layer|%32s", layer_name) <= 0)
-		return;
-	if (strcmp(layer_name, "background") == 0)
-		layer = &data->layers[0];
-	else if (strcmp(layer_name, "foreground") == 0)
-		layer = &data->layers[1];
-	else
-		return;
-
-	/* Check if weight/height has been specified. */
-	if (data->w == 0 || data->h == 0)
-		return;
-
-	amount = data->w * data->h;
-	current = 0;
-
-	if (!(layer->tiles = calloc(amount, sizeof (unsigned short))))
-		return;
-
-	for (int tile; fscanf(fp, "%d", &tile) && current < amount; ++current)
-		layer->tiles[current] = tile;
-}
-
-static void
-parse(struct map_data *data, const char *line, FILE *fp)
-{
-	if (strncmp(line, "title", 5) == 0)
-		sscanf(line, "title|" MAX_F(MAP_TITLE_MAX), data->title);
-	else if (strncmp(line, "width", 5) == 0)
-		sscanf(line, "width|%u", &data->w);
-	else if (strncmp(line, "height", 6) == 0)
-		sscanf(line, "height|%u", &data->h);
-	else if (strncmp(line, "tilewidth", 9) == 0)
-		sscanf(line, "tilewidth|%hu", &data->tile_w);
-	else if (strncmp(line, "tileheight", 10) == 0)
-		sscanf(line, "tileheight|%hu", &data->tile_h);
-	else if (strncmp(line, "origin", 6) == 0)
-		sscanf(line, "origin|%d|%d", &data->origin_x, &data->origin_y);
-	else if (strncmp(line, "tileset", 7) == 0)
-		sscanf(line, "tileset|" MAX_F(MAP_TILESET_MAX), data->tileset);
-	else if (strncmp(line, "layer", 5) == 0)
-		parse_layer(data, line, fp);
-}
-
-static bool
-check(struct map_data *data)
-{
-	if (strlen(data->title) == 0)
-		return error_printf("data has no title");
-	if (data->w == 0 || data->h == 0)
-		return error_printf("data has null sizes");
-	if (data->tile_w == 0 || data->tile_h == 0)
-		return error_printf("data has null tile sizes");
-	if (!data->layers[0].tiles || !data->layers[1].tiles)
-		return error_printf("could not allocate data");
-
-	return true;
-}
-
-static void
-draw_layer(struct map *map, const struct map_layer *layer)
-{
-	assert(map);
-	assert(layer);
-
-	struct sprite sprite;
-	int x = 0, y = 0;
-
-	sprite_init(&sprite, &map->tileset, map->data->tile_w, map->data->tile_h);
-
-	for (unsigned int r = 0; r < map->data->w; ++r) {
-		for (unsigned int c = 0; c < map->data->h; ++c) {
-			unsigned int si = r * map->data->w + c;
-			unsigned int sr = (layer->tiles[si] - 1) / sprite.ncols;
-			unsigned int sc = (layer->tiles[si] - 1) % sprite.nrows;
-
-			if (layer->tiles[si] != 0)
-				sprite_draw(&sprite, sr, sc, x, y);
-
-			x += map->data->tile_w;
-		}
-
-		x = 0;
-		y += map->data->tile_h;
-	}
-}
-
-bool
-map_data_open(struct map_data *data, const char *path)
-{
-	assert(data);
-	assert(path);
-
-	memset(data, 0, sizeof (*data));
-
-	FILE *fp = fopen(path, "r");
-	char line[BUFSIZ];
-
-	if (!fp)
-		return false;
-
-	while (fgets(line, sizeof (line), fp)) {
-		/* Remove \n if any */
-		line[strcspn(line, "\n")] = '\0';
-		parse(data, line, fp);
-	}
-
-	fclose(fp);
-
-	if (!check(data)) {
-		map_data_finish(data);
-		return false;
-	}
-
-	/* Compute real size. */
-	data->real_w = data->w * data->tile_w;
-	data->real_h = data->h * data->tile_h;
-
-	return true;
-}
-
-void
-map_data_finish(struct map_data *data)
-{
-	assert(data);
-
-	free(data->layers[0].tiles);
-	free(data->layers[1].tiles);
-
-	memset(data, 0, sizeof (*data));
-}
-
-bool
-map_init(struct map *map, struct map_data *data)
-{
-	assert(map);
-	assert(data);
-
-	if (!(image_open(&map->tileset, sys_datapath("tilesets/%s", data->tileset))))
-		goto failure;
-	if (!(texture_new(&map->picture, data->real_w, data->real_h)))
-		goto failure;
-
-	map->data = data;
-	map_repaint(map);
-
-	return true;
-
-failure:
-	map_data_finish(data);
-
-	return false;
-}
-
-void
-map_draw(struct map *map, int srcx, int srcy)
-{
-	texture_scale(&map->picture, srcx, srcy, window.w, window.h,
-	    0, 0, window.w, window.h, 0.0);
-}
-
-void
-map_repaint(struct map *map)
-{
-	PAINTER_BEGIN(&map->picture);
-	draw_layer(map, &map->data->layers[0]);
-	draw_layer(map, &map->data->layers[1]);
-	PAINTER_END();
-}
-
-void
-map_finish(struct map *map)
-{
-	assert(map);
-
-	texture_finish(&map->tileset);
-	texture_finish(&map->picture);
-
-	memset(map, 0, sizeof (*map));
-}
--- a/src/core/map.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-/*
- * map.h -- game map
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_MAP_H
-#define MOLKO_MAP_H
-
-/**
- * \file map.h
- * \brief Game map.
- */
-
-#include <stdbool.h>
-#include <stdio.h>
-
-#include "texture.h"
-
-/**
- * \brief Max title length for a map.
- */
-#define MAP_TITLE_MAX   32
-
-/**
- * \brief Max filename for tilesets.
- */
-#define MAP_TILESET_MAX FILENAME_MAX
-
-/**
- * \brief Map layer.
- */
-struct map_layer {
-	unsigned short *tiles;          /*!< (RO) Array of tiles, depending on the map size. */
-};
-
-/**
- * \brief Map definition structure.
- *
- * This structure only defines the map characteristics. It does not have any
- * logic and is left for game state.
- */
-struct map_data {
-	char title[MAP_TITLE_MAX];      /*!< (RW) The map title. */
-	char tileset[MAP_TILESET_MAX];  /*!< (RO) Name of tileset to use. */
-	int origin_x;                   /*!< (RO) Where the player starts in X. */
-	int origin_y;                   /*!< (RO) Where the player starts in Y. */
-	unsigned int real_w;            /*!< (RO) Real width in pixels. */
-	unsigned int real_h;            /*!< (RO) Real height in pixels. */
-	unsigned int w;                 /*!< (RO) Map width in cells. */
-	unsigned int h;                 /*!< (RO) Map height in cells. */
-	unsigned short tile_w;          /*!< (RO) Pixels per cell (width). */
-	unsigned short tile_h;          /*!< (RO) Pixels per cell (height). */
-	struct map_layer layers[2];     /*!< (RO) Layers (background, foreground). */
-};
-
-/**
- * \brief High level map object.
- *
- * This structure reference a map and perform drawing operations.
- */
-struct map {
-	struct map_data *data;          /*!< (RW, ref) Map data. */
-	struct texture tileset;         /*!< (RW) Tileset to use. */
-	struct texture picture;         /*!< (RO) Map drawn into a picture. */
-};
-
-/**
- * Open a map defintion
- *
- * \pre data != NULL
- * \pre path != NULL
- * \param data the map defintion to fill
- * \param path the path to the map
- * \return True if successfully loaded.
- */
-bool
-map_data_open(struct map_data *data, const char *path);
-
-/**
- * Dispose the map definition data.
- *
- * \pre data != NULL
- * \param data the map definition
- */
-void
-map_data_finish(struct map_data *data);
-
-/**
- * Initialize this map.
- *
- * \pre map != NULL
- * \pre data != NULL
- * \param map the map to initialize
- * \param data the definition to reference
- * \return False on errors.
- */
-bool
-map_init(struct map *map, struct map_data *data);
-
-/**
- * Render a map.
- *
- * \pre map != NULL
- * \param map the map to render
- * \param srcx the x coordinate region
- * \param srcy the y coordinate region
- */
-void
-map_draw(struct map *map, int srcx, int srcy);
-
-/**
- * Force map repaint on its texture.
- *
- * \pre map != NULL
- * \param map the map to repaint
- * \warning This function does not render anything on the screen.
- */
-void
-map_repaint(struct map *map);
-
-/**
- * Dispose map resources.
- *
- * \pre map != NULL
- * \param map the map to close
- */
-void
-map_finish(struct map *map);
-
-#endif /* !MOLKO_MAP_H */
--- a/src/core/map_state.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,350 +0,0 @@
-/*
- * map_state.c -- state when player is on a map
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-
-#include "debug.h"
-#include "event.h"
-#include "game.h"
-#include "map.h"
-#include "map_state.h"
-#include "painter.h"
-#include "state.h"
-#include "texture.h"
-#include "walksprite.h"
-#include "window.h"
-
-/*
- * This is the speed the player moves on the map.
- *
- * SPEED represents the number of pixels it must move per SEC.
- * SEC simply represends the number of milliseconds in one second.
- */
-#define SPEED 100
-#define SEC   1000
-
-/*
- * Those are margins within the edge of the screen. The camera always try to
- * keep those padding between the player and the screen.
- */
-#define MARGIN_WIDTH    80
-#define MARGIN_HEIGHT   80
-
-/*
- * Convenient macros to access the state data.
- */
-#define MAP()           (&map_state_data.map)
-#define PLAYER()        (&map_state_data.player)
-#define VIEW()          (&map_state_data.view)
-
-/*
- * This structure defines the possible movement of the player as flags since
- * it's possible to make diagonal movements.
- */
-enum movement {
-	MOVING_UP       = 1 << 0,
-	MOVING_RIGHT    = 1 << 1,
-	MOVING_DOWN     = 1 << 2,
-	MOVING_LEFT     = 1 << 3
-};
-
-/*
- * A bit of explanation within this array. The structure walksprite requires
- * an orientation between 0-7 depending on the user direction.
- *
- * Since keys for moving the character may be pressed at the same time, we need
- * a conversion table from "key pressed" to "orientation".
- *
- * When an orientation is impossible, it is set to -1. Example, when both left
- * and right are pressed.
- *
- * MOVING_UP    = 0001 = 0x1
- * MOVING_RIGHT = 0010 = 0x2
- * MOVING_DOWN  = 0100 = 0x3
- * MOVING_LEFT  = 1000 = 0x4
- */
-static unsigned int orientations[16] = {
-	[0x1] = 0,
-	[0x2] = 2,
-	[0x3] = 1,
-	[0x4] = 4,
-	[0x6] = 3,
-	[0x8] = 6,
-	[0x9] = 7,
-	[0xC] = 5
-};
-
-/*
- * Additional data that is not necessary to expose in map_state_data.
- */
-static struct {
-	struct {
-		enum movement moving;
-		struct walksprite ws;
-	} player;
-
-	struct {
-		int x;
-		int y;
-		unsigned int w;
-		unsigned int h;
-	} margin;
-} cache;
-
-static void
-center(void)
-{
-	VIEW()->x = PLAYER()->x - (VIEW()->w / 2);
-	VIEW()->y = PLAYER()->y - (VIEW()->h / 2);
-
-	if (VIEW()->x < 0)
-		VIEW()->x = 0;
-	else if ((unsigned int)VIEW()->x > MAP()->data.real_w - VIEW()->w)
-		VIEW()->x = MAP()->data.real_w - VIEW()->w;
-
-	if (VIEW()->y < 0)
-		VIEW()->y = 0;
-	else if ((unsigned int)VIEW()->y > MAP()->data.real_h - VIEW()->h)
-		VIEW()->y = MAP()->data.real_h - VIEW()->h;
-}
-
-static void
-enter(void)
-{
-	/* Adjust map properties. */
-	struct map *m = &map_state_data.map.map;
-
-	map_repaint(m);
-	MAP()->data.real_w = m->picture.w;
-	MAP()->data.real_h = m->picture.h;
-
-	/* Adjust view. */
-	VIEW()->w = window.w;
-	VIEW()->h = window.h;
-
-	/* Adjust margin. */
-	cache.margin.w = VIEW()->w - (MARGIN_WIDTH * 2);
-	cache.margin.h = VIEW()->h - (MARGIN_HEIGHT * 2);
-
-	/* Center the view by default. */
-	center();
-
-	/* Final bits. */
-	walksprite_init(&cache.player.ws, &PLAYER()->sprite, 300);
-}
-
-static void
-leave(void)
-{
-}
-
-static void
-handle_keydown(const union event *event)
-{
-	switch (event->key.key) {
-	case KEY_UP:
-		cache.player.moving |= MOVING_UP;
-		break;
-	case KEY_RIGHT:
-		cache.player.moving |= MOVING_RIGHT;
-		break;
-	case KEY_DOWN:
-		cache.player.moving |= MOVING_DOWN;
-		break;
-	case KEY_LEFT:
-		cache.player.moving |= MOVING_LEFT;
-		break;
-	default:
-		break;
-	}
-
-	PLAYER()->angle = orientations[cache.player.moving];
-}
-
-static void
-handle_keyup(const union event *event)
-{
-	switch (event->key.key) {
-	case KEY_UP:
-		cache.player.moving &= ~(MOVING_UP);
-		break;
-	case KEY_RIGHT:
-		cache.player.moving &= ~(MOVING_RIGHT);
-		break;
-	case KEY_DOWN:
-		cache.player.moving &= ~(MOVING_DOWN);
-		break;
-	case KEY_LEFT:
-		cache.player.moving &= ~(MOVING_LEFT);
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-move_right(unsigned int delta)
-{
-	PLAYER()->x += delta;
-
-	if (PLAYER()->x > (int)(cache.margin.x + cache.margin.w)) {
-		VIEW()->x = (PLAYER()->x - VIEW()->w) + MARGIN_WIDTH;
-
-		if (VIEW()->x >= (int)(MAP()->data.real_w - VIEW()->w))
-			VIEW()->x = MAP()->data.real_w - VIEW()->w;
-	}
-
-	if (PLAYER()->x > (int)MAP()->data.real_w - 48)
-		PLAYER()->x = MAP()->data.real_w - 48;
-}
-
-static void
-move_left(unsigned int delta)
-{
-	PLAYER()->x -= delta;
-
-	if (PLAYER()->x < cache.margin.x) {
-		VIEW()->x = PLAYER()->x - MARGIN_WIDTH;
-
-		if (VIEW()->x < 0)
-			VIEW()->x = 0;
-	}
-
-	if (PLAYER()->x < 0)
-		PLAYER()->x = 0;
-}
-
-static void
-move_down(unsigned int delta)
-{
-	PLAYER()->y += delta;
-
-	if (PLAYER()->y > (int)(cache.margin.y + cache.margin.h)) {
-		VIEW()->y = (PLAYER()->y - VIEW()->h) + MARGIN_HEIGHT;
-
-		if (VIEW()->y >= (int)(MAP()->data.real_h - VIEW()->h))
-			VIEW()->y = MAP()->data.real_h - VIEW()->h;
-	}
-
-	if (PLAYER()->y > (int)MAP()->data.real_h - 48)
-		PLAYER()->y = MAP()->data.real_h - 48;
-}
-
-static void
-move_up(unsigned int delta)
-{
-	PLAYER()->y -= delta;
-
-	if (PLAYER()->y < cache.margin.y) {
-		VIEW()->y = PLAYER()->y - MARGIN_HEIGHT;
-
-		if (VIEW()->y < 0)
-			VIEW()->y = 0;
-	}
-
-	if (PLAYER()->y < 0)
-		PLAYER()->y = 0;
-}
-
-static void
-move(unsigned int ticks)
-{
-	/* This is the amount of pixels the player must move. */
-	const int delta = SPEED * ticks / SEC;
-
-	/* This is the rectangle within the view where users must be. */
-	cache.margin.x = VIEW()->x + MARGIN_WIDTH;
-	cache.margin.y = VIEW()->y + MARGIN_HEIGHT;
-
-	int dx = 0;
-	int dy = 0;
-
-	if (cache.player.moving == 0)
-		return;
-
-	if (cache.player.moving & MOVING_UP)
-		dy = -1;
-	if (cache.player.moving & MOVING_DOWN)
-		dy = 1;
-	if (cache.player.moving & MOVING_LEFT)
-		dx = -1;
-	if (cache.player.moving & MOVING_RIGHT)
-		dx = 1;
-
-	/* Move the player and adjust view if needed. */
-	if (dx > 0)
-		move_right(delta);
-	else if (dx < 0)
-		move_left(delta);
-
-	if (dy > 0)
-		move_down(delta);
-	else if (dy < 0)
-		move_up(delta);
-
-	walksprite_update(&cache.player.ws, ticks);
-}
-
-static void
-handle(const union event *event)
-{
-	switch (event->type) {
-	case EVENT_KEYDOWN:
-		handle_keydown(event);
-		break;
-	case EVENT_KEYUP:
-		handle_keyup(event);
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-update(unsigned int ticks)
-{
-	move(ticks);
-}
-
-static void
-draw(void)
-{
-	struct debug_report report = DEBUG_INIT_DEFAULTS;
-
-	map_draw(&map_state_data.map.map, VIEW()->x, VIEW()->y);
-	walksprite_draw(
-		&cache.player.ws,
-		PLAYER()->angle,
-		PLAYER()->x - VIEW()->x,
-		PLAYER()->y - VIEW()->y);
-
-	debug_printf(&report, "position: %d, %d", PLAYER()->x,
-	    PLAYER()->y);
-	debug_printf(&report, "view: %d, %d", VIEW()->x,
-	    VIEW()->y);
-}
-
-struct map_state_data map_state_data;
-
-struct state map_state = {
-	.enter = enter,
-	.leave = leave,
-	.update = update,
-	.handle = handle,
-	.draw = draw
-};
--- a/src/core/map_state.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * map_state.h -- state when player is on a map
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_MAP_STATE_H
-#define MOLKO_MAP_STATE_H
-
-/**
- * \file map_state.h
- * \brief State when player is on a map.
- * \ingroup states
- */
-
-#include "map.h"
-#include "sprite.h"
-
-/**
- * \brief Data for the state.
- *
- * Update this structure before switching to this state.
- */
-extern struct map_state_data {
-	/**
-	 * Map properties.
-	 */
-	struct {
-		struct map_data data;   /*!< (RW) Map data. */
-		struct map map;         /*!< (RW) Map object. */
-	} map;
-
-	/**
-	 * Player position.
-	 *
-	 * If you adjust this structure, it is strictly encouraged to update
-	 * the view as well.
-	 */
-	struct {
-		struct sprite sprite;   /*!< (RW) The sprite to use */
-		int x;                  /*!< (RO) Player position in x */
-		int y;                  /*!< (RO) Player position in y */
-		int angle;              /*!< (RO) Player angle (see walksprite) */
-	} player;
-
-	/**
-	 * Position and size of the view.
-	 */
-	struct {
-		int x;                  /*!< (RW) Position in x */
-		int y;                  /*!< (RW) Position in y */
-		unsigned int w;         /*!< (RO) View width */
-		unsigned int h;         /*!< (RO) View height */
-	} view;
-} map_state_data; /*!< Access to data. */
-
-/**
- * \brief State when player is on a map.
- */
-extern struct state map_state;
-
-#endif /* !MOLKO_MAP_STATE_H */
--- a/src/core/maths.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * maths.c -- basic maths
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "maths.h"
-
-bool
-maths_is_boxed(int x, int y, unsigned int w, unsigned int h, int px, int py)
-{
-	return px >= x &&
-	       py >= y &&
-	       px <= x + w &&
-	       py <= y + h;
-}
-
-void
-maths_centerize(int *x,
-               int *y,
-               unsigned int w,
-               unsigned int h,
-               int px,
-               int py,
-               unsigned int pw,
-               unsigned int ph)
-{
-	if (x)
-		*x = px + (pw / 2) - (w / 2);
-	if (y)
-		*y = py + (ph / 2) - (h / 2);
-}
--- a/src/core/maths.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * maths.h -- basic maths
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_MATHS_H
-#define MOLKO_MATHS_H
-
-#include <stdbool.h>
-
-/**
- * \file maths.h
- * \brief Basic maths.
- */
-
-/**
- * Tells if a coordinate is within a rectangle region.
- *
- * \param x the region start
- * \param y the region start
- * \param w the region width
- * \param h the region height
- * \param px the point to test
- * \param py the point to test
- * \return True if within the region
- */
-bool
-maths_is_boxed(int x, int y, unsigned int w, unsigned int h, int px, int py);
-
-/**
- * Update x, y to be centered into a parent region.
- *
- * You can select to ignore horizontal/vertical centering by passing NULL to x
- * or y respectively.
- *
- * \param x the pointer to x coordinate to modify
- * \param y the pointer yo y coordinate to modify
- * \param w the object width
- * \param h the object height
- * \param px the parent region start
- * \param py the parent region start
- * \param pw the parent region width
- * \param ph the parent region height
- */
-void
-maths_centerize(int *x,
-                int *y,
-                unsigned int w,
-                unsigned int h,
-                int px,
-                int py,
-                unsigned int pw,
-                unsigned int ph);
-
-#endif /* !MOLKO_MATHS_H */
--- a/src/core/message.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,261 +0,0 @@
-/*
- * message.c -- message dialog
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "action.h"
-#include "event.h"
-#include "font.h"
-#include "frame.h"
-#include "label.h"
-#include "message.h"
-#include "painter.h"
-#include "panic.h"
-#include "sprite.h"
-#include "texture.h"
-#include "theme.h"
-#include "util.h"
-#include "window.h"
-
-#define MESSAGE_SPEED   100     /* Time delay for animations */
-#define MESSAGE_TIMEOUT 5000    /* Time for auto-closing */
-
-#define WIDTH   (window.w * 0.75)
-#define HEIGHT  (window.h * 0.125)
-
-#define THEME(msg) (msg->theme ? msg->theme : theme_default())
-
-static void
-action_handle(struct action *action, const union event *ev)
-{
-	assert(action);
-	assert(ev);
-
-	message_handle(action->data, ev);
-}
-
-static bool
-action_update(struct action *action, unsigned int ticks)
-{
-	assert(action);
-
-	return message_update(action->data, ticks);
-}
-
-static void
-action_draw(struct action *action)
-{
-	assert(action);
-
-	message_draw(action->data);
-}
-
-static void
-action_finish(struct action *action)
-{
-	assert(action);
-
-	free(action->data);
-}
-
-void
-message_start(struct message *msg)
-{
-	assert(msg);
-
-	msg->elapsed = 0;
-	msg->scale = 0.0;
-	msg->state = msg->flags & MESSAGE_QUICK ? MESSAGE_SHOWING : MESSAGE_OPENING;
-}
-
-void
-message_handle(struct message *msg, const union event *ev)
-{
-	assert(msg);
-	assert(ev);
-
-	/* Skip if the message animation hasn't complete. */
-	if (msg->state != MESSAGE_SHOWING)
-		return;
-
-	/* Only keyboard event are valid. */
-	if (ev->type != EVENT_KEYDOWN || msg->state == MESSAGE_NONE)
-		return;
-
-	switch (ev->key.key) {
-	case KEY_UP:
-		if (msg->index > 0)
-			msg->index--;
-		break;
-	case KEY_DOWN:
-		if (msg->index < 5 && msg->text[msg->index + 1])
-			msg->index++;
-		break;
-	case KEY_ENTER:
-		msg->state = msg->flags & MESSAGE_QUICK ? MESSAGE_NONE : MESSAGE_HIDING;
-		msg->elapsed = 0;
-		break;
-	default:
-		break;
-	}
-}
-
-bool
-message_update(struct message *msg, unsigned int ticks)
-{
-	assert(msg);
-
-	msg->elapsed += ticks;
-
-	switch (msg->state) {
-	case MESSAGE_OPENING:
-		msg->scale = (double)msg->elapsed / (double)MESSAGE_SPEED;
-
-		if (msg->scale > 1)
-			msg->scale = 1;
-
-		if (msg->elapsed >= MESSAGE_SPEED) {
-			msg->state = MESSAGE_SHOWING;
-			msg->elapsed = 0;
-		}
-
-		break;
-	case MESSAGE_SHOWING:
-		/* Do automatically switch state if requested by the user. */
-		if (msg->flags & MESSAGE_AUTOMATIC && msg->elapsed >= MESSAGE_TIMEOUT) {
-			msg->state = msg->flags & MESSAGE_QUICK ? MESSAGE_NONE : MESSAGE_HIDING;
-			msg->elapsed = 0;
-		}
-
-		break;
-	case MESSAGE_HIDING:
-		msg->scale = 1 - (double)msg->elapsed / (double)MESSAGE_SPEED;
-
-		if (msg->scale < 0)
-			msg->scale = 0;
-		if (msg->elapsed >= MESSAGE_SPEED) {
-			msg->state = MESSAGE_NONE;
-			msg->elapsed = 0;
-		}
-
-		break;
-	default:
-		break;
-	}
-
-	return msg->state == MESSAGE_NONE;
-}
-
-static void
-draw_frame(const struct message *msg)
-{
-	assert(msg);
-
-	struct frame frame = {
-		.w = WIDTH,
-		.h = HEIGHT
-	};
-
-	frame_draw(&frame);
-}
-
-static void
-draw_lines(const struct message *msg)
-{
-	struct font *font;
-	unsigned int lineh;
-
-	font = THEME(msg)->fonts[THEME_FONT_INTERFACE];
-	lineh = font_height(font);
-
-	for (int i = 0; i < 6; ++i) {
-		if (!msg->text[i])
-			continue;
-
-		struct label label = {
-			.x = 10,
-			.y = 10 + (i * lineh),
-			.h = lineh,
-			.theme = msg->theme,
-			.text = msg->text[i],
-			.flags = LABEL_NO_HCENTER
-		};
-
-		/*
-		 * The function label_draw will normally use
-		 * THEME_FONT_INTERFACE so update its color if needed.
-		 */
-		if (msg->flags & MESSAGE_QUESTION && msg->index == i)
-			label.color = THEME(msg)->colors[THEME_COLOR_SELECTED];
-
-		label_draw(&label);
-	}
-}
-
-void
-message_draw(struct message *msg)
-{
-	assert(msg);
-
-	struct texture tex;
-	int x, y, w, h;
-
-	if (!texture_new(&tex, WIDTH, HEIGHT))
-		panic();
-
-	PAINTER_BEGIN(&tex);
-	draw_frame(msg);
-	draw_lines(msg);
-	PAINTER_END();
-
-	/* Compute scaling. */
-	w = WIDTH * msg->scale;
-	h = HEIGHT * msg->scale;
-
-	/* Compute position. */
-	x = (window.w / 2) - (w / 2);
-	y = HEIGHT;
-
-	texture_scale(&tex, 0, 0, WIDTH, HEIGHT, x, y, w, h, 0.0);
-	texture_finish(&tex);
-}
-
-void
-message_hide(struct message *msg)
-{
-	assert(msg);
-
-	msg->state = MESSAGE_HIDING;
-	msg->elapsed = 0;
-}
-
-void
-message_action(const struct message *msg, struct action *action)
-{
-	assert(msg);
-	assert(action);
-
-	memset(action, 0, sizeof (struct action));
-	action->data = ememdup(msg, sizeof (struct message));
-	action->handle = action_handle;
-	action->update = action_update;
-	action->draw = action_draw;
-	action->finish = action_finish;
-}
--- a/src/core/message.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-/*
- * message.h -- message dialog
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_MESSAGE_H
-#define MOLKO_MESSAGE_H
-
-/**
- * \file message.h
- * \brief Message dialog.
- * \ingroup actions
- * \ingroup drawing
- *
- * This module's purpose is to show a dialog box into the screen to show text
- * and optionally ask the user a question.
- *
- * By itself, it is very low level and does not prevent other parts of the game
- * to use the input so you probably need to inhibit input if your dialog is
- * meant to be displayed on a map.
- *
- * To use it use the following procedure:
- *
- * 1. Create a struct message object and set required properties,
- * 2. Call \ref message_start to reset the state,
- * 3. Call \ref message_handle and \ref message_update with appropriate values,
- * 4. Call \ref message_draw to render the dialog.
- *
- * Depending on message flags or user input, step 3 may return true in this
- * case you should stop using the message as it has completed rendering.
- *
- * \note All properties must exist until the object is no longer used.
- *
- * \code
- * struct message msg = {
- * 	// You can show up to 6 lines.
- * 	.text = {
- * 		"Hello, what's up?"
- * 	},
- * 	// This image will be shown on the left as user face.
- * 	.avatar = mysuperavatar,
- * 	// This should point to a image that is used as background.
- * 	.frame = mysuperframe,
- * 	// The first color is normal text, the second is for selected text
- * 	// in case of question.
- * 	.colors = { 0xffffffff, 0x0000ffff },
- * 	// This indicates this message is a question.
- * 	.flags = MESSAGE_QUESTION
- * };
- * \endcode
- */
-
-#include <stdbool.h>
-
-#include "texture.h"
-
-struct action;
-struct font;
-struct theme;
-
-union event;
-
-/**
- * \brief Message flags.
- */
-enum message_flags {
-	MESSAGE_AUTOMATIC       = (1 << 0),     /*!< Will automatically change state by itself. */
-	MESSAGE_QUESTION        = (1 << 1),     /*!< The message is a question. */
-	MESSAGE_QUICK           = (1 << 2),     /*!< Avoid animations. */
-};
-
-/**
- * \brief Message state.
- */
-enum message_state {
-	MESSAGE_NONE,           /*!< Message hasn't start yet or is finished */
-	MESSAGE_OPENING,        /*!< Message animation is opening */
-	MESSAGE_SHOWING,        /*!< Message is displaying */
-	MESSAGE_HIDING          /*!< Message animation for hiding */
-};
-
-/**
- * \brief Message object.
- *
- * This structure is used to display a message into the screen. It does not own
- * any user properties and therefore must exist while using it.
- */
-struct message {
-	const char *text[6];            /*!< (RW) Lines of text to show. */
-	struct texture *frame;          /*!< (RW, ref) Frame to use. */
-	struct texture *avatar;         /*!< (RW, ref, optional) Avatar face. */
-	unsigned int index;             /*!< (RW) Line selected */
-	enum message_flags flags;       /*!< (RW) Message flags */
-	enum message_state state;       /*!< (RO) Current state */
-	struct theme *theme;            /*!< (RW, ref, optional) Theme to use. */
-	unsigned int elapsed;           /*!< (RO) Time elapsed. */
-	double scale;                   /*!< (RO) Current scale [0-1]. */
-};
-
-/**
- * Start opening the message. This function will reset the message state and
- * elapsed time.
- *
- * \pre msg != NULL
- * \param msg the message
- */
-void
-message_start(struct message *msg);
-
-/**
- * Handle input events.
- *
- * This function will alter state of the message and change its selection in
- * case of question.
- *
- * \pre msg != NULL
- * \pre ev != NULL
- * \param msg the message
- * \param ev the event which occured
- */
-void
-message_handle(struct message *msg, const union event *ev);
-
-/**
- * Update the message state and elapsed time..
- *
- * \pre msg != NULL
- * \param msg the message
- * \param ticks the elapsed delay since last frame
- * \return true if it has finished
- */
-bool
-message_update(struct message *msg, unsigned int ticks);
-
-/**
- * Draw the message into the screen.
- *
- * \pre msg != NULL
- * \param msg the message
- */
-void
-message_draw(struct message *msg);
-
-/**
- * Start hiding the message.
- *
- * \pre msg != NULL
- * \param msg the message
- * \note You should still continue to draw the message as the animation is not
- *       finished!
- */
-void
-message_hide(struct message *msg);
-
-/**
- * Convert message into an action.
- *
- * \pre msg != NULL
- * \pre action != NULL
- * \param msg the message to copy from
- * \param action the action to fill
- */
-void
-message_action(const struct message *msg, struct action *action);
-
-#endif /* !MOLKO_MESSAGE_H */
--- a/src/core/mouse.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * mouse.h -- mouse definitions
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_MOUSE_H
-#define MOLKO_MOUSE_H
-
-/**
- * \file mouse.h
- * \brief Mouse definitions.
- * \ingroup input
- */
-
-/**
- * \brief Buttons from mouse.
- *
- * This enumeration is used as both flags or constants. For example when the
- * user press one button on the mouse it generates one constant event. On the
- * other hand, while moving the mouse the user may have one or more buttons
- * pressed, thus the OR'ed combination.
- */
-enum mouse_button {
-	MOUSE_BUTTON_UNKNOWN    = 0,            /*!< No buttons pressed */
-	MOUSE_BUTTON_LEFT       = (1 << 0),     /*!< Left button pressed */
-	MOUSE_BUTTON_MIDDLE     = (1 << 1),     /*!< Middle button pressed */
-	MOUSE_BUTTON_RIGHT      = (1 << 2)      /*!< Right button pressed */
-};
-
-#endif /* !MOLKO_MOUSE_H */
--- a/src/core/painter.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/*
- * painter.c -- basic drawing routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <math.h>
-
-#include "color.h"
-#include "painter.h"
-#include "texture.h"
-#include "window.h"
-#include "window_p.h"
-
-/* Current texture renderer. */
-static struct texture *renderer;
-
-struct texture *
-painter_get_target(void)
-{
-	return renderer;
-}
-
-void
-painter_set_target(struct texture *tex)
-{
-	renderer = tex;
-	SDL_SetRenderTarget(RENDERER(), tex ? tex->handle : NULL);
-}
-
-unsigned long
-painter_get_color(void)
-{
-	Uint8 r = 0, g = 0, b = 0, a = 0;
-
-	SDL_GetRenderDrawColor(RENDERER(), &r, &g, &b, &a);
-
-	return COLOR_HEX(r, g, b, a);
-}
-
-void
-painter_set_color(unsigned long color)
-{
-	SDL_SetRenderDrawColor(
-		RENDERER(),
-		COLOR_R(color),
-		COLOR_G(color),
-		COLOR_B(color),
-		COLOR_A(color)
-	);
-}
-
-void
-painter_draw_line(int x1, int y1, int x2, int y2)
-{
-	SDL_RenderDrawLine(RENDERER(), x1, y1, x2, y2);
-}
-
-void
-painter_draw_point(int x1, int y1)
-{
-	SDL_RenderDrawPoint(RENDERER(), x1, y1);
-}
-
-void
-painter_draw_rectangle(int x, int y, unsigned int width, unsigned int height)
-{
-	const SDL_Rect rect = {
-		.w = width,
-		.h = height,
-		.x = x,
-		.y = y
-	};
-
-	SDL_RenderFillRect(RENDERER(), &rect);
-}
-
-void
-painter_draw_circle(int x, int y, int radius)
-{
-	// Note that there is more to altering the bitrate of this 
-	// method than just changing this value.  See how pixels are
-	// altered at the following web page for tips:
-	//   http://www.libsdl.org/intro.en/usingvideo.html
-	static const int BPP = 4;
-
-	//double ra = (double)radius;
-
-	for (double dy = 1; dy <= radius; dy += 1.0) {
-		double dx = floor(sqrt((2.0 * radius * dy) - (dy * dy)));
-
-		SDL_RenderDrawLine(RENDERER(), x - dx, y + dy - radius, x + dx, y + dy - radius);
-		SDL_RenderDrawLine(RENDERER(), x - dx, y - dy + radius, x + dx, y - dy + radius);
-	}
-}
-
-void
-painter_clear(void)
-{
-	SDL_RenderClear(RENDERER());
-}
-
-void
-painter_present(void)
-{
-	SDL_RenderPresent(RENDERER());
-}
--- a/src/core/painter.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-/*
- * painter.h -- basic drawing routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_PAINTER_H
-#define MOLKO_PAINTER_H
-
-/**
- * \file painter.h
- * \brief Basic drawing routines.
- * \ingroup drawing
- */
-
-#include <stdbool.h>
-
-struct texture;
-
-/**
- * Give the current texture being used for rendering, maybe NULL if the
- * rendering is on root.
- *
- * \return Texture or NULL.
- */
-struct texture *
-painter_get_target(void);
-
-/**
- * Set the rendering context to the given texture.
- *
- * Since this function change an internal global variable it is strongly
- * encouraged to store a local backup of the current texture using \a
- * painter_get_target and call this function with it afterwards.
- *
- * If texture is NULL, use default context aka the window.
- *
- * \param tex the texture
- * \see \ref PAINTER_BEGIN
- * \see \ref PAINTER_END
- */
-void
-painter_set_target(struct texture *tex);
-
-/**
- * Get the current drawing color.
- *
- * \return the color in RRGGBBAA format
- */
-unsigned long
-painter_get_color(void);
-
-/**
- * Set the rendering drawing color.
- *
- * \param color in RRGGBBAA format
- */
-void
-painter_set_color(unsigned long color);
-
-/**
- * Draw a line.
- *
- * \param x1 first X coordinate
- * \param y1 first Y coordinate
- * \param x2 second X coordinate
- * \param y2 second Y coordinate
- */
-void
-painter_draw_line(int x1, int y1, int x2, int y2);
-
-/**
- * Draw a pixel point.
- *
- * \param x the X coordinate
- * \param y the Y coordinate
- */
-void
-painter_draw_point(int x, int y);
-
-/**
- * Draw a rectangle
- *
- * \param x the X coordinate
- * \param y the Y coordinate
- * \param w the rectangle width
- * \param h the rectangle height
- */
-void
-painter_draw_rectangle(int x, int y, unsigned int w, unsigned int h);
-
-void
-painter_draw_circle(int x, int y, int radius);
-
-/**
- * Clear the window.
- */
-void
-painter_clear(void);
-
-/**
- * Present the window, only call this function one time in the main loop.
- */
-void
-painter_present(void);
-
-/**
- * Use this macro to start painting on the texture to store the current
- * rendering context and put it back afterwards.
- *
- * \pre tex != NULL
- * \param tex the texture to use
- * \see \ref PAINTER_END
- */
-#define PAINTER_BEGIN(tex    )                                          \
-do {                                                                    \
-        struct texture *__current_texture__;                            \
-                                                                        \
-        __current_texture__ = painter_get_target();                     \
-        painter_set_target((tex))
-
-/**
- * Use this macro at the end of rendering into a given texture.
- *
- * \see \ref PAINTER_BEGIN
- */
-#define PAINTER_END()                                                   \
-        painter_set_target(__current_texture__);                        \
-} while (0)
-
-#endif /* !MOLKO_PAINTER_H */
--- a/src/core/panic.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * panic.c -- unrecoverable error handling
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "error.h"
-#include "panic.h"
-
-static noreturn void
-terminate(void)
-{
-	fprintf(stderr, "abort: %s", error());
-	exit(1);
-}
-
-void (*panic_handler)(void) = terminate;
-
-noreturn void
-panicf(const char *fmt, ...)
-{
-	assert(fmt);
-
-	va_list ap;
-
-	/*
-	 * Store the error before calling panic because va_end would not be
-	 * called.
-	 */
-	va_start(ap, fmt);
-	error_vprintf(fmt, ap);
-	va_end(ap);
-
-	panic();
-}
-
-noreturn void
-vpanicf(const char *fmt, va_list ap)
-{
-	assert(fmt);
-	assert(panic_handler);
-
-	error_vprintf(fmt, ap);
-	panic();
-}
-
-noreturn void
-panic(void)
-{
-	assert(panic_handler);
-
-	panic_handler();
-
-	/*
-	 * This should not happen, if it does it means the user did not fully
-	 * satisfied the constraint of panic_handler.
-	 */
-	fprintf(stderr, "abort: panic handler returned");
-	exit(1);
-}
--- a/src/core/panic.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * panic.h -- unrecoverable error handling
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_PANIC_H
-#define MOLKO_PANIC_H
-
-/**
- * \file panic.h
- * \brief Unrecoverable error handling.
- * \ingroup basics
- *
- * This set of functions should be used to detect runtime errors that are
- * unexpected. They should be used only when the game cannot continue because
- * it is in a unrecoverable state.
- *
- * Examples of appropriate use cases:
- *
- * - Game saved data is corrupt,
- * - Assets are missing,
- * - No more memory.
- *
- * In other contexts, use asserts to indicates programming error and
- * appropriate solutions to recover the game otherwise.
- */
-
-#include <stdarg.h>
-#include <stdnoreturn.h>
-
-#include "plat.h"
-
-/**
- * \brief Global panic handler.
- *
- * The default implementation shows the last error and exit with code 1. The
- * function must not return so you have to implement a setjmp/longjmp or a
- * exception to be thrown.
- *
- * If the user defined function returns, panic routines will finally exit with
- * code 1.
- */
-extern void (*panic_handler)(void);
-
-/**
- * Terminate the program using the \ref panic_handler routine.
- *
- * This function will first set the global error with the provided format
- * string and then call the handler.
- *
- * \pre fmt != NULL
- * \param fmt the printf(3) format string
- */
-noreturn void
-panicf(const char *fmt, ...) PLAT_PRINTF(1, 2);
-
-/**
- * Similar to \ref panicf but with a arguments pointer.
- *
- * \pre fmt != NULL
- * \param fmt the printf(3) format string
- * \param ap the arguments pointer
- */
-noreturn void
-vpanicf(const char *fmt, va_list ap) PLAT_PRINTF(1, 0);
-
-/**
- * Similar to \ref panicf but use last error stored using \ref error.h
- * routines.
- */
-noreturn void
-panic(void);
-
-#endif /* !MOLKO_PANIC_H */
--- a/src/core/plat.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * plat.h -- non-portable platform specific code
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_PLAT_H
-#define MOLKO_PLAT_H
-
-/**
- * \file plat.h
- * \brief Non-portable platform specific code.
- */
-
-/*
- * This block is used for doxygen documentation, the macros here are never
- * exposed.
- */
-#if defined(DOXYGEN)
-
-/**
- * Printf specifier for function supporting the printf(3) syntax. This is
- * currently only supported on GCC/Clang
- */
-#define PLAT_PRINTF(p1, p2)
-
-#else
-
-#if defined(__GNUC__)
-#define PLAT_PRINTF(p1, p2) __attribute__ ((format (printf, p1, p2)))
-#else
-#define PLAT_PRINTF(p1, p2)
-#endif
-
-#endif /* !DOXYGEN  */
-
-#endif /* !MOLKO_PLAT_H */
--- a/src/core/rbuf.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * rbuf.c -- basic utility for reading input buffers
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include "rbuf.h"
-
-void
-rbuf_open(struct rbuf *rb, const void *data, size_t datasz)
-{
-	assert(rb);
-	assert(data);
-
-	rb->s = data;
-	rb->e = rb->s + datasz;
-}
-
-bool
-rbuf_readline(struct rbuf *rb, char *output, size_t outputsz)
-{
-	assert(rb);
-	assert(output);
-	assert(outputsz > 0);
-
-	if (rb->s == rb->e)
-		return false;
-
-	for (--outputsz; rb->s != rb->e && *rb->s != '\n' && outputsz; outputsz--)
-		*output++ = *rb->s++;
-
-	/* Not enough space? */
-	if (!outputsz && rb->s != rb->e && *rb->s != '\n')
-		return false;
-
-	/* Remove this '\n' if still present. */
-	if (rb->s != rb->e && *rb->s == '\n')
-		rb->s++;
-
-	*output = '\0';
-
-	return true;
-}
--- a/src/core/rbuf.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * rbuf.h -- basic utility for reading input buffers
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_RBUF_H
-#define MOLKO_RBUF_H
-
-/**
- * \file rbuf.h
- * \brief Basic utility for reading input buffers.
- */
-
-#include <stdbool.h>
-#include <stddef.h>
-
-/**
- * \brief Input object to store progression.
- */
-struct rbuf {
-	const char *s;  /*!< (RO) Pointer to current character. */
-	const char *e;  /*!< (RO) Pointer to end of array. */
-};
-
-/**
- * Open this input buffer.
- *
- * \pre rb != NULL
- * \pre data != NULL
- * \param rb the input object
- * \param data the data to read
- * \param datasz the size of buffer
- */
-void
-rbuf_open(struct rbuf *rb, const void *data, size_t datasz);
-
-/**
- * Read the next line from the input.
- *
- * This function writes at most outputsz - 1 and is always NULL terminated
- * unless the function returns false which indicates either end of buffer or
- * too small output size.
- *
- * Example of use (`some_data` is assumed to be a buffer).
- *
- * \code
- * struct rbuf rb;
- * char line[1024];
- *
- * rbuf_open(&rb, some_data, sizeof (some_data));
- *
- * while (rbuf_readline(&rb, line, sizeof (line))) {
- *     printf("line contents: >[%s]<\n", line);
- * }
- * \endcode
- *
- * \pre rb != NULL
- * \pre output != NULL
- * \pre outputsz > 0
- * \param rb the input object
- * \param output the output buffer
- * \param outputsz the output buffer size
- * \return true if a line was read correctly
- */
-bool
-rbuf_readline(struct rbuf *rb, char *output, size_t outputsz);
-
-#endif /* !MOLKO_RBUF_H */
--- a/src/core/save.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,214 +0,0 @@
-/*
- * save.c -- save functions
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <sqlite3.h>
-
-#include "error.h"
-#include "save.h"
-#include "sys.h"
-
-static sqlite3 *db;
-
-static const char *sinit =
-	"BEGIN EXCLUSIVE TRANSACTION;"
-	""
-	"CREATE TABLE IF NOT EXISTS property("
-	"  id INTEGER PRIMARY KEY AUTOINCREMENT,"
-	"  key TEXT NOT NULL UNIQUE,"
-	"  value TEXT NOT NULL"
-	");"
-	""
-	"COMMIT"
-;
-
-static const char *sbegin =
-	"BEGIN EXCLUSIVE TRANSACTION"
-;
-
-static const char *scommit =
-	"COMMIT"
-;
-
-static const char *srollback =
-	"ROLLBACK"
-;
-
-static const char *sset_property =
-	"INSERT OR REPLACE INTO property("
-	"  key,"
-	"  value"
-	")"
-	"VALUES("
-	"  ?,"
-	"  ?"
-	");"
-;
-
-static const char *sget_property =
-	"SELECT value"
-	"  FROM property"
-	" WHERE key = ?"
-;
-
-static const char *sremove_property =
-	"DELETE"
-	"  FROM property"
-	" WHERE key = ?"
-;
-
-static bool
-exec(const char *sql)
-{
-	if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK)
-		return error_printf("%s", sqlite3_errmsg(db));
-
-	return true;
-}
-
-bool
-save_open(unsigned int idx)
-{
-	return save_open_path(sys_savepath(idx));
-}
-
-bool
-save_open_path(const char *path)
-{
-	assert(path);
-
-	if (sqlite3_open(path, &db) != SQLITE_OK)
-		return error_printf("database open error: %s", sqlite3_errmsg(db));
-	if (sqlite3_exec(db, sinit, NULL, NULL, NULL) != SQLITE_OK)
-		return error_printf("database init error: %s", sqlite3_errmsg(db));
-
-	return true;
-}
-
-bool
-save_set_property(const char *key, const char *value)
-{
-	assert(key);
-	assert(value && strlen(value) <= SAVE_PROPERTY_VALUE_MAX);
-
-	sqlite3_stmt *stmt = NULL;
-
-	if (!exec(sbegin))
-		return false;
-	if (sqlite3_prepare(db, sset_property, -1, &stmt, NULL) != SQLITE_OK)
-		goto sqlite3_err;
-	if (sqlite3_bind_text(stmt, 1, key, -1, NULL) != SQLITE_OK ||
-	    sqlite3_bind_text(stmt, 2, value, -1, NULL) != SQLITE_OK)
-		goto sqlite3_err;
-	if (sqlite3_step(stmt) != SQLITE_DONE)
-		goto sqlite3_err;
-
-	sqlite3_finalize(stmt);
-
-	return exec(scommit);
-
-sqlite3_err:
-	if (stmt) {
-		sqlite3_finalize(stmt);
-		exec(srollback);
-	}
-
-	return error_printf("%s", sqlite3_errmsg(db));
-}
-
-const char *
-save_get_property(const char *key)
-{
-	assert(key);
-
-	static char value[SAVE_PROPERTY_VALUE_MAX + 1];
-	const char *ret = value;
-	sqlite3_stmt *stmt = NULL;
-
-	memset(value, 0, sizeof (value));
-
-	if (sqlite3_prepare(db, sget_property, -1, &stmt, NULL) != SQLITE_OK)
-		goto sqlite3_err;
-	if (sqlite3_bind_text(stmt, 1, key, -1, NULL) != SQLITE_OK)
-		goto sqlite3_err;
-
-	switch (sqlite3_step(stmt)) {
-	case SQLITE_DONE:
-		/* Not found. */
-		ret = NULL;
-		break;
-	case SQLITE_ROW:
-		/* Found. */
-		snprintf(value, sizeof (value), "%s", sqlite3_column_text(stmt, 0));
-		break;
-	default:
-		/* Error. */
-		goto sqlite3_err;
-	}
-
-	sqlite3_finalize(stmt);
-
-	return ret;
-
-sqlite3_err:
-	if (stmt)
-		sqlite3_finalize(stmt);
-
-	error_printf("%s", sqlite3_errmsg(db));
-
-	return NULL;
-}
-
-bool
-save_remove_property(const char *key)
-{
-	assert(key);
-
-	sqlite3_stmt *stmt = NULL;
-
-	if (!exec(sbegin))
-		return false;
-	if (sqlite3_prepare(db, sremove_property, -1, &stmt, NULL) != SQLITE_OK)
-		goto sqlite3_err;
-	if (sqlite3_bind_text(stmt, 1, key, -1, NULL) != SQLITE_OK)
-		goto sqlite3_err;
-	if (sqlite3_step(stmt) != SQLITE_DONE)
-		goto sqlite3_err;
-
-	sqlite3_finalize(stmt);
-
-	return exec(scommit);
-
-sqlite3_err:
-	if (stmt)
-		sqlite3_finalize(stmt);
-
-	error_printf("%s", sqlite3_errmsg(db));
-
-	return false;
-}
-
-void
-save_finish(void)
-{
-	if (db)
-		sqlite3_close(db);
-}
--- a/src/core/save.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/*
- * save.h -- save functions
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_SAVE_H
-#define MOLKO_SAVE_H
-
-/**
- * \file save.h
- * \brief Save functions.
- */
-
-#include <stdbool.h>
-
-/**
- * \brief Max property value.
- */
-#define SAVE_PROPERTY_VALUE_MAX 1024
-
-/**
- * Open a database by index.
- *
- * This function use the preferred path to store local files under the user
- * home directory. The parameter idx specifies the save slot to use.
- *
- * \param idx the save slot
- * \return false on error
- */
-bool
-save_open(unsigned int idx);
-
-/**
- * Open the save slot specified by path.
- *
- * \pre path != NULL
- * \param path the path to the save slot
- * \return false on error
- */
-bool
-save_open_path(const char *path);
-
-/**
- * Sets an arbitrary property.
- *
- * If the property already exists, replace it.
- *
- * \pre key != NULL
- * \pre value != NULL && strlen(value) <= SAVE_PROPERTY_VALUE_MAX
- * \param key the property key
- * \param value the property value
- */
-bool
-save_set_property(const char *key, const char *value);
-
-/**
- * Get a property.
- *
- * \pre key != NULL
- * \param key the property key
- * \return the key or NULL if not found
- */
-const char *
-save_get_property(const char *key);
-
-/**
- * Remove a property.
- *
- * \pre key != NULL
- * \param key the property key
- * \return false on error
- */
-bool
-save_remove_property(const char *key);
-
-/**
- * Close the save slot.
- */
-void
-save_finish(void);
-
-#endif /* !MOLKO_SAVE_H */
--- a/src/core/script.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/*
- * script.c -- convenient sequence of actions
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "script.h"
-#include "util.h"
-
-static void
-script_action_finish(struct action *a)
-{
-	assert(a);
-
-	script_finish(a->data);
-	free(a->data);
-}
-
-static void
-script_action_handle(struct action *a, const union event *ev)
-{
-	assert(a);
-	assert(ev);
-
-	script_handle(a->data, ev);
-}
-
-static bool
-script_action_update(struct action *a, unsigned int ticks)
-{
-	assert(a);
-
-	return script_update(a->data, ticks);
-}
-
-static void
-script_action_draw(struct action *a)
-{
-	assert(a);
-
-	script_draw(a->data);
-}
-
-void
-script_init(struct script *s)
-{
-	assert(s);
-
-	memset(s, 0, sizeof (struct script));
-	s->tail = &s->head;
-}
-
-void
-script_start(struct script *s)
-{
-	assert(s);
-
-	s->iter = s->head;
-}
-
-void
-script_append(struct script *s, const struct action *a)
-{
-	assert(s);
-	assert(a);
-	assert(a->update);
-
-	struct script_action *iter = ecalloc(1, sizeof (struct script_action));
-
-	memcpy(&iter->action, a, sizeof (struct action));
-	*s->tail = iter;
-	s->tail = &iter->next;
-}
-
-void
-script_handle(struct script *s, const union event *ev)
-{
-	assert(s);
-	assert(ev);
-
-	if (s->iter && s->iter->action.handle)
-		s->iter->action.handle(&s->iter->action, ev);
-}
-
-bool
-script_update(struct script *s, unsigned int ticks)
-{
-	assert(s);
-
-	if (!s->iter)
-		return true;
-
-	struct action *a = &s->iter->action;
-
-	if (a->update(a, ticks)) {
-		if (a->end)
-			a->end(a);
-		if (a->finish)
-			a->finish(a);
-
-		s->iter = s->iter->next;
-	}
-
-	return s->iter == NULL;
-}
-
-void
-script_draw(struct script *s)
-{
-	assert(s);
-
-	if (s->iter && s->iter->action.draw)
-		s->iter->action.draw(&s->iter->action);
-}
-
-void
-script_action(const struct script *s, struct action *action)
-{
-	assert(s);
-	assert(action);
-
-	memset(action, 0, sizeof (struct action));
-	action->data = ememdup(s, sizeof (struct script));
-	action->handle = script_action_handle;
-	action->update = script_action_update;
-	action->draw = script_action_draw;
-	action->finish = script_action_finish;
-}
-
-void
-script_finish(struct script *s)
-{
-	assert(s);
-
-	struct script_action *iter, *next;
-
-	for (iter = s->head; iter; iter = next) {
-		next = iter->next;
-		free(iter);
-	}
-
-	memset(s, 0, sizeof (struct script));
-}
--- a/src/core/script.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * script.h -- convenient sequence of actions
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_SCRIPT_H
-#define MOLKO_SCRIPT_H
-
-/**
- * \file script.h
- * \brief Convenient sequence of actions.
- * \ingroup actions
- *
- * Those routines wrap individual actions into a sequence of actions into an
- * action itself.
- *
- * This is convenient for scenarios where you need to specify several
- * sequential actions that neet to wait before continuing.
- *
- * In a nutshell, to write a scenario you should:
- *
- * 1. Create a script with see \ref script_init,
- * 2. Create one or more actions and append with \ref script_append,
- * 3. Start the action using \ref script_start,
- * 4. Put the script into the game using \ref game_add_action.
- *
- * \warning You must always call \ref script_init before using this object.
- */
-
-#include <stdbool.h>
-
-#include "action.h"
-
-union event;
-
-/**
- * \brief Single-linked list of actions.
- */
-struct script_action {
-	struct action action;           /*!< (RW) Action to use */
-	struct script_action *next;     /*!< (RO) Pointer to next action */
-};
-
-/**
- * \brief Sequence of actions and state holder.
- */
-struct script {
-	struct script_action *iter;     /*!< (RO) Current action */
-	struct script_action *head;     /*!< (RO) Beginning */
-	struct script_action **tail;    /*!< (RO) Pointer to add to tail */
-};
-
-/**
- * Initialize a script.
- *
- * This is mandatory before using any functions, do not zero-initialize the
- * structure yourself.
- *
- * \pre s != NULL
- * \param s the script
- */
-void
-script_init(struct script *s);
-
-/**
- * Call this function before putting the script in the game.
- *
- * \pre s != NULL
- * \param s the script
- */
-void
-script_start(struct script *s);
-
-/**
- * Append a new action to the script.
- *
- * The action is copied into the script and does not need to be allocated on
- * the heap.
- *
- * The action can be empty but must have at least update member set.
- *
- * \pre s != NULL
- * \pre a != NULL && a->update
- * \param s the script
- * \param a the action to copy
- */
-void
-script_append(struct script *s, const struct action *a);
-
-/**
- * Handle the event into the current action.
- *
- * \pre s != NULL
- * \pre ev != NULL
- * \param s the script
- * \param ev the event
- * \note You usually don't need to call this yourself.
- */
-void
-script_handle(struct script *s, const union event *ev);
-
-/**
- * Update the current action.
- *
- * \pre s != NULL
- * \param s the script
- * \param ticks the number of milliseconds since last frame
- * \note You usually don't need to call this yourself.
- */
-bool
-script_update(struct script *s, unsigned int ticks);
-
-/**
- * Draw the current action.
- *
- * \pre s != NULL
- * \param s the script
- * \note You usually don't need to call this yourself.
- */
-void
-script_draw(struct script *s);
-
-/**
- * Create an action from the script for use into the game.
- *
- * This function is meant to transform the script into an action itself and be
- * added to the game using \ref game_add_action.
- *
- * \pre s != NULL
- * \pre dst != NULL
- * \param s the script
- * \param dst the action to build with the script
- */
-void
-script_action(const struct script *s, struct action *dst);
-
-/**
- * Destroy all the actions into the script.
- *
- * \pre s != NULL
- * \param s the script
- * \note You usually don't need to call this yourself.
- */
-void
-script_finish(struct script *s);
-
-#endif /* !MOLKO_SCRIPT_H */
--- a/src/core/sound.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * sound.c -- sound support
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdio.h>
-
-#include <SDL_mixer.h>
-
-#include "sound.h"
-#include "error_p.h"
-
-bool
-sound_open(struct sound *snd, const char *path)
-{
-	assert(snd);
-	assert(path);
-
-	if (!(snd->handle = Mix_LoadMUS(path)))
-		return error_sdl();
-
-	return true;
-}
-
-bool
-sound_openmem(struct sound *snd, const void *buffer, size_t buffersz)
-{
-	assert(snd);
-	assert(buffer);
-
-	SDL_RWops *ops;
-
-	if (!(ops = SDL_RWFromConstMem(buffer, buffersz)) ||
-	    !(snd->handle = Mix_LoadMUS_RW(ops, true)))
-		return error_sdl();
-
-	return true;
-}
-
-bool
-sound_play(struct sound *snd)
-{
-	assert(snd);
-
-	int n = 1;
-
-	if (snd->flags & SOUND_LOOP)
-		n = -1;
-	if (Mix_PlayMusic(snd->handle, n) < 0)
-		return error_sdl();
-
-	return true;
-}
-
-void
-sound_pause(struct sound *snd)
-{
-	/* Not needed yet. */
-	(void)snd;
-
-	Mix_PauseMusic();
-}
-
-void
-sound_resume(struct sound *snd)
-{
-	/* Not needed yet. */
-	(void)snd;
-
-	Mix_ResumeMusic();
-}
-
-void
-sound_stop(struct sound *snd)
-{
-	/* Not needed yet. */
-	(void)snd;
-
-	Mix_HaltMusic();
-}
-
-void
-sound_finish(struct sound *snd)
-{
-	assert(snd);
-
-	if (snd->handle) {
-		Mix_HaltMusic();
-		Mix_FreeMusic(snd->handle);
-	}
-
-	memset(snd, 0, sizeof (*snd));
-}
--- a/src/core/sound.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-/*
- * sound.h -- sound support
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_SOUND_H
-#define MOLKO_SOUND_H
-
-/**
- * \file sound.h
- * \brief Sound support.
- */
-
-#include <stdbool.h>
-#include <stddef.h>
-
-/**
- * \brief Sound flags.
- */
-enum sound_flags {
-	SOUND_NONE,                     /*!< No flags. */
-	SOUND_LOOP      = (1 << 0)      /*!< Loop the music. */
-};
-
-/**
- * \brief Sound chunk.
- */
-struct sound {
-	enum sound_flags flags;         /*!< (RW) Flags. */
-	void *handle;                   /*!< (RO) Native handle. */
-};
-
-/**
- * Open a sound audio file.
- *
- * \pre snd != NULL
- * \pre path != NULL
- * \param snd the sound object to initialize
- * \param path the path to the audio file
- * \return False on errors.
- */
-bool
-sound_open(struct sound *snd, const char *path);
-
-/**
- * Open a sound audio from a buffer.
- *
- * \pre snd != NULL
- * \pre buffer != NULL
- * \param snd the sound object to initialize
- * \param buffer the buffer
- * \param buffersz the buffer size
- * \return False on errors.
- * \warning The buffer must exists until the sound object is closed.
- */
-bool
-sound_openmem(struct sound *snd, const void *buffer, size_t buffersz);
-
-/**
- * Start playing the sound.
- *
- * This function will resume the playback since the beginning.
- *
- * \pre snd != NULL
- * \param snd the sound object
- * \return False on errors.
- */
-bool
-sound_play(struct sound *snd);
-
-/**
- * Pause the sound music.
- *
- * \pre snd != NULL
- * \param snd the sound object
- */
-void
-sound_pause(struct sound *snd);
-
-/**
- * Resume the sound music.
- *
- * \pre snd != NULL
- * \param snd the sound object
- */
-void
-sound_resume(struct sound *snd);
-
-/**
- * Stop the sound music.
- *
- * \pre snd != NULL
- * \param snd the sound object
- */
-void
-sound_stop(struct sound *snd);
-
-/**
- * Close the associated resources.
- *
- * \pre snd != NULL
- * \param snd the sound object
- */
-void
-sound_finish(struct sound *snd);
-
-#endif /* !MOLKO_SOUND_H */
--- a/src/core/sprite.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * sprite.c -- image sprites
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include "sprite.h"
-#include "texture.h"
-
-void
-sprite_init(struct sprite *sprite,
-            struct texture *tex,
-            unsigned int cellw,
-            unsigned int cellh)
-{
-	assert(sprite);
-	assert(tex && texture_ok(tex));
-
-	sprite->texture = tex;
-	sprite->cellw = cellw;
-	sprite->cellh = cellh;
-	sprite->nrows = tex->h / cellh;
-	sprite->ncols = tex->w / cellw;
-}
-
-void
-sprite_draw(struct sprite *sprite, unsigned int r, unsigned int c, int x, int y)
-{
-	assert(sprite);
-
-	texture_scale(
-		sprite->texture,
-		c * sprite->cellw,      /* src y */
-		r * sprite->cellh,      /* src x */
-		sprite->cellw,          /* src width */
-		sprite->cellh,          /* src height */
-		x,                      /* dst x */
-		y,                      /* dst y */
-		sprite->cellw,          /* dst width */
-		sprite->cellh,          /* dst height */
-		0.0                     /* angle */
-	);
-}
--- a/src/core/sprite.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * sprite.h -- image sprites
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_SPRITE_H
-#define MOLKO_SPRITE_H
-
-/**
- * \file sprite.h
- * \brief Image sprites.
- * \ingroup drawing
- */
-
-struct texture;
-
-/**
- * \brief Sprite structure.
- */
-struct sprite {
-	struct texture *texture;        /*!< Texture to access (RO) */
-	unsigned int cellw;             /*!< Width per cell (RW) */
-	unsigned int cellh;             /*!< Height per cell (RW) */
-	unsigned int nrows;             /*!< Number of rows (RW) */
-	unsigned int ncols;             /*!< Number of columns (RW) */
-};
-
-/**
- * Initialize a sprite.
- *
- * The sprite does not take ownership of texture and must be valid until the
- * sprite is no longer used.
- *
- * This function is only provided as convenience, user may initialize the
- * sprite by itself if wanted.
- *
- * The fields `nrows' and `ncols' will be determined automatically from the
- * texture size.
- *
- * \pre sprite != NULL
- * \pre tex != NULL && texture_ok(tex)
- * \param sprite the sprite to initialize
- * \param tex the texture
- * \param cellw the width per cell in pixels
- * \param cellh the height per cell in pixels
- */
-void
-sprite_init(struct sprite *sprite,
-            struct texture *tex,
-            unsigned int cellw,
-            unsigned int cellh);
-
-/**
- * Draw the sprite component from row `r' and column `c'.
- *
- * \pre sprite != NULL
- * \param sprite the sprite to draw
- * \param r the row number
- * \param c the column number
- * \param x the X destination
- * \param y the Y destination
- * \warning No bounds checking
- */
-void
-sprite_draw(struct sprite *sprite, unsigned int r, unsigned int c, int x, int y);
-
-#endif /* !MOLKO_SPRITE_H */
--- a/src/core/state.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * state.h -- abstract state
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_STATE_H
-#define MOLKO_STATE_H
-
-/**
- * \file state.h
- * \brief Abstract state.
- * \ingroup states
- */
-
-union event;
-
-/**
- * \brief Abstract state.
- */
-struct state {
-	/**
-	 * This function is called when the state is entered.
-	 */
-	void (*enter)(void);
-
-	/**
-	 * This function is called when the state is about to be left.
-	 */
-	void (*leave)(void);
-
-	/**
-	 * This function is called for each event that happened.
-	 */
-	void (*handle)(const union event *);
-
-	/**
-	 * This function is called to update the game, with the number of
-	 * milliseconds since the last frame.
-	 */
-	void (*update)(unsigned int ticks);
-
-	/**
-	 * This function is supposed to draw the game.
-	 */
-	void (*draw)(void);
-};
-
-#endif /* !MOLKO_STATE_H */
--- a/src/core/sys.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-/*
- * sys.c -- system routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#include <SDL.h>
-#include <SDL_image.h>
-#include <SDL_mixer.h>
-#include <SDL_ttf.h>
-
-#if !defined(_WIN32)            /* Assuming POSIX */
-#	include <sys/types.h>
-#	include <dirent.h>
-#endif
-
-#include "error.h"
-#include "error_p.h"
-#include "sys.h"
-
-#if defined(_WIN32)
-
-static void
-determine(char path[], size_t pathlen)
-{
-	char *base = SDL_GetBasePath();
-
-	/* On Windows, the data hierarchy is the same as the project. */
-	snprintf(path, pathlen, "%sassets", base);
-	SDL_free(base);
-}
-
-#else                           /* Assuming POSIX */
-
-static bool
-is_absolute(const char *path)
-{
-	assert(path);
-
-	return path[0] == '/';
-}
-
-static void
-determine(char path[], size_t pathlen)
-{
-	char localassets[PATH_MAX];
-	char *base = SDL_GetBasePath();
-	DIR *dp;
-
-	/* Try assets directory where executable lives. */
-	snprintf(localassets, sizeof (localassets), "%sassets", base);
-
-	if ((dp = opendir(localassets))) {
-		snprintf(path, pathlen, "%sassets", base);
-		closedir(dp);
-	} else {
-		/* We are not in the project source directory. */
-		if (is_absolute(SHAREDIR)) {
-			/* SHAREDIR is absolute */
-			snprintf(path, pathlen, "%s/molko", SHAREDIR);
-		} else if (is_absolute(BINDIR)) {
-			/* SHAREDIR is relative but BINDIR is absolute */
-			snprintf(path, pathlen, "%s/%s/molko", PREFIX, SHAREDIR);
-		} else {
-			/* SHAREDIR, BINDIR are both relative */
-			char *ptr = strstr(base, BINDIR);
-
-			if (ptr) {
-				*ptr = '\0';
-				snprintf(path, pathlen, "%s%s/molko", base, SHAREDIR);
-			} else {
-				/* Unable to determine. */
-				snprintf(path, pathlen, ".");
-			}
-		}
-	}
-
-	SDL_free(base);
-}
-
-#endif
-
-bool
-sys_init(void)
-{
-#if defined(__MINGW64__)
-	/* On MinGW buffering leads to painful debugging. */
-	setbuf(stderr, NULL);
-	setbuf(stdout, NULL);
-#endif
-
-	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
-		return error_sdl();
-	if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG)
-		return error_sdl();
-	if (TTF_Init() < 0)
-		return error_sdl();
-	if (Mix_Init(MIX_INIT_OGG) != MIX_INIT_OGG)
-		return error_sdl();
-	if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0)
-		return error_sdl();
-
-	return true;
-}
-
-const char *
-sys_datadir(void)
-{
-	static char path[PATH_MAX];
-
-	if (path[0] == '\0')
-		determine(path, sizeof (path));
-
-	return path;
-}
-
-const char *
-sys_datapath(const char *fmt, ...)
-{
-	const char *ret;
-	va_list ap;
-
-	va_start(ap, fmt);
-	ret = sys_datapathv(fmt, ap);
-	va_end(ap);
-
-	return ret;
-}
-
-const char *
-sys_datapathv(const char *fmt, va_list ap)
-{
-	static char path[PATH_MAX];
-	char filename[FILENAME_MAX];
-
-	vsnprintf(filename, sizeof (filename), fmt, ap);
-	snprintf(path, sizeof (path), "%s/%s", sys_datadir(), filename);
-
-	return path;
-}
-
-const char *
-sys_savepath(unsigned int idx)
-{
-	static char path[PATH_MAX];
-	char *pref;
-
-	if ((pref = SDL_GetPrefPath("malikania", "molko"))) {
-		snprintf(path, sizeof (path), "%ssave-%u", pref, idx);
-		SDL_free(pref);
-	} else
-		snprintf(path, sizeof (path), "save-%u", idx);
-
-	return path;
-}
-
-void
-sys_finish(void)
-{
-	Mix_Quit();
-	TTF_Quit();
-	IMG_Quit();
-	SDL_Quit();
-}
--- a/src/core/sys.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * sys.h -- system routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_SYS_H
-#define MOLKO_SYS_H
-
-/**
- * \file sys.h
- * \brief System routines.
- * \ingroup basics
- */
-
-#include <stdarg.h>
-#include <stdbool.h>
-
-/**
- * Initialize the system, should be called in the beginning of the main.
- */
-bool
-sys_init(void);
-
-/**
- * Get the base system directory path.
- *
- * \return the path where the executable lives
- */
-const char *
-sys_datadir(void);
-
-/**
- * Construct path to assets directory using printf-like format.
- *
- * \param fmt the format string
- * \return the path to the file
- * \note This function returns pointer to static string.
- */
-const char *
-sys_datapath(const char *fmt, ...);
-
-/**
- * Similar to \a sys_datapath.
- *
- * \param fmt the format string
- * \param ap the variadic arguments pointer
- * \return the path to the file
- * \note This function returns pointer to static string.
- */
-const char *
-sys_datapathv(const char *fmt, va_list ap);
-
-/**
- * Compute the path to the save file for the given game state.
- *
- * \param idx the save number
- * \return the path to the database file
- * \note This only compute the path, it does not check the presence of the file
- * \post The returned value will never be NULL
- */
-const char *
-sys_savepath(unsigned int idx);
-
-/**
- * Close the system.
- */
-void
-sys_finish(void);
-
-#endif /* !MOLKO_SYS_H */
--- a/src/core/texture.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- * texture.c -- basic texture management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include "error.h"
-#include "error_p.h"
-#include "texture.h"
-#include "texture_p.h"
-#include "util.h"
-#include "window.h"
-#include "window_p.h"
-
-bool
-texture_new(struct texture *tex, unsigned int w, unsigned int h)
-{
-	assert(tex);
-
-	tex->handle = SDL_CreateTexture(RENDERER(),
-	    SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, w, h);
-
-	if (!tex->handle) {
-		tex->w = tex->h = 0;
-		return error_sdl();
-	}
-
-	tex->w = w;
-	tex->h = h;
-
-	return true;
-}
-
-bool
-texture_ok(const struct texture *tex)
-{
-	assert(tex);
-
-	return tex->handle && tex->w && tex->h;
-}
-
-void
-texture_draw(struct texture *tex, int x, int y)
-{
-	assert(tex);
-
-	SDL_Rect dst = {
-		.x = x,
-		.y = y,
-		.w = tex->w,
-		.h = tex->h
-	};
-
-	SDL_RenderCopy(RENDERER(), tex->handle, NULL, &dst);
-}
-
-void
-texture_scale(struct texture *tex,
-              int src_x,
-              int src_y,
-              unsigned src_w,
-              unsigned src_h,
-              int dst_x,
-              int dst_y,
-              unsigned dst_w,
-              unsigned dst_h,
-              double angle)
-{
-	const SDL_Rect src = {
-		.x = src_x,
-		.y = src_y,
-		.w = src_w,
-		.h = src_h
-	};
-	const SDL_Rect dst = {
-		.x = dst_x,
-		.y = dst_y,
-		.w = dst_w,
-		.h = dst_h
-	};
-
-	SDL_RenderCopyEx(RENDERER(), tex->handle, &src, &dst, angle, NULL, SDL_FLIP_NONE);
-}
-
-void
-texture_finish(struct texture *tex)
-{
-	assert(tex);
-
-	if (tex->handle)
-		SDL_DestroyTexture(tex->handle);
-
-	memset(tex, 0, sizeof (*tex));
-}
-
-/* private */
-
-bool
-texture_from_surface(struct texture *tex, SDL_Surface *surface)
-{
-	assert(tex);
-	assert(surface);
-
-	if (!(tex->handle = SDL_CreateTextureFromSurface(RENDERER(), surface))) {
-		tex->w = tex->h = 0;
-		return error_sdl();
-	}
-
-	tex->w = surface->w;
-	tex->h = surface->h;
-
-	return true;
-}
--- a/src/core/texture.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/*
- * texture.h -- basic texture management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_TEXTURE_H
-#define MOLKO_TEXTURE_H
-
-/**
- * \file texture.h
- * \brief Basic texture management.
- * \ingroup drawing
- *
- * See also \a image.h for usage of textures.
- */
-
-#include <stdbool.h>
-
-/**
- * \brief Texture object.
- */
-struct texture {
-	unsigned int w;         /*!< (RO) Texture width. */
-	unsigned int h;         /*!< (RO) Texture height. */
-	void *handle;           /*!< (RO) Native handle. */
-};
-
-/**
- * Create a new texture.
- *
- * \pre tex != NULL
- * \param tex the texture to initialize
- * \param w the width
- * \param h the height
- * \return False on error.
- */
-bool
-texture_new(struct texture *tex, unsigned int w, unsigned int h);
-
-/**
- * Check if the texture is valid.
- *
- * This function simply checks if the texture is initialized and has non-null
- * dimensions.
- *
- * \pre tex != NULL
- * \param tex the texture to check
- * \return True if the texture is initialized
- */
-bool
-texture_ok(const struct texture *tex);
-
-/**
- * Simple texture drawing.
- *
- * \pre tex != NULL
- * \param tex the texture
- * \param x the X coordinate
- * \param y the Y coordinate
- */
-void
-texture_draw(struct texture *tex, int x, int y);
-
-/**
- * Advanced texture drawing.
- *
- * \pre tex != NULL
- * \param tex the texture
- * \param src_x the source rectangle X coordinate
- * \param src_y the source rectangle Y coordinate
- * \param src_w the source rectangle width
- * \param src_h the source rectangle height
- * \param dst_x the destination rectangle X coordinate
- * \param dst_y the destination rectangle Y coordinate
- * \param dst_w the destination rectangle width
- * \param dst_h the destination rectangle height
- * \param angle the angle
- */
-void
-texture_scale(struct texture *tex,
-              int src_x,
-              int src_y,
-              unsigned src_w,
-              unsigned src_h,
-              int dst_x,
-              int dst_y,
-              unsigned dst_w,
-              unsigned dst_h,
-              double angle);
-
-/**
- * Close the texture, do not use afterwards.
- *
- * \pre tex != NULL
- * \param tex the texture
- */
-void
-texture_finish(struct texture *tex);
-
-#endif /* !MOLKO_TEXTURE_H */
--- a/src/core/texture_p.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * texture_p.h -- (PRIVATE) basic texture management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_TEXTURE_P_H
-#define MOLKO_TEXTURE_P_H
-
-#include <stdbool.h>
-
-#include <SDL.h>
-
-struct texture;
-
-bool
-texture_from_surface(struct texture *tex, SDL_Surface *surface);
-
-#endif /* !MOLKO_TEXTURE_P_H */
--- a/src/core/theme.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,254 +0,0 @@
-/*
- * theme.c -- abstract theming
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stddef.h>
-
-#include "button.h"
-#include "checkbox.h"
-#include "font.h"
-#include "frame.h"
-#include "label.h"
-#include "maths.h"
-#include "painter.h"
-#include "panic.h"
-#include "texture.h"
-#include "theme.h"
-#include "util.h"
-
-#include "assets/fonts/ComicNeue-Regular.h"
-
-#define THEME(t) (t ? t : &default_theme)
-
-#define CHECKBOX_W 16
-#define CHECKBOX_H 16
-#define CHECKBOX_RAD 6
-
-static struct font default_font;
-
-static void
-box(int x, int y, unsigned int w, unsigned int h)
-{
-	/* Some basic outlines. */
-	painter_set_color(0x4d3533ff);
-
-	painter_draw_line(x, y, x + w, y);
-	painter_draw_line(x, y + h, x + w, y + h);
-	painter_draw_line(x, y, x, y + h);
-	painter_draw_line(x + w, y, x + w, y + h);
-}
-
-static void
-draw_frame(struct theme *t, const struct frame *frame)
-{
-	if (frame->style == FRAME_STYLE_BOX)
-		painter_set_color(0x6e4c30ff);
-	else
-		painter_set_color(0xce9248ff);
-
-	painter_draw_rectangle(frame->x, frame->y, frame->w, frame->h);
-	box(frame->x, frame->y, frame->w, frame->h);
-}
-
-static void
-draw_label(struct theme *t, const struct label *label)
-{
-	struct texture tex;
-	int x = label->x, y = label->y;
-	int *px = &x, *py = &y;
-
-	if (label->flags & LABEL_NO_HCENTER)
-		px = NULL;
-	if (label->flags & LABEL_NO_VCENTER)
-		py = NULL;
-
-	/* Shadow text, only if enabled. */
-	if (!(label->flags & LABEL_NO_SHADOW)) {
-		t->fonts[THEME_FONT_INTERFACE]->color = t->colors[THEME_COLOR_SHADOW];
-
-		if (!font_render(t->fonts[THEME_FONT_INTERFACE], &tex, label->text))
-			panic();
-
-		maths_centerize(px, py, tex.w, tex.h,
-		    label->x, label->y, label->w, label->h);
-
-		texture_draw(&tex, x + 1, y + 1);
-		texture_finish(&tex);
-	}
-
-	/* Normal text. */
-	t->fonts[THEME_FONT_INTERFACE]->color = label->color
-		? label->color
-		: t->colors[THEME_COLOR_NORMAL];
-
-	if (!font_render(t->fonts[THEME_FONT_INTERFACE], &tex, label->text))
-		panic();
-
-	maths_centerize(px, py, tex.w, tex.h,
-	    label->x, label->y, label->w, label->h);
-
-	texture_draw(&tex, x, y);
-	texture_finish(&tex);
-}
-
-static void
-draw_button(struct theme *t, const struct button *button)
-{
-	struct label label = {
-		.text = button->text,
-		.x = button->x,
-		.y = button->y,
-		.w = button->w,
-		.h = button->h
-	};
-
-	painter_set_color(0xabcdefff);
-	painter_draw_rectangle(button->x, button->y, button->w, button->h);
-
-	label_draw(&label);
-
-	box(button->x, button->y, button->w, button->h);
-}
-
-static void
-draw_checkbox(struct theme *t, const struct checkbox *cb)
-{
-	box(cb->x, cb->y, CHECKBOX_W, CHECKBOX_H);
-
-	if (cb->checked)
-		painter_draw_rectangle(cb->x + 5, cb->y + 5, CHECKBOX_W - 9, CHECKBOX_H - 9);
-
-	if (cb->label) {
-		const unsigned int w = cb->w - (t->padding * 2) - CHECKBOX_W;
-		const int x = cb->x + (t->padding * 2) + CHECKBOX_W;
-
-		struct label label = {
-			.text = cb->label,
-			.flags = LABEL_NO_HCENTER,
-			.x = x,
-			.y = cb->y,
-			.w = w,
-			.h = cb->h
-		};
-
-		draw_label(t, &label);
-	}
-}
-
-/* Default theme. */
-static struct theme default_theme = {
-	.colors = {
-		[THEME_COLOR_NORMAL]    = 0xffffffff,
-		[THEME_COLOR_SELECTED]  = 0x006554ff,
-		[THEME_COLOR_SHADOW]    = 0x000000ff
-	},
-	.padding = 10,
-	.draw_frame = draw_frame,
-	.draw_label = draw_label,
-	.draw_button = draw_button,
-	.draw_checkbox = draw_checkbox
-};
-
-/* Default font catalog. */
-#define FONT(bin, size, index)                                          \
-        { bin, sizeof (bin), size, &default_theme.fonts[index] }
-
-static struct font_catalog {
-	const unsigned char *data;
-	const size_t datasz;
-	unsigned int size;
-	struct font **dest;
-	struct font font;
-} default_fonts[] = {
-	FONT(ComicNeue_Regular, 20, THEME_FONT_INTERFACE)
-};
-
-bool
-theme_init(void)
-{
-	/* Open all fonts. */
-	for (size_t i = 0; i < NELEM(default_fonts); ++i) {
-		struct font_catalog *fc = &default_fonts[i];
-
-		if (!font_openmem(&fc->font, fc->data, fc->datasz, fc->size))
-			goto failed;
-
-		/* Reference this font into the catalog. */
-		*default_fonts[i].dest = &default_fonts[i].font;
-	}
-
-	return true;
-
-failed:
-	theme_finish();
-
-	return false;
-}
-
-struct theme *
-theme_default(void)
-{
-	return &default_theme;
-}
-
-unsigned int
-theme_padding(const struct theme *t)
-{
-	return THEME(t)->padding;
-}
-
-void
-theme_draw_frame(struct theme *t, const struct frame *frame)
-{
-	assert(frame);
-
-	THEME(t)->draw_frame(THEME(t), frame);
-}
-
-void
-theme_draw_label(struct theme *t, const struct label *label)
-{
-	assert(label);
-
-	THEME(t)->draw_label(THEME(t), label);
-}
-
-void
-theme_draw_button(struct theme *t, const struct button *button)
-{
-	assert(button);
-
-	THEME(t)->draw_button(THEME(t), button);
-}
-
-void
-theme_draw_checkbox(struct theme *t, const struct checkbox *cb)
-{
-	assert(cb);
-
-	THEME(t)->draw_checkbox(THEME(t), cb);
-}
-
-void
-theme_finish(void)
-{
-	for (size_t i = 0; i < NELEM(default_fonts); ++i) {
-		font_finish(&default_fonts[i].font);
-		*default_fonts[i].dest = NULL;
-	}
-}
--- a/src/core/theme.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-/*
- * theme.h -- abstract theming
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_THEME_H
-#define MOLKO_THEME_H
-
-/**
- * \file theme.h
- * \brief Abstract theming.
- */
-
-#include <stdbool.h>
-
-struct checkbox;
-struct button;
-struct font;
-struct frame;
-struct label;
-
-/**
- * \brief Font component.
- */
-enum theme_font {
-	THEME_FONT_INTERFACE,   /*!< Font for interface elements. */
-	THEME_FONT_LAST         /*!< Unused. */
-};
-
-/**
- * \brief Theme colors.
- */
-enum theme_color {
-	THEME_COLOR_NORMAL,     /*!< Normal font color. */
-	THEME_COLOR_SELECTED,   /*!< Font color for selected elements. */
-	THEME_COLOR_SHADOW,     /*!< Shadow color. */
-	THEME_COLOR_LAST        /*!< Unused. */
-};
-
-/**
- * \brief Abstract theme structure.
- */
-struct theme {
-	/**
-	 * (RW, ref) Fonts catalog.
-	 */
-	struct font *fonts[THEME_FONT_LAST];
-
-	/**
-	 * (RW) Miscellaneous colors.
-	 */
-	unsigned long colors[THEME_COLOR_LAST];
-
-	/**
-	 * (RW) Padding between GUI elements.
-	 */
-	unsigned int padding;
-
-	/**
-	 * Draw a frame.
-	 *
-	 * This function is used to draw a box usually as a container where UI
-	 * elements will be put.
-	 *
-	 * \see \ref theme_draw_frame
-	 */
-	void (*draw_frame)(struct theme *, const struct frame *);
-
-	/**
-	 * Draw a label.
-	 *
-	 * \see \ref theme_draw_label
-	 */
-	void (*draw_label)(struct theme *, const struct label *);
-
-	/**
-	 * Draw a button.
-	 *
-	 * \see \ref theme_draw_button
-	 */
-	void (*draw_button)(struct theme *, const struct button *);
-
-	/**
-	 * Draw a checkbox.
-	 *
-	 * \see \ref theme_draw_button
-	 */
-	void (*draw_checkbox)(struct theme *t, const struct checkbox *);
-};
-
-/**
- * Initialize the theming system.
- *
- * \return false on errors
- * \warning This function must be called before any other theme functions.
- */
-bool
-theme_init(void);
-
-/**
- * Get a reference to the default theme.
- *
- * \return A non-owning pointer to a static storage for the default theme
- */
-struct theme *
-theme_default(void);
-
-/**
- * Get the desired padding between GUI elements.
- *
- * \param t the theme to use (may be NULL)
- * \return the padding in pixels
- */
-unsigned int
-theme_padding(const struct theme *t);
-
-/**
- * Draw a frame.
- *
- * \pre frame != NULL
- * \param t the theme to use (may be NULL)
- * \param frame the frame
- */
-void
-theme_draw_frame(struct theme *t, const struct frame *frame);
-
-/**
- * Draw a label.
- *
- * \pre label != NULL
- * \param t the theme to use (may be NULL)
- * \param label the label
- */
-void
-theme_draw_label(struct theme *t, const struct label *label);
-
-/**
- * Draw a button.
- *
- * \pre button != NULL
- * \param t the theme to use (may be NULL)
- * \param button the button
- */
-void
-theme_draw_button(struct theme *t, const struct button *button);
-
-/**
- * Draw a checkbox.
- *
- * \param t the theme to use (may be NULL)
- * \param cb the checkbox
- */
-void
-theme_draw_checkbox(struct theme *t, const struct checkbox *cb);
-
-/**
- * Close associated resources.
- */
-void
-theme_finish(void);
-
-#endif /* !MOLKO_THEME_H */
--- a/src/core/util.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * util.c -- utilities
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <SDL.h>
-
-#include "panic.h"
-#include "util.h"
-
-void *
-emalloc(size_t size)
-{
-	void *mem;
-
-	if (!(mem = malloc(size)))
-		panicf("%s", strerror(errno));
-
-	return mem;
-}
-
-void *
-ecalloc(size_t n, size_t size)
-{
-	void *mem;
-
-	if (!(mem = calloc(n, size)))
-		panicf("%s", strerror(errno));
-
-	return mem;
-}
-
-void *
-ememdup(const void *ptr, size_t size)
-{
-	void *mem;
-
-	if (!(mem = malloc(size)))
-		panicf("%s", strerror(errno));
-
-	return memcpy(mem, ptr, size);
-}
-
-char *
-eprintf(const char *fmt, ...)
-{
-	assert(fmt);
-
-	va_list ap;
-	char *ret;
-
-	va_start(ap, fmt);
-	ret = evprintf(fmt, ap);
-	va_end(ap);
-
-	return ret;
-}
-
-char *
-evprintf(const char *fmt, va_list args)
-{
-	assert(fmt);
-
-	va_list ap;
-	int size;
-	char *ret;
-
-	/* Count number of bytes required. */
-	va_copy(ap, args);
-
-	if ((size = vsnprintf(NULL, 0, fmt, ap)) < 0)
-		panicf("%s", strerror(errno));
-
-	/* Do actual copy. */
-	ret = emalloc(size + 1);
-	va_copy(ap, args);
-
-	if (vsnprintf(ret, size, fmt, ap) != size) {
-		free(ret);
-		panicf("%s", strerror(errno));
-	}
-
-	return ret;
-}
-
-void
-delay(unsigned int ms)
-{
-	SDL_Delay(ms);
-}
--- a/src/core/util.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/*
- * util.h -- utilities
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_UTIL_H
-#define MOLKO_UTIL_H
-
-/**
- * \file util.h
- * \brief Utilities.
- * \ingroup basics
- *
- * This file contains several utilities.
- *
- * \note In contrast to other files, identifiers are not prefixed with `util_`
- *       for convenience.
- */
-
-#include <stdarg.h>
-#include <stddef.h>
-
-#include "plat.h"
-
-/**
- * Get the number of elements in a static array.
- *
- * \param x the array
- * \return the number of elements
- */
-#define NELEM(x) sizeof ((x)) / sizeof ((x)[0])
-
-/**
- * Wrapper around malloc(3) that exits on allocation failure.
- *
- * \param size the size
- * \return a pointer
- * \post returned pointer will never be NULL
- */
-void *
-emalloc(size_t size);
-
-/**
- * Wrapper around calloc(3) that exits on allocation failure.
- *
- * \param n the number of objects to allocate
- * \param size the size per n
- * \return a pointer
- * \post returned pointer will never be NULL
- */
-void *
-ecalloc(size_t n, size_t size);
-
-/**
- * Copy the region specified by ptr.
- *
- * \pre ptr != NULL
- * \param ptr the pointer
- * \param size the size of the memory to copy
- * \return a pointer
- * \post returned pointer will never be NULL
- */
-void *
-ememdup(const void *ptr, size_t size);
-
-/**
- * Create a dynamically allocated string in the printf(3) format string.
- *
- * \pre fmt != NULL
- * \return The heap allocated string.
- * \post Returned string will never be NULL.
- */
-char *
-eprintf(const char *fmt, ...) PLAT_PRINTF(1, 2);
-
-/**
- * Similar to \ref eprintf with arguments pointer.
- *
- * \copydoc eprintf
- */
-char *
-evprintf(const char *fmt, va_list ap) PLAT_PRINTF(1, 0);
-
-/**
- * Put the thread to sleep for a given amount of milliseconds.
- *
- * \param ms the number of milliseconds to wait
- */
-void
-delay(unsigned int ms);
-
-#endif /* !MOLKO_UTIL_H */
--- a/src/core/wait.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * wait.c -- wait action
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "action.h"
-#include "wait.h"
-#include "util.h"
-
-static bool
-action_update(struct action *a, unsigned int ticks)
-{
-	assert(a);
-
-	return wait_update(a->data, ticks);
-}
-
-static void
-action_finish(struct action *a)
-{
-	assert(a);
-
-	free(a->data);
-}
-
-void
-wait_start(struct wait *w)
-{
-	assert(w);
-	w->elapsed = 0u;
-}
-
-bool
-wait_update(struct wait *w, unsigned int ticks)
-{
-	assert(w);
-
-	w->elapsed += ticks;
-
-	if (w->elapsed >= w->delay)
-		w->elapsed = w->delay;
-
-	return w->elapsed >= w->delay;
-}
-
-void
-wait_action(const struct wait *w, struct action *a)
-{
-	assert(w);
-	assert(a);
-
-	memset(a, 0, sizeof (struct action));
-	a->data = ememdup(w, sizeof (struct wait));
-	a->update = action_update;
-	a->finish = action_finish;
-}
--- a/src/core/wait.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * wait.h -- wait action
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_WAIT_H
-#define MOLKO_WAIT_H
-
-/**
- * \file wait.h
- * \brief Wait action.
- * \ingroup actions
- *
- * This module is meant to create a delayed action.
- *
- * Combined with \ref script.h, you can create a sequence of actions with
- * delays between each.
- *
- * \code
- * struct script script;
- * struct action action;
- *
- * // Prepare the script.
- * script_init(&script);
- *
- * // Add some actions to script using script_append.
- * // ...
- *
- * // Wait one second delay before next action.
- * wait_action(&(struct wait) { .delay = 1000 }, &action);
- * script_append(&script, &action);
- *
- * // Add more actions after this delay.
- * // ...
- * \endcode
- */
-
-#include <stdbool.h>
-
-struct action;
-
-/**
- * \brief Wait action.
- */
-struct wait {
-	unsigned int delay;             /*!< (RW) Time to wait in milliseconds */
-	unsigned int elapsed;           /*!< (RO) Elapsed time */
-};
-
-/**
- * Start the wait action.
- *
- * This function is equivalent to `w->elapsed = 0`;
- *
- * \pre w != NULL
- * \param w the wait object
- */
-void
-wait_start(struct wait *w);
-
-/**
- * Update the wait object.
- *
- * \pre w != NULL
- * \param w the wait object
- * \param ticks the number of milliseconds since last frame
- * \return true if complete
- */
-bool
-wait_update(struct wait *w, unsigned int ticks);
-
-/**
- * Create an action from the wait object.
- *
- * \pre w != NULL
- * \pre a != NULL
- * \param w the wait object to copy from
- * \param a the action to fill
- */
-void
-wait_action(const struct wait *w, struct action *a);
-
-#endif /* !MOLKO_WAIT_H */
--- a/src/core/walksprite.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * walksprite.c -- sprite designed for walking entities
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <string.h>
-
-#include "walksprite.h"
-#include "sprite.h"
-
-void
-walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay)
-{
-	assert(ws);
-	assert(sprite);
-
-	memset(ws, 0, sizeof (struct walksprite));
-	ws->sprite = sprite;
-	ws->delay = delay;
-}
-
-void
-walksprite_update(struct walksprite *ws, unsigned int ticks)
-{
-	assert(ws);
-
-	ws->elapsed += ticks;
-
-	if (ws->elapsed >= ws->delay) {
-		ws->index += 1;
-
-		if (ws->index >= ws->sprite->ncols)
-			ws->index = 0;
-
-		ws->elapsed = 0;
-	}
-}
-
-void
-walksprite_draw(struct walksprite *ws, unsigned int orientation, int x, int y)
-{
-	assert(ws);
-	assert(orientation < 8);
-
-	sprite_draw(ws->sprite, orientation, ws->index, x, y);
-}
--- a/src/core/walksprite.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * walksprite.h -- sprite designed for walking entities
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_WALKSPRITE_H
-#define MOLKO_WALKSPRITE_H
-
-/**
- * \file walksprite.h
- * \brief Sprite designed for walking entities.
- * \ingroup drawing
- */
-
-struct sprite;
-
-/**
- * \brief Sprite designed for walking entities.
- *
- * This structure works with sprite images that are defined as using the
- * following conventions:
- *
- * ```
- * 7   0   1
- *   ↖ ↑ ↗
- * 6 ←   → 2
- *   ↙ ↓ ↘
- * 5   4   3
- * ```
- *
- * Where numbers define row in the sprite according to the character
- * orientation. In other terms, your image sprite should look like this:
- *
- * ```
- * row columns in your image
- * ---|---------------------
- *  0 | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
- *  1 | ↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗↗
- *  2 | →→→→→→→→→→→→→→→→→→→→
- *  3 | ↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘↘
- *  4 | ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
- *  5 | ↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙↙
- *  6 | ←←←←←←←←←←←←←←←←←←←←
- *  7 | ↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖↖
- * ```
- */
-struct walksprite {
-	struct sprite *sprite;  /*!< (RW) The sprite to use */
-	unsigned int delay;     /*!< (RW) The delay between frames */
-	unsigned int index;     /*!< (RO) Current column index */
-	unsigned int elapsed;   /*!< (RO) Elapsed time since last frame */
-};
-
-/**
- * Initialize the walking sprite.
- *
- * \pre ws != NULL
- * \pre sprite != NULL
- * \param ws the walking sprite
- * \param sprite the sprite to use
- * \param delay the delay between sprites
- */
-void
-walksprite_init(struct walksprite *ws, struct sprite *sprite, unsigned int delay);
-
-/**
- * Update the walking sprite
- *
- * \pre ws != NULL
- * \param ws the walking sprite
- * \param ticks the number of milliseconds between last frame
- */
-void
-walksprite_update(struct walksprite *ws, unsigned int ticks);
-
-/**
- * Draw the appropriate sprite cell to the screen according to the orientation
- * given.
- *
- * \pre ws != NULL
- * \pre orientation < 8
- * \param ws the walking sprite
- * \param orientation the orientation (or the row between 0 and 7)
- * \param x the x coordinate
- * \param y the y coordinate
- */
-void
-walksprite_draw(struct walksprite *ws, unsigned int orientation, int x, int y);
-
-#endif /* !MOLKO_WALKSPRITE_H */
--- a/src/core/window.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * window.c -- basic window management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include <SDL.h>
-
-#include "error_p.h"
-#include "window.h"
-#include "window_p.h"
-
-static struct window_handle handle = {
-	.win = NULL,
-	.renderer = NULL
-};
-
-struct window window = {
-	.handle = &handle
-};
-
-bool
-window_init(const char *title, unsigned int w, unsigned int h)
-{
-	assert(title);
-
-	if (SDL_CreateWindowAndRenderer(w, h, SDL_WINDOW_OPENGL,
-	    &handle.win, &handle.renderer) < 0)
-		return error_sdl();
-
-	SDL_SetWindowTitle(handle.win, title);
-
-	window.w = w;
-	window.h = h;
-
-	return true;
-}
-
-void
-window_finish(void)
-{
-	if (handle.renderer)
-		SDL_DestroyRenderer(handle.renderer);
-	if (handle.win)
-		SDL_DestroyWindow(handle.win);
-}
--- a/src/core/window.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * window.h -- basic window management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_WINDOW_H
-#define MOLKO_WINDOW_H
-
-/**
- * \file window.h
- * \brief Basic window management.
- * \ingroup drawing
- */
-
-#include <stdbool.h>
-
-/**
- * \brief Global exposed window structure.
- */
-struct window {
-	unsigned int w;         /*!< (RO) Window width. */
-	unsigned int h;         /*!< (RO) Window height. */
-	void *handle;           /*!< (RO) Native handle. */
-};
-
-/**
- * \brief Access to global window structure.
- */
-extern struct window window;
-
-/**
- * Initialize window.
- *
- * \pre title != NULL
- * \param title the window title
- * \param width the desired width
- * \param height the desired height
- * \return true on success
- */
-bool
-window_init(const char *title, unsigned int width, unsigned int height);
-
-/**
- * Close the window and destroy associated resources.
- */
-void
-window_finish(void);
-
-#endif /* !MOLKO_WINDOW_H */
--- a/src/core/window_p.h	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * window.c -- (PRIVATE) basic window management
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_WINDOW_P_H
-#define MOLKO_WINDOW_P_H
-
-#include <SDL.h>
-
-struct window_handle {
-	SDL_Window *win;
-	SDL_Renderer *renderer;
-};
-
-/* Convenient macros to access the native handle from global window object. */
-#define WINDOW()        (((struct window_handle *)window.handle)->win)
-#define RENDERER()      (((struct window_handle *)window.handle)->renderer)
-
-#endif /* !MOLKO_WINDOW_P_H */
--- a/src/molko/CMakeLists.txt	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for molko
-#
-# Copyright (c) 2020 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(molko)
-add_executable(molko main.c)
-target_link_libraries(molko libadventure)
--- a/src/molko/main.c	Mon Oct 05 13:05:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/*
- * main.c -- Molko's Adventure
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <setjmp.h>
-#include <stdnoreturn.h>
-
-#include <clock.h>
-#include <event.h>
-#include <game.h>
-#include <panic.h>
-#include <sys.h>
-#include <theme.h>
-#include <util.h>
-#include <window.h>
-
-#include <panic_state.h>
-#include <splashscreen_state.h>
-
-#define WINDOW_WIDTH 1280
-#define WINDOW_HEIGHT 720
-
-static jmp_buf panic_buf;
-
-static noreturn void
-unrecoverable(void)
-{
-	longjmp(panic_buf, 1);
-}
-
-static void
-init(void)
-{
-	if (!sys_init())
-		panic();
-	if (!window_init("Molko's Adventure", WINDOW_WIDTH, WINDOW_HEIGHT))
-		panic();
-
-	/*
-	 * From here, we can setup our panic state which requires a window
-	 * to be running.
-	 */
-
-	/* Init unrecoverable panic state. */
-	panic_state_init();
-	panic_handler = unrecoverable;
-
-	if (!theme_init())
-		panic();
-
-	/* Default state is splash screen */
-	game_switch(&splashscreen_state, true);
-}
-
-static void
-run(void)
-{
-	struct clock clock = { 0 };
-
-	while (game.state) {
-		unsigned int elapsed = clock_elapsed(&clock);
-
-		clock_start(&clock);
-
-		for (union event ev; event_poll(&ev); ) {
-			switch (ev.type) {
-			case EVENT_QUIT:
-				return;
-			default:
-				game_handle(&ev);
-				break;
-			}
-		}
-
-		game_update(elapsed);
-		game_draw();
-
-		if ((elapsed = clock_elapsed(&clock)) < 20)
-			delay(20 - elapsed);
-	}
-}
-
-static void
-close(void)
-{
-	window_finish();
-	sys_finish();
-}
-
-int
-main(int argc, char **argv)
-{
-	(void)argc;
-	(void)argv;
-
-	if (setjmp(panic_buf) == 0) {
-		/* Initial game run. */
-		init();
-		run();
-	} else {
-		/* Clear event queue to avoid accidental key presses. */
-		for (union event ev; event_poll(&ev); )
-			continue;
-
-		game_switch(&panic_state, true);
-		run();
-	}
-
-	close();
-
-	return 0;
-}
--- a/tests/test-color.c	Mon Oct 05 13:05:09 2020 +0200
+++ b/tests/test-color.c	Mon Oct 05 13:25:06 2020 +0200
@@ -18,7 +18,7 @@
 
 #include <greatest.h>
 
-#include <color.h>
+#include <core/color.h>
 
 TEST
 red(void)
--- a/tests/test-error.c	Mon Oct 05 13:05:09 2020 +0200
+++ b/tests/test-error.c	Mon Oct 05 13:25:06 2020 +0200
@@ -18,7 +18,7 @@
 
 #include <greatest.h>
 
-#include <error.h>
+#include <core/error.h>
 
 TEST
 simple(void)
--- a/tests/test-inventory.c	Mon Oct 05 13:05:09 2020 +0200
+++ b/tests/test-inventory.c	Mon Oct 05 13:25:06 2020 +0200
@@ -19,8 +19,8 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include "item.h"
-#include "inventory.h"
+#include <core/item.h>
+#include <core/inventory.h>
 
 static struct item potion = {
 	.name = "Potion",
--- a/tests/test-rbuf.c	Mon Oct 05 13:05:09 2020 +0200
+++ b/tests/test-rbuf.c	Mon Oct 05 13:25:06 2020 +0200
@@ -19,7 +19,7 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <rbuf.h>
+#include <core/rbuf.h>
 
 /* Don't use "" to avoid '\0' */
 const char data1[] = { 'a', 'b', 'c', '\n', 'd', 'e', 'f', '\n' };
--- a/tests/test-save.c	Mon Oct 05 13:05:09 2020 +0200
+++ b/tests/test-save.c	Mon Oct 05 13:25:06 2020 +0200
@@ -20,7 +20,7 @@
 
 #include <greatest.h>
 
-#include "save.h"
+#include "core/save.h"
 
 #define NAME "test.db"
 
--- a/tests/test-script.c	Mon Oct 05 13:05:09 2020 +0200
+++ b/tests/test-script.c	Mon Oct 05 13:25:06 2020 +0200
@@ -18,7 +18,7 @@
 
 #include <greatest.h>
 
-#include <script.h>
+#include <core/script.h>
 
 static bool
 truth(struct action *a, unsigned int ticks)
--- a/tools/bcc/CMakeLists.txt	Mon Oct 05 13:05:09 2020 +0200
+++ b/tools/bcc/CMakeLists.txt	Mon Oct 05 13:25:06 2020 +0200
@@ -17,4 +17,4 @@
 #
 
 project(molko-bcc)
-add_executable(bcc bcc.c)
+molko_define_executable(TARGET bcc SOURCES bcc.c FOLDER tools)
--- a/tools/map/CMakeLists.txt	Mon Oct 05 13:05:09 2020 +0200
+++ b/tools/map/CMakeLists.txt	Mon Oct 05 13:25:06 2020 +0200
@@ -17,5 +17,10 @@
 #
 
 project(molko-map)
-add_executable(map map.c)
-target_link_libraries(map Jansson::Jansson)
+
+molko_define_executable(
+	TARGET map
+	SOURCES map.c
+	FOLDER tools
+	LIBRARIES Jansson::Jansson
+)