Forráskód Böngészése

Massive code refactoring and documentation.

Iñigo Valentin 4 éve
szülő
commit
d8aef2778f
44 módosított fájl, 7701 hozzáadás és 3191 törlés
  1. 1 0
      .gitignore
  2. 27 6
      Makefile
  3. 7 7
      doxygen-cli.conf
  4. 2657 0
      doxygen-gui.conf
  5. 167 25
      src/RuneOptimizer/RuneOptimizer.c
  6. 603 49
      src/RuneOptimizer/RuneOptimizer.h
  7. 143 105
      src/RuneOptimizer/db/db.c
  8. 45 33
      src/RuneOptimizer/db/db.h
  9. 196 59
      src/RuneOptimizer/error/error.h
  10. 7 2
      src/RuneOptimizer/gui/gui.c
  11. 14 4
      src/RuneOptimizer/gui/gui.h
  12. 153 100
      src/RuneOptimizer/help/help.c
  13. 11 2
      src/RuneOptimizer/help/help.h
  14. 1335 102
      src/RuneOptimizer/optimize/optimize.c
  15. 565 237
      src/RuneOptimizer/optimize/optimize.h
  16. 0 137
      src/RuneOptimizer/optimize/optimize_count_runes_for_sets.c
  17. 0 71
      src/RuneOptimizer/optimize/optimize_fetch_unit.c
  18. 0 61
      src/RuneOptimizer/optimize/optimize_get_runes.c
  19. 0 530
      src/RuneOptimizer/optimize/optimize_parse_arguments.c
  20. 0 439
      src/RuneOptimizer/optimize/optimize_print.c
  21. 0 129
      src/RuneOptimizer/optimize/optimize_query.c
  22. 10 2
      src/RuneOptimizer/player/player.c
  23. 25 3
      src/RuneOptimizer/player/player.h
  24. 7 1
      src/RuneOptimizer/team/team.c
  25. 51 94
      src/RuneOptimizer/team/team.h
  26. 55 29
      src/RuneOptimizer/team/team_add_unit.c
  27. 63 32
      src/RuneOptimizer/team/team_create.c
  28. 43 21
      src/RuneOptimizer/team/team_delete.c
  29. 12 2
      src/RuneOptimizer/team/team_list.c
  30. 54 30
      src/RuneOptimizer/team/team_remove_unit.c
  31. 325 3
      src/RuneOptimizer/unit/unit.c
  32. 13 7
      src/RuneOptimizer/unit/unit.h
  33. 0 325
      src/RuneOptimizer/unit/unit_list.c
  34. 13 16
      src/RuneOptimizer/update/update.c
  35. 589 83
      src/RuneOptimizer/update/update.h
  36. 14 4
      src/RuneOptimizer/update/update_current_stats.c
  37. 11 2
      src/RuneOptimizer/update/update_db_tables.c
  38. 16 2
      src/RuneOptimizer/update/update_efficiency.c
  39. 8 2
      src/RuneOptimizer/update/update_get_monster_name.c
  40. 12 2
      src/RuneOptimizer/update/update_info.c
  41. 415 2
      src/RuneOptimizer/update/update_json.c
  42. 0 263
      src/RuneOptimizer/update/update_json_rune.c
  43. 0 144
      src/RuneOptimizer/update/update_json_unit.c
  44. 34 24
      src/RuneOptimizer/update/update_rune_totals.c

+ 1 - 0
.gitignore

@@ -14,3 +14,4 @@
 *.exe
 util/
 doc/
+bin/

+ 27 - 6
Makefile

@@ -4,13 +4,13 @@ ifeq ($(OS),Windows_NT)
 		RM = del /F /Q
 		MKDIR = mkdir
 	else # in a bash-like shell, like msys
-		RM = rm -f
+		RM = rm -rf
 		MKDIR = mkdir -p
 	endif
 	EXTENSION=.exe
 	INC=-I C:\MinGW\lib
 else
-	RM = rm -f
+	RM = rm -rf
 	MKDIR = mkdir -p
 	EXTENSION=
 	INC=
@@ -22,6 +22,7 @@ CFLAGS=
 OPTS_DEBUG=-Wall -g
 OPTS_TEST=
 OPTS=-O3
+OPTS_REPORT=-O3 -fdump-tree-all
 LIBS=-lsqlite3 -lm -ljson-c -lpthread
 OUT=bin/RuneOptimizer
 OUT_DEBUG=bin/RuneOptimizer_DEBUG
@@ -40,29 +41,49 @@ GUI_INSTALL_DIR=/usr/share/
 GUI_EXECUTABLE_SRC=/usr/share/RuneOptimizerGUI/RuneOptimizer.py
 GUI_EXECUTABLE_DST=/usr/local/bin/RuneOptimizerGUI
 
+DOC_COMMAND=doxygen
+
 default :
+	@echo Compiling...
 	@$(CC) -o $(OUT)$(EXTENSION) $(SRC) $(INC) $(LIBS) $(OPTS)
 	@echo Compiled executable $(OUT)$(EXTENSION)
 
 debug :
-	$(CC) -o $(OUT_DEBUG)$(EXTENSION) $(SRC) $(INC) $(LIBS)
+	@echo Compiling with debug symbols...
+	@$(CC) -o $(OUT_DEBUG)$(EXTENSION) $(SRC) $(INC) $(LIBS)
 	@echo Compiled debug executable $(OUT_DEBUG)
 
 test : default
+	@echo Generating tests...
 	@$(CC) $(OPTS_TEST) -o $(TEST_OUT_UNIT)$(EXTENSION) $(TEST_SRC_UNIT) $(INC) $(LIBS) $(TEST_FUNCTION)
 	@echo Compiled testing executable $(TEST_OUT_UNIT)$(EXTENSION)
 	@$(CC) $(OPTS_TEST) -o $(TEST_OUT_INTEGRATION)$(EXTENSION) $(TEST_SRC_INTEGRATION) $(INC) $(LIBS) $(TEST_FUNCTION)
 	@echo Compiled testing executable $(TEST_OUT_INTEGRATION)$(EXTENSION)
 	@$(CC) $(OPTS_TEST) -o $(TEST_OUT_E2E)$(EXTENSION) $(TEST_SRC_E2E) $(INC) $(LIBS) $(TEST_FUNCTION)
 	@echo Compiled testing executable $(TEST_OUT_E2E)$(EXTENSION)
+
 install :
+	@echo Installing...
 	@mkdir -p $(INSTALL_DIR)
 	@cp $(OUT)$(EXTENSION) $(INSTALL_DIR)
 	@cp -rf RuneOptimizerGUI $(GUI_INSTALL_DIR)
 	-@rm $(GUI_EXECUTABLE_DST)
 	@ln -s $(GUI_EXECUTABLE_SRC) $(GUI_EXECUTABLE_DST)
+	@echo Installed RuneOptimizer and RuneOptimizerGUI
+
+docs :
+        ifeq ($(shell which $(DOC_COMMAND)),)
+	$(error "No $(DOC_COMMAND) commannd found. Install it and run 'make doc' to generate documentation")
+        else
+	@echo Generating documentation...
+	@mkdir -p doc/cli
+	@mkdir -p doc/gui
+	@doxygen doxygen-cli.conf
+	@doxygen doxygen-gui.conf 2>/dev/null
+	@echo Documentation generated in doc/
+        endif
 clean :
-# TODO: Delete database?
-	@$(RM) $(OUT)$(EXTENSION)
-	@$(RM) $(OUT_DEBUG)$(EXTENSION)
+	@echo Cleaning...
+	@$(RM) bin/*
+	@$(RM) doc/*
 	@echo All clean

+ 7 - 7
doxygen.conf → doxygen-cli.conf

@@ -58,7 +58,7 @@ PROJECT_LOGO           =
 # entered, it will be relative to the location where doxygen was started. If
 # left blank the current directory will be used.
 
-OUTPUT_DIRECTORY       =doc/
+OUTPUT_DIRECTORY       =doc/cli/
 
 # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
 # directories (in 2 levels) under the output directory of each output format and
@@ -195,7 +195,7 @@ SHORT_NAMES            = NO
 # description.)
 # The default value is: NO.
 
-JAVADOC_AUTOBRIEF      = NO
+JAVADOC_AUTOBRIEF      = YES
 
 # If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
 # such as
@@ -213,7 +213,7 @@ JAVADOC_BANNER         = NO
 # requiring an explicit \brief command for a brief description.)
 # The default value is: NO.
 
-QT_AUTOBRIEF           = NO
+QT_AUTOBRIEF           = YES
 
 # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
 # multi-line C++ special comment block (i.e. a block of //! or /// comments) as
@@ -355,7 +355,7 @@ TOC_INCLUDE_HEADINGS   = 5
 # globally by setting AUTOLINK_SUPPORT to NO.
 # The default value is: YES.
 
-AUTOLINK_SUPPORT       = YES
+AUTOLINK_SUPPORT       = NO
 
 # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
 # to include (a tag file for) the STL sources as input, then you should set this
@@ -509,7 +509,7 @@ EXTRACT_PACKAGE        = NO
 # included in the documentation.
 # The default value is: NO.
 
-EXTRACT_STATIC         = NO
+EXTRACT_STATIC         = YES
 
 # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
 # locally in source files will be included in the documentation. If set to NO,
@@ -794,7 +794,7 @@ CITE_BIB_FILES         =
 # messages are off.
 # The default value is: NO.
 
-QUIET                  = NO
+QUIET                  = YES
 
 # The WARNINGS tag can be used to turn on/off the warning messages that are
 # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
@@ -952,7 +952,7 @@ RECURSIVE              = YES
 # Note that relative paths are relative to the directory from which doxygen is
 # run.
 
-EXCLUDE                =
+EXCLUDE                =src/test/
 
 # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
 # directories that are symbolic links (a Unix file system feature) are excluded

+ 2657 - 0
doxygen-gui.conf

@@ -0,0 +1,2657 @@
+# Doxyfile 1.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "RuneOptimizer GUI"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =doc/gui/
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all generated output in the proper direction.
+# Possible values are: None, LTR, RTL and Context.
+# The default value is: None.
+
+OUTPUT_TEXT_DIRECTION  = None
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER         = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING       = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE  = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which efficively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS       = 1
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL   = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  =RuneOptimizerGUI/
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
+# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
+# *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f18 \
+                         *.f \
+                         *.for \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.ice
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
+# YES then doxygen will add the directory of each input to the include path.
+# The default value is: YES.
+
+CLANG_ADD_INC_PATHS    = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see:
+# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT    = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE      =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = https://cdn.jsdelivr.net/npm/mathjax@2
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD    = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS        = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD     = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc and
+# plantuml temporary files.
+# The default value is: YES.
+
+DOT_CLEANUP            = YES

+ 167 - 25
src/RuneOptimizer/RuneOptimizer.c

@@ -17,21 +17,18 @@
 
 /**
  * @file RuneOptimizer.c
- * Main function of the program.
+ *
+ * Implementation of the functions used by the gui command.
+ *
+ * This file implements the main function, and the functions declared in
+ * {@link RuneOptimizer.h}.
  */
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
 #include <string.h>
 #include <sqlite3.h>
 #include <math.h>
-#include <unistd.h>
-#include <time.h>
-#include <json-c/json.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <pthread.h>
 #include "RuneOptimizer.h"
 #include "error/error.h"
 #include "db/db.c"
@@ -43,6 +40,143 @@
 #include "player/player.c"
 #include "gui/gui.c"
 
+/**
+ * DEF stat multiplier.
+ *
+ * For effective HP calculation.
+ */
+#define EHP_DEF_MULTIPLIER 3.5f
+
+/**
+ * DEF base value.
+ *
+ * For effective HP calculation.
+ */
+#define EHP_DEF_BASE 1140.0f
+
+/**
+ * HP stat divider.
+ *
+ * For effective HP calculation.
+ */
+#define EHP_HP_DIVIDER 1000.0f
+
+/**
+ * Just 100.
+ *
+ * For perccentage calculations.
+ */
+#define PERCENT 100.0f
+
+/**
+ * Command version.
+ *
+ * Keyword to launch the version command.
+ */
+#define CMD_VERSION "version"
+
+/**
+ * Command update.
+ *
+ * Keyword to launch the update command.
+ */
+#define CMD_UPDATE "update"
+
+/**
+ * Command optimize.
+ *
+ * Keyword to launch the optimize command.
+ */
+#define CMD_OPTIMIZE "optimize"
+
+/**
+ * Command help.
+ *
+ * Keyword to launch the help command.
+ */
+#define CMD_HELP "help"
+
+/**
+ * Command team.
+ *
+ * Keyword to launch the team command.
+ */
+#define CMD_TEAM "team"
+
+/**
+ * Command unit.
+ *
+ * Keyword to launch the unit command.
+ */
+#define CMD_UNIT "unit"
+
+/**
+ * Command player.
+ *
+ * Keyword to launch the player command.
+ */
+#define CMD_PLAYER "player"
+
+/**
+ * Command gui.
+ *
+ * Keyword to launch the gui command.
+ */
+#define CMD_GUI "gui"
+
+/**
+ * Home environment variable.
+ *
+ * Key to get the environment variable to determine the user directory.
+ */
+#define ENV_VAR_HOME "HOME"
+
+/**
+ * The default path to the database.
+ *
+ * Relative (and to be appended to) the user directory path.
+ * @todo: This won't work on Windows.
+ */
+#define DEFAULT_DB_PATH_FROM_HOME "/.local/share/RuneOptimizer/data.sqlite"
+
+/**
+ * Argument cutter for program arguments.
+ *
+ * Determines how many parameters will be removed from the start of the list of
+ * parameters passed to the program before passing that list to any command that
+ * needs them.
+ *
+ * Basically it to remove the executable name and the command name.
+ */
+#define ARGS_CUT_FOR_COMMANDS 2
+
+sqlite3 *db = NULL;
+char db_location[DB_PATH_LEN];
+
+extern unsigned int calculate_ehp(unsigned int hp, unsigned short def){
+    // Sorry, but this is the formula, and I don't understand it either.
+    // Take it or leave it.
+    unsigned int ehp = ceil(
+      (((((float) def) * EHP_DEF_MULTIPLIER) + EHP_DEF_BASE) * ((float) hp)) /
+      EHP_HP_DIVIDER
+    );
+    return ehp;
+}
+
+extern unsigned short calculate_dmg(
+  unsigned short atk, unsigned short crr, unsigned short crd
+){
+    float crr_capped = (float) crr;
+    if (crr_capped > CRR_CAP){
+        crr_capped = CRR_CAP;
+    }
+    unsigned short dmg = ceil(
+      ((float)atk * ((PERCENT - crr_capped) / PERCENT)) + // Non-crit
+      ((float)atk * (crr_capped / PERCENT) * ((float)crd / PERCENT)) // Crit
+    );
+    return(dmg);
+}
+
 int main(int argc, char *argv[]){
     // Parse the arguments to find the command (index 1)
 
@@ -53,54 +187,62 @@ int main(int argc, char *argv[]){
     }
 
     // Set the global database location
-    strcat(db_location, getenv("HOME"));
-    strcat(db_location, "/.local/share/RuneOptimizer/data.sqlite");
+    strcat(db_location, getenv(ENV_VAR_HOME));
+    strcat(db_location, DEFAULT_DB_PATH_FROM_HOME);
 
     int result = SUCCESS;
 
     // Version command
-    if (strcmp(argv[1], "version") == 0){
+    if (strcmp(argv[1], CMD_VERSION) == 0){
         printf("%s\n", VERSION);
         return(SUCCESS);
     }
 
     // Update command
-    else if (strcmp(argv[1], "update") == 0){
-        return(cmd_update(argc - 2, argv + 2));
+    else if (strcmp(argv[1], CMD_UPDATE) == 0){
+        return(
+          update(argc - ARGS_CUT_FOR_COMMANDS, argv + ARGS_CUT_FOR_COMMANDS)
+        );
     }
 
     // Optimize command.
-    else if (strcmp(argv[1], "optimize") == 0){
+    else if (strcmp(argv[1], CMD_OPTIMIZE) == 0){
         // Pass the rest of the arguments to the team command.
-        return(cmd_optimize(argc - 2, argv + 2));
+        return(
+          optimize(argc - ARGS_CUT_FOR_COMMANDS, argv + ARGS_CUT_FOR_COMMANDS)
+        );
     }
 
     // Help command. Call and return
-    else if (strcmp(argv[1], "help") == 0){
-        cmd_help();
+    else if (strcmp(argv[1], CMD_HELP) == 0){
+        help();
         return(SUCCESS);
     }
 
     // Team command.
-    else if (strcmp(argv[1], "team") == 0){
+    else if (strcmp(argv[1], CMD_TEAM) == 0){
         // Pass the rest of the arguments to the team command.
-        return(cmd_team(argc - 2, argv + 2));
+        return(
+          team(argc - ARGS_CUT_FOR_COMMANDS, argv + ARGS_CUT_FOR_COMMANDS)
+        );
     }
 
     // Unit command.
-    else if (strcmp(argv[1], "unit") == 0){
+    else if (strcmp(argv[1], CMD_UNIT) == 0){
         // Pass the rest of the arguments to the team command.
-        return(cmd_unit(argc - 2, argv + 2));
+        return(
+          unit(argc - ARGS_CUT_FOR_COMMANDS, argv + ARGS_CUT_FOR_COMMANDS)
+        );
     }
 
     // Player command.
-    else if (strcmp(argv[1], "player") == 0){
-        return(cmd_player());
+    else if (strcmp(argv[1], CMD_PLAYER) == 0){
+        return(player());
     }
 
     // GUI command.
-    else if (strcmp(argv[1], "gui") == 0){
-        return(cmd_gui());
+    else if (strcmp(argv[1], CMD_GUI) == 0){
+        return(gui());
     }
 
     // Any other command is an error

+ 603 - 49
src/RuneOptimizer/RuneOptimizer.h

@@ -17,240 +17,747 @@
 
 /**
  * @file RuneOptimizer.h
- * Declarations for elements used across the program.
+ *
+ * Declarations of the functions and data types used across the application.
+ *
+ * This file declares all the functions and data types used from anywhere in the
+ * program.
  */
 
+#pragma once
+
+#include <sqlite3.h>
+
 /**
- * Application version
+ * Application version.
+ *
+ * Metadata, only used in the help and version commands.
  */
 #define VERSION "0.1-RC1"
 
 /**
  * Application author.
+ *
+ * Metadata, only used in the help command.
  */
 #define AUTHOR "Iñigo Valentin"
 
 /**
  * Application author email.
+ *
+ * Metadata, only used in the help command.
  */
 #define MAIL "i@inigovalentin.com"
 
 /**
- * Mock boolean value TRUE
+ * Boolean value TRUE.
+ *
+ * Mocked boolean for consistence across functions.
  */
 #define TRUE 1
 
 /**
- * Mock boolean value of FALSE.
+ * Boolean value FALSE.
+ *
+ * Mocked boolean for consistence across functions.
  */
 #define FALSE 0
 
 /**
- * Set ID of Energy runes.
+ * Energy Set.
+ *
+ * Set ID of Energy runes, as given by Com2Us.
  */
 #define ENERGY 1
 
 /**
- * Set ID of Guard runes.
+ * Guard Set.
+ *
+ * Set ID of Guard runes, as given by Com2Us.
  */
 #define GUARD 2
 
 /**
- * Set ID of Swift runes.
+ * Swift Set.
+ *
+ * Set ID of Swift runes, as given by Com2Us.
  */
 #define SWIFT 3
 
 /**
- * Set ID of Blade runes.
+ * Blade Set.
+ *
+ * Set ID of Blade runes, as given by Com2Us.
  */
 #define BLADE 4
 
 /**
- * Set ID of Rage runes.
+ * Rage Set.
+ *
+ * Set ID of Rage runes, as given by Com2Us.
  */
 #define RAGE 5
 
 /**
- * Set ID of Focus runes.
+ * Focus Set.
+ *
+ * Set ID of Focus runes, as given by Com2Us.
  */
 #define FOCUS 6
 
 /**
- * Set ID of Endure runes.
+ * Endure Set.
+ *
+ * Set ID of Endure runes, as given by Com2Us.
  */
 #define ENDURE 7
 
 /**
- * Set ID of Fatal runes.
+ * Fatal Set.
+ *
+ * Set ID of Fatal runes, as given by Com2Us.
  */
 #define FATAL 8
 
 /**
- * Set ID of Despair runes.
+ * Despair Set.
+ *
+ * Set ID of Despair runes, as given by Com2Us.
  */
 #define DESPAIR 10
 
 /**
- * Set ID of Vampire runes.
+ * Vampire Set.
+ *
+ * Set ID of Vampire runes, as given by Com2Us.
  */
 #define VAMPIRE 11
 
 /**
- * Set ID of Violent runes.
+ * Violent Set.
+ *
+ * Set ID of Violent runes, as given by Com2Us.
  */
 #define VIOLENT 13
 
 /**
- * Set ID of Nemesis runes.
+ * Nemesis Set.
+ *
+ * Set ID of Nemesis runes, as given by Com2Us.
  */
 #define NEMESIS 14
 
 /**
- * Set ID of Will runes.
+ * Will Set.
+ *
+ * Set ID of Will runes, as given by Com2Us.
  */
 #define WILL 15
 
 /**
- * Set ID of Shield runes.
+ * Shield Set.
+ *
+ * Set ID of Shield runes, as given by Com2Us.
  */
 #define SHIELD 16
 
 /**
- * Set ID of Revenge runes.
+ * Revenge Set.
+ *
+ * Set ID of Revenge runes, as given by Com2Us.
  */
 #define REVENGE 17
 
 /**
- * Set ID of Destroy runes.
+ * Destroy Set.
+ *
+ * Set ID of Destroy runes, as given by Com2Us.
  */
 #define DESTROY 18
 
 /**
- * Set ID of Fight runes.
+ * Fight Set.
+ *
+ * Set ID of Fight runes, as given by Com2Us.
  */
 #define FIGHT 19
 
 /**
- * Set ID of Determination runes.
+ * Determination Set.
+ *
+ * Set ID of Determination runes, as given by Com2Us.
  */
 #define DETERMINATION 20
 
 /**
- * Set ID of Enhance runes.
+ * Enhance Set.
+ *
+ * Set ID of Enhance runes, as given by Com2Us.
  */
 #define ENHANCE 21
 
 /**
- * Set ID of Accuracy runes.
+ * Accuracy Set.
+ *
+ * Set ID of Accuracy runes, as given by Com2Us.
  */
 #define ACCURACY 22
 
 /**
- * Set ID of Tolerance runes.
+ * Tolerance Set.
+ *
+ * Set ID of Tolerance runes, as given by Com2Us.
  */
 #define TOLERANCE 23
 
 
 /**
- * Stat ID for HP stat in runes..
+ * HP rune stat.
+ *
+ * Rune stat ID for HP in runes, as given by Com2Us.
  */
 #define HP_FLAT 1
 
 /**
- * Stat ID for HP% stat in runes..
+ * HP% rune stat.
+ *
+ * Rune stat ID for HP% in runes, as given by Com2Us.
  */
 #define HP_PERCENT 2
 
 /**
- * Stat ID for ATK stat in runes..
+ * ATK rune stat.
+ *
+ * Rune stat ID for ATK in runes, as given by Com2Us.
  */
 #define ATK_FLAT 3
 
 /**
- * Stat ID for ATK% stat in runes..
+ * ATK% rune stat.
+ *
+ * Rune stat ID for ATK% in runes, as given by Com2Us.
  */
 #define ATK_PERCENT 4
 
 /**
- * Stat ID for DEF stat in runes..
+ * DEF rune stat.
+ *
+ * Rune stat ID for DEF in runes, as given by Com2Us.
  */
 #define DEF_FLAT 5
 
 /**
- * Stat ID for DEF% stat in runes..
+ * DEF% rune stat.
+ *
+ * Rune stat ID for DEF% in runes, as given by Com2Us.
  */
 #define DEF_PERCENT 6
 
 /**
- * Stat ID for SPD stat in runes.
+ * SPD rune stat.
+ *
+ * Rune stat ID for SPD in runes, as given by Com2Us.
  */
 #define SPD 8
 
 /**
- * Stat ID for CRR stat in runes.
+ * CRR rune stat.
+ *
+ * Rune stat ID for CRR in runes, as given by Com2Us.
  */
 #define CRR 9
 
 /**
- * Stat ID for CRD stat in runes.
+ * CRD rune stat.
+ *
+ * Rune stat ID for CRD in runes, as given by Com2Us.
  */
 #define CRD 10
 
 /**
- * Stat ID for RES stat in runes.
+ * RES rune stat.
+ *
+ * Rune stat ID for RES in runes, as given by Com2Us.
  */
 #define RES 11
 
 /**
- * Stat ID for ACC stat in runes.
+ * ACC rune stat.
+ *
+ * Rune stat ID for ACC in runes, as given by Com2Us.
  */
 #define ACC 12
 
+/**
+ * Maximum length of Unit IDs.
+ *
+ * It can never be higher thahn this.
+ */
+#define UNIT_ID_LEN 14
+
+/**
+ * Maximum length of Unit name.
+ *
+ * It can never be higher thahn this.
+ */
+#define UNIT_NAME_LEN 128
 
+/**
+ * Maximum length of Rune IDs.
+ *
+ * It can never be higher thahn this.
+ */
+#define RUNE_ID_LEN 14
 
 /**
- * Global database connection.
+ * Maximum length of Teams IDs.
+ *
+ * It can never be higher thahn this.
  */
-sqlite3 *db = NULL;
+#define TEAM_ID_LEN 4
 
 /**
- * Path to the database.
+ * Length for the database file path.
+ *
+ * Totally arbitrary.
+ * @todo This may be worriesome.
+ */
+#define DB_PATH_LEN 512
+
+/**
+ * Rune slots.
+ *
+ * Number of rune slots. In-game, and in many parts of this program, slots are
+ * used with a 1-index.
+ */
+#define RUNE_SLOTS 6
+
+/**
+ * CRR Cap.
+ *
+ * Critical rate does nothing over 100%, so for more realistic calcultations,
+ * it's better to have it capped.
+ */
+#define CRR_CAP 100.0f
+
+/**
+ * RES Cap.
+ *
+ * Resistance does nothing over 100%, so for more realistic calcultations, it's
+ * better to have it capped.
+ */
+#define RES_CAP 100.0f
+
+/**
+ * ACC Cap.
+ *
+ * In the game, accurary is effectively capped at 85%, so for more realistic
+ * calcultations, it's better to have it capped.
  */
-char db_location[512];
+#define ACC_CAP 85.0f
+
+/**
+ * Number of stats defined in the game.
+ *
+ * It's not actually 13, because 0 and 7 are never used in game, but is a good
+ * value for counters and loops.
+ */
+#define DIFFERENT_STATS 13
+
+/**
+ * Number of rune sets defined in the game.
+ *
+ * It's not actually 25, because 0, 9 and 12 are never used in game, but is a
+ * good value for counters and loops.
+ */
+#define DIFFERENT_SETS 25
+
+/**
+ * Number of rune sets defined in the game.
+ *
+ * It's not actually 26, because a lot of them are never used in game, but is a
+ * good value for counters and loops.
+ */
+#define DIFFERENT_QUALITIES 16
+
+/**
+ * Rune max stars.
+ *
+ * Watch out, a rune can't have 0 stars, so in loos, better start at 1.
+ */
+#define RUNE_MAX_STARS 6
+
+/**
+ * Structure representing a unit.
+ *
+ * Represents an entity from the table 'unit', but is doesn't have that mucha
+ * data, just the mambers needed for optimization and some other thigs. For a
+ * more complete representation of the table, {@link DB_Unit} can be used.
+ */
+typedef struct Unit {
+    /**
+     * Unit ID.
+     *
+     * The ID as given by Com2Us.
+     */
+    unsigned char id[UNIT_ID_LEN];
+
+    /**
+     * The Unit name.
+     *
+     * The name as given by Com2Us, except for Homunculus. For them, the user
+     * given by the naem will be used.
+     */
+    unsigned char name[UNIT_NAME_LEN];
+
+    /**
+     * The unit base HP.
+     *
+     * The Unit HP, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
+    unsigned int base_hp;
+
+    /**
+     * The unit base ATK.
+     *
+     * The Unit ATK, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
+    unsigned short base_atk;
+
+    /**
+     * The unit base DEF.
+     *
+     * The Unit DEF, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
+    unsigned short base_def;
+
+    /**
+     * The unit base SPD.
+     *
+     * The Unit SPD, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
+    unsigned short base_spd;
+
+    /**
+     * The unit base CRR.
+     *
+     * The Unit CRR, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
+    unsigned short base_crr;
+
+    /**
+     * The unit base CRD.
+     *
+     * The Unit CRD, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
+    unsigned short base_crd;
+
+    /**
+     * The unit base RES.
+     *
+     * The Unit RES, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
+    unsigned short base_res;
+
+    /**
+     * The unit base ACC.
+     *
+     * The Unit ACC, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
+    unsigned short base_acc;
+
+    /**
+     * The unit base EHP.
+     *
+     * The Unit EHP, at it's current level, without counting runes, artifacts,
+     * towers... See {@link calculate_ehp} for more details bout EHP.
+     */
+    unsigned int base_ehp;
+
+    /**
+     * The unit base DMG.
+     *
+     * The Unit DMG, at it's current level, without counting runes, artifacts,
+     * towers...See {@link calculate_ehp} for more details bout EHP.
+     */
+    unsigned short base_dmg;
+
+    /**
+     * The unit base HP.
+     *
+     * The Unit HP, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
+    unsigned int current_hp;
+
+    /**
+     * The unit base ATK.
+     *
+     * The Unit ATK, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
+    unsigned short current_atk;
+
+    /**
+     * The unit base DEF.
+     *
+     * The Unit DEF, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
+    unsigned short current_def;
+
+    /**
+     * The unit base SPD.
+     *
+     * The Unit SPD, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
+    unsigned short current_spd;
+
+    /**
+     * The unit base CRR.
+     *
+     * The Unit CRR, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
+    unsigned short current_crr;
+
+    /**
+     * The unit base CRD.
+     *
+     * The Unit CRD, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
+    unsigned short current_crd;
+
+    /**
+     * The unit base RES.
+     *
+     * The Unit RES, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
+    unsigned short current_res;
+
+    /**
+     * The unit base ACC.
+     *
+     * The Unit ACC, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
+    unsigned short current_acc;
+
+    /**
+     * The unit base EHP.
+     *
+     * The Unit EHP, at it's current level, counting equiped runes, but not
+     * artifacts or towers.See {@link calculate_ehp} for more details bout EHP.
+     */
+    unsigned int current_ehp;
+
+    /**
+     * The unit base DMG.
+     *
+     * The Unit DMG, at it's current level, counting equiped runes, but not
+     * artifacts or towers. See {@link calculate_ehp} for more details bout EHP.
+     */
+    unsigned short current_dmg;
+} Unit;
 
 /**
  * Number of runes for a given list of runes.
+ *
+ * It just holds numbers of rune sets. See {@link optimize_count_runes_for_sets}
+ * for a use case.
  */
 typedef struct Rune_Set_Count {
+
+    /**
+     * Energy count.
+     *
+     * Number of Energy runes.
+     */
     unsigned short energy;
+
+    /**
+     * Guard count.
+     *
+     * Number of Guard runes.
+     */
     unsigned short guard;
+
+    /**
+     * Swift count.
+     *
+     * Number of Swift runes.
+     */
     unsigned short swift;
+
+    /**
+     * Blade count.
+     *
+     * Number of Blade runes.
+     */
     unsigned short blade;
+
+    /**
+     * Rage count.
+     *
+     * Number of Rage runes.
+     */
     unsigned short rage;
+
+    /**
+     * Focus count.
+     *
+     * Number of Focus runes.
+     */
     unsigned short focus;
+
+    /**
+     * Endure count.
+     *
+     * Number of Endure runes.
+     */
     unsigned short endure;
+
+    /**
+     * Fatal count.
+     *
+     * Number of Fatal runes.
+     */
     unsigned short fatal;
+
+    /**
+     * Despair count.
+     *
+     * Number of Despair runes.
+     */
     unsigned short despair;
+
+    /**
+     * Vampire count.
+     *
+     * Number of Vampire runes.
+     */
     unsigned short vampire;
+
+    /**
+     * Violent count.
+     *
+     * Number of Violent runes.
+     */
     unsigned short violent;
+
+    /**
+     * Nemesis count.
+     *
+     * Number of Nemesis runes.
+     */
     unsigned short nemesis;
+
+    /**
+     * Will count.
+     *
+     * Number of Will runes.
+     */
     unsigned short will;
+
+    /**
+     * Shield count.
+     *
+     * Number of Shield runes.
+     */
     unsigned short shield;
+
+    /**
+     * Revenge count.
+     *
+     * Number of Revenge runes.
+     */
     unsigned short revenge;
+
+    /**
+     * Destroy count.
+     *
+     * Number of Destroy runes.
+     */
     unsigned short destroy;
+
+    /**
+     * Fight count.
+     *
+     * Number of Fight runes.
+     */
     unsigned short fight;
+
+    /**
+     * Determination count.
+     *
+     * Number of Determination runes.
+     */
     unsigned short determination;
+
+    /**
+     * Enhance count.
+     *
+     * Number of Enhance runes.
+     */
     unsigned short enhance;
+
+    /**
+     * Accuracy count.
+     *
+     * Number of Accuracy runes.
+     */
     unsigned short accuracy;
+
+    /**
+     * Tolerance count.
+     *
+     * Number of Tolerance runes.
+     */
     unsigned short tolerance;
 } Rune_Set_Count;
 
+/**
+ * Names for run stats.
+ *
+ * Indexed by Com2Us ID. Watch out for indexes 0 and 7, they are undefined in
+ * the game.
+ */
+const char STAT_NAMES[DIFFERENT_STATS][9] = {
+  "NULL", "HP_FLAT", "HP",  "ATK_FLAT", "ATK", "DEF_FLAT",
+  "DEF",  "NULL",    "SPD", "CRR",      "CRD", "RES",      "ACC"
+};
+
+/**
+ * Names for rune sets.
+ *
+ * Indexed by Com2Us ID.Watch out for indexes 0, 9 and 12, they are undefined in
+ * the game.
+ */
+const char SET_NAMES[DIFFERENT_SETS][9] = {
+  "NULL",    "ENERGY",  "GUARD",    "SWIFT",   "BLADE",    "RAGE",
+  "FOCUS",   "ENDURE",  "FATAL",    "NULL",    "DESPAIR",  "VAMPIRE",
+  "NULL",    "VIOLENT", "NEMESIS",  "WILL",    "SHIELD",   "REVENGE",
+  "DESTROY", "FIGHT",   "DETERMIN", "ENHANCE", "ACCURACY", "TOLERANCE"
+};
+
 /**
  * Names for rune qualities.
  *
- * Indexed by Com2Us ID.
+ * Indexed by Com2Us ID. 1-5 are qualities for normal runes, 11-15 for ancient
+ * runes. All the others are not defined in the game,
  */
-const char quality_names[][26] = {
+const char QUALITY_NAMES[DIFFERENT_QUALITIES][9] = {
   "NULL",
   "NORMAL",   "MAGIC",   "RARE",   "HERO",    "LEGEND",  // 1-5
   "NULL",     "NULL",    "NULL",   "NULL",    "NULL",
@@ -258,11 +765,16 @@ const char quality_names[][26] = {
 };
 
 /**
- * Names for rune stats, .
+ * Names for rune stats, in a printable format.
+ *
+ * They hold a 4 digit stat, padded to the right, with a percent sign on the
+ * right for the stats that are percentual. All padded to the right with a
+ * single space, for a total length of 10 characters.
  *
- * Indexed by Com2Us ID.
+ * Indexed by Com2Us ID. Watch out for indexes 0 and 7, they are undefined in
+ * the game.
  */
-const char stat_names_printable[][13] = {
+const char STAT_NAMES_PRINTABLE[DIFFERENT_STATS][12] = {
   "NULL",
   "HP  %4d  ", "HP  %4d%% ", "ATK %4d  ", "ATK %4d%% ", "DEF %4d  ", "DEF %4d%% ", // 1-6
   "NULL",
@@ -272,12 +784,13 @@ const char stat_names_printable[][13] = {
 /**
  * Max roll values for each stat.
  *
- * Indexed by stat ID and rune stars. Works both for initial rolls and
- * power-ups.
+ * Used for efficiency calculations. Indexed by
+ * - Stat id (indexes 0 and 7 undefined in game).
+ * - Rune stars (1-6, dont use index 0).
  *
- * TODO: For ancient runes, the initial rolls are higher.
+ * @todo For ancient runes, the initial rolls are higher.
  */
-const int stat_roll_max[13][7] = {
+const int STAT_ROLL_MAX[DIFFERENT_STATS][RUNE_MAX_STARS + 1] = {
   {-1, -1, -1, -1, -1, -1, -1}, // NULL (unused)
   {-1, 60, 105, 165, 225, 300, 375}, // HP
   {-1, 2, 3, 5, 6, 7, 8}, // HP%
@@ -293,6 +806,47 @@ const int stat_roll_max[13][7] = {
   {-1, 2, 3, 4, 5, 7, 8} // ACC
 };
 
+/**
+ * Global database connection.
+ *
+ * Used across the app. Opened in {@link db_open}.
+ */
+extern sqlite3 *db;
+
+/**
+ * Path to the database.
+ *
+ * When possible, use be an absolute path.
+ */
+extern char db_location[DB_PATH_LEN];
+
+/**
+ * Calculates effective HP.
+ *
+ * EHP is a complex stat, depending on HP and DEF. In short, the formula is
+ * ((( def * 3.5) + 1140) * hp) / 1000 .
+ *
+ * @param[in] hp HP stat.
+ * @param[in] def DEF stat.
+ * @return Calculated EHP.
+ */
+extern unsigned int calculate_ehp(unsigned int hp, unsigned short def);
+
+/**
+ * Calculates damage.
+ *
+ * DMG is a complex stat, depending on ATK, CRR and CRD. In short, the formula
+ * is (atk * ((100 - crr_capped) / 100)) +  (atk * (crr / 100) * (crd / 100)) .
+ *
+ * @param[in] atk ATK stat.
+ * @param[in] crr CRR stat.
+ * @param[in] crd CRD stat.
+ * @return Calculated DMG.
+ */
+extern unsigned short calculate_dmg(
+  unsigned short atk, unsigned short crr, unsigned short crd
+);
+
 /**
  * Starts the program.
  *

+ 143 - 105
src/RuneOptimizer/db/db.c

@@ -17,12 +17,50 @@
 
 /**
  * @file db.c
+ *
  * Implementation of the database functions.
+ *
+ * This file implements all the database related functions defined in
+ * {@link db.h}. It also defines and implements some static functions used by
+ * them.
  */
 
+#include <stdio.h>
+#include <sqlite3.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
 #include "db.h"
 
-int db_close(){
+/**
+ * Ensures that the directory structure for the database exist.
+ *
+ * Creates the required directories for the file in the glovan variable
+ * {@link db_location}. It doesn't create the database file itself. It doesn't
+ * have return values, so the caller won't know if the folder structure was
+ * succesfully created, but {@link db_open} will throw an error when called
+ * if they werent created.
+ */
+static void db_create_directories();
+
+/**
+ * Creates all database tables.
+ *
+ * Runs CREATE TABLE stetements against the database to set up all the tables
+ * the application uses. It is called from {@link db_open} if it detects that
+ * the database has just been created. All the statements contains the IF NOT
+ * EXIST clause, so there will be no errors if they actually exists.
+ *
+ * In case of error, it will print a message to stderr.
+ *
+ * @return {@link SUCCESS} if all the tables were created, or an error defined
+ * in {@link error.h} if one or more tables could not be created.
+ */
+static int db_create_tables();
+
+extern int db_close(){
     if (db != NULL){
         int result = sqlite3_close_v2(db);
         if (result != SQLITE_OK){
@@ -37,8 +75,109 @@ int db_close(){
     return(SUCCESS);
 }
 
-void db_create_directories(){
-    char dir_to_make[512];
+extern int db_open(char *path){
+    char exists = TRUE;
+    if (access( db_location, F_OK ) != 0) {
+        exists = FALSE;
+        db_create_directories();
+    }
+
+    // Get the path, relative to the program
+    char location[sizeof(db_location)];
+
+    // If db specified as argument, use it, else use the default location.
+    if (path == NULL) strcpy(location, db_location);
+    else strcpy(location, path);
+    if (
+        SUCCESS !=
+        sqlite3_open_v2(
+          location, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL
+        )
+    ){
+        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
+        db_close();
+        return(ERROR_DB_CANT_OPEN);
+    }
+
+    // If the database was just created, create the tables
+    if (exists == FALSE){
+        db_create_tables();
+    }
+
+    return(SUCCESS);
+}
+
+extern int db_query(sqlite3_stmt **stmt, char query[], char *parameters[]){
+
+    // If the connection has not been initialized, do it now
+    if (NULL == db) db_open(NULL);
+
+
+    if (SQLITE_OK != sqlite3_prepare_v2(db, query, -1, stmt, 0)) {
+        fprintf(
+          stderr, "ERROR executing query '%s': %s\n", query, sqlite3_errmsg(db)
+        );
+        sqlite3_finalize(*stmt);
+        return(ERROR_DB_QUERY);
+    }
+
+    // Loop and bind parameters
+    char total_parameters = sqlite3_bind_parameter_count(*stmt);
+    if (total_parameters > 0 && parameters == NULL){
+        return(ERROR_DB_QUERY_NO_PARAMETERS);
+    }
+    for (int i = 0; i < total_parameters; i ++){
+        sqlite3_bind_text(
+          *stmt, i + 1, parameters[i], strlen(parameters[i]), NULL
+        );
+    }
+
+    //printf("PREP QUERY: %s\n", sqlite3_expanded_sql(*stmt));
+
+    return(SUCCESS);
+}
+
+extern int db_execute(char query[], char *parameters[]){
+
+    // If the connection has not been initialized, do it now
+    if (NULL == db) db_open(NULL);
+
+    sqlite3_stmt *stmt;
+    if (SQLITE_OK != sqlite3_prepare_v2(db, query, -1, &stmt, 0)) {
+        fprintf(
+          stderr, "ERROR executing statement '%s': %s\n",
+          query, sqlite3_errmsg(db)
+        );
+        sqlite3_finalize(stmt);
+        return(ERROR_DB_EXECUTE);
+    }
+
+    // Loop and bind parameters
+    char total_parameters = sqlite3_bind_parameter_count(stmt);
+    if (total_parameters > 0 && parameters == NULL){
+        return(ERROR_DB_EXECUTE_NO_PARAMETERS);
+    }
+    for (int i = 0; i < total_parameters; i ++){
+        sqlite3_bind_text(
+          stmt, i + 1, parameters[i], strlen(parameters[i]), NULL
+        );
+    }
+    //printf("PREP QUERY: %s\n", sqlite3_expanded_sql(stmt));
+    if (SQLITE_DONE != sqlite3_step(stmt)){
+        fprintf(
+          stderr, "ERROR Executing statement '%s': %s\n",
+          query, sqlite3_errmsg(db)
+        );
+        sqlite3_finalize(stmt);
+        return(ERROR_DB_EXECUTE);
+    }
+
+    sqlite3_finalize(stmt);
+    return(SUCCESS);
+}
+
+static void db_create_directories(){
+    char dir_to_make[sizeof(db_location)];
     int last_path_separator = -1;
     for(int i = 0; i < strlen(db_location); i++){
         if(db_location[i] == '/' || db_location[i] == '\\'){
@@ -54,7 +193,7 @@ void db_create_directories(){
     return;
 }
 
-int db_create_tables(){
+static int db_create_tables(){
     // Table rune_stats
     if (
       SUCCESS !=
@@ -221,104 +360,3 @@ int db_create_tables(){
 
     return SUCCESS;
 }
-
-int db_open(char *path){
-    char exists = TRUE;
-    if (access( db_location, F_OK ) != 0) {
-        exists = FALSE;
-        db_create_directories();
-    }
-
-    // Get the path, relative to the program
-    char location[512];
-
-    // If db specified as argument, use it, else use the default location.
-    if (path == NULL) strcpy(location, db_location);
-    else strcpy(location, path);
-    if (
-        SUCCESS !=
-        sqlite3_open_v2(
-          location, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL
-        )
-    ){
-        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
-        db_close();
-        return(ERROR_DB_CANT_OPEN);
-    }
-
-    // If the database was just created, create the tables
-    if (exists == FALSE){
-        db_create_tables();
-    }
-
-    return(SUCCESS);
-}
-
-int db_query(sqlite3_stmt **stmt, char query[], char *parameters[]){
-
-    // If the connection has not been initialized, do it now
-    if (NULL == db) db_open(NULL);
-
-
-    if (SQLITE_OK != sqlite3_prepare_v2(db, query, -1, stmt, 0)) {
-        fprintf(
-          stderr, "ERROR executing query '%s': %s\n", query, sqlite3_errmsg(db)
-        );
-        sqlite3_finalize(*stmt);
-        return(ERROR_DB_QUERY);
-    }
-
-    // Loop and bind parameters
-    char total_parameters = sqlite3_bind_parameter_count(*stmt);
-    if (total_parameters > 0 && parameters == NULL){
-        return(ERROR_DB_QUERY_NO_PARAMETERS);
-    }
-    for (int i = 0; i < total_parameters; i ++){
-        sqlite3_bind_text(
-          *stmt, i + 1, parameters[i], strlen(parameters[i]), NULL
-        );
-    }
-
-    //printf("PREP QUERY: %s\n", sqlite3_expanded_sql(*stmt));
-
-    return(SUCCESS);
-}
-
-int db_execute(char query[], char *parameters[]){
-
-    // If the connection has not been initialized, do it now
-    if (NULL == db) db_open(NULL);
-
-    sqlite3_stmt *stmt;
-    if (SQLITE_OK != sqlite3_prepare_v2(db, query, -1, &stmt, 0)) {
-        fprintf(
-          stderr, "ERROR executing statement '%s': %s\n",
-          query, sqlite3_errmsg(db)
-        );
-        sqlite3_finalize(stmt);
-        return(ERROR_DB_EXECUTE);
-    }
-
-    // Loop and bind parameters
-    char total_parameters = sqlite3_bind_parameter_count(stmt);
-    if (total_parameters > 0 && parameters == NULL){
-        return(ERROR_DB_EXECUTE_NO_PARAMETERS);
-    }
-    for (int i = 0; i < total_parameters; i ++){
-        sqlite3_bind_text(
-          stmt, i + 1, parameters[i], strlen(parameters[i]), NULL
-        );
-    }
-    //printf("PREP QUERY: %s\n", sqlite3_expanded_sql(stmt));
-    if (SQLITE_DONE != sqlite3_step(stmt)){
-        fprintf(
-          stderr, "ERROR Executing statement '%s': %s\n",
-          query, sqlite3_errmsg(db)
-        );
-        sqlite3_finalize(stmt);
-        return(ERROR_DB_EXECUTE);
-    }
-
-    sqlite3_finalize(stmt);
-    return(SUCCESS);
-}

+ 45 - 33
src/RuneOptimizer/db/db.h

@@ -17,63 +17,75 @@
 
 /**
  * @file db.h
- * Declaration of the database functions.
- */
-
-/**
- * Finalizes a database connection.
  *
- * @return SUCCESS or an SQLITE error code.
+ * Declarations of the database functions.
+ *
+ * This file declares all the database related functions implemented in
+ * {@link db.c}.
  */
-int db_close();
 
-/**
- * Ensures that the directory structure for the database exist.
- */
-void db_create_directories();
+#pragma once
+
+#include <sqlite3.h>
 
 /**
- * Creates all database tables.
+ * Finalizes a database connection.
+ *
+ * @return {@link SUCCESS} if the databse was closes or an SQLITE error code if
+ * something went wrong.
  */
-int db_create_tables();
+extern int db_close();
 
 /**
  * Opens the database connection.
  * 
- * Sets up the global db connection. On error, it prints a description to
- * stderr.
+ * Sets up  and enables the global db connection {@link db}. On error, it prints
+ * a description to stderr.
  *
- * @param[in] path Database path, relative to the execution path. Optional.
- * @return SUCCESS if the connection gets opened, or ERROR_DB_CANT_OPEN on
- * error.
+ * @param[in] path Database path, relative to the execution path. Optional, if
+ * passed as null, the path in the global variable {@link db_location} will be
+ * used.
+ * @return {@link SUCCESS} if the connection gets opened, or
+ * {@link ERROR_DB_CANT_OPEN} on error.
  */
-int db_open(char *path);
+extern int db_open(char *path);
 
 
 /**
  * Executes a database query for a result.
  * 
- * Uses the global database connection. If the connection is not initializad, it
- * calls @{see db_open}. On error, it prints a description to stderr.
+ * Uses the global database connection {@link db}. If the connection is not
+ * initializad, it calls {@link db_open}. On error, it prints a description to
+ * stderr.
  *
- * @param[out] stmt Statement to store the query results.
- * @param[in] query Query to execute.
+ * @param[out] stmt Statement to store the query results. Don't pass an used
+ * statement without having finalized it.
+ * @param[in] query Query to execute. Parameter placeholders can be indicated as
+ * '?'. Use only select parameters. For insert, update, delete, create, drop,
+ * etc use {@link db_execute}.
  * @param[in] parameters List of string parameters to bind to the query. They
- * all will be considered strings.
- * @return SUCCESS if the query is executed and the statment ready to be read,
- * or ERROR_DB_QUERY on error.
+ * all will be considered strings. It must have a size equal or greater than the
+ * number of parameters defined in the query with the symbol '?', but it can't
+ * be shorter.
+ * @return {@link SUCCESS} if the query is executed and the statment ready to
+ * be read, or {@link ERROR_DB_QUERY} on error.
  */
-int db_query(sqlite3_stmt **stmt, char query[], char *parameters[]);
+extern int db_query(sqlite3_stmt **stmt, char query[], char *parameters[]);
 
 /**
  * Executes a database statement.
  * 
- * Uses the global database connection. If the connection is not initializad, it
- * calls @{see db_open}On error, it prints a description to stderr.
+ * Uses the global database connection {@link db}. If the connection is not
+ * initializad, it calls {@link db_open}. On error, it prints a description to
+ * stderr.
  *
- * @param[in] query Query to execute.
+ * @param[in] query Query to execute. Parameter placeholders can be indicated as
+ * '?'. Don't use SELECT statements, use {@link db_query} for that.
  * @param[in] parameters List of string parameters to bind to the query. They
- * all will be considered strings.
- * @return SUCCESS if the query is executed or ERROR_DB_EXECUTE on error.
+ * all will be considered strings. It must have a size equal or greater than the
+ * number of parameters defined in the query with the symbol '?', but it can't
+ * be shorter.
+ * @return {@link SUCCESS} if the query is executed and the statment ready to
+ * be read, or {@link ERROR_DB_EXECUTE} on error.
  */
-int db_execute(char query[], char *parameters[]);
+extern int db_execute(char query[], char *parameters[]);

+ 196 - 59
src/RuneOptimizer/error/error.h

@@ -17,356 +17,493 @@
 
 /**
  * @file error.h
- * Definitions for error codes.
+ *
+ * Definitions for status and error codes.
  */
 
+#pragma once
+
 /**
  * Success indicator.
+ *
+ * It usually indicates that everything went OK.
  */
-#define SUCCESS -0
+#define SUCCESS 0
 
 /**
  * Indicator for an unimplemented functionality.
+ *
+ * It's usually returnd by some not-fully-implemented functionality.
  */
 #define UNIMPLEMENTED -800
 
 /**
- * Error indicating that no command has been passed to the program.
+ * User input error.
+ *
+ * Indicates that no command has been passed to the program.
  */
 #define ERROR_INPUT_NO_COMMAND -100
 
 /**
- * Error indicating that an invlaid command has been passed to the program.
+ * User input error.
+ *
+ * Indicates that an invlaid command has been passed to the program.
  */
 #define ERROR_INPUT_INVALID_COMMAND -101
 
 /**
- * Error indicating that no unit ID or name has been passed to the optimizer
+ * Optimizer user input error.
+ *
+ * Indicates that no unit ID or name has been passed to the optimizer
  * command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_UNIT -102
 
 /**
- * Error indicating an invalid value for the level parameter for the optimizer
+ * Optimizer user input error.
+ *
+ * Indicates an invalid value for the level parameter for the optimizer
  * comman.
  */
 #define ERROR_INPUT_OPTIMIZE_INVALID_LEVEL -103
 
 /**
- * Error indicating a missing value for the level parameter for the optimizer
+ * Optimizer user input error.
+ *
+ * Indicates a missing value for the level parameter for the optimizer
  * comman.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_LEVEL -104
 
 /**
- * Error indicating that no combination or an invalid combination of runes has
+ * Optimizer user input error.
+ *
+ * Indicates that no combination or an invalid combination of runes has
  * been passed to the optimizer command. This option is mandatory, and the list
  * of sets must make up for 6 runes.
  */
 #define ERROR_INPUT_OPTIMIZE_INVALID_SET -105
 
 /**
- * Error indicating that no combination or an invalid combination of runes has
+ * Optimizer user input error.
+ *
+ * Indicates that no combination or an invalid combination of runes has
  * been passed to the optimizer command. This option is mandatory, and the list
  * of sets must make up for 6 runes.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_SET -106
 
 /**
- * Error indicating that unregcognized stats have been passed to the stats
+ * Optimizer user input error.
+ *
+ * Indicates that unregcognized stats have been passed to the stats
  * option for the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_INVALID_STAT -107
 
 /**
- * Error indicating that the stats parameter has not been passed to the
+ * Optimizer user input error.
+ *
+ * Indicates that the stats parameter has not been passed to the
  * optimizer command. This parameter is mandatory.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_STAT -108
 
 /**
- * Error indicating that no value has been passed to the min HP parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min HP parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_HP -109
 
 /**
- * Error indicating that no value has been passed to the min ATK parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min ATK parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_ATK -110
 
 /**
- * Error indicating that no value has been passed to the min DEF parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min DEF parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_DEF -111
 
 /**
- * Error indicating that no value has been passed to the min SPD parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min SPD parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_SPD -112
 
 /**
- * Error indicating that no value has been passed to the min CRR parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min CRR parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_CRR -113
 
 /**
- * Error indicating that no value has been passed to the min CRD parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min CRD parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_CRD -114
 
 /**
- * Error indicating that no value has been passed to the min RES parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min RES parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_RES -115
 
 /**
- * Error indicating that no value has been passed to the min ACC parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min ACC parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_ACC -116
 
 /**
- * Error indicating that no value has been passed to the min EHP parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min EHP parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_EHP -117
 
 /**
- * Error indicating that no value has been passed to the min DMG parameter for
+ * Optimizer user input error.
+ *
+ * Indicates that no value has been passed to the min DMG parameter for
  * the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_DMG -118
 
 /**
- * Error indicating that no values have been passed to the exclude teams
+ * Optimizer user input error.
+ *
+ * Indicates that no values have been passed to the exclude teams
  * parameter for the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_TEAMS -119
 
 /**
- * Error indicating that no values have been passed to the exclude units
+ * Optimizer user input error.
+ *
+ * Indicates that no values have been passed to the exclude units
  * parameter for the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_NO_UNITS -119
 
 /**
- * Error indicating that not enough rune sets have been passed to the sets
+ * Optimizer user input error.
+ *
+ * Indicates that not enough rune sets have been passed to the sets
  * option for the optimizer command.
  */
 #define ERROR_INPUT_OPTIMIZE_INCOMPLETE_SETS -120
 
 /**
- * Error indicating that no action has been passed to the team command.
+ * Optimizer user input error.
+ *
+ * Indicates that not value has been passed to the threads option.
+ */
+#define ERROR_INPUT_OPTIMIZE_NO_THREADS -121
+
+/**
+ * Team command user input error.
+ *
+ * Indicates that no action has been passed to the team command.
  */
 #define ERROR_INPUT_TEAM_NO_ACTION -121
 
 /**
- * Error indicating that an invalid action has been passed to the team command.
+ * Team command user input error.
+ *
+ * Indicates that an invalid action has been passed to the team command.
  */
 #define ERROR_INPUT_TEAM_INVALID_ACTION -122
 
 /**
- * Error indicating that an invalid number of arguments have been passed to the
+ * Team command user input error.
+ *
+ * Indicates that an invalid number of arguments have been passed to the
  * team creation option. It requires one or two parameters.
  */
 #define ERROR_INPUT_TEAM_CREATE_ARGUMENT_COUNT -123
 
 /**
- * Error indicating that an invalid priority has been passed to the team
+ * Team command user input error.
+ *
+ * Indicates that an invalid priority has been passed to the team
  * creation option.
  */
 #define ERROR_INPUT_TEAM_CREATE_PRIORITY -124
 
 /**
- * Error indicating that no arguments has been passed to the update command.
- */
-#define ERROR_INPUT_UPDATE_NO_ARGUMENTS -125
-
-/**
- * Error indicating that an unrecognized source has been passed to the update
- * command.
- */
-#define ERROR_INPUT_UPDATE_UNKNOWN_SOURCE -126
-
-/**
- * Error indicating that the selected team does not exist in the database.
+ * Team command user input error.
+ *
+ * Indicates that the selected team does not exist in the database.
  */
 #define ERROR_INPUT_TEAM_VERIFY_TEAM -127
 
 /**
- * Error indicating that the selected team to include a unit to does not exist
+ * Team command user input error.
+ *
+ * Indicates that the selected team to include a unit to does not exist
  * in the database.
  */
 #define ERROR_INPUT_TEAM_VERIFY_UNIT_TEAM -128
 
 /**
- * Error indicating that the unit to include in a team does not exist in the
+ * Team command user input error.
+ *
+ * Indicates that the unit to include in a team does not exist in the
  * database.
  */
 #define ERROR_INPUT_TEAM_VERIFY_UNIT -129
 
 /**
- * Error indicating that the unit to include in a team is already part of the
+ * Team command user input error.
+ *
+ * Indicates that the unit to include in a team is already part of the
  * team.
  */
 #define ERROR_INPUT_TEAM_VERIFY_INCLUDED -130
 
 /**
- * Error indicating that an invalid number of arguments have been passed to the
+ * Team command user input error.
+ *
+ * Indicates that an invalid number of arguments have been passed to the
  * team deletion option. It requires only one argument: the team ID.
  */
 #define ERROR_INPUT_TEAM_DELETE_ARGUMENT_COUNT -131
 
 /**
- * Error indicating that no identifier has been passed to the unit command. The
+ * Update command user input error.
+ *
+ * Indicates that no arguments has been passed to the update command.
+ */
+#define ERROR_INPUT_UPDATE_NO_ARGUMENTS -125
+
+/**
+ * Update command user input error.
+ *
+ * Indicates that an unrecognized source has been passed to the update
+ * command.
+ */
+#define ERROR_INPUT_UPDATE_UNKNOWN_SOURCE -126
+
+
+/**
+ * Unit command user input error.
+ *
+ * Indicates that no identifier has been passed to the unit command. The
  * identifier is mandatory and can be a unit ID or part of a name (case
  * insensitive).
  */
 #define ERROR_INPUT_UNIT_NO_ID -132
 
 /**
- * Error indicating that the database could not be opened, for any reason.
+ * Database error.
+ *
+ * Indicates that the database could not be opened, for any reason.
  */
 #define ERROR_DB_CANT_OPEN -200
 
 /**
+ * Database error.
+ *
  * Error fetching a query results.
  */
 #define ERROR_DB_QUERY -232
 
 /**
+ * Database error.
+ *
  * Error executing statement.
  */
 #define ERROR_DB_EXECUTE -233
 
 /**
- * Error indicating that no parameters have been passed to db_query for a query
+ * Database error.
+ *
+ * Indicates that no parameters have been passed to db_query for a query
  * that requires them.
  */
 #define ERROR_DB_QUERY_NO_PARAMETERS -235
 
 /**
- * Error indicating that no parameters have been passed to db_execute for a
+ * Database error.
+ *
+ * Indicates that no parameters have been passed to db_execute for a
  * query that requires them.
  */
 #define ERROR_DB_EXECUTE_NO_PARAMETERS -236
 
 /**
+ * Database error.
+ *
  * Error droping a table.
  */
 #define ERROR_DB_DROP -234
 
 /**
- * Error indicating that the table rune_stats could not be created.
+ * Database error.
+ *
+ * Indicates that the table rune_stats could not be created.
  */
 #define ERROR_DB_CREATE_RUNE_STATS -213
 
 /**
- * Error indicating that the table runes could not be created.
+ * Database error.
+ *
+ * Indicates that the table runes could not be created.
  */
 #define ERROR_DB_CREATE_RUNES -214
 
 /**
- * Error indicating that the table units could not be created.
+ * Database error.
+ *
+ * Indicates that the table units could not be created.
  */
 #define ERROR_DB_CREATE_UNITS -215
 
 /**
- * Error indicating that the table teams could not be created.
+ * Database error.
+ *
+ * Indicates that the table teams could not be created.
  */
 #define ERROR_DB_CREATE_TEAMS -216
 
 /**
- * Error indicating that the table units_teams could not be created.
+ * Database error.
+ *
+ * Indicates that the table units_teams could not be created.
  */
 #define ERROR_DB_CREATE_UNITS_TEAMS -217
 
 /**
- * Error indicating that the table info could not be created.
+ * Database error.
+ *
+ * Indicates that the table info could not be created.
  */
 #define ERROR_DB_CREATE_INFO -226
 
 /**
+ * Database error.
+ *
  * Error inserting into rune_stats.
  */
 #define ERROR_DB_INSERT_RUNE_STATS -218
 
 /**
+ * Database error.
+ *
  * Error inserting into runes.
  */
 #define ERROR_DB_INSERT_RUNES -219
 
 /**
+ * Database error.
+ *
  * Error inserting into units.
  */
 #define ERROR_DB_INSERT_UNITS -220
 
 /**
+ * Database error.
+ *
  * Error inserting into teams.
  */
 #define ERROR_DB_INSERT_TEAMS -221
 
 /**
+ * Database error.
+ *
  * Error inserting into units_teams.
  */
 #define ERROR_DB_INSERT_UNITS_TEAMS -222
 
 /**
+ * Database error.
+ *
  * Error inserting into info.
  */
 #define ERROR_DB_INSERT_INFO -227
 
 /**
+ * Database error.
+ *
  * Error updating the table units.
  */
 #define ERROR_DB_UPDATE_UNITS -223
 
 /**
+ * Database error.
+ *
  * Error deletng from units_teams.
  */
 #define ERROR_DB_DELETE_UNITS_TEAMS -229
 
 /**
+ * Database error.
+ *
  * Error deleting from table teams.
  */
 #define ERROR_DB_DELETE_TEAMS -231
 
 /**
- * Error indicating that the requestd unit doesn't exist in the database.
+ * Database error.
+ *
+ * Indicates that the requestd unit doesn't exist in the database.
  */
 #define ERROR_DB_SELECT_UNIT -202
 
 /**
- * Error indicating that the team does not exist in the database.
+ * Database error.
+ *
+ * Indicates that the team does not exist in the database.
  */
 #define ERROR_DB_SELECT_TEAM -230
 
 /**
- * Error indicating that a rune doesn't exist in the database.
+ * Database error.
+ *
+ * Indicates that a rune doesn't exist in the database.
  */
 #define ERROR_DB_SELECT_RUNE -237
 
 /**
- * Error indicating that there is no info in the database. The update command
+ * Database error.
+ *
+ * Indicates that there is no info in the database. The update command
  * must be run to populate the database.
  */
 #define ERROR_DB_SELECT_INFO -238
 
 /**
- * Error indicating that a new ID for a team could not be retrieved from the
+ * Database error.
+ *
+ * Indicates that a new ID for a team could not be retrieved from the
  * database. This indcates that no teams exists yet, so it's safe to pick 1 for
  * the new ID.
  */
 #define ERROR_DB_NEW_TEAM_ID -207
 
 /**
+ * Database error.
+ *
  * Error reading from tables teams, units, or units_teams.
  */
 #define ERROR_DB_VERIFY_TEAM_UNIT -228

+ 7 - 2
src/RuneOptimizer/gui/gui.c

@@ -17,11 +17,16 @@
 
 /**
  * @file gui.c
- * Implementation of the gui command.
+ *
+ * Implementation of the functions used by the gui command.
+ *
+ * This file implements the functions used by the gui command declared in
+ * {@link gui.h}.
  */
 
 #include "gui.h"
+#include "../db/db.h"
 
-int cmd_gui(){
+int gui(){
     db_open(NULL);
 }

+ 14 - 4
src/RuneOptimizer/gui/gui.h

@@ -17,12 +17,22 @@
 
 /**
  * @file gui.h
- * Declaration of the gui command.
+ *
+ * Declarations of the functions related to the gui command.
+ *
+ * This file declares all the functions used by the gui command implemented in
+ * {@link gui.c}.
  */
 
+#pragma once
+
 /**
- * Makes sure that the db is set up for the gui.
+ * Makes sure that the database is set up for the gui.
+ *
+ * This will make sure that the database exists in the default location, and
+ * that all the tables are created by making a call to {@link db_open}.
  *
- * @return SUCCESS or ERROR_BD_CANT_OPEN if the database cant be created.
+ * @return {@link SUCCESS} or {@link ERROR_DB_CANT_OPEN} if the database
+ * can't be created or accessed.
  */
-int cmd_gui();
+int gui();

+ 153 - 100
src/RuneOptimizer/help/help.c

@@ -17,111 +17,164 @@
 
 /**
  * @file help.c
- * Implementation of the help command.
+ *
+ * Implementation of the functions used by the help command.
+ *
+ * This file implements the functions used by the help command declared in
+ * {@link help.h}.
  */
 
 #include "help.h"
 
-void cmd_help(){
+void help(){
     printf("\nRune Optimizer %s\n", VERSION);
     printf("%s <%s>\n", AUTHOR, MAIL);
-    printf("\n  Usage:\n");
-    printf("  RuneOptimizer [command] [options]\n");
-    printf("\n\n  Command: help\n");
-    printf("\n    Display this help text and exists. It has no options.\n");
-    printf("\n\n  Command: player\n");
-    printf("\n    Displays info about the player. It takes no options.\n");
-    printf("\n\n  Command: gui\n");
-    printf("\n    Sets up the database to be used by the GUI. No need to run it manually.\n");
-    printf("\n    Usage\n");
-    printf("\n\n  Command: unit\n");
-    printf("\n    View info about units.\n");
-    printf("\n    Usage\n");
-    printf("\n    Usage\n");
-    printf("\n\n  Command: update\n");
-    printf("\n    Updates the information and builds a database. Usage.\n");
-    printf("    RuneOptimizer update [source] [options]\n");
-    printf("\n      [source] can be either: \n");
-    printf("        A JSON file exported from the game: \n");
-    printf("        A SQLite file from a SWDB instance (unimplemented)\n");
-    printf("        A SWDB profile URL (unimplemented)\n");
-    printf("        A Swarfarm profile URL (unimplemented)\n");
-    printf("        Options: \n\n");
-    printf("          -s | --six-stars     Only save the info about the 6 star units.\n");
-    printf("                               If a unit has runes, it will be saved anyway.\n");
-    printf("          -r | --with-runes    Only save info about units with runes.\n");
-    printf("          -t | --clear-teams   Delete all team information (can't be undone!).\n");
-    printf("          -g | --gui           Formats the output to be consumed by the GUI.\n");
-    printf("\n\n  Command: unit\n");
-    printf("\n    View info about units.\n");
-    printf("\n    Usage\n");
-    printf("    RuneOptimizer unit [term]\n");
-    printf("\n      [term] can be a full unit ID or part of a name (case insensitive).\n");
-    printf("\n\n  Command: team\n");
-    printf("\n    Manages teams.\n");
-    printf("\n    Usage\n");
-    printf("    RuneOptimizer team [action] [options]\n");
-    printf("\n      Actions: \n\n");
-    printf("        list [id] <options>        List list of all or the selected team.\n");
-    printf("          [id] is optional and can be a team ID.\n");
-    printf("          Options: \n");
-    printf("            -u | --units        Include the units in the details.\n");
-    printf("\n        create [name] [priority]   Creates a new team.\n");
-    printf("          [name] The new team name, mandatory.\n");
-    printf("          [priority] Team priority (0-50). Optional, defaults to 0.\n");
-    printf("\n        delete [id]                Deletes a team and it's units.\n");
-    printf("          [id] The team ID, mandatory.\n");
-    printf("          WARNING! This can't be undone!\n");
-    printf("\n        add_unit [team] [unit]     Adds a unit to a team.\n");
-    printf("          [team] The team ID, mandatory.\n");
-    printf("          [unit] The unit ID, mandatory.\n");
-    printf("\n        remove_unit [team] [unit]  Removes a unit from a team.\n");
-    printf("          [team] The team ID, mandatory.\n");
-    printf("          [unit] The unit ID, mandatory.\n");
-    printf("\n\n  Command: optimize\n");
-    printf("\n    Calculates an optimization for a unit.\n");
-    printf("\n    Usage\n");
-    printf("    RuneOptimizer optimize [unit] <options>\n");
-    printf("\n      [unit] can be a unit ID or a unit name (case sensitive)\n");
-    printf("\n      Options: \n\n");
-    printf("        -h | --min_hp <NUM>          Minumum HP to consider in the optimization.\n");
-    printf("                                     It defaults to the unit's current value.\n");
-    printf("        -a | --min_atk <NUM>         Minumum ATK to consider in the optimization.\n");
-    printf("                                     It defaults to the unit's current value.\n");
-    printf("        -d | --min_def <NUM>         Minumum DEF to consider in the optimization.\n");
-    printf("                                     It defaults to the unit's current value.\n");
-    printf("        -s | --min_spd <NUM>         Minumum SPD to consider in the optimization.\n");
-    printf("                                     It defaults to the unit's current value.\n");
-    printf("        -c | --min_crr <NUM>         Minumum CRIT RATE to consider in the optimization.\n");
-    printf("                                     It defaults to the unit's current value.\n");
-    printf("        -d | --min_crd <NUM>         Minumum CRIT DAMAGE to consider in the optimization.\n");
-    printf("                                     It defaults to the unit's current value.\n");
-    printf("        -r | --min_res <NUM>         Minumum RES to consider in the optimization.\n");
-    printf("                                     It defaults to the unit's current value.\n");
-    printf("        -f | --min_acc <NUM>         Minumum ACC to consider in the optimization.\n");
-    printf("                                     It defaults to the unit's current value.\n");
-    printf("        -p | --min_ehp <NUM>         Minumum effective HP to consider in the optimization.\n");
-    printf("                                     It defaults to 0.\n");
-    printf("        -m | --min_dmg <NUM>         Minumum computed damage to consider in the optimization.\n");
-    printf("                                     It defaults to 0.\n");
-    printf("        -l | --level <LV>            Level to consider the runes during the optimization.\n");
-    printf("                                     It only affects the rune main stats. Valid values are\n");
-    printf("                                     'current', '12' and '15'. Default is 'current'\n");
-    printf("        -t | --stats <ST1>,<ST2>...  Stats than can be selected as mains for slots 2, 4 and 6.\n");
-    printf("                                     Only the selected stats will be included, so this option\n");
-    printf("                                     is mandatory. Accepted values are 'hp', 'atk', 'def',\n");
-    printf("                                     'hpflat', 'atkflat', 'defflat', 'spd', 'crr', 'crd',\n");
-    printf("                                     'res' and 'acc'. Values must be comma-separated, and up\n");
-    printf("                                     to 12 can be included.\n");
-    printf("        -e | --sets <S1>,<S2>...     Rune sets that than the unit being optimized must have.\n");
-    printf("        -i | --opt-sets <S1>,<S2>... Other rune sets that can be used to complement the required ones.\n");
-    printf("        -k | --broken                Allow the unit to have broken sets, other than the required ones.\n");
-    printf("        -o | --storage               Use only runes not assigned to units.\n");
-    printf("        -x | --no-teams <T1>,<T2>... Exclude runes assigned to units in selected teams.\n");
-    printf("                                     Team IDs can be supplied, comma-separated.\n");
-    printf("        -u | --no-units <U1>,<U2>... Exclude runes assigned to units in selected units.\n");
-    printf("                                     Unit IDs can be supplied, comma-separated.\n");
-    printf("        -g | --gui                   Formats the output to be consumed by the GUI.\n");
-    printf("        -b | --threads <NUM>         Use <NUM> threads for optimizaton (1-8).\n");
+    printf(
+      "\n"
+      "Rune Optimizer " VERSION "\n"
+      AUTHOR "Iñigo Valentin <" MAIL ">\n"
+      "\n"
+      "  Usage:\n"
+      "  RuneOptimizer [command] [options]\n"
+      "\n"
+      "\n"
+      "  Command: help\n"
+      "\n"
+      "    Display this help text and exists. It has no options.\n"
+      "\n"
+      "\n"
+      "  Command: player\n"
+      "\n"
+      "    Displays info about the player. It takes no options.\n"
+      "\n"
+      "\n"
+      "  Command: gui\n"
+      "\n"
+      "    Sets up the database to be used by the GUI. No need to run it manually.\n"
+      "\n"
+      "    Usage\n"
+      "\n"
+      "\n"
+      "  Command: unit\n"
+      "\n"
+      "    View info about units.\n"
+      "\n"
+      "    Usage\n"
+      "\n"
+      "    Usage\n"
+      "\n"
+      "\n"
+      "  Command: update\n"
+      "\n"
+      "    Updates the information and builds a database. Usage.\n"
+      "    RuneOptimizer update [source] [options]\n"
+      "\n"
+      "      [source] can be either: \n"
+      "        A JSON file exported from the game: \n"
+      "        A SQLite file from a SWDB instance (unimplemented)\n"
+      "        A SWDB profile URL (unimplemented)\n"
+      "        A Swarfarm profile URL (unimplemented)\n"
+      "        Options: \n"
+      "\n"
+      "          -s | --six-stars     Only save the info about the 6 star units.\n"
+      "                               If a unit has runes, it will be saved anyway.\n"
+      "          -r | --with-runes    Only save info about units with runes.\n"
+      "          -t | --clear-teams   Delete all team information (can't be undone!).\n"
+      "          -g | --gui           Formats the output to be consumed by the GUI.\n"
+      "\n"
+      "\n"
+      "  Command: unit\n"
+      "\n"
+      "    View info about units.\n"
+      "\n"
+      "    Usage\n"
+      "    RuneOptimizer unit [term]\n"
+      "\n"
+      "      [term] can be a full unit ID or part of a name (case insensitive).\n"
+      "\n"
+      "\n"
+      "  Command: team\n"
+      "\n"
+      "    Manages teams.\n"
+      "\n"
+      "    Usage\n"
+      "    RuneOptimizer team [action] [options]\n"
+      "\n"
+      "      Actions: \n"
+      "\n"
+      "        list [id] <options>        List list of all or the selected team.\n"
+      "          [id] is optional and can be a team ID.\n"
+      "          Options: \n"
+      "            -u | --units        Include the units in the details.\n"
+      "\n"
+      "        create [name] [priority]   Creates a new team.\n"
+      "          [name] The new team name, mandatory.\n"
+      "          [priority] Team priority (0-50). Optional, defaults to 0.\n"
+      "\n"
+      "        delete [id]                Deletes a team and it's units.\n"
+      "          [id] The team ID, mandatory.\n"
+      "          WARNING! This can't be undone!\n"
+      "\n"
+      "        add_unit [team] [unit]     Adds a unit to a team.\n"
+      "          [team] The team ID, mandatory.\n"
+      "          [unit] The unit ID, mandatory.\n"
+      "\n"
+      "        remove_unit [team] [unit]  Removes a unit from a team.\n"
+      "          [team] The team ID, mandatory.\n"
+      "          [unit] The unit ID, mandatory.\n"
+      "\n"
+      "\n"
+      "  Command: optimize\n"
+      "\n"
+      "    Calculates an optimization for a unit.\n"
+      "\n"
+      "    Usage\n"
+      "    RuneOptimizer optimize [unit] <options>\n"
+      "\n"
+      "      [unit] can be a unit ID or a unit name (case sensitive)\n"
+      "\n"
+      "      Options: \n"
+      "\n"
+      "        -h | --min_hp <NUM>          Minumum HP to consider in the optimization.\n"
+      "                                     It defaults to the unit's current value.\n"
+      "        -a | --min_atk <NUM>         Minumum ATK to consider in the optimization.\n"
+      "                                     It defaults to the unit's current value.\n"
+      "        -d | --min_def <NUM>         Minumum DEF to consider in the optimization.\n"
+      "                                     It defaults to the unit's current value.\n"
+      "        -s | --min_spd <NUM>         Minumum SPD to consider in the optimization.\n"
+      "                                     It defaults to the unit's current value.\n"
+      "        -c | --min_crr <NUM>         Minumum CRIT RATE to consider in the optimization.\n"
+      "                                     It defaults to the unit's current value.\n"
+      "        -d | --min_crd <NUM>         Minumum CRIT DAMAGE to consider in the optimization.\n"
+      "                                     It defaults to the unit's current value.\n"
+      "        -r | --min_res <NUM>         Minumum RES to consider in the optimization.\n"
+      "                                     It defaults to the unit's current value.\n"
+      "        -f | --min_acc <NUM>         Minumum ACC to consider in the optimization.\n"
+      "                                     It defaults to the unit's current value.\n"
+      "        -p | --min_ehp <NUM>         Minumum effective HP to consider in the optimization.\n"
+      "                                     It defaults to 0.\n"
+      "        -m | --min_dmg <NUM>         Minumum computed damage to consider in the optimization.\n"
+      "                                     It defaults to 0.\n"
+      "        -l | --level <LV>            Level to consider the runes during the optimization.\n"
+      "                                     It only affects the rune main stats. Valid values are\n"
+      "                                     'current', '12' and '15'. Default is 'current'\n"
+      "        -t | --stats <ST1>,<ST2>...  Stats than can be selected as mains for slots 2, 4 and 6.\n"
+      "                                     Only the selected stats will be included, so this option\n"
+      "                                     is mandatory. Accepted values are 'hp', 'atk', 'def',\n"
+      "                                     'hpflat', 'atkflat', 'defflat', 'spd', 'crr', 'crd',\n"
+      "                                     'res' and 'acc'. Values must be comma-separated, and up\n"
+      "                                     to 12 can be included.\n"
+      "        -e | --sets <S1>,<S2>...     Rune sets that than the unit being optimized must have.\n"
+      "        -i | --opt-sets <S1>,<S2>... Other rune sets that can be used to complement the required ones.\n"
+      "        -k | --broken                Allow the unit to have broken sets, other than the required ones.\n"
+      "        -o | --storage               Use only runes not assigned to units.\n"
+      "        -x | --no-teams <T1>,<T2>... Exclude runes assigned to units in selected teams.\n"
+      "                                     Team IDs can be supplied, comma-separated.\n"
+      "        -u | --no-units <U1>,<U2>... Exclude runes assigned to units in selected units.\n"
+      "                                     Unit IDs can be supplied, comma-separated.\n"
+      "        -g | --gui                   Formats the output to be consumed by the GUI.\n"
+      "        -b | --threads <NUM>         Use <NUM> threads for optimizaton (1-8).\n"
+
+    );
     return;
 }

+ 11 - 2
src/RuneOptimizer/help/help.h

@@ -17,10 +17,19 @@
 
 /**
  * @file help.h
- * Declaration of the help command.
+ *
+ * Declarations of the functions related to the help command.
+ *
+ * This file declares all the functions used by the help command implemented in
+ * {@link help.c}.
  */
 
+#pragma once
+
 /**
  * Displays the help text.
+ *
+ * Displays the help text, with a description of the program and the available
+ * commands with details on how to use them.
  */
-void cmd_help();
+void help();

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1335 - 102
src/RuneOptimizer/optimize/optimize.c


+ 565 - 237
src/RuneOptimizer/optimize/optimize.h

@@ -17,14 +17,29 @@
 
 /**
  * @file optimize.h
- * Declaration of the functions used by the optiimzer command.
+ *
+ * Declarations of the functions and data typer related to the optimixe command.
+ *
+ * This file declares all the functions and data types used by the optimize
+ * command implemented in {@link optimize.c}.
  */
 
+#pragma once
+
+#include "../RuneOptimizer.h"
+
 /**
  * Hard limit on the number of results
  */
 #define MAX_RESULTS 5000
 
+/**
+ * Limit on runes per slot for the optimizations.
+ *
+ * Number format.
+ */
+#define LIMIT_RUNES_PER_SLOT 500
+
 /**
  * Hard limit on the number of teams or units that can be excluded from
  * optimization.
@@ -32,325 +47,638 @@
 #define MAX_EXCLUSIONS 128
 
 /**
- * Structure representing a unit. Represents an entity from the table 'unit'.
+ * Maximum number of sets.
+ *
+ * Maximum for the requested sets option.
  */
-typedef struct Unit {
-    unsigned char id[12];
-    unsigned char name[50];
-    unsigned int base_hp;
-    unsigned short base_atk;
-    unsigned short base_def;
-    unsigned short base_spd;
-    unsigned short base_crr;
-    unsigned short base_crd;
-    unsigned short base_acc;
-    unsigned short base_res;
-    unsigned int base_ehp;
-    unsigned short base_dmg;
-    unsigned int current_hp;
-    unsigned short current_atk;
-    unsigned short current_def;
-    unsigned short current_spd;
-    unsigned short current_crr;
-    unsigned short current_crd;
-    unsigned short current_acc;
-    unsigned short current_res;
-    unsigned int current_ehp;
-    unsigned short current_dmg;
-} Unit;
+#define MAX_SETS 3
 
 /**
- * Structure representing a rune.
+ * A rune.
+ *
+ * Contains usefull information to operate with runes.
  */
 typedef struct Rune {
-    unsigned char id[12];
+
+    /**
+     * The rune ID.
+     *
+     * Unit ID, as given by Com2Us.
+     */
+    unsigned char id[RUNE_ID_LEN];
+
+    /**
+     * The slot of the rune
+     *
+     * Can be [1-6].
+     */
     unsigned char slot;
+
+    /**
+     * Rune set id.
+     *
+     * Identifier of the set the rune belongs to.
+     */
     unsigned char set;
-    unsigned char unit[12];
+
+    /**
+     * ID of the unit the rune is assigned to.
+     *
+     * NULL if the rune is not assigned.
+     */
+    unsigned char unit[UNIT_ID_LEN];
+
+    /**
+     * HP% stat.
+     *
+     * HP% given by the rune, in any of it's stats.
+     */
     unsigned char hp_percent;
+
+    /**
+     * ATK% stat.
+     *
+     * ATK% given by the rune, in any of it's stats.
+     */
     unsigned char atk_percent;
+
+    /**
+     * DEF% stat.
+     *
+     * DEF% given by the rune, in any of it's stats.
+     */
     unsigned char def_percent;
+
+    /**
+     * HP stat.
+     *
+     * HP given by the rune, in any of it's stats.
+     */
     unsigned short hp_flat;
+
+    /**
+     * ATK stat.
+     *
+     * ATK given by the rune, in any of it's stats.
+     */
     unsigned char atk_flat;
+
+    /**
+     * DEF stat.
+     *
+     * DEF given by the rune, in any of it's stats.
+     */
     unsigned char def_flat;
+
+    /**
+     * SPD stat.
+     *
+     * SPD given by the rune, in any of it's stats.
+     */
     unsigned char spd;
+
+    /**
+     * CRR stat.
+     *
+     * CRR given by the rune, in any of it's stats.
+     */
     unsigned char crr;
+
+    /**
+     * CRD stat.
+     *
+     * CRD given by the rune, in any of it's stats.
+     */
     unsigned char crd;
-    unsigned char acc;
+
+    /**
+     * RES stat.
+     *
+     * RES given by the rune, in any of it's stats.
+     */
     unsigned char res;
+
+    /**
+     * ACC stat.
+     *
+     * ACC given by the rune, in any of it's stats.
+     */
+    unsigned char acc;
 } Rune;
 
+
 /**
- * A set of stats.
+ * Stats of a unit.
+ *
+ * Can be used for base stats or for current stats.
  */
 typedef struct Stats {
+
+    /**
+     * HP stat.
+     *
+     * Unit health. Unit gets defeated in battle when it reaches 0.
+     */
     unsigned int hp;
+
+    /**
+     * ATK stat.
+     *
+     * Unit attack power. Retermines how much damage it does.
+     */
     unsigned short atk;
+
+    /**
+     * DEF stat.
+     *
+     * Unit defense. Reduces incoming damage.
+     */
     unsigned short def;
+
+    /**
+     * SPD stat.
+     *
+     * Unit speed. Determines turn order.
+     */
     unsigned short spd;
+
+    /**
+     * CRR stat.
+     *
+     * Chance of landing a critical hit. Capped at 100.
+     */
     unsigned short crr;
+
+    /**
+     * CRD stat.
+     *
+     * Extra damage done when landing a critical hit.
+     */
     unsigned short crd;
-    unsigned short acc;
+
+    /**
+     * RES stat.
+     *
+     * Chance of resisting a harmful effect. Cant be lower than 15.
+     */
     unsigned short res;
+
+    /**
+     * ACC stat.
+     *
+     * Chance of landing a harmfull effect. Effective cap is 85.
+     */
+    unsigned short acc;
+
+    /**
+     * EHP stat.
+     *
+     * EHP is a complex stat that depends on {@link hp} and {@link def}. See
+     * {@link calculate_ehp} for more details.
+     */
     unsigned int ehp;
+
+    /**
+     * DMG stat.
+     *
+     * DMG is a complex stat that depends on {@link atk} and {@link crr} and
+     * {@link crr}. See {@link calculate_ehp} for more details.
+     */
     unsigned short dmg;
 } Stats;
 
+/**
+ * Indicates ponderations for stats.
+ *
+ * Ponderations are used to give more or less weight to a stat when calculating
+ * a {@link Result}.rating.
+ *
+ * @todo Implement ponderations.
+ */
 typedef struct Stat_Ponderation {
+
+    /**
+     * HP ponderation.
+     *
+     * Weight given to the HP stat.
+     */
     float hp;
+
+    /**
+     * ATK ponderation.
+     *
+     * Weight given to the ATK stat.
+     */
     float atk;
+
+    /**
+     * DEF ponderation.
+     *
+     * Weight given to the DEF stat.
+     */
     float def;
+
+    /**
+     * SPD ponderation.
+     *
+     * Weight given to the SPD stat.
+     */
     float spd;
+
+    /**
+     * CRR ponderation.
+     *
+     * Weight given to the CRR stat.
+     */
     float crr;
+
+    /**
+     * CRD ponderation.
+     *
+     * Weight given to the CRD stat.
+     */
     float crd;
-    float acc;
+
+    /**
+     * RES ponderation.
+     *
+     * Weight given to the RES stat.
+     */
     float res;
+
+    /**
+     * ACC ponderation.
+     *
+     * Weight given to the ACC stat.
+     */
+    float acc;
 } Stat_Ponderation;
 
 /**
- * A result, composed of 6 runes.
+ * A result of the optimization.
+ *
+ * {@link optimize_thread} loads one for each combination that match all the
+ * criteria passed to the optimizer.
  */
 typedef struct Result {
-    unsigned char rune_ids[6][12];
+
+    /**
+     * Runes.
+     *
+     * The runes that compose the result.
+     */
+    unsigned char rune_ids[RUNE_SLOTS][RUNE_ID_LEN];
+
+    /**
+     * The rating of the result.
+     *
+     * Calculated by comparing each stat (except EHP and DMG) with the unit
+     * current stats.
+     */
     signed int rating;
+
+    /**
+     * Result stats.
+     *
+     * The stats the unit would have with the result runes equipped.
+     */
     struct Stats stats;
 } Result;
 
 /**
  * Options for the optimizer.
+ *
+ * The options that can be passed to the optimizer via arguments. Default values
+ * are assigned in {@link optimize_set_default_options}, and the argument values
+ * are set in {@link optimize_parse_arguments}.
  */
 typedef struct Optimizer_Options {
-    unsigned char id[64];
+
+    /**
+     * Unit ID.
+     *
+     * Mandatory, has no default value. Must be de first parameter passed to the
+     * optimizer. For a while, it may contain a Unit name so the size is
+     * increased.
+     */
+    unsigned char id[UNIT_NAME_LEN];
+
+    /**
+     * Rune to consider the levels at during optimization.
+     *
+     * The level option argument is -l or --level, and the value can be
+     * 'current', '12', or '15', for {@link LVCURR}, {@link LV12}, or
+     * {@link LV15}, respectively. If not specifier, the default value is
+     * {@link LVCURR}.
+     *
+     * At current level, the optimization will be done considering the rune as
+     * is, but at levels 12 or 15, if the rune is currently in a lower level,
+     * the main stat will be considered to have the value it would have if the
+     * rune was at that level.
+     */
     unsigned char level;
-    unsigned char sets[3];
+
+    /**
+     * Sets of runes that the unit must have.
+     *
+     * These are the sets of runes that the unit must have after optimization.
+     * Any combination of runes that doesn't conform at least these sets will
+     * be discarded.
+     *
+     * The parameter to set this option is -e or --sets, and the sets have to be
+     * passed by name, lowercase, separated by commas. This option is mandatory
+     * and at least one set needs to be passed. Sets can be repeated, but the
+     * sum of runes in every set cant be more than 6. Only the first three sets
+     * passed will be read, the rest will be ignored.
+     *
+     * Some examples:
+     *
+     * @code
+     * --sets violent,energy           :OK, optimize for violent,energy
+     * --sets violent,rage             :ERROR, too many runes.
+     * --sets shield                   :OK, optimize for at least one blade
+     *                                  set.
+     * --sets will,will,will           :OK, optimize for three will sets.
+     * --sets VioLenT                  :ERROR, unrecognized set (lowercase!)
+     * --sets will,rage,blade,swift:   :OK, check for will,rage,blade (swift
+     *                                  is ignored!)
+     * @endcode
+     */
+    unsigned char sets[MAX_SETS];
+
+    /**
+     * Indicates if the sets in {@link sets} amount for 6 runes.
+     *
+     * This is not a configurable option, but a handy flag. The default value is
+     * {@link FALSE} and will be checked in {@link optimize}.
+     */
     unsigned char full_set;
-    unsigned char optional_sets[25];
-    unsigned char stats[13];
+
+    /**
+     * Other sets of runes that can be used.
+     *
+     * When the sets passed in th eoption {@link sets} don't amount to 6 runes,
+     * more sets can be indicated here. If so, only runes of the selected sets
+     * will be used to fill the remaining slots, but unless {@link broken_sets}
+     * is set, its not guaranteed that full sets will be formed.
+     *
+     * The parameter to set this option is -i or --opt-sets, and the sets have
+     * to be passed by name, lowercase, separated by commas. This option is
+     * optional, but if used, at least one set needs to be passed. Repeated sets
+     * are ignored, and setting the same that in {@link sets} will have no
+     * effect. It can take as many as rune sets are, but optimization times
+     * increase exponencially for every set.
+     */
+    unsigned char optional_sets[DIFFERENT_SETS];
+
+    /**
+     * Stats allowed in the even slots.
+     *
+     * Use this option to indicate wich stats are allowed to be used in slots 2,
+     * 4 and 6. Only the runes with a main stat in this list will be considered
+     * during the optimization. The parameter is -t or --stats, and the stats
+     * have to be passed separated by commas.
+     *
+     * Accepted values are 'hp',
+     * 'hpflat', 'atk', 'atkflat', 'def', 'defflat', 'spd', 'crr', 'crd', 'res'
+     * and 'acc'. As many as the user want can be passed, and repeated ones will
+     * be ignored.
+     */
+    unsigned char stats[DIFFERENT_STATS];
+
+    /**
+     * Min stats for the unit.
+     *
+     * During optimization, only the runes that leave the unit with at least
+     * this stats will be considered a match. These are optional parameters and,
+     * except min EHP and min DMG, which default to 0, the rest of stat
+     * minimum default to the unit's current values.
+     *
+     * The parameters to set these valuesare:
+     *
+     * <pre>
+     * -h | --min_hp  N
+     * -a | --min_atk N
+     * -d | --min_def N
+     * -s | --min_spd N
+     * -c | --min_crr N
+     * -d | --min_crd N
+     * -r | --min_res N
+     * -f | --min_acc N
+     * -p | --min_ehp N
+     * -m | --min_dmg N
+     * </pre>
+     */
     Stats *min_stats;
+
+    /**
+     * Option to format the optput for the GUI.
+     *
+     * This is not intended to be used by the user. It changes the output format
+     * to be consumed by the GUI. To set it, the parameter -g or --gui must be
+     * passed (it takes no options).
+     */
     unsigned char gui;
+
+    /**
+     * Flag to use only unassigned runes.
+     *
+     * If this option is set to {@link TRUE}, only runes in storage (i.e. not
+     * assigned to any unit will be considered during optimization). Runes
+     * assigned to the unit being currently optimizad will of course be
+     * considered even with this option.
+     *
+     * The parameter to set this option is -o or --storage, and it takes no
+     * options.
+     */
     unsigned char storage;
-    unsigned char excluded_teams[MAX_EXCLUSIONS][8];
-    unsigned char total_excluded_teams;
-    unsigned char excluded_units[MAX_EXCLUSIONS][16];
-    unsigned char total_excluded_units;
-    unsigned char broken_sets;
-    unsigned char threads;
-    // TODO: unimplemented options;
-    Stat_Ponderation ponderation;
 
-} Optimizer_Options;
+    /**
+     * List of teams to ignore during optimization.
+     *
+     * For every team indicated here, no rune of it's units will be considered
+     * during optimization. If the unit currently being optimized is in one of
+     * these teams, the unit's runes will still be considered.
+     *
+     * The parameter for this option is -x or --no-teams, followed by a comma
+     * separated list of team IDs (not names). If more teams that
+     * {@link MAX_EXCLUSIONS} are indicated, the last ones wil be ignored.
+     */
+    unsigned char excluded_teams[MAX_EXCLUSIONS][TEAM_ID_LEN];
 
-/**
- * Data package used by optimize_thread.
- */
-typedef struct Optimizer_Data {
-    unsigned int thread_id;
-    Rune runes[7][1000];
-    unsigned int count[7];
-    unsigned char start_at;
-    unsigned char end_at;
-    Result results[MAX_RESULTS];
-    unsigned int total_results;
-    Optimizer_Options options;
-    unsigned long long max_combinations;
-    Rune_Set_Count requested_set_count;
-    Unit unit;
-} Optimizer_Data;
+    /**
+     * Indicates how many teams are excluded.
+     *
+     * This is not a configurable option, but a handy counter. The default value
+     * is 0, and will be set when {@link excluded_teams} is populated.
+     */
+    unsigned char total_excluded_teams;
 
-/**
- * Names for run stats.
- * 
- * Indexed by Com2Us ID.
- */
-const char stat_names[][13] = {
-  "NULL", "HP_FLAT", "HP",  "ATK_FLAT", "ATK", "DEF_FLAT",
-  "DEF",  "NULL",    "SPD", "CRR",      "CRD", "RES",      "ACC"
-};
+    /**
+     * List of units to ignore during optimization.
+     *
+     * For every unit indicated here, it's units will be considered during
+     * optimization. If the unit currently being optimized is in the list, it's
+     * runes will still be considered.
+     *
+     * The parameter for this option is -u or --no-units, followed by a comma
+     * separated list of unit IDs (not names). If more units that
+     * {@link MAX_EXCLUSIONS} are indicated, the last ones wil be ignored. If is
+     * not enough, consider making a team and exclude with
+     * {@link excluded_teams}.
+     */
+    unsigned char excluded_units[MAX_EXCLUSIONS][UNIT_ID_LEN];
 
-/**
- * Names for rune sets.
- * 
- * Indexed by Com2Us ID.
- */
-const char set_names[][25] = {
-  "NULL",    "ENERGY",  "GUARD",         "SWIFT",   "BLADE",    "RAGE",
-  "FOCUS",   "ENDURE",  "FATAL",         "NULL",    "DESPAIR",  "VAMPIRE",
-  "NULL",    "VIOLENT", "NEMESIS",       "WILL",    "SHIELD",   "REVENGE",
-  "DESTROY", "FIGHT",   "DETERMINATION", "ENHANCE", "ACCURACY", "TOLERANCE"
-};
+    /**
+     * Indicates how many units are excluded.
+     *
+     * This is not a configurable option, but a handy counter. The default value
+     * is 0, and will be set when {@link excluded_units} is populated.
+     */
+    unsigned char total_excluded_units;
 
-/**
- * Function to be executed by each thread of the optimizer.
- *
- * @param[in|out] vargp Must be a Optimizer_Data pointer casted to void.
- */
-void *optimize_thread(void *vargp);
+    /**
+     * Option to enable broken sets.
+     *
+     * If {@link sets} doesn't amount for six runes, this option will discard
+     * any result that is not formed by complete sets. The default value is
+     * {@link FALSE}. To set it, use the parameter -k or --broken (it takes no
+     * options).
+     */
+    unsigned char broken_sets;
 
-/**
- * Calculates how many runes of each type it takes to satisfy a lst of up to
- * three sets.
- *
- * @param[in] sets List of up to three sets.
- * @param[out] requested_set_count Structure to populate. It will have the
- * number of runes of each type needed to form the sets.
- * @return Number of requested runes. In ost cases, it should be 6.
- */
-unsigned char optimize_count_runes_for_sets(
-  unsigned char sets[3], Rune_Set_Count *requested_set_count
-);
+    /**
+     * Number of thread to be used during optimization.
+     *
+     * Calculation of rune combinations can be done in separateed threads. Each
+     * thread shares the same amount of work as the others, so the more threads,
+     * the faster the optimzation is! The default value is 1, and can be set
+     * passing the parameter -b or --threads, followed by a numeric value. No
+     * more than 8 threads can be used.
+     */
+    unsigned char threads;
 
-/**
- * Populates a Unit structure with data from the database.
- *
- * @param[in] id Unit ID.
- * @param[out] unit Structure to populate.
- * @return SUCCESS if the unit is loaded, or ERROR_DB_SELECT_UNIT if the
- * unit doesn't exist in the database.
- */
-int optimize_fetch_unit(char id[64], struct Unit *unit);
+    /**
+     * Weights for each stat.
+     *
+     * To calculate the rating of a results, different stats can be weighted
+     * differently. The higher the ponderation of a stat, the more effect will
+     * it have in the rating. Default values are 1 for every stat, and the value
+     * can be a float between 0 and 2.
+     *
+     * @todo Implement
+     * @todo Once implemented, document the argument ot use.
+     * @todo Once implemented, document here if EHP and DMG can be weighted.
+     */
+    Stat_Ponderation ponderation;
 
-/**
- * Gets the list of runes to test during the optimization from the database.
- *
- * Im assumming 600 runes per slot is a safe estimate. I hope it doesn't
- * come back to bite me.
- * Im using a 7 position array, and the index 0 is ignored. This is
- * is because I REALLY NEED to use 1-indexes to match rune slots.
- *
- * @param[in] query_even Query to execute for even slots.
- * @param[in] query_odd Query to execute for odd slots.
- * @param[out] runes List of runes to populate.
- * @param[out] rune_count Number of runes retrieved for each slot.
- * @return SUCCESS or an error code.
- */
-int optimize_get_runes(
-  char query_even[3500], char query_odd[3500],
-  struct Rune runes[7][600], int rune_count[7]
-);
+} Optimizer_Options;
 
 /**
- * Parses the arguments for the optimize command.
+ * Data package used by the optimizer.
  *
- * @param[in] argc Number of argument passed to the optimizer command.
- * @param[in] argv Arguments passed to the optimizer.
- * @param[out] options Options to set.
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
+ * This is the data that {@link optimize_thread} takes. Each thread must have
+ * it's own data package.
  */
-int optimize_parse_arguments(
-  int argc, char argv[][128], Optimizer_Options *options
-);
+typedef struct Optimizer_Data {
 
-/**
- * Print a nice summary with all the data fethced from the command line and db.
- *
- * It is 17 lines high and un to 80 characters wide.
- *
- * @param[in] unit Unit data.
- * @param[in] options Options passed to the optimizer.
- * @param[in] rune_count Number of runes for each slot.
- * @param[in] max_combinations Total combinations to test during optimization.
- */
-void optimize_print_summary(
-  struct Unit *unit, Optimizer_Options *options,
-  unsigned int rune_count[7], unsigned long max_combinations
-);
+    /**
+     * Numeric ID of the thread.
+     *
+     * Usually, the spawing order.
+     */
+    unsigned int thread_id;
 
-/**
- * Prints a nice summary with all de details of a result.
- *
- * It is 43 lines high and 97 characters wide.
- *
- * @param[in] unit Unit data.
- * @param[in] result Result to display.
- * @return SUCCESS or an error code.
- */
-int optimize_print_result(struct Unit *unit, Result *result);
+    /**
+     * List of runes.
+     *
+     * These are the runes to test during optimization. The 0 index is not used
+     * and can be empty or have garbage.
+     */
+    Rune runes[RUNE_SLOTS + 1][LIMIT_RUNES_PER_SLOT];
 
-/**
- * Prepares and prints the output for the GUI.
- *
- * Basically, it formats the output to JSON.
- *
- * @param[in] results All results.
- * @param[in] result_count Number of results.
- * @return SUCCESS or an error code.
- */
-int optimize_print_gui(Result results[5000], int result_count);
+    /**
+     * Runes counter for each slot.
+     *
+     * Indicates the size of each {@link runes}. Index 0 is not used.
+     */
+    unsigned int count[RUNE_SLOTS + 1];
 
-/**
- * Generates the query to get the runes from the databas for even slots.
- *
- * @param[in] options Options passed to the optimizer.
- * @param[out] query String with the query.
- */
-void optimize_query_for_even_slots(
-    Optimizer_Options *options, char query[3500]
-);
+    /**
+     * The rune in slot 1 that the thread must start making checks.
+     *
+     * Each thread test a segment of slot 1 agains every combination of slots
+     * 2 to 6, this is where it should start checking.
+     */
+    unsigned char start_at;
 
-/**
- * Generates the query to get the runes from the databas for odd slots.
- *
- * @param[in] options Options passed to the optimizer.
- * @param[out] query String with the query.
- */
-void optimize_query_for_odd_slots(Optimizer_Options *options, char query[3500]);
+    /**
+     * The first rune in slot 1 that the thread must not check.
+     *
+     * Each thread test a segment of slot 1 agains every combination of slots
+     * 2 to 6, this is the the position of slot 1 that this thread must not
+     * test.
+     */
+    unsigned char end_at;
 
-/**
- * Sorts the result array.
- *
- * Sorts them by rating.
- *
- * @param[in,out] results List of results to sort.
- * @param[in] total Number of results.
- */
-void optimize_sort_results(Result results[5000], int total);
+    /**
+     * List of results.
+     *
+     * The thread saves every succesfull combination here.
+     */
+    Result results[MAX_RESULTS];
 
-/**
- * Calculates efficient HP.
- *
- * @param[in] hp HP stat.
- * @param[in] def DEF stat.
- * @return Calculated EHP.
- */
-unsigned int optimize_calculate_ehp(unsigned int hp, unsigned short def);
+    /**
+     * Number of results.
+     *
+     * The total number of results the thread has found.
+     */
+    unsigned int total_results;
 
-/**
- * Calculates damage.
- *
- * @param[in] atk ATK stat.
- * @param[in] crr CRR stat.
- * @param[in] crd CRD stat.
- * @return Calculated DMG.
- */
-unsigned short optimize_calculate_dmg(
-  unsigned short atk, unsigned short crr, unsigned short crd
-);
+    /**
+     * The options passed to the optimizer.
+     *
+     * The threads also needs to know some of these options.
+     */
+    Optimizer_Options options;
 
-/**
- * Sets the default options for the optimizer.
- *
- * @param[out] options Options to set defaults to.
- */
-void optimize_set_default_options(Optimizer_Options *options);
+    /**
+     * Max testable combinations.
+     *
+     * Not just for this thread, but the sum of combinations to test by every
+     * thread.
+     */
+    unsigned long long max_combinations;
 
-/**
- * Verifies if a given set of runes contains any broken set.
- *
- * @param set_count The set to check.
- * @return TRUE if the set has any broken sets, false otherwise.
- */
-unsigned char optimize_contains_broken(Rune_Set_Count *set_count);
+    /**
+     * Set count calculated from the options passed to the optimizer.
+     *
+     * A set count to compare every rune combination against.
+     */
+    Rune_Set_Count requested_set_count;
+
+    /**
+     * The optimized unit
+     *
+     * The unit being optimized, with all the info previously loaded.
+     */
+    Unit unit;
+} Optimizer_Data;
 
 /**
  * Starts the optimization process.
  *
- * @param[in] argc Number of arguments passed to the optimize
- * command.
- * @param[in] argv Arguments passed to the optimize command.
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
+ * Validates the arguments, gets the neccessary runes and starts the
+ * optimization process. On error, it will print a message to stderr.
+ *
+ * @param[in] argc Number of argument passed to the optimizer command. As a
+ * rule, it must me two less than the argc received by the {@link main}
+ * function of the program.
+ * @param[in] argv Arguments passed to the optimizer. As a rule, they must be
+ * the same than the argv received by the {@link main} function of the program
+ * without the first two. The first of them must be a unit ID or name. Apart
+ * from that, only two of them are mandatory: --stats / -t and --sets / -e.
+ * @return {@link SUCCESS} if the optimization was done coreclty, or an error
+ * defined in {@link error.h} if there were problems with any of them.
  */
-int cmd_optimize(int argc, char *argv[]);
+int optimize(int argc, char *argv[]);

+ 0 - 137
src/RuneOptimizer/optimize/optimize_count_runes_for_sets.c

@@ -1,137 +0,0 @@
-/*
- * This file is part of RuneOptimizer.
- *
- * RuneOptimizer is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @file optimize_count_runes_for_sets.c
- * Implementation of optimize_count_runes_for_sets.
- */
-
-unsigned char optimize_count_runes_for_sets(
-  unsigned char sets[3], Rune_Set_Count *requested_set_count
-){
-    requested_set_count->energy = 0;
-    requested_set_count->guard = 0;
-    requested_set_count->swift = 0;
-    requested_set_count->blade = 0;
-    requested_set_count->rage = 0;
-    requested_set_count->focus = 0;
-    requested_set_count->endure = 0;
-    requested_set_count->fatal = 0;
-    requested_set_count->despair = 0;
-    requested_set_count->vampire = 0;
-    requested_set_count->violent = 0;
-    requested_set_count->nemesis = 0;
-    requested_set_count->will = 0;
-    requested_set_count->shield = 0;
-    requested_set_count->revenge = 0;
-    requested_set_count->destroy = 0;
-    requested_set_count->fight = 0;
-    requested_set_count->determination = 0;
-    requested_set_count->enhance = 0;
-    requested_set_count->accuracy = 0;
-    requested_set_count->tolerance = 0;
-    char total_requested_runes = 0;
-    for (int i = 0; i < 3; i ++){
-        switch (sets[i]){
-            case ENERGY:
-                requested_set_count->energy += 2;
-                total_requested_runes += 2;
-                break;
-            case GUARD:
-                requested_set_count->guard += 2;
-                total_requested_runes += 2;
-                break;
-            case SWIFT:
-                requested_set_count->swift += 4;
-                total_requested_runes += 4;
-                break;
-            case BLADE:
-                requested_set_count->blade += 2;
-                total_requested_runes += 2;
-                break;
-            case RAGE:
-                requested_set_count->rage += 4;
-                total_requested_runes += 4;
-                break;
-            case FOCUS:
-                requested_set_count->focus += 2;
-                total_requested_runes += 2;
-                break;
-            case ENDURE:
-                requested_set_count->endure += 2;
-                total_requested_runes += 2;
-                break;
-            case FATAL:
-                requested_set_count->fatal += 4;
-                total_requested_runes += 4;
-                break;
-            case DESPAIR:
-                requested_set_count->despair += 4;
-                total_requested_runes += 4;
-                break;
-            case VAMPIRE:
-                requested_set_count->vampire += 4;
-                total_requested_runes += 4;
-                break;
-            case VIOLENT:
-                requested_set_count->violent += 4;
-                total_requested_runes += 4;
-                break;
-            case NEMESIS:
-                requested_set_count->nemesis += 2;
-                total_requested_runes += 2;
-                break;
-            case WILL:
-                requested_set_count->will += 2;
-                total_requested_runes += 2;
-                break;
-            case SHIELD:
-                requested_set_count->shield += 2;
-                total_requested_runes += 2;
-                break;
-            case REVENGE:
-                requested_set_count->revenge += 2;
-                total_requested_runes += 2;
-                break;
-            case DESTROY:
-                requested_set_count->destroy += 2;
-                total_requested_runes += 2;
-                break;
-            case FIGHT:
-                requested_set_count->fight += 2;
-                total_requested_runes += 2;
-                break;
-            case DETERMINATION:
-                requested_set_count->determination += 2;
-                total_requested_runes += 2;
-                break;
-            case ENHANCE:
-                requested_set_count->enhance += 2;
-                total_requested_runes += 2;
-                break;
-            case ACCURACY:
-                requested_set_count->accuracy += 2;
-                total_requested_runes += 2;
-                break;
-            case TOLERANCE:
-                requested_set_count->tolerance += 2;
-                total_requested_runes += 2;
-                break;
-        }
-    }
-    return total_requested_runes;
-}

+ 0 - 71
src/RuneOptimizer/optimize/optimize_fetch_unit.c

@@ -1,71 +0,0 @@
-/*
- * This file is part of RuneOptimizer.
- *
- * RuneOptimizer is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @file optimize_fetch_unit.c
- * Implementation of optimize_fetch_unit.
- */
-
-int optimize_fetch_unit(char id[64], struct Unit *unit){
-    sqlite3_stmt *stmt_unit;
-    char *parameters[2] = {id, id};
-    db_query(
-      &stmt_unit,
-      "SELECT "
-      "id, name, base_hp, base_atk, base_def, base_spd, base_crr, base_crd, "
-      "base_res, base_acc, current_hp, current_atk, current_def, current_spd, "
-      "current_crr, current_crd, current_res, current_acc "
-      "FROM units WHERE id = ? OR name = ?",
-      parameters
-    );
-    // Fetch just one line
-    int step = sqlite3_step(stmt_unit);
-
-    // Populate the unit structure with the red data.
-    if (step != SQLITE_ROW) {
-        fprintf(stderr, "Unit not found: %s\n", sqlite3_errmsg(db));
-        sqlite3_finalize(stmt_unit);
-        return(ERROR_DB_SELECT_UNIT);
-    }
-    strcpy(unit->id, sqlite3_column_text(stmt_unit, 0));
-    strcpy(unit->name, sqlite3_column_text(stmt_unit, 1));
-    unit->base_hp = sqlite3_column_int(stmt_unit, 2);
-    unit->base_atk = sqlite3_column_int(stmt_unit, 3);
-    unit->base_def = sqlite3_column_int(stmt_unit, 4);
-    unit->base_spd = sqlite3_column_int(stmt_unit, 5);
-    unit->base_crr = sqlite3_column_int(stmt_unit, 6);
-    unit->base_crd = sqlite3_column_int(stmt_unit, 7);
-    unit->base_res = sqlite3_column_int(stmt_unit, 8);
-    unit->base_acc = sqlite3_column_int(stmt_unit, 9);
-    unit->base_ehp = optimize_calculate_ehp(unit->base_hp, unit->base_def);
-    unit->base_dmg =
-      optimize_calculate_dmg(unit->base_atk, unit->base_crr, unit->base_crd);
-    unit->current_hp = sqlite3_column_int(stmt_unit, 10);
-    unit->current_atk = sqlite3_column_int(stmt_unit, 11);
-    unit->current_def = sqlite3_column_int(stmt_unit, 12);
-    unit->current_spd = sqlite3_column_int(stmt_unit, 13);
-    unit->current_crr = sqlite3_column_int(stmt_unit, 14);
-    unit->current_crd = sqlite3_column_int(stmt_unit, 15);
-    unit->current_res = sqlite3_column_int(stmt_unit, 16);
-    unit->current_acc = sqlite3_column_int(stmt_unit, 17);
-    unit->current_ehp =
-      optimize_calculate_ehp(unit->current_hp, unit->current_def);
-    unit->current_dmg = optimize_calculate_dmg(
-      unit->current_atk, unit->current_crr, unit->current_crd
-    );
-    return(SUCCESS);
-}

+ 0 - 61
src/RuneOptimizer/optimize/optimize_get_runes.c

@@ -1,61 +0,0 @@
-/*
- * This file is part of RuneOptimizer.
- *
- * RuneOptimizer is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @file optimize_get_runes.c
- * Implementation of optimize_get_runes.
- */
-
-int optimize_get_runes(
-  char query_even[1500], char query_odd[1500],
-  struct Rune runes[7][600], int rune_count[7]
-){
-    char **query;
-    sqlite3 *db = NULL;
-    sqlite3_stmt *stmt_runes[7];
-    char *parameters[1];
-    parameters[0] = malloc(sizeof(int));
-    for (char i = 1; i < 7; i ++){
-        if (i % 2 == 0) query = &query_even;
-        else  query = &query_odd;
-        sprintf(parameters[0], "%d", i);
-        db_query(&stmt_runes[i], *query, parameters);
-        int j = 0;
-        while (SQLITE_ROW == sqlite3_step(stmt_runes[i])){
-            strcpy(runes[i][j].id, sqlite3_column_text(stmt_runes[i], 0));
-            strcpy(runes[i][j].unit, sqlite3_column_text(stmt_runes[i], 1));
-            runes[i][j].slot = sqlite3_column_int(stmt_runes[i], 2);
-            runes[i][j].set = sqlite3_column_int(stmt_runes[i], 3);
-            runes[i][j].hp_flat = sqlite3_column_int(stmt_runes[i], 4);
-            runes[i][j].atk_flat = sqlite3_column_int(stmt_runes[i], 5);
-            runes[i][j].def_flat = sqlite3_column_int(stmt_runes[i], 6);
-            runes[i][j].hp_percent = sqlite3_column_int(stmt_runes[i], 7);
-            runes[i][j].atk_percent = sqlite3_column_int(stmt_runes[i], 8);
-            runes[i][j].def_percent = sqlite3_column_int(stmt_runes[i], 9);
-            runes[i][j].spd = sqlite3_column_int(stmt_runes[i], 10);
-            runes[i][j].crr = sqlite3_column_int(stmt_runes[i], 11);
-            runes[i][j].crd = sqlite3_column_int(stmt_runes[i], 12);
-            runes[i][j].res = sqlite3_column_int(stmt_runes[i], 13);
-            runes[i][j].acc = sqlite3_column_int(stmt_runes[i], 14);
-            j ++;
-        }
-        rune_count[i] = j;
-    }
-    for (int r = 1; r < 7; r ++) sqlite3_finalize(stmt_runes[r]);
-    free(parameters[0]);
-    return SUCCESS;
-}

+ 0 - 530
src/RuneOptimizer/optimize/optimize_parse_arguments.c

@@ -1,530 +0,0 @@
-/*
- * This file is part of RuneOptimizer.
- *
- * RuneOptimizer is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @file optimize_parse_arguments.c
- * Implementation of optimize_parse_arguments.
- */
-
-int optimize_parse_arguments(
-  int argc, char argv[][128], Optimizer_Options *options
-){
-    // Get unit identifier
-    if (argc < 1){
-        fprintf(stderr, "No unit specified for optimization\n");
-        return ERROR_INPUT_OPTIMIZE_NO_UNIT;
-    }
-    if (strlen(argv[0]) > 63){
-        strncpy(options->id, argv[0], 63);
-        options->id[63] = '\0';
-    }
-    else{
-        strcpy(options->id, argv[0]);
-    }
-
-    // Loop command line arguments
-    for (int i = 1; i < argc; i ++){
-
-        // Rune level arguments
-        if (strcmp("--level", argv[i]) == 0 || strcmp("-l", argv[i]) == 0){
-            if (i < argc - 1){
-                if (strcmp("current", argv[i + 1]) == 0) options->level = 0;
-                else if (strcmp("12", argv[i + 1]) == 0) options->level = 12;
-                else if (strcmp("15", argv[i + 1]) == 0) options->level = 15;
-                else{
-                    fprintf(
-                      stderr,
-                      "Invalid option for argument %s: %s\n"
-                      "Valid options are 'current', '12' or '15'\n",
-                      argv[i], argv[i + 1]
-                    );
-                    return ERROR_INPUT_OPTIMIZE_INVALID_LEVEL;
-                }
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr,
-                  "Argument %s requires a value.\n"
-                  "Valid options are 'current', '12' or '15'\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_LEVEL;
-            }
-        }
-
-        // Excluded teams
-        else if (
-          strcmp("--no-teams", argv[i]) == 0 || strcmp("-x", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                // Separate string by commas
-                // Returns first token
-                char opt_list[128];
-                strcpy(opt_list, argv[i + 1]);
-                char *token = strtok(opt_list, ",");
-
-                // Keep printing tokens while one of the
-                // delimiters present in the list, or until its complete
-                while (token != NULL){
-                    strcpy(
-                      options->excluded_teams[options->total_excluded_teams],
-                      token
-                    );
-                    options->total_excluded_teams ++;
-                    token = strtok(NULL, ",");
-                }
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr,
-                  "Argument %s requires a comma-separated list of values.\n",
-                  argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_TEAMS;
-            }
-        }
-
-        // Excluded units
-        else if (
-          strcmp("--no-units", argv[i]) == 0 || strcmp("-u", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                // Separate string by commas
-                // Returns first token
-                char opt_list[128];
-                strcpy(opt_list, argv[i + 1]);
-                char *token = strtok(opt_list, ",");
-
-                // Keep printing tokens while one of the
-                // delimiters present in the list, or until its complete
-                while (token != NULL){
-                    strcpy(
-                      options->excluded_units[options->total_excluded_units],
-                      token
-                    );
-                    options->total_excluded_units ++;
-                    token = strtok(NULL, ",");
-                }
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr,
-                  "Argument %s requires a comma-separated list of values.\n",
-                  argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_UNITS;
-            }
-        }
-
-        // Mandatory rune sets argument
-        else if (strcmp("--sets", argv[i]) == 0 || strcmp("-e", argv[i]) == 0){
-            if (i < argc - 1){
-                // Separate string by commas
-                int j = 0;
-                // Returns first token
-                char *token = strtok(argv[i + 1], ",");
-
-                // Keep printing tokens while one of the
-                // delimiters present in the list, or until its complete
-                while (token != NULL && j < 3){
-                    if (strcmp(token, "energy") == 0)
-                        options->sets[j] = ENERGY;
-                    else if (strcmp(token, "guard") == 0)
-                        options->sets[j] = GUARD;
-                    else if (strcmp(token, "swift") == 0)
-                        options->sets[j] = SWIFT;
-                    else if (strcmp(token, "blade") == 0)
-                        options->sets[j] = BLADE;
-                    else if (strcmp(token, "rage") == 0)
-                        options->sets[j] = RAGE;
-                    else if (strcmp(token, "focus") == 0)
-                        options->sets[j] = FOCUS;
-                    else if (strcmp(token, "endure") == 0)
-                        options->sets[j] = ENDURE;
-                    else if (strcmp(token, "fatal") == 0)
-                        options->sets[j] = FATAL;
-                    else if (strcmp(token, "despair") == 0)
-                        options->sets[j] = DESPAIR;
-                    else if (strcmp(token, "vampire") == 0)
-                        options->sets[j] = VAMPIRE;
-                    else if (strcmp(token, "violent") == 0)
-                        options->sets[j] = VIOLENT;
-                    else if (strcmp(token, "nemesis") == 0)
-                        options->sets[j] = NEMESIS;
-                    else if (strcmp(token, "will") == 0)
-                        options->sets[j] = WILL;
-                    else if (strcmp(token, "shield") == 0)
-                        options->sets[j] = SHIELD;
-                    else if (strcmp(token, "revenge") == 0)
-                        options->sets[j] = REVENGE;
-                    else if (strcmp(token, "destroy") == 0)
-                        options->sets[j] = DESTROY;
-                    else if (strcmp(token, "fight") == 0)
-                        options->sets[j] = FIGHT;
-                    else if (strcmp(token, "determination") == 0)
-                        options->sets[j] = DETERMINATION;
-                    else if (strcmp(token, "enhance") == 0)
-                        options->sets[j] = ENHANCE;
-                    else if (strcmp(token, "accuracy") == 0)
-                        options->sets[j] = ACCURACY;
-                    else if (strcmp(token, "tolerance") == 0)
-                        options->sets[j] = TOLERANCE;
-                    else{
-                        fprintf(stderr, "Unknown rune set %s.\n", token);
-                        return ERROR_INPUT_OPTIMIZE_INVALID_SET;
-                    }
-                    token = strtok(NULL, ",");
-                    j ++;
-                }
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr,
-                  "Argument %s requires a comma-separated list of values.\n",
-                  argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_SET;
-            }
-        }
-
-        // Optional rune sets argument
-        else if (strcmp("--opt-sets", argv[i]) == 0 || strcmp("-i", argv[i]) == 0){
-            if (i < argc - 1){
-                // Separate string by commas
-                int j = 0;
-                // Returns first token
-                char *token = strtok(argv[i + 1], ",");
-
-                // Keep printing tokens while one of the
-                // delimiters present in the list, or until its complete
-                while (token != NULL){
-                    if (strcmp(token, "energy") == 0)
-                        options->optional_sets[ENERGY] = TRUE;
-                    else if (strcmp(token, "guard") == 0)
-                        options->optional_sets[GUARD] = TRUE;
-                    else if (strcmp(token, "swift") == 0)
-                        options->optional_sets[SWIFT] = TRUE;
-                    else if (strcmp(token, "blade") == 0)
-                        options->optional_sets[BLADE] = TRUE;
-                    else if (strcmp(token, "rage") == 0)
-                        options->optional_sets[RAGE] = TRUE;
-                    else if (strcmp(token, "focus") == 0)
-                        options->optional_sets[FOCUS] = TRUE;
-                    else if (strcmp(token, "endure") == 0)
-                        options->optional_sets[ENDURE] = TRUE;
-                    else if (strcmp(token, "fatal") == 0)
-                        options->optional_sets[FATAL] = TRUE;
-                    else if (strcmp(token, "despair") == 0)
-                        options->optional_sets[DESPAIR] = TRUE;
-                    else if (strcmp(token, "vampire") == 0)
-                        options->optional_sets[VAMPIRE] = TRUE;
-                    else if (strcmp(token, "violent") == 0)
-                        options->optional_sets[VIOLENT] = TRUE;
-                    else if (strcmp(token, "nemesis") == 0)
-                        options->optional_sets[NEMESIS] = TRUE;
-                    else if (strcmp(token, "will") == 0)
-                        options->optional_sets[WILL] = TRUE;
-                    else if (strcmp(token, "shield") == 0)
-                        options->optional_sets[SHIELD] = TRUE;
-                    else if (strcmp(token, "revenge") == 0)
-                        options->optional_sets[REVENGE] = TRUE;
-                    else if (strcmp(token, "destroy") == 0)
-                        options->optional_sets[DESTROY] = TRUE;
-                    else if (strcmp(token, "fight") == 0)
-                        options->optional_sets[FIGHT] = TRUE;
-                    else if (strcmp(token, "determination") == 0)
-                        options->optional_sets[DETERMINATION] = TRUE;
-                    else if (strcmp(token, "enhance") == 0)
-                        options->optional_sets[ENHANCE] = TRUE;
-                    else if (strcmp(token, "accuracy") == 0)
-                        options->optional_sets[ACCURACY] = TRUE;
-                    else if (strcmp(token, "tolerance") == 0)
-                        options->optional_sets[TOLERANCE] = TRUE;
-                    else{
-                        fprintf(stderr, "Unknown rune set %s.\n", token);
-                        return ERROR_INPUT_OPTIMIZE_INVALID_SET;
-                    }
-                    token = strtok(NULL, ",");
-                    j ++;
-                }
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr,
-                  "Argument %s requires a comma-separated list of values.\n",
-                  argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_SET;
-            }
-        }
-
-        // Accepted stats arguments
-        else if (strcmp("--stats", argv[i]) == 0 || strcmp("-t", argv[i]) == 0){
-            if (i < argc - 1){
-                // Separate string by commas
-                // Returns first token
-                char *token = strtok(argv[i + 1], ",");
-
-                // Keep printing tokens while one of the
-                // delimiters present in the list, or until its complete
-                while (token != NULL){
-                    if (strcmp(token, "hp") == 0)
-                        options->stats[HP_PERCENT] = TRUE;
-                    else if (strcmp(token, "atk") == 0)
-                        options->stats[ATK_PERCENT] = TRUE;
-                    else if (strcmp(token, "def") == 0)
-                        options->stats[DEF_PERCENT] = TRUE;
-                    else if (strcmp(token, "hpflat") == 0)
-                        options->stats[HP_FLAT] = TRUE;
-                    else if (strcmp(token, "atkflat") == 0)
-                        options->stats[ATK_FLAT] = TRUE;
-                    else if (strcmp(token, "defflat") == 0)
-                        options->stats[DEF_FLAT] = TRUE;
-                    else if (strcmp(token, "spd") == 0)
-                        options->stats[SPD] = TRUE;
-                    else if (strcmp(token, "crr") == 0)
-                        options->stats[CRR] = TRUE;
-                    else if (strcmp(token, "crd") == 0)
-                        options->stats[CRD] = TRUE;
-                    else if (strcmp(token, "res") == 0)
-                        options->stats[RES] = TRUE;
-                    else if (strcmp(token, "acc") == 0)
-                        options->stats[ACC] = TRUE;
-                    else{
-                        fprintf(stderr, "Unknown rune stat %s.\n", token);
-                        return ERROR_INPUT_OPTIMIZE_INVALID_STAT;
-                    }
-                    token = strtok(NULL, ",");
-                }
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr,
-                  "Argument %s requires a comma-separated list of values.\n",
-                  argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_STAT;
-            }
-        }
-
-        // Minimum stats arguments.
-        else if (
-          strcmp("--min-hp", argv[i]) == 0 || strcmp("-h", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned short stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                options->min_stats->hp = stat_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_HP;
-            }
-        }
-        else if (
-          strcmp("--min-atk", argv[i]) == 0 || strcmp("-a", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned short stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                options->min_stats->atk = stat_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_ATK;
-            }
-        }
-        else if (
-          strcmp("--min-def", argv[i]) == 0 || strcmp("-d", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned short stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                options->min_stats->def = stat_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_DEF;
-            }
-        }
-        else if (
-          strcmp("--min-spd", argv[i]) == 0 || strcmp("-s", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned short stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                options->min_stats->spd = stat_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_SPD;
-            }
-        }
-        else if (
-          strcmp("--min-crr", argv[i]) == 0 || strcmp("-c", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned short stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                else if (stat_tmp > 100) stat_tmp = 100;
-                options->min_stats->crr = stat_tmp;
-                // Advance one position in argument reading
-                i ++;
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_CRR;
-            }
-        }
-        else if (
-          strcmp("--min-crd", argv[i]) == 0 || strcmp("-d", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned short stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                options->min_stats->crd = stat_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_CRD;
-            }
-        }
-        else if (
-          strcmp("--min-res", argv[i]) == 0 || strcmp("-r", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned short stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                else if (stat_tmp > 100) stat_tmp = 100;
-                options->min_stats->res = stat_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_RES;
-            }
-        }
-        else if (
-          strcmp("--min-acc", argv[i]) == 0 || strcmp("-f", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned short stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                else if (stat_tmp > 85) stat_tmp = 85;
-                options->min_stats->acc = stat_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_ACC;
-            }
-        }
-        else if (
-          strcmp("--min-ehp", argv[i]) == 0 || strcmp("-p", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned int stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                options->min_stats->ehp = stat_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_EHP;
-            }
-        }
-        else if (
-          strcmp("--min-dmg", argv[i]) == 0 || strcmp("-m", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned short stat_tmp = atoi(argv[i + 1]);
-                if (stat_tmp == 1) stat_tmp = 0;
-                options->min_stats->dmg = stat_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value.\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_DMG;
-            }
-        }
-        // Allow broken sets?
-        else if (
-          strcmp("--broken", argv[i]) == 0 || strcmp("-k", argv[i]) == 0
-        ){
-            options->broken_sets = TRUE;
-        }
-        // Storage option?
-        else if (
-          strcmp("--storage", argv[i]) == 0 || strcmp("-o", argv[i]) == 0
-        ){
-            options->storage = TRUE;
-        }
-        // GUI invoked?
-        else if (strcmp("--gui", argv[i]) == 0 || strcmp("-g", argv[i]) == 0){
-            options->gui = TRUE;
-        }
-        else if (
-          strcmp("--threads", argv[i]) == 0 || strcmp("-b", argv[i]) == 0
-        ){
-            if (i < argc - 1){
-                unsigned char threads_tmp = atoi(argv[i + 1]);
-                if (threads_tmp < 1) threads_tmp = 1;
-                else if (threads_tmp > 8) threads_tmp = 8;
-                options->threads = threads_tmp;
-                i ++; // Advance one position in argument reading
-            }
-            else{
-                fprintf(
-                  stderr, "Argument %s requires a numeric value [1-8].\n", argv[i]
-                );
-                return ERROR_INPUT_OPTIMIZE_NO_ACC;
-            }
-        }
-
-    }
-    return SUCCESS;
-}

+ 0 - 439
src/RuneOptimizer/optimize/optimize_print.c

@@ -1,439 +0,0 @@
-/*
- * This file is part of RuneOptimizer.
- *
- * RuneOptimizer is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @file optimize_print.c
- * Implementation of functions to print the optimizer output.
- */
-
-void optimize_print_summary(
-  struct Unit *unit, Optimizer_Options *options,
-  unsigned int rune_count[7], unsigned long max_combinations
-){
-    // This is an output example:
-    ////////////////////////////////
-    //
-    // -----------------------------------    Requested rune sets:
-    // | Lushen                          |       RAGE  BLADE
-    // | ID: 7223811472                  |
-    // -----------------------------------    Accepted stats:
-    // | STAT | BASE   | CURR.  | MIN.   |       ATK  CRR  CRD
-    // -----------------------------------
-    // | HP:  |  9225  | 12262  | 10000  |    Considering runes at level 15
-    // | ATK: |   900  |  2482  |  2482  |
-    // | DEF: |   461  |   703  |   703  |    Runes considered by slot:
-    // | SPD: |   103  |   159  |   159  |      1: 27    2: 39    3: 25
-    // | CRR: |    15% |    79% |    79% |      4: 35    5: 24    6: 32
-    // | CRD: |    50% |   188% |   188% |
-    // | RES: |    15% |    35% |    35% |    Total combinations: 707616000
-    // | ACC: |     0% |    11% |    10% |
-    // -----------------------------------
-    //
-    printf(
-      " -----------------------------------------    Requested rune sets:\n"
-    );
-    printf(" | %*s |      ", -37, unit->name);
-    for (int i = 0; i < 3; i ++){
-        if (options->sets[i] == TRUE) printf(" %s ", set_names[options->sets[i]]);
-        else break;
-    }
-    printf("\n");
-    printf(" | ID: %*s |\n", -33, unit->id);
-    printf(" -----------------------------------------    Accepted stats:\n");
-    printf(" | STAT | BASE     | CURR.    | MIN.     |      ");
-    for (int i = 0; i < 13; i ++){
-        if (options->stats[i] == TRUE)
-            printf(" %s ", stat_names[options->stats[i]]);
-        else break;
-    }
-    printf("\n");
-    printf(" -----------------------------------------\n");
-    printf(
-      " | HP:  | %*d  | %*d  | %*d  |    ", 7,
-      unit->base_hp, 7, unit->current_hp, 7, options->min_stats->hp
-    );
-    if (options->level == 0) printf("Using runes at their current level\n");
-    else printf("Considering runes at level %d\n", options->level);
-    printf(
-      " | ATK: | %*d  | %*d  | %*d  |\n", 7,
-      unit->base_atk, 7, unit->current_atk, 7, options->min_stats->atk
-    );
-    printf(
-      " | DEF: | %*d  | %*d  | %*d  |    Runes considered by slot:\n",
-      7, unit->base_def, 7, unit->current_def, 7, options->min_stats->def
-    );
-    printf(
-      " | SPD: | %*d  | %*d  | %*d  |      1:%*d    2:%*d    3:%*d\n",
-      7, unit->base_spd, 7, unit->current_spd, 7, options->min_stats->spd,
-      3, rune_count[1], 3, rune_count[2], 3, rune_count[3]
-    );
-    printf(
-      " | CRR: | %*d\% | %*d\% | %*d\% |      4:%*d    5:%*d    6:%*d\n",
-      7, unit->base_crr, 7, unit->current_crr, 7, options->min_stats->crr,
-      3, rune_count[4], 3, rune_count[5], 3, rune_count[6]
-    );
-    printf(
-      " | CRD: | %*d\% | %*d\% | %*d\% |\n",
-      7, unit->base_crd, 7, unit->current_crd, 7, options->min_stats->crd
-    );
-    printf(
-      " | RES: | %*d\% | %*d\% | %*d\% |    Total combinations: %llu\n",
-      7, unit->base_res, 7, unit->current_res, 7, options->min_stats->res,
-      max_combinations
-    );
-    printf(
-      " | ACC: | %*d\% | %*d\% | %*d\% |\n",
-      7, unit->base_acc, 7, unit->current_acc, 7, options->min_stats->acc
-    );
-    printf(
-      " | EHP: | %*d  | %*d  | %*d  |\n",
-      7, unit->base_ehp, 7, unit->current_ehp, 7, options->min_stats->ehp
-    );
-    printf(
-      " | DMG: | %*d  | %*d  | %*d  |\n",
-      7, unit->base_dmg, 7, unit->current_dmg, 7, options->min_stats->dmg
-    );
-    printf(" -----------------------------------------\n");
-    return;
-}
-
-int optimize_print_result(struct Unit *unit, Result *result){
-    printf(" ------------------------------\n");
-    printf(" | %*s |\n", -26, unit->name);
-    printf(" | ID: %*s |\n", -22, unit->id);
-    printf(" ------------------------------\n");
-    printf(" | STAT | CURR.    | NEW      |\n");
-    printf(" ------------------------------\n");
-    printf(" | HP:  | %*d  | %*d  |\n", 7, unit->current_hp, 7, result->stats.hp);
-    printf(" | ATK: | %*d  | %*d  |\n", 7, unit->current_atk, 7, result->stats.atk);
-    printf(" | DEF: | %*d  | %*d  |\n", 7, unit->current_def, 7, result->stats.def);
-    printf(" | SPD: | %*d  | %*d  |\n", 7, unit->current_spd, 7, result->stats.spd);
-    printf(" | CRR: | %*d\% | %*d\% |\n", 7, unit->current_crr, 7, result->stats.crr);
-    printf(" | CRD: | %*d\% | %*d\% |\n", 7, unit->current_crd, 7, result->stats.crd);
-    printf(" | RES: | %*d\% | %*d\% |\n", 7, unit->current_res, 7, result->stats.res);
-    printf(" | ACC: | %*d\% | %*d\% |\n", 7, unit->current_acc, 7, result->stats.acc);
-    printf(" | EHP: | %*d  | %*d  |\n", 7, unit->current_ehp, 7, result->stats.ehp);
-    printf(" | DMG: | %*d  | %*d  |\n", 7, unit->current_dmg, 7, result->stats.dmg);
-    printf(" ------------------------------\n");
-
-    // This bit may be hard to follow.
-    // I'm populating  8 lines of text with data, to display the runes in
-    // a nice table format.
-    //
-    // This is an output exaple:
-    //
-    // ------------------------------  ------------------------------  ------------------------------
-    // |6|RAGE         | 23285581330|  |1|BLADE        | 22677809846|  |2|BLADE        | 21432847749|
-    // ------------------------------  ------------------------------  ------------------------------
-    // | Storage       |        +12 |  | Storage       |        +12 |  | Perna         |        +15 |
-    // ------------------------------  ------------------------------  ------------------------------
-    // | ACC           48           |  | ATK_FLAT     118           |  | SPD           42           |
-    // | RES            6           |  |                            |  |                            |
-    // | ATK_FLAT      19           |  | RES           14           |  | CRD           16           |
-    // | CRR           12           |  | ACC            8           |  | CRR           10           |
-    // | HP            14           |  | HP_FLAT      580           |  | ATK            7 + 3       |
-    // | CRD           14           |  | CRR           10           |  | DEF            7 + 3       |
-    // ------------------------------  ------------------------------  ------------------------------
-    //
-    // ------------------------------  ------------------------------  ------------------------------
-    // |5|RAGE         | 26260912967|  |4|RAGE         | 27947761086|  |3|RAGE         | 27654723287|
-    // ------------------------------  ------------------------------  ------------------------------
-    // | Lushen        |        +15 |  | Lushen        |        +15 |  | Covenant      |        +12 |
-    // ------------------------------  ------------------------------  ------------------------------
-    // | HP_FLAT     2448           |  | CRD           80           |  | DEF_FLAT     118           |
-    // |                            |  |                            |  | HP_FLAT      167           |
-    // | CRR           16           |  | CRR            6           |  | RES            8           |
-    // | SPD            6 + 2       |  | RES           11           |  | DEF           11           |
-    // | CRD           11           |  | SPD           18           |  | CRD           18           |
-    // | ATK            6 + 5       |  | ATK            8           |  | CRR           12           |
-    // ------------------------------  ------------------------------  ------------------------------
-    //
-    // I know, I'm breaking the 80-characters-line rule.
-
-    char present[8][130];
-    strcpy(present[0], "");
-    strcpy(present[1], "");
-    strcpy(present[2], "");
-    strcpy(present[3], "");
-    strcpy(present[4], "");
-    strcpy(present[5], "");
-    strcpy(present[6], "");
-    strcpy(present[7], "");
-
-    // Retrieve the runes from the database
-    printf("\n");
-    char *parameters[1];
-    for (int i = 6; i != 0;){
-        parameters[0] = result->rune_ids[i - 1];
-        sqlite3_stmt *rune_res;
-
-        db_query(
-          &rune_res,
-          "SELECT "
-          "runes.id, runes.slot, runes.type, units.id, units.name, runes.level "
-          "FROM runes LEFT JOIN units ON runes.unit = units.id "
-          "WHERE runes.id = ?",
-          parameters
-        );
-        if (SQLITE_ROW == sqlite3_step(rune_res)) {
-            char tmp[130];
-            strcpy(tmp, "");
-            strcat(present[0], "|");
-            sprintf(tmp, "%*d", 1, sqlite3_column_int(rune_res, 1));
-            strcat(present[0], tmp);
-            strcat(present[0], "|");
-            sprintf(
-              tmp, "%*s|", -13, set_names[sqlite3_column_int(rune_res, 2)]
-            );
-            strcat(present[0], tmp);
-            sprintf(tmp, "%*s|  ", 12, sqlite3_column_text(rune_res, 0));
-            strcat(present[0], tmp);
-            strcat(present[1], "|");
-            if (sqlite3_column_type(rune_res, 3) == SQLITE_NULL){
-                sprintf(tmp, " %*s", -14, "Storage");
-                strcat(present[1], tmp);
-                strcat(present[1], "|");
-            }
-            else{
-                sprintf(tmp, " %*s", -14, sqlite3_column_text(rune_res, 4));
-                strcat(present[1], tmp);
-                strcat(present[1], "|");
-            }
-            // Rune level
-            sprintf(
-              tmp, "        +%*s |  ", 2, sqlite3_column_text(rune_res, 5)
-            );
-            strcat(present[1], tmp);
-
-            // Get stats
-            sqlite3_stmt *stats_res;
-            db_query(
-              &stats_res,
-              "SELECT rune, slot, stat, value, enchant, grind "
-              "FROM rune_stats "
-              "WHERE rune = ?",
-              parameters
-            );
-            int curr_slot = -1;
-            while (1 == 1){
-                int status = sqlite3_step(stats_res);
-                if (status == SQLITE_ROW){
-                    // Print empty lines for no-stats
-                    while (sqlite3_column_int(stats_res, 1) != curr_slot){
-                        sprintf(tmp, "|                            |  ");
-                        strcat(present[curr_slot + 3], tmp);
-                        curr_slot ++;
-                    }
-                    if (sqlite3_column_int(stats_res, 1) == curr_slot){
-                        strcat(present[curr_slot + 3], "| ");
-                        sprintf(
-                          tmp,
-                          "%*s",
-                          -9, stat_names[sqlite3_column_int(stats_res, 2)]
-                        );
-                        strcat(present[curr_slot + 3], tmp);
-                        sprintf(
-                          tmp, " %*d", 6, sqlite3_column_int(stats_res, 3)
-                        );
-                        strcat(present[curr_slot + 3], tmp);
-
-                        // Display grinds
-                        if (sqlite3_column_int(stats_res, 5) > 0){
-                            sprintf(
-                              tmp,
-                              " + %*d", -8, sqlite3_column_int(stats_res, 5)
-                            );
-                        }
-                        else{
-                            sprintf(tmp, "           ");
-                        }
-                        strcat(present[curr_slot + 3], tmp);
-                        strcat(present[curr_slot + 3], "|  ");
-                    }
-
-                    curr_slot ++;
-                    }
-                else{
-                    break;
-                }
-            }
-            // Populate all empty stat lines
-            while (curr_slot <= 4){
-                sprintf(tmp, "|                            |  ");
-                strcat(present[curr_slot + 3], tmp);
-                curr_slot ++;
-            }
-            sqlite3_finalize(stats_res);
-        }
-        else{
-            fprintf(stderr, "Errors in row: %s\n", sqlite3_errmsg(db));
-        }
-        sqlite3_finalize(rune_res);
-
-        // Loop control
-        // It's weird, but I wanna present the runes in the same format the
-        // game does:
-        //
-        // 6 1 2
-        // 5 4 3
-        // After slots 2 and 3, the generated strings are written.
-        if (i == 6) i = 1;
-        else if (i == 1) i = 2;
-        else if (i == 2){
-            // Print and reinitialize the strings
-            printf(
-              "------------------------------  "
-              "------------------------------  "
-              "------------------------------\n"
-            );
-            printf(present[0]);
-            printf(
-              "\n------------------------------  "
-              "------------------------------  "
-              "------------------------------\n"
-            );
-            printf(present[1]);
-            printf(
-              "\n------------------------------  "
-              "------------------------------  "
-              "------------------------------\n"
-            );
-            printf(present[2]);
-            printf("\n");
-            printf(present[3]);
-            printf("\n");
-            printf(present[4]);
-            printf("\n");
-            printf(present[5]);
-            printf("\n");
-            printf(present[6]);
-            printf("\n");
-            printf(present[7]);
-            printf(
-              "\n------------------------------  "
-              "------------------------------  "
-              "------------------------------\n"
-            );
-            strcpy(present[0], "");
-            strcpy(present[1], "");
-            strcpy(present[2], "");
-            strcpy(present[3], "");
-            strcpy(present[4], "");
-            strcpy(present[5], "");
-            strcpy(present[6], "");
-            strcpy(present[7], "");
-            i = 5;
-        }
-        else if (i == 5) i = 4;
-        else if (i == 4) i = 3;
-        else if (i == 3){
-            // Print and exit loop
-            printf(
-              "\n------------------------------  "
-              "------------------------------  "
-              "------------------------------\n"
-            );
-            printf(present[0]);
-            printf(
-              "\n------------------------------  "
-              "------------------------------  "
-              "------------------------------\n"
-            );
-            printf(present[1]);
-            printf(
-              "\n------------------------------  "
-              "------------------------------  "
-              "------------------------------\n"
-            );
-            printf(present[2]);
-            printf("\n");
-            printf(present[3]);
-            printf("\n");
-            printf(present[4]);
-            printf("\n");
-            printf(present[5]);
-            printf("\n");
-            printf(present[6]);
-            printf("\n");
-            printf(present[7]);
-            printf(
-              "\n------------------------------  "
-              "------------------------------  "
-              "------------------------------\n"
-            );
-            i = 0;
-        }
-    }
-    return SUCCESS;
-}
-
-int optimize_print_gui(Result results[5000], int result_count){
-    //Print for GUI
-    char tmp[300];
-    strcpy(tmp, "");
-    char json[300];
-    printf("{\"result_count\":%d,\"results\":[", result_count);
-    int result_limit = 100;
-    for (int i = 0; i < result_count && i < result_limit; i++){
-        //printf("RES LOOP %d", i);
-        sprintf(tmp, "{\"id\":%d,\"rating\":%d,", i, results[i].rating);
-        strcpy(json, tmp);
-        sprintf(tmp, "\"hp\":%d,", results[i].stats.hp);
-        strcat(json, tmp);
-        sprintf(tmp, "\"atk\":%d,", results[i].stats.atk);
-        strcat(json, tmp);
-        sprintf(tmp, "\"dfc\":%d,", results[i].stats.def);
-        strcat(json, tmp);
-        sprintf(tmp, "\"spd\":%d,", results[i].stats.spd);
-        strcat(json, tmp);
-        sprintf(tmp, "\"crr\":%d,", results[i].stats.crr);
-        strcat(json, tmp);
-
-        sprintf(tmp, "\"crd\":%d,", results[i].stats.crd);
-        strcat(json, tmp);
-        sprintf(tmp, "\"res\":%d,", results[i].stats.res);
-        strcat(json, tmp);
-        sprintf(tmp, "\"acc\":%d,", results[i].stats.acc);
-        strcat(json, tmp);
-        sprintf(tmp, "\"ehp\":%d,", results[i].stats.ehp);
-        strcat(json, tmp);
-        sprintf(tmp, "\"dmg\":%d,", results[i].stats.dmg);
-        strcat(json, tmp);
-        strcat(json, "\"runes\":[");
-        //printf("    A %s", json);
-        for (int j = 0; j < 5; j++){
-            //printf("    RUNE LOOP %d", j);
-            sprintf(tmp, "\"%s\",", results[i].rune_ids[j]);
-            strcat(json, tmp);
-        }
-        //printf("    B %s", json);
-        sprintf(tmp, "\"%s\"", results[i].rune_ids[5]);
-        strcat(json, tmp);
-        strcat(json, "]},");
-
-        // If last result, remove last comma
-        if (i == result_count - 1 || i == result_limit - 1){
-            json[strlen(json) - 1] = 0;
-        }
-
-        printf(json);
-    }
-
-    // End and print
-    printf("]}\n");
-    return SUCCESS;
-}

+ 0 - 129
src/RuneOptimizer/optimize/optimize_query.c

@@ -1,129 +0,0 @@
-/*
- * This file is part of RuneOptimizer.
- *
- * RuneOptimizer is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @file optimize_print.c
- * Implementation of functions to build queries to get runes for the
- * optimizer.
- */
-
-void optimize_query_for_even_slots(
-    Optimizer_Options *options, char query[3500]
-){
-    char stat_set[3];
-    int y;
-    optimize_query_for_odd_slots(options, query);
-    strcat(query, "  AND main_stat IN (");
-    for (int i = 0; i < 13; i ++){
-        if (options->stats[i] == TRUE){
-            sprintf(stat_set, "%d", i);
-            strcat(query, stat_set);
-            strcat(query, ", ");
-        }
-    }
-    query[strlen(query) - 2] = '\0'; // Remove last coma
-    strcat(query, ") -- Main stats\n");
-    //printf("\n\nQUERY: %s\n\n", query);
-    return;
-}
-
-void optimize_query_for_odd_slots(Optimizer_Options *options, char query[3500]){
-    char column[10];
-    char cur_set[3];
-    char stat_set[3];
-    if (options->level == 12) strcpy(column, "lv12_");
-    else if (options->level == 15) strcpy(column, "lv15_");
-    else strcpy(column, "current_");
-    strcpy(query, "SELECT id, unit, slot, type, ");
-    strcat(query, column);
-    strcat(query, "hp_flat, ");
-    strcat(query, column);
-    strcat(query, "atk_flat, ");
-    strcat(query, column);
-    strcat(query, "def_flat, ");
-    strcat(query, column);
-    strcat(query, "hp_percent, ");
-    strcat(query, column);
-    strcat(query, "atk_percent, ");
-    strcat(query, column);
-    strcat(query, "def_percent, ");
-    strcat(query, column);
-    strcat(query, "spd, ");
-    strcat(query, column);
-    strcat(query, "crr, ");
-    strcat(query, column);
-    strcat(query, "crd, ");
-    strcat(query, column);
-    strcat(query, "res, ");
-    strcat(query, column);
-    strcat(query, "acc\nFROM runes\nWHERE\n  slot = ? -- Slot\n");
-    strcat(query, "  AND type IN (");
-    for (int i = 0; i < 3; i ++){
-        if (options->sets[i] != 0){
-            sprintf(cur_set, "%d", options->sets[i]);
-            strcat(query, cur_set);
-            strcat(query, ", ");
-        }
-    }
-    if (options->full_set == FALSE){
-        for (int i = 0; i < 25; i ++){
-            if (options->optional_sets[i] == TRUE){
-                sprintf(cur_set, "%d", i);
-                strcat(query, cur_set);
-                strcat(query, ", ");
-            }
-        }
-    }
-    query[strlen(query) - 2] = '\0'; // Remove last coma
-    strcat(query, ") -- Sets\n");
-    if (options->storage == TRUE){
-        // They are not null, are empty!
-        strcat(query, "  AND (unit = '' OR unit = '");
-        strcat(query, options->id);
-        strcat(query, "') -- Only storage\n");
-    }
-    // Excluded teams (overriden by storage option)
-    if (options->storage == FALSE && options->total_excluded_teams > 0){
-        strcat(query, "  AND (unit = '' OR unit = '");
-        strcat(query, options->id);
-        strcat(
-        query, "' OR unit NOT IN (SELECT unit FROM units_teams WHERE team IN("
-        );
-        for (int i = 0; i < options->total_excluded_teams; i ++){
-            strcat(query, "'");
-            strcat(query, options->excluded_teams[i]);
-            strcat(query, "', ");
-        }
-        query[strlen(query) - 2] = '\0'; // Remove last coma
-        strcat(query, "))) -- Excluded teams\n ");
-    }
-    // Excluded units (overriden by storage option)
-    if (options->storage == FALSE && options->total_excluded_units > 0){
-        strcat(query, " AND (unit = '' OR unit = '");
-        strcat(query, options->id);
-        strcat(query, "' OR unit NOT IN (");
-        for (int i = 0; i < options->total_excluded_units; i ++){
-            strcat(query, "'");
-            strcat(query, options->excluded_units[i]);
-            strcat(query, "', ");
-        }
-        query[strlen(query) - 2] = '\0'; // Remove last coma
-        strcat(query, ")) -- Excluded units");
-    }
-    //printf("QUERY: %s\n", query);
-    return;
-}

+ 10 - 2
src/RuneOptimizer/player/player.c

@@ -17,12 +17,20 @@
 
 /**
  * @file player.c
- * Implementation of the player command.
+ *
+ * Implementation of the functions used by the player command.
+ *
+ * This file implements the functions used by the player command declared in
+ * {@link player.h}.
  */
 
+#include <stdio.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
+#include "../db/db.h"
 #include "player.h"
 
-int cmd_player(){
+extern int player(){
     sqlite3_stmt *stmt;
     db_query(
       &stmt,

+ 25 - 3
src/RuneOptimizer/player/player.h

@@ -17,12 +17,34 @@
 
 /**
  * @file player.h
- * Declaration of the player command.
+ *
+ * Declarations of the functions related to the player command.
+ *
+ * This file declares all the functions used by the player command implemented
+ * in {@link player.c}.
  */
 
+#pragma once
+
 /**
  * Prints info about the player.
  *
- * @return SUCCESS or ERROR_BD_SELECT_INFO if there is no data in the database.
+ * The following info is printed:
+ * - Player name.
+ * - Player ID.
+ * - Player level.
+ * - Database last update timestamp.
+ * - Indicator for modifications applied since the update.
+ * - Total units in database.
+ * - Total units at level 40.
+ * - Total units with runes.
+ * - Total runes.
+ * - Total assigned runes.
+ * - Total unassigned runes.
+ * - Total teams.
+ * - Total units in at least one team.
+ *
+ * @return {@link SUCCESS} or {@link ERROR_DB_SELECT_INFO} if there is no data
+ * in the database.
  */
-int cmd_player();
+extern int player();

+ 7 - 1
src/RuneOptimizer/team/team.c

@@ -17,9 +17,15 @@
 
 /**
  * @file team.c
+ *
  * Implementation of the team command.
+ *
+ * This file implements the team command declared in {@link team.h}.
  */
 
+#include <stdio.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
 #include "team.h"
 #include "team_list.c"
 #include "team_create.c"
@@ -27,7 +33,7 @@
 #include "team_add_unit.c"
 #include "team_remove_unit.c"
 
-int cmd_team(int argc, char *argv[]){
+extern int team(int argc, char *argv[]){
     if (argc < 1){
         fprintf(stderr, "Command team needs an action\n");
         return(ERROR_INPUT_TEAM_NO_ACTION);

+ 51 - 94
src/RuneOptimizer/team/team.h

@@ -17,22 +17,14 @@
 
 /**
  * @file team.h
- * Declaration of the functions used by the team command.
+ *
+ * Declarations of the functions related to the team command.
+ *
+ * This file declares all the functions used by the team command implemented in
+ * {@link team.c} and other files.
  */
 
-/**
- * Validates the options for adding a unit to a team.
- * 
- * It checks if the unit and team IDs exist, and if the unit is already a member
- * of the team.
- * 
- * @param[in] team ID of the team to add the unit to.
- * @param[in] unit ID of the unit to add.
- * @return SUCCESS if everything is OK, ERROR_INPUT_TEAM_VERIFY_UNIT_TEAM if the
- * team doesn't exist, ERROR_INPUT_TEAM_VERIFY_UNIT_UNIT if the unit doesn't
- * exist or ERROR_DB_VERIFY_TEAM_UNIT for other errors.
- */
-int team_add_unit_validate(char *team, char *unit);
+#pragma once
 
 /**
  * Adds a unit to a team.
@@ -40,13 +32,14 @@ int team_add_unit_validate(char *team, char *unit);
  * Inserts a row in the table 'units_teams'. In case of error, it will print a
  * description to stderr.
  *
- * @param argc[in] Number of arguments passed to the option.
- * @param argv[in] Aguments passed to the option.
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
+ * @param[in] argc Number of arguments passed to the option. It should be
+ * exactly 2.
+ * @param[in] argv Aguments passed to the option. They should be exactly two:
+ * the team ID, and the unit ID.
+ * @return {@link SUCCESS} if the unit was added, or an error defined in
+ * {@link error.h} if there were errors.
  */
-int team_add_unit(int argc, char *argv[]);
+extern int team_add_unit(int argc, char *argv[]);
 
 /**
  * Creates a team.
@@ -55,46 +48,15 @@ int team_add_unit(int argc, char *argv[]);
  * (optionally) priority. It will have no units in 'units_teams'. In case of
  * error, it will print a description to stderr.
  *
- * @param argc[in] Number of arguments passed to the option.
- * @param argv[in] Arguments passed to the option. It needs to have a size of 1
- * or two. The frst one must be the new team name, the seecond one is optional
- * and is the priority of the new team. If not specified, the priority will be
- * 0.
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
- */
-int team_create(int argc, char *argv[]);
-
-/**
- * Validates a string as a priority for a team.
- * 
- * To be valid, the string must contain a number between 0 and 50.
- * 
- * @param[in] priority String to evaluate as priority.
- * @return 0-50 if the priority is valid, -1 otherwise.
- */
-int team_create_validate_priority(char *priority);
-
-/**
- * Gets the next available id for the table teams.
- * 
- * It will get the nexxt ID to the highest one currently in the table 'teams',
- * but it will not get any unused one lower than that.
- * 
- * @return -1 on error, positive integer with the ID on success.
+ * @param[in] argc Number of arguments passed to the option. It should be
+ * exactly 1 or 2.
+ * @param[in] argv Arguments passed to the option. The first one is a name for
+ * the new team, the seecond one is optional and is the priority of the new
+ * team. If not specified, the priority will be 0.
+ * @return {@link SUCCESS} if the team was created, or an error defined in
+ * {@link error.h} if there were errors.
  */
-int team_create_get_next_id();
-
-/**
- * Validates data for team deletion.
- * 
- * Checks if the team exists.
- * 
- * @return SUCCESS if everything is OK, ERROR_INPUT_TEAM_VERIFY if the team
- * doesn't exist, or ERROR_DB_SELECT_TEAM for any database errors.
- */
-int team_delete_validate(char *team);
+extern int team_create(int argc, char *argv[]);
 
 /**
  * Deletes a team.
@@ -103,58 +65,53 @@ int team_delete_validate(char *team);
  * 'units_teams'. In case of error, it will print a
  * description to stderr.
  *
- * @param argc[in] Argument count.
- * @param argv[in] Argument list.
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
+ * @param[in] argc Number of arguments passed to the option. It should be
+ * exactly 1.
+ * @param[in] argv Aguments passed to the option. They should be exactly one:
+ * the team ID.
+ * @return {@link SUCCESS} if the team was deleted, or an error defined in
+ * {@link error.h} if there were errors.
  */
-int team_delete(int argc, char *argv[]);
+extern int team_delete(int argc, char *argv[]);
 
 /**
  * Displays a list of teams ar a single team info.
  *  *
- * @param argc[in] Number of arguments passed to the option.
- * @param argv[in] Arguments passed to the option. If one of them is the -u or
+ * @param[in] argc Number of arguments passed to the option.
+ * @param[in] argv Arguments passed to the option. If a team ID is passed, it
+ * must be the first parameter. If one of the parameters is the -u or
  * --units option, it will also print the units for each of the printed teams.
- * @return Allways SUCCESS.
- */
-int team_list(int argc, char *argv[]);
-
-/**
- * Performs a validation for the unit removal function.
- * 
- * It chechs that a unit exists in units_teams for a team.
- * 
- * @param[in] team ID of the team to check.
- * @param[in] unit ID of the unit to check.
- * @return SUCCESS if the unit was removed from the team,
- * ERROR_INPUT_TEAM_VERIFY_UNIT_TEAM if the unit is not part of the team, or
- * ERROR_DB_VERIFY_TEAM_UNIT on error.
+ * @return {@link SUCCESS}, even if no team was listed, or a database error
+ * defined in {@link error.h}.
  */
-int team_remove_unit_validate(char *team, char *unit);
+extern int team_list(int argc, char *argv[]);
 
 /**
  * Removes a unit from a team.
  *
  * It deletes the entry in the table 'units_teams'.
  *
- * @param argc[in] Number or arguments passed to the option.
- * @param argv[in] Argument passed to the option.
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
+ * @param[in] argc Number of arguments passed to the option. It should be
+ * exactly 2.
+ * @param[in] argv Aguments passed to the option. They should be exactly two:
+ * the team ID, and the unit ID.
+ * @return {@link SUCCESS} if the unit was removed, or an error defined in
+ * {@link error.h} if there were errors.
  */
-int team_remove_unit(int argc, char *argv[]);
+extern int team_remove_unit(int argc, char *argv[]);
 
 /**
  * Parses the arguments passes to the team function and calls the appripiate
  * function.
  *
- * @param[in] argc Number of arguments passed to the team command.
- * @param[in] argv Arguments passed to the team command.
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
+ * @param[in] argc Number of argument passed to the team command. As a
+ * rule, it must me two less than the argc received by the {@link main}
+ * function of the program.
+ * @param[in] argv Arguments passed to the optimizer. As a rule, they must be
+ * the same than the argv received by the {@link main} function of the program
+ * without the first two. The first of them must be a command action, ant the
+ * rest of them, parameters for the action.
+ * @return {@link SUCCESS} if the command was succesfull, or an error defined in
+ * {@link error.h} if there were errors.
  */
-int cmd_team(int argc, char *argv[]);
+extern int team(int argc, char *argv[]);

+ 55 - 29
src/RuneOptimizer/team/team_add_unit.c

@@ -17,38 +17,36 @@
 
 /**
  * @file team_add_unit.c
- * Implementation of functions to add units to teams.
+ *
+ * Implementation of {@link team_add_unit}.
+ *
+ * This file implements the function {@link team_add_unit} declared in
+ * {@link team.h}. It also defines and implements an static function for
+ * validation.
  */
 
-int team_add_unit_validate(char *team, char *unit){
-    int status = SUCCESS;
-    sqlite3_stmt *stmt_verify;
-    char *parameters[4] = {team, unit, team, unit};
-    db_query(
-      &stmt_verify,
-      "SELECT "
-      "(SELECT count(id) FROM teams WHERE id = ?) AS team, "
-      "(SELECT count(id) FROM units WHERE id = ?) AS unit, "
-      "(SELECT count(*) FROM units_teams WHERE team = ? AND unit = ?) AS inc",
-      parameters
-    );
-    if (SQLITE_ROW != sqlite3_step(stmt_verify)){
-        status = ERROR_DB_VERIFY_TEAM_UNIT;
-    }
-    else if (sqlite3_column_int(stmt_verify, 0) == 0){
-        status = ERROR_INPUT_TEAM_VERIFY_TEAM;
-    }
-    else if (sqlite3_column_int(stmt_verify, 1) == 0){
-        status = ERROR_INPUT_TEAM_VERIFY_UNIT;
-    }
-    else if (sqlite3_column_int(stmt_verify, 2) != 0){
-        status = ERROR_INPUT_TEAM_VERIFY_INCLUDED;
-    }
-    sqlite3_finalize(stmt_verify);
-    return(status);
-}
+#include <stdio.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
+#include "../db/db.h"
+#include "team.h"
+
+/**
+ * Validates the options for adding a unit to a team.
+ *
+ * It checks if the unit and team IDs exist, and if the unit is already a member
+ * of the team.
+ *
+ * @param[in] team ID of the team to add the unit to.
+ * @param[in] unit ID of the unit to add.
+ * @return {@link SUCCESS} if everything is OK and the unit can be added,
+ * {@link ERROR_INPUT_TEAM_VERIFY_UNIT_TEAM} if the team doesn't exist,
+ * {@link ERROR_INPUT_TEAM_VERIFY_UNIT} if the unit doesn't exist or
+ * {@link ERROR_DB_VERIFY_TEAM_UNIT} for other errors.
+ */
+static int team_add_unit_validate(char *team, char *unit);
 
-int team_add_unit(int argc, char *argv[]){
+extern int team_add_unit(int argc, char *argv[]){
     if (argc != 2){
         fprintf(
           stderr, "add_unit needs exactly two arguments, %d supplied\n",
@@ -101,3 +99,31 @@ int team_add_unit(int argc, char *argv[]){
     team_list(2, args_to_list);
     return(SUCCESS);
 }
+
+static int team_add_unit_validate(char *team, char *unit){
+    int status = SUCCESS;
+    sqlite3_stmt *stmt_verify;
+    char *parameters[4] = {team, unit, team, unit};
+    db_query(
+      &stmt_verify,
+      "SELECT "
+      "(SELECT count(id) FROM teams WHERE id = ?) AS team, "
+      "(SELECT count(id) FROM units WHERE id = ?) AS unit, "
+      "(SELECT count(*) FROM units_teams WHERE team = ? AND unit = ?) AS inc",
+      parameters
+    );
+    if (SQLITE_ROW != sqlite3_step(stmt_verify)){
+        status = ERROR_DB_VERIFY_TEAM_UNIT;
+    }
+    else if (sqlite3_column_int(stmt_verify, 0) == 0){
+        status = ERROR_INPUT_TEAM_VERIFY_TEAM;
+    }
+    else if (sqlite3_column_int(stmt_verify, 1) == 0){
+        status = ERROR_INPUT_TEAM_VERIFY_UNIT;
+    }
+    else if (sqlite3_column_int(stmt_verify, 2) != 0){
+        status = ERROR_INPUT_TEAM_VERIFY_INCLUDED;
+    }
+    sqlite3_finalize(stmt_verify);
+    return(status);
+}

+ 63 - 32
src/RuneOptimizer/team/team_create.c

@@ -17,43 +17,41 @@
 
 /**
  * @file team_create.c
- * Implementation of functions to create teams.
+ *
+ * Implementation of {@link team_create}.
+ *
+ * This file implements the function {@link team_create} declared in
+ * {@link team.h}. It also defines and implements some static functions used by
+ * it.
  */
 
-int team_create_validate_priority(char *priority){
-    int prio = atoi(priority);
-    // Has an actual 0 been passed?
-    // Or is the 0 returned by atoi bc priority is no number?
-    if (prio == 0 && strspn(priority, "0") != strlen(priority)){
-        return(-1);
-    }
-    if (prio < 0 || prio > 50){
-      return(-1);
-    }
-    return(prio);
-}
-
-int team_create_get_next_id(){
-    int new_id = -1;
-    sqlite3_stmt *stmt_id;
+#include <stdio.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
+#include "../db/db.h"
+#include "team.h"
 
-    // Get the new id for the team
-    db_query(
-      &stmt_id, "SELECT max(CAST(id AS INTEGER)) + 1 AS id FROM teams", NULL
-    );
-    if (SQLITE_ROW != sqlite3_step(stmt_id)){
-        fprintf(stderr, "Unable to read teams: %s\n", sqlite3_errmsg(db));
-        sqlite3_finalize(stmt_id);
-        return(-1);
-    }
+/**
+ * Validates a string as a priority for a team.
+ *
+ * To be valid, the string must contain a number between 0 and 50.
+ *
+ * @param[in] priority String to evaluate as priority.
+ * @return 0-50 if the priority is valid, -1 if it's not a valid priority.
+ */
+static int team_create_validate_priority(char *priority);
 
-    // Get all parameters and convert to char.
-    new_id = sqlite3_column_int(stmt_id, 0);
-    sqlite3_finalize(stmt_id);
-    return(new_id);
-}
+/**
+ * Gets the next available id for the table teams.
+ *
+ * It will get the nexxt ID to the highest one currently in the table 'teams',
+ * but it will not get any unused one lower than that.
+ *
+ * @return -1 on error, positive integer with the ID on success.
+ */
+static int team_create_get_next_id();
 
-int team_create(int argc, char *argv[]){
+extern int team_create(int argc, char *argv[]){
     if (argc < 1 || argc > 2){
         fprintf(
           stderr, "Team creation takes 1 or 2 arguments, %d supplied\n", argc
@@ -100,3 +98,36 @@ int team_create(int argc, char *argv[]){
     printf("Team ID %d '%s' created with priority %d\n", new_id, name, priority);
     return(SUCCESS);
 }
+
+static int team_create_validate_priority(char *priority){
+    int prio = atoi(priority);
+    // Has an actual 0 been passed?
+    // Or is the 0 returned by atoi bc priority is no number?
+    if (prio == 0 && strspn(priority, "0") != strlen(priority)){
+        return(-1);
+    }
+    if (prio < 0 || prio > 50){
+      return(-1);
+    }
+    return(prio);
+}
+
+static int team_create_get_next_id(){
+    int new_id = -1;
+    sqlite3_stmt *stmt_id;
+
+    // Get the new id for the team
+    db_query(
+      &stmt_id, "SELECT max(CAST(id AS INTEGER)) + 1 AS id FROM teams", NULL
+    );
+    if (SQLITE_ROW != sqlite3_step(stmt_id)){
+        fprintf(stderr, "Unable to read teams: %s\n", sqlite3_errmsg(db));
+        sqlite3_finalize(stmt_id);
+        return(-1);
+    }
+
+    // Get all parameters and convert to char.
+    new_id = sqlite3_column_int(stmt_id, 0);
+    sqlite3_finalize(stmt_id);
+    return(new_id);
+}

+ 43 - 21
src/RuneOptimizer/team/team_delete.c

@@ -17,30 +17,32 @@
 
 /**
  * @file team_delete.c
- * Implementation of functions to delete teams.
+ *
+ * Implementation of {@link team_delete}.
+ *
+ * This file implements the function {@link team_delete} declared in
+ * {@link team.h}. It also defines and implements an static function for
+ * validation.
  */
 
-int team_delete_validate(char *team){
-    // Verify that the team exists.
-    sqlite3_stmt *stmt_verify;
-    char *parameters[1] = {team};
-    db_query(
-      &stmt_verify,
-      "SELECT count(id) AS c FROM teams WHERE id = ?", parameters
-    );
-    if (SQLITE_ROW != sqlite3_step(stmt_verify)){
-        sqlite3_finalize(stmt_verify);
-        return(ERROR_DB_SELECT_TEAM);
-    }
-    if (sqlite3_column_int(stmt_verify, 0) == 0){
-        sqlite3_finalize(stmt_verify);
-        return(ERROR_INPUT_TEAM_VERIFY_TEAM);
-    }
-    sqlite3_finalize(stmt_verify);
-    return(SUCCESS);
-}
+#include <stdio.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
+#include "../db/db.h"
+#include "team.h"
+
+/**
+ * Validates data for team deletion.
+ *
+ * Checks if the team exists.
+ *
+ * @return {@link SUCCESS} if everything is OK and the team can be deleted,
+ * {@link ERROR_INPUT_TEAM_VERIFY_TEAM} if the team doesn't exist, or
+ * {@link ERROR_DB_SELECT_TEAM} for any database errors.
+ */
+static int team_delete_validate(char *team);
 
-int team_delete(int argc, char *argv[]){
+extern int team_delete(int argc, char *argv[]){
     if (argc != 1){
         fprintf(
           stderr,
@@ -77,3 +79,23 @@ int team_delete(int argc, char *argv[]){
     }
     return(SUCCESS);
 }
+
+static int team_delete_validate(char *team){
+    // Verify that the team exists.
+    sqlite3_stmt *stmt_verify;
+    char *parameters[1] = {team};
+    db_query(
+      &stmt_verify,
+      "SELECT count(id) AS c FROM teams WHERE id = ?", parameters
+    );
+    if (SQLITE_ROW != sqlite3_step(stmt_verify)){
+        sqlite3_finalize(stmt_verify);
+        return(ERROR_DB_SELECT_TEAM);
+    }
+    if (sqlite3_column_int(stmt_verify, 0) == 0){
+        sqlite3_finalize(stmt_verify);
+        return(ERROR_INPUT_TEAM_VERIFY_TEAM);
+    }
+    sqlite3_finalize(stmt_verify);
+    return(SUCCESS);
+}

+ 12 - 2
src/RuneOptimizer/team/team_list.c

@@ -17,10 +17,20 @@
 
 /**
  * @file team_list.c
- * Implementation of team_list.
+ *
+ * Implementation of {@link team_list}.
+ *
+ * This file implements the function {@link team_list} declared in
+ * {@link team.h}.
  */
 
-int team_list(int argc, char *argv[]){
+#include <stdio.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
+#include "../db/db.h"
+#include "team.h"
+
+extern int team_list(int argc, char *argv[]){
     // Get parameters
     char show_units = FALSE;
     int number_of_options = 0;

+ 54 - 30
src/RuneOptimizer/team/team_remove_unit.c

@@ -17,39 +17,34 @@
 
 /**
  * @file team_remove_unit.c
- * Implementation of functions to remove units from teams.
+ *
+ * Implementation of {@link team_remove_unit}.
+ *
+ * This file implements the function {@link team_remove_unit} declared in
+ * {@link team.h}. It also defines and implements an static function for
+ * validation.
  */
 
-int team_remove_unit_validate(char *team, char *unit){
-    sqlite3_stmt *stmt_validate;
-    char *parameters[2] = {team, unit};
-    db_query(
-      &stmt_validate,
-      "SELECT count(unit) AS inc FROM units_teams WHERE team = ? AND unit = ?",
-      parameters
-    );
-    if (SQLITE_ROW != sqlite3_step(stmt_validate)){
-        fprintf(
-          stderr, "Unable to verify unit and team: %s\n", sqlite3_errmsg(db)
-        );
-        sqlite3_finalize(stmt_validate);
-        return(ERROR_DB_VERIFY_TEAM_UNIT);
-    }
-    if (sqlite3_column_int(stmt_validate, 0) == 0){
-        fprintf(
-          stderr,
-          "There is no unit with ID '%s' in team with ID '%s'\n",
-          unit,
-          team
-        );
-        sqlite3_finalize(stmt_validate);
-        return(ERROR_INPUT_TEAM_VERIFY_UNIT_TEAM);
-    }
-    sqlite3_finalize(stmt_validate);
-    return SUCCESS;
-}
+#include <stdio.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
+#include "../db/db.h"
+#include "team.h"
+
+/**
+ * Performs a validation for the unit removal function.
+ *
+ * It chechs that a unit exists in units_teams for a team.
+ *
+ * @param[in] team ID of the team to check.
+ * @param[in] unit ID of the unit to check.
+ * @return {@link SUCCESS} if everything was OK and the unit can be removed from
+ * the team, {@link ERROR_INPUT_TEAM_VERIFY_UNIT_TEAM} if the unit is not part
+ * of the team, or {@link ERROR_DB_VERIFY_TEAM_UNIT} on any database error.
+ */
+static int team_remove_unit_validate(char *team, char *unit);
 
-int team_remove_unit(int argc, char *argv[]){
+extern int team_remove_unit(int argc, char *argv[]){
     if (argc != 2){
         fprintf(
           stderr, "remove_unit needs exactly two argument, %d supplied\n",
@@ -88,3 +83,32 @@ int team_remove_unit(int argc, char *argv[]){
     team_list(2, args_to_list);
     return(SUCCESS);
 }
+
+static int team_remove_unit_validate(char *team, char *unit){
+    sqlite3_stmt *stmt_validate;
+    char *parameters[2] = {team, unit};
+    db_query(
+      &stmt_validate,
+      "SELECT count(unit) AS inc FROM units_teams WHERE team = ? AND unit = ?",
+      parameters
+    );
+    if (SQLITE_ROW != sqlite3_step(stmt_validate)){
+        fprintf(
+          stderr, "Unable to verify unit and team: %s\n", sqlite3_errmsg(db)
+        );
+        sqlite3_finalize(stmt_validate);
+        return(ERROR_DB_VERIFY_TEAM_UNIT);
+    }
+    if (sqlite3_column_int(stmt_validate, 0) == 0){
+        fprintf(
+          stderr,
+          "There is no unit with ID '%s' in team with ID '%s'\n",
+          unit,
+          team
+        );
+        sqlite3_finalize(stmt_validate);
+        return(ERROR_INPUT_TEAM_VERIFY_UNIT_TEAM);
+    }
+    sqlite3_finalize(stmt_validate);
+    return SUCCESS;
+}

+ 325 - 3
src/RuneOptimizer/unit/unit.c

@@ -17,16 +17,338 @@
 
 /**
  * @file unit.c
- * Implementation of the unit command.
+ *
+ * Implementation of the functions used by the unit command.
+ *
+ * This file implements the functions used by the unit command declared in
+ * {@link unit.h}.
  */
 
+#include <stdio.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
+#include "../db/db.h"
 #include "unit.h"
-#include "unit_list.c"
 
-int cmd_unit(int argc, char *argv[]){
+/**
+ * Displays a list of units  ar a single team info.
+ *
+ * It will print them all to stdout. If none were found, a message indicating so
+ * will be printed instead.
+ *
+ * @param[in] search Search term. Can be the exact ID or part of the name (case
+ * insensitive).
+ * @return The number of units found by the search criteria.
+ */
+static int unit_list(char *search);
+
+extern int unit(int argc, char *argv[]){
     if (argc < 1){
         fprintf(stderr, "Command unit needs an identifier (ID or name)\n");
         return(ERROR_INPUT_UNIT_NO_ID);
     }
     return(unit_list(argv[0]));
 }
+
+static int unit_list(char *search){
+    char query[300] = "SELECT id, name, priority FROM teams ";
+    char search_name[96] = "%";
+    strcat(search_name, search);
+    strcat(search_name, "%");
+    char *parameters[2] = {search, search_name};
+    sqlite3_stmt *stmt_units;
+    sqlite3_stmt *stmt_runes;
+    sqlite3_stmt *stmt_stats;
+    char rune_lines[30][80];
+    db_query(
+      &stmt_units,
+      "SELECT "
+      "  id,          name,        stars,       level,      storage, "
+      "  base_hp,     base_atk,    base_def,    base_spd, "
+      "  base_crr,    base_crd,    base_res,    base_acc, "
+      "  current_hp,  current_atk, current_def, current_spd, "
+      "  current_crr, current_crd, current_res, current_acc "
+      "FROM units WHERE id = ? OR name LIKE ?",
+      parameters
+    );
+    int units_found = 0;
+    int unit_has_runes = FALSE;
+    char tmp[32];
+    while (SQLITE_ROW == sqlite3_step(stmt_units)){
+        char unit_name[14];
+
+        // Print a separator between units
+        if (units_found > 0){
+            printf(
+            "##############################################################\n"
+            "##############################################################\n\n"
+            );
+        }
+        units_found ++;
+
+        printf("                 ----------------------------\n");
+        printf("                 | STAT | BASE    | CURR.   |\n");
+        printf("  =============  ----------------------------\n");
+        strncpy(unit_name, sqlite3_column_text(stmt_units, 1), 13);
+        printf(" %*s  ", 14, unit_name);
+        printf(
+          "| HP:  | %*d  | %*d  |\n",
+          6, sqlite3_column_int(stmt_units, 5),
+          6, sqlite3_column_int(stmt_units, 13)
+        );
+        printf("   #%*s", -13, sqlite3_column_text(stmt_units, 0));
+        printf(
+          "| ATK: | %*d  | %*d  |\n",
+          6, sqlite3_column_int(stmt_units, 6),
+          6, sqlite3_column_int(stmt_units, 14)
+        );
+        printf(
+          "  =============  | DEF: | %*d  | %*d  |\n",
+          6, sqlite3_column_int(stmt_units, 7),
+          6, sqlite3_column_int(stmt_units, 15)
+        );
+        printf(
+          "                 | SPD: | %*d  | %*d  |\n",
+          6, sqlite3_column_int(stmt_units, 8),
+          6, sqlite3_column_int(stmt_units, 16)
+        );
+        printf("    Lv.%*d", -2, sqlite3_column_int(stmt_units, 3));
+        printf("    %d*  ", sqlite3_column_int(stmt_units, 2));
+        printf(
+          "| CRR: | %*d% | %*d% |\n",
+          6, sqlite3_column_int(stmt_units, 9),
+          6, sqlite3_column_int(stmt_units, 17)
+        );
+        printf(
+          "                 | CRD: | %*d% | %*d% |\n",
+          6, sqlite3_column_int(stmt_units, 10),
+          6, sqlite3_column_int(stmt_units, 18)
+        );
+        printf("   Storage: ");
+        if (1 == sqlite3_column_int(stmt_units, 4)){
+            printf("Yes");
+        }
+        else{
+            printf("No ");
+        }
+        printf(
+          "  | RES: | %*d% | %*d% |\n",
+          6, sqlite3_column_int(stmt_units, 11),
+          6, sqlite3_column_int(stmt_units, 19)
+        );
+        printf(
+          "                 | ACC: | %*d% | %*d% |\n",
+          6, sqlite3_column_int(stmt_units, 12),
+          6, sqlite3_column_int(stmt_units, 20)
+        );
+        printf(
+          "                 | EHP: | %*d  | %*d  |\n",
+          6,
+          calculate_ehp(
+            sqlite3_column_int(stmt_units, 5),
+            sqlite3_column_int(stmt_units, 7)
+          ),
+          6,
+          calculate_ehp(
+            sqlite3_column_int(stmt_units, 13),
+            sqlite3_column_int(stmt_units, 15)
+          )
+        );
+        printf(
+          "                 | DMG: | %*d  | %*d  |\n",
+          6,
+          calculate_dmg(
+            sqlite3_column_int(stmt_units, 6),
+            sqlite3_column_int(stmt_units, 9),
+            sqlite3_column_int(stmt_units, 10)
+          ),
+          6,
+          calculate_dmg(
+            sqlite3_column_int(stmt_units, 14),
+            sqlite3_column_int(stmt_units, 17),
+            sqlite3_column_int(stmt_units, 18)
+          )
+        );
+        printf("                 ----------------------------\n");
+
+        // Get runes
+        strcpy(tmp, sqlite3_column_text(stmt_units, 0));
+        char *rune_parameters[1] = {tmp};
+        db_query(
+          &stmt_runes,
+          "SELECT "
+          "  id,    slot,    type,        stars, "
+          "  level, quality, efficiency,  max_efficiency "
+          "FROM runes WHERE unit = ? "
+          "ORDER BY slot = 3, slot = 4, slot = 5, slot = 2, slot = 1, slot = 6",
+          rune_parameters
+        );
+        for (int i = 0; i < 30; i ++){
+            if (i == 0 || i == 13 || i == 15 || i == 28){
+                strcpy(
+                  rune_lines[i],
+                  " ------------------- "
+                  " ------------------- "
+                  " -------------------\n"
+                );
+            }
+            else if (i == 3 || i == 10 || i == 18 || i == 25){
+                strcpy(
+                  rune_lines[i],
+                  " |-----------------| "
+                  " |-----------------| "
+                  " |-----------------|\n"
+                );
+            }
+            else if (
+              i == 1  || i == 2  || (i > 3 && i < 10) ||i == 11 ||
+              i == 12 || i == 16 || i == 17 || (i > 18 && i < 29)
+            ){
+                strcpy(
+                  rune_lines[i],
+                  " |                 | "
+                  " |                 | "
+                  " |                 |\n"
+                );
+            }
+            else{
+                strcpy(rune_lines[i], "\n");
+            }
+        }
+        unit_has_runes = FALSE;
+        while (SQLITE_ROW == sqlite3_step(stmt_runes)){
+            unit_has_runes = TRUE;
+            int slot = sqlite3_column_int(stmt_runes, 1);
+            int top_line_to_add = -1;
+            int position_to_add = -1;
+            if (slot == 6 || slot == 1 || slot == 2){
+                top_line_to_add = 0;
+            }
+            else{
+                top_line_to_add = 15;
+            }
+            if (slot == 6 || slot == 5){
+                position_to_add = 3;
+            }
+            else if (slot == 1 || slot == 4){
+                position_to_add = 24;
+            }
+            else{
+                position_to_add = 45;
+            }
+            // Rune slot
+            strncpy(
+              rune_lines[top_line_to_add + 1] + position_to_add,
+              sqlite3_column_text(stmt_runes, 1),
+              1
+            );
+            // Slot / ID separator
+            strncpy(
+              rune_lines[top_line_to_add + 1] + position_to_add + 1, "| #", 3
+            );
+            // ID
+            strncpy(
+              rune_lines[top_line_to_add + 1] + position_to_add + 4,
+              sqlite3_column_text(stmt_runes, 0),
+              strlen(sqlite3_column_text(stmt_runes, 0))
+            );
+            // Set name
+            strncpy(
+              rune_lines[top_line_to_add + 2] + position_to_add,
+              SET_NAMES[sqlite3_column_int(stmt_runes, 2)],
+              strlen(SET_NAMES[sqlite3_column_int(stmt_runes, 2)])
+            );
+            // Power up level
+            strncpy(
+              rune_lines[top_line_to_add + 2] + position_to_add + 7,
+              " +      ",
+              7
+            );
+            strncpy(
+              rune_lines[top_line_to_add + 2] + position_to_add + 9,
+              sqlite3_column_text(stmt_runes, 4),
+              strlen(sqlite3_column_text(stmt_runes, 4))
+            );
+            // Stars
+            strncpy(
+              rune_lines[top_line_to_add + 2] + position_to_add + 13,
+              sqlite3_column_text(stmt_runes, 3),
+              1
+            );
+            strncpy(
+              rune_lines[top_line_to_add + 2] + position_to_add + 14, "*", 1
+            );
+            // Quality
+            strncpy(
+              rune_lines[top_line_to_add + 11] + position_to_add,
+              QUALITY_NAMES[sqlite3_column_int(stmt_runes, 5)],
+              strlen(QUALITY_NAMES[sqlite3_column_int(stmt_runes, 5)])
+            );
+            // Efficiency
+            sprintf(
+              tmp,
+              "%6.2f%%/%6.2f%%",
+              sqlite3_column_double(stmt_runes, 6),
+              sqlite3_column_double(stmt_runes, 7)
+            );
+            strncpy(
+              rune_lines[top_line_to_add + 12] + position_to_add,
+              tmp,
+              strlen(tmp)
+            );
+            // Get stats
+            strcpy(tmp, sqlite3_column_text(stmt_runes, 0));
+            char *stat_parameters[1] = {tmp};
+            db_query(
+              &stmt_stats,
+              "SELECT slot, stat, value, grind, enchant "
+              "FROM rune_stats WHERE rune = ?  ORDER BY slot",
+              stat_parameters
+            );
+            while (SQLITE_ROW == sqlite3_step(stmt_stats)){
+                // Stat name and value
+                sprintf(
+                  tmp,
+                  STAT_NAMES_PRINTABLE[sqlite3_column_int(stmt_stats, 1)],
+                  sqlite3_column_int(stmt_stats, 2)
+                );
+                strncpy(
+                  rune_lines[
+                    top_line_to_add + 5 + sqlite3_column_int(stmt_stats, 0)
+                  ] + position_to_add,
+                  tmp,
+                  9
+                );
+                // Enchanted?
+                if (1 == sqlite3_column_int(stmt_stats, 4)){
+                    strncpy(
+                      rune_lines[top_line_to_add + 5 + sqlite3_column_int(stmt_stats, 0)] + position_to_add + 9,
+                      "*",
+                      1
+                    );
+                }
+                // Grinded?
+                if (0 < sqlite3_column_int(stmt_stats, 3)){
+                    sprintf(tmp, "+%-4d", sqlite3_column_int(stmt_stats, 3));
+                    strncpy(
+                      rune_lines[top_line_to_add + 5 + sqlite3_column_int(stmt_stats, 0)] + position_to_add + 10,
+                      tmp,
+                      5
+                    );
+                }
+            }
+            sqlite3_finalize(stmt_stats);
+        }
+        sqlite3_finalize(stmt_runes);
+        if (TRUE == unit_has_runes){
+            for (int i = 0; i < 30; i ++){
+                printf("%s",rune_lines[i]);
+            }
+        }
+    }
+    sqlite3_finalize(stmt_units);
+    if (units_found == 0){
+        printf("No units found\n");
+    }
+    return(units_found);
+}

+ 13 - 7
src/RuneOptimizer/unit/unit.h

@@ -17,14 +17,20 @@
 
 /**
  * @file unit.h
- * Declaration of the functions used by the unit command.
+ *
+ * Declarations of the functions related to the unit command.
+ *
+ * This file declares all the functions used by the unit command implemented in
+ * {@link unit.c}.
  */
 
+#pragma once
+
 /**
- * Displays a list of units  ar a single team info.
- *  *
- * @param search[in] Search term. Can be the exact ID or part of the name (case
- * insensitive).
- * @return The number of units found by the search criteria.
+ * Handles the unit command.
+ *
+ * @param[in] argc Number of arguments passed to the unit command.
+ * @param[in] argv Arguments passed to the unit command.
+ * @return The number of units found.
  */
-int unit_list(char *search);
+extern int unit(int argc, char *argv[]);

+ 0 - 325
src/RuneOptimizer/unit/unit_list.c

@@ -1,325 +0,0 @@
-/*
- * This file is part of RuneOptimizer.
- *
- * RuneOptimizer is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @file unit_list.c
- * Implementation of unit_list.
- */
-
-int unit_list(char *search){
-
-    char query[300] = "SELECT id, name, priority FROM teams ";
-    char search_name[96] = "%";
-    strcat(search_name, search);
-    strcat(search_name, "%");
-    char *parameters[2] = {search, search_name};
-    sqlite3_stmt *stmt_units;
-    sqlite3_stmt *stmt_runes;
-    sqlite3_stmt *stmt_stats;
-    char rune_lines[30][80];
-    db_query(
-      &stmt_units,
-      "SELECT "
-      "  id,          name,        stars,       level,      storage, "
-      "  base_hp,     base_atk,    base_def,    base_spd, "
-      "  base_crr,    base_crd,    base_res,    base_acc, "
-      "  current_hp,  current_atk, current_def, current_spd, "
-      "  current_crr, current_crd, current_res, current_acc "
-      "FROM units WHERE id = ? OR name LIKE ?",
-      parameters
-    );
-    int units_found = 0;
-    int unit_has_runes = FALSE;
-    char tmp[32];
-    while (SQLITE_ROW == sqlite3_step(stmt_units)){
-        char unit_name[14];
-
-        // Print a separator between units
-        if (units_found > 0){
-            printf(
-            "##############################################################\n"
-            "##############################################################\n\n"
-            );
-        }
-        units_found ++;
-
-        printf("                 ----------------------------\n");
-        printf("                 | STAT | BASE    | CURR.   |\n");
-        printf("  =============  ----------------------------\n");
-        strncpy(unit_name, sqlite3_column_text(stmt_units, 1), 13);
-        printf(" %*s  ", 14, unit_name);
-        printf(
-          "| HP:  | %*d  | %*d  |\n",
-          6, sqlite3_column_int(stmt_units, 5),
-          6, sqlite3_column_int(stmt_units, 13)
-        );
-        printf("   #%*s", -13, sqlite3_column_text(stmt_units, 0));
-        printf(
-          "| ATK: | %*d  | %*d  |\n",
-          6, sqlite3_column_int(stmt_units, 6),
-          6, sqlite3_column_int(stmt_units, 14)
-        );
-        printf(
-          "  =============  | DEF: | %*d  | %*d  |\n",
-          6, sqlite3_column_int(stmt_units, 7),
-          6, sqlite3_column_int(stmt_units, 15)
-        );
-        printf(
-          "                 | SPD: | %*d  | %*d  |\n",
-          6, sqlite3_column_int(stmt_units, 8),
-          6, sqlite3_column_int(stmt_units, 16)
-        );
-        printf("    Lv.%*d", -2, sqlite3_column_int(stmt_units, 3));
-        printf("    %d*  ", sqlite3_column_int(stmt_units, 2));
-        printf(
-          "| CRR: | %*d% | %*d% |\n",
-          6, sqlite3_column_int(stmt_units, 9),
-          6, sqlite3_column_int(stmt_units, 17)
-        );
-        printf(
-          "                 | CRD: | %*d% | %*d% |\n",
-          6, sqlite3_column_int(stmt_units, 10),
-          6, sqlite3_column_int(stmt_units, 18)
-        );
-        printf("   Storage: ");
-        if (1 == sqlite3_column_int(stmt_units, 4)){
-            printf("Yes");
-        }
-        else{
-            printf("No ");
-        }
-        printf(
-          "  | RES: | %*d% | %*d% |\n",
-          6, sqlite3_column_int(stmt_units, 11),
-          6, sqlite3_column_int(stmt_units, 19)
-        );
-        printf(
-          "                 | ACC: | %*d% | %*d% |\n",
-          6, sqlite3_column_int(stmt_units, 12),
-          6, sqlite3_column_int(stmt_units, 20)
-        );
-        printf(
-          "                 | EHP: | %*d  | %*d  |\n",
-          6,
-          optimize_calculate_ehp(
-            sqlite3_column_int(stmt_units, 5),
-            sqlite3_column_int(stmt_units, 7)
-          ),
-          6,
-          optimize_calculate_ehp(
-            sqlite3_column_int(stmt_units, 13),
-            sqlite3_column_int(stmt_units, 15)
-          )
-        );
-        printf(
-          "                 | DMG: | %*d  | %*d  |\n",
-          6,
-          optimize_calculate_dmg(
-            sqlite3_column_int(stmt_units, 6),
-            sqlite3_column_int(stmt_units, 9),
-            sqlite3_column_int(stmt_units, 10)
-          ),
-          6,
-          optimize_calculate_dmg(
-            sqlite3_column_int(stmt_units, 14),
-            sqlite3_column_int(stmt_units, 17),
-            sqlite3_column_int(stmt_units, 18)
-          )
-        );
-        printf("                 ----------------------------\n");
-
-        // Get runes
-        strcpy(tmp, sqlite3_column_text(stmt_units, 0));
-        char *rune_parameters[1] = {tmp};
-        db_query(
-          &stmt_runes,
-          "SELECT "
-          "  id,    slot,    type,        stars, "
-          "  level, quality, efficiency,  max_efficiency "
-          "FROM runes WHERE unit = ? "
-          "ORDER BY slot = 3, slot = 4, slot = 5, slot = 2, slot = 1, slot = 6",
-          rune_parameters
-        );
-        for (int i = 0; i < 30; i ++){
-            if (i == 0 || i == 13 || i == 15 || i == 28){
-                strcpy(
-                  rune_lines[i],
-                  " ------------------- "
-                  " ------------------- "
-                  " -------------------\n"
-                );
-            }
-            else if (i == 3 || i == 10 || i == 18 || i == 25){
-                strcpy(
-                  rune_lines[i],
-                  " |-----------------| "
-                  " |-----------------| "
-                  " |-----------------|\n"
-                );
-            }
-            else if (
-              i == 1  || i == 2  || (i > 3 && i < 10) ||i == 11 ||
-              i == 12 || i == 16 || i == 17 || (i > 18 && i < 29)
-            ){
-                strcpy(
-                  rune_lines[i],
-                  " |                 | "
-                  " |                 | "
-                  " |                 |\n"
-                );
-            }
-            else{
-                strcpy(rune_lines[i], "\n");
-            }
-        }
-        unit_has_runes = FALSE;
-        while (SQLITE_ROW == sqlite3_step(stmt_runes)){
-            unit_has_runes = TRUE;
-            int slot = sqlite3_column_int(stmt_runes, 1);
-            int top_line_to_add = -1;
-            int position_to_add = -1;
-            if (slot == 6 || slot == 1 || slot == 2){
-                top_line_to_add = 0;
-            }
-            else{
-                top_line_to_add = 15;
-            }
-            if (slot == 6 || slot == 5){
-                position_to_add = 3;
-            }
-            else if (slot == 1 || slot == 4){
-                position_to_add = 24;
-            }
-            else{
-                position_to_add = 45;
-            }
-            // Rune slot
-            strncpy(
-              rune_lines[top_line_to_add + 1] + position_to_add,
-              sqlite3_column_text(stmt_runes, 1),
-              1
-            );
-            // Slot / ID separator
-            strncpy(
-              rune_lines[top_line_to_add + 1] + position_to_add + 1, "| #", 3
-            );
-            // ID
-            strncpy(
-              rune_lines[top_line_to_add + 1] + position_to_add + 4,
-              sqlite3_column_text(stmt_runes, 0),
-              strlen(sqlite3_column_text(stmt_runes, 0))
-            );
-            // Set name
-            strncpy(
-              rune_lines[top_line_to_add + 2] + position_to_add,
-              set_names[sqlite3_column_int(stmt_runes, 2)],
-              strlen(set_names[sqlite3_column_int(stmt_runes, 2)])
-            );
-            // Power up level
-            strncpy(
-              rune_lines[top_line_to_add + 2] + position_to_add + 7,
-              " +      ",
-              7
-            );
-            strncpy(
-              rune_lines[top_line_to_add + 2] + position_to_add + 9,
-              sqlite3_column_text(stmt_runes, 4),
-              strlen(sqlite3_column_text(stmt_runes, 4))
-            );
-            // Stars
-            strncpy(
-              rune_lines[top_line_to_add + 2] + position_to_add + 13,
-              sqlite3_column_text(stmt_runes, 3),
-              1
-            );
-            strncpy(
-              rune_lines[top_line_to_add + 2] + position_to_add + 14, "*", 1
-            );
-            // Quality
-            strncpy(
-              rune_lines[top_line_to_add + 11] + position_to_add,
-              quality_names[sqlite3_column_int(stmt_runes, 5)],
-              strlen(quality_names[sqlite3_column_int(stmt_runes, 5)])
-            );
-            // Efficiency
-            sprintf(
-              tmp,
-              "%6.2f%%/%6.2f%%",
-              sqlite3_column_double(stmt_runes, 6),
-              sqlite3_column_double(stmt_runes, 7)
-            );
-            strncpy(
-              rune_lines[top_line_to_add + 12] + position_to_add,
-              tmp,
-              strlen(tmp)
-            );
-            // Get stats
-            strcpy(tmp, sqlite3_column_text(stmt_runes, 0));
-            char *stat_parameters[1] = {tmp};
-            db_query(
-              &stmt_stats,
-              "SELECT slot, stat, value, grind, enchant "
-              "FROM rune_stats WHERE rune = ?  ORDER BY slot",
-              stat_parameters
-            );
-            while (SQLITE_ROW == sqlite3_step(stmt_stats)){
-                // Stat name and value
-                sprintf(
-                  tmp,
-                  stat_names_printable[sqlite3_column_int(stmt_stats, 1)],
-                  sqlite3_column_int(stmt_stats, 2)
-                );
-                strncpy(
-                  rune_lines[
-                    top_line_to_add + 5 + sqlite3_column_int(stmt_stats, 0)
-                  ] + position_to_add,
-                  tmp,
-                  9
-                );
-                // Enchanted?
-                if (1 == sqlite3_column_int(stmt_stats, 4)){
-                    strncpy(
-                      rune_lines[top_line_to_add + 5 + sqlite3_column_int(stmt_stats, 0)] + position_to_add + 9,
-                      "*",
-                      1
-                    );
-                }
-                // Grinded?
-                if (0 < sqlite3_column_int(stmt_stats, 3)){
-                    sprintf(tmp, "+%-4d", sqlite3_column_int(stmt_stats, 3));
-                    strncpy(
-                      rune_lines[top_line_to_add + 5 + sqlite3_column_int(stmt_stats, 0)] + position_to_add + 10,
-                      tmp,
-                      5
-                    );
-                }
-            }
-            sqlite3_finalize(stmt_stats);
-        }
-        sqlite3_finalize(stmt_runes);
-        if (TRUE == unit_has_runes){
-            for (int i = 0; i < 30; i ++){
-                printf("%s",rune_lines[i]);
-            }
-        }
-    }
-    sqlite3_finalize(stmt_units);
-    if (units_found == 0){
-        printf("No units found\n");
-    }
-    return(units_found);
-}

+ 13 - 16
src/RuneOptimizer/update/update.c

@@ -17,34 +17,31 @@
 
 /**
  * @file update.c
- * Implementation of the team command.
+ *
+ * Implementation of the update command.
+ *
+ * This file implements the update command declared in {@link update.h}.
  */
 
+#include <stdio.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
 #include "update.h"
 #include "update_current_stats.c"
 #include "update_get_monster_name.c"
 #include "update_db_tables.c"
 #include "update_rune_totals.c"
-#include "update_json_rune.c"
-#include "update_json_unit.c"
 #include "update_info.c"
-#include "update_json.c"
 #include "update_efficiency.c"
+#include "update_json.c"
 
-/**
- * Parses the command parameters and calls one of the update functions.
- *
- * @param[in] argc Number of arguments passed to the update command.
- * @param[in] argv Arguments passed to the update command.
- * @return SUCCESS or an error code.
- */
-int cmd_update(int argc, char *argv[]){
+extern int update(int argc, char *argv[]){
 
     // Options
-    char six_stars = FALSE;
-    char with_runes = FALSE;
-    char clear_teams = FALSE;
-    char gui = FALSE;
+    unsigned char six_stars = FALSE;
+    unsigned char with_runes = FALSE;
+    unsigned char clear_teams = FALSE;
+    unsigned char gui = FALSE;
 
     // One argument mandatory
     if (argc == 0){

+ 589 - 83
src/RuneOptimizer/update/update.h

@@ -17,114 +17,644 @@
 
 /**
  * @file update.h
- * Declarations for elements used by the team command.
+ *
+ * Declarations of the functions and data types related to the update command.
+ *
+ * This file declares all the functions and data types used by the update
+ * command implemented in {@link update.c} and other files.
  */
 
+#pragma once
+
+#include "../RuneOptimizer.h"
+
 /**
- * Structure representing a rune stat, with the same fields as the table
- * 'rune_stats' in the database.
+ * Max substats in a rune.
+ *
+ * Defines the maximum number of substats a rune can have. Main and innates
+ * don't count.
  */
-struct Rune_Stat {
+#define MAX_SUBSTATS 4
+
+/**
+ * Structure representing a rune stat
+ *
+ * It has the same members as columns hast the table 'rune_stats' in the
+ * database.
+ */
+typedef struct Rune_Stat {
+    /**
+     * Stat ID.
+     *
+     * The type of stat the rune stat increments.
+     */
     unsigned char stat;
+
+    /**
+     * Stat value.
+     *
+     * The value the rune increments for a unit stat.
+     */
     unsigned int value;
+
+    /**
+     * The value increment by grind.
+     *
+     * If the stat has not been grinded, it will be 0.
+     */
     unsigned int grind;
+
+    /**
+     * Indicates if the stat has been enchanted (changed).
+     *
+     * If so, it will be 1. Else, 0.
+     */
     unsigned char enchant;
 } Rune_Stat;
 
 /**
- * Structure representing a unit, with the same fields as the table 'unit' in
- * the database.
+ * Structure representing a unit.
+ *
+ * It has the same members as columns have the table 'unit' in the database.
  */
 typedef struct DB_Unit {
-    unsigned char id[12];
+    /**
+     * Unit ID.
+     *
+     * The ID as given by Com2Us.
+     */
+    unsigned char id[UNIT_ID_LEN];
+
+    /**
+     * Unit generic ID.
+     *
+     * The generic ID as given by Com2Us.
+     */
     unsigned int monster;
-    unsigned char name[128];
+
+    /**
+     * The Unit name.
+     *
+     * The name as given by Com2Us, except for Homunculus. For them, the user
+     * given by the naem will be used.
+     */
+    unsigned char name[UNIT_NAME_LEN];
+
+    /**
+     * Unit stars.
+     *
+     * The unit current stars [1-6].
+     */
     unsigned char stars;
+
+    /**
+     * Unit stars.
+     *
+     * The unit current level [1-40].
+     */
     unsigned char level;
+
+    /**
+     * The unit base HP.
+     *
+     * The Unit HP, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
     unsigned int base_hp;
+
+    /**
+     * The unit base ATK.
+     *
+     * The Unit ATK, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
     unsigned short base_atk;
+
+    /**
+     * The unit base DEF.
+     *
+     * The Unit DEF, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
     unsigned short base_def;
+
+    /**
+     * The unit base SPD.
+     *
+     * The Unit SPD, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
     unsigned short base_spd;
+
+    /**
+     * The unit base CRR.
+     *
+     * The Unit CRR, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
     unsigned short base_crr;
+
+    /**
+     * The unit base CRD.
+     *
+     * The Unit CRD, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
     unsigned short base_crd;
-    unsigned short base_acc;
+
+    /**
+     * The unit base RES.
+     *
+     * The Unit RES, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
     unsigned short base_res;
+
+    /**
+     * The unit base ACC.
+     *
+     * The Unit ACC, at it's current level, without counting runes, artifacts,
+     * towers...
+     */
+    unsigned short base_acc;
+
+    /**
+     * The unit base EHP.
+     *
+     * The Unit EHP, at it's current level, without counting runes, artifacts,
+     * towers... See {@link calculate_ehp} for more details bout EHP.
+     */
     unsigned int base_ehp;
+
+    /**
+     * The unit base DMG.
+     *
+     * The Unit DMG, at it's current level, without counting runes, artifacts,
+     * towers...See {@link calculate_ehp} for more details bout EHP.
+     */
     unsigned short base_dmg;
+
+    /**
+     * The unit base HP.
+     *
+     * The Unit HP, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
     unsigned int current_hp;
+
+    /**
+     * The unit base ATK.
+     *
+     * The Unit ATK, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
     unsigned short current_atk;
+
+    /**
+     * The unit base DEF.
+     *
+     * The Unit DEF, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
     unsigned short current_def;
+
+    /**
+     * The unit base SPD.
+     *
+     * The Unit SPD, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
     unsigned short current_spd;
+
+    /**
+     * The unit base CRR.
+     *
+     * The Unit CRR, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
     unsigned short current_crr;
+
+    /**
+     * The unit base CRD.
+     *
+     * The Unit CRD, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
     unsigned short current_crd;
-    unsigned short current_acc;
+
+    /**
+     * The unit base RES.
+     *
+     * The Unit RES, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
     unsigned short current_res;
+
+    /**
+     * The unit base ACC.
+     *
+     * The Unit ACC, at it's current level, counting equiped runes, but not
+     * artifacts or towers.
+     */
+    unsigned short current_acc;
+
+    /**
+     * The unit base EHP.
+     *
+     * The Unit EHP, at it's current level, counting equiped runes, but not
+     * artifacts or towers.See {@link calculate_ehp} for more details bout EHP.
+     */
     unsigned int current_ehp;
+
+    /**
+     * The unit base DMG.
+     *
+     * The Unit DMG, at it's current level, counting equiped runes, but not
+     * artifacts or towers. See {@link calculate_ehp} for more details bout EHP.
+     */
     unsigned short current_dmg;
 } BD_Unit;
 
 /**
- * Structure representing a rune, with the same fields as the table 'runes' in
- * the database.
+ * Structure representing a rune.
+ *
+ * COntains the same members as columns has the table 'runes' in the database.
  */
 typedef struct DB_Rune {
-    unsigned char id[12];
+    /**
+     * Rune ID.
+     *
+     * The ID as given by Com2Us.
+     */
+    unsigned char id[RUNE_ID_LEN];
+
+    /**
+     * The slot of the rune
+     *
+     * Can be [1-6].
+     */
     unsigned char slot;
+
+    /**
+     * The rune quality.
+     *
+     * Can be [1-5].
+     */
     unsigned char quality;
+
+    /**
+     * Rune efficiency.
+     *
+     * See {@link update_efficiency} for more information on efficiency
+     * calculation.
+     */
     float efficiency;
+
+    /**
+     * Rune efficiency.
+     *
+     * See {@link update_efficiency} for more information on efficiency
+     * calculation.
+     */
     float max_efficiency;
+
+    /**
+     * The stars (grade) of the rune
+     *
+     * Can be [1-6].
+     */
     unsigned char stars;
+
+    /**
+     * Rune set id.
+     *
+     * Identifier of the set the rune belongs to.
+     */
     unsigned char set;
+
+    /**
+     * Rune level.
+     *
+     * Current level, can be [0-15].
+     */
     unsigned char level;
+
+    /**
+     * Rune value.
+     *
+     * Rune market value, in mana stones
+     */
     unsigned int buy_value;
+
+    /**
+     * Rune value.
+     *
+     * Rune second hand value, in mana stones
+     */
     unsigned int sell_value;
-    unsigned char unit[12];
+
+    /**
+     * ID of the unit the rune is assigned to.
+     *
+     * Empty if the rune is not assigned.
+     */
+    unsigned char unit[UNIT_ID_LEN];
+
+    /**
+     * HP% stat at current level.
+     *
+     * HP% given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_hp_percent;
+
+    /**
+     * ATK% stat at current level.
+     *
+     * ATK% given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_atk_percent;
+
+    /**
+     * DEF% stat at current level.
+     *
+     * DEF% given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_def_percent;
+
+    /**
+     * HP stat at current level.
+     *
+     * HP given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_hp_flat;
+
+    /**
+     * ATK stat at current level.
+     *
+     * ATK given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_atk_flat;
+
+    /**
+     * DEF stat at current level.
+     *
+     * DEF given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_def_flat;
+
+    /**
+     * SPD stat at current level.
+     *
+     * SPD given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_spd;
+
+    /**
+     * CRR stat at current level.
+     *
+     * CRR given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_crr;
+
+    /**
+     * CRD stat at current level.
+     *
+     * CRD given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_crd;
-    unsigned int current_acc;
+
+    /**
+     * RES stat at current level.
+     *
+     * RES given by the rune, in any of it's stats, at it's current level.
+     */
     unsigned int current_res;
+
+    /**
+     * ACC stat at current level.
+     *
+     * ACC given by the rune, in any of it's stats, at it's current level.
+     */
+    unsigned int current_acc;
+
+    /**
+     * HP% stat at current level.
+     *
+     * HP% given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_hp_percent;
+
+    /**
+     * ATK% stat at current level.
+     *
+     * ATK% given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_atk_percent;
+
+    /**
+     * DEF% stat at current level.
+     *
+     * DEF% given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_def_percent;
+
+    /**
+     * HP stat at current level.
+     *
+     * HP given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_hp_flat;
+
+    /**
+     * ATK stat at current level.
+     *
+     * ATK given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_atk_flat;
+
+    /**
+     * DEF stat at current level.
+     *
+     * DEF given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_def_flat;
+
+    /**
+     * SPD stat at current level.
+     *
+     * SPD given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_spd;
+
+    /**
+     * CRR stat at current level.
+     *
+     * CRR given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_crr;
+
+    /**
+     * CRD stat at current level.
+     *
+     * CRD given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_crd;
-    unsigned int lv12_acc;
+
+    /**
+     * RES stat at current level.
+     *
+     * RES given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
     unsigned int lv12_res;
+
+    /**
+     * ACC stat at current level.
+     *
+     * ACC given by the rune, in any of it's stats, at it's current level or at
+     * level 12, whichever is higher.
+     */
+    unsigned int lv12_acc;
+
+    /**
+     * HP% stat at current level.
+     *
+     * HP% given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_hp_percent;
+
+    /**
+     * ATK% stat at current level.
+     *
+     * ATK% given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_atk_percent;
+
+    /**
+     * DEF% stat at current level.
+     *
+     * DEF% given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_def_percent;
+
+    /**
+     * HP stat at current level.
+     *
+     * HP given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_hp_flat;
+
+    /**
+     * ATK stat at current level.
+     *
+     * ATK given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_atk_flat;
+
+    /**
+     * DEF stat at current level.
+     *
+     * DEF given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_def_flat;
+
+    /**
+     * SPD stat at current level.
+     *
+     * SPD given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_spd;
+
+    /**
+     * CRR stat at current level.
+     *
+     * CRR given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_crr;
+
+    /**
+     * CRD stat at current level.
+     *
+     * CRD given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_crd;
-    unsigned int lv15_acc;
+
+    /**
+     * RES stat at current level.
+     *
+     * RES given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
     unsigned int lv15_res;
+
+    /**
+     * ACC stat at current level.
+     *
+     * ACC given by the rune, in any of it's stats, at it's current level or at
+     * level 15, whichever is higher.
+     */
+    unsigned int lv15_acc;
+
+    /**
+     * Main stat.
+     *
+     * The main stat of the rune.
+     */
     struct Rune_Stat main;
+
+    /**
+     * Innate stat.
+     *
+     * NULL if the rune doesn't have an innate stat.
+     */
     struct Rune_Stat innate;
+
+    /**
+     * Rune substats.
+     *
+     * Each of the rune substats., up to 4.
+     */
+    struct Rune_Stat stats[MAX_SUBSTATS];
+
+    /**
+     * Substat counter.
+     *
+     * Indicates how many substats the rune has [0-4].
+     */
     unsigned char stat_count;
-    struct Rune_Stat stats[4];
 } DB_Rune;
 
 
 /**
  * Values for main stats.
  *
- * Nested by stat, stars, level(0->12, 1->15)
+ * Since the main stat values are fixed for each level, this is a handy
+ * reference to get values at levels 12 and 15.
+ *
+ * Nested by:
+ *  - stat ID (Wathcout for indexes 0 and 7, they are unuused in game).
+ *  - Rune stars (1-index, dont use 0).
+ *  - Level: Position 0 for level 12, position 1 for level 15.
  */
-const int main_stats_values[13][7][2] = {
+const int MAIN_STATS_VALUES[DIFFERENT_STATS][RUNE_MAX_STARS + 1][2] = {
   { //NULL (unused)
       {0, 0},
       {0, 0},
@@ -249,11 +779,10 @@ const int main_stats_values[13][7][2] = {
  * current_* columns in the database for every unit with at least one rune
  * assigned.
  *
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
+ * @return {@link SUCCESS} if the update was done correclty, or an error defined
+ * in {@link error.h} if there were errors.
  */
-int update_current_stats();
+extern int update_current_stats();
 
 /**
  * Recreates the tables in the database.
@@ -262,12 +791,12 @@ int update_current_stats();
  * tables. By default, itdoes this to all tables except 'teams' and
  * 'units_teams'.
  *
- * @param[in] clear_teams Indicator to recreate tables teams and units_teams.
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
+ * @param[in] clear_teams {@link TRUE} to also recreate the tables 'teams' and
+ * 'units_teams', effectively deleting the user defined teams.
+ * @return {@link SUCCESS} if the tables were recreated, or an error defined
+ * in {@link error.h} if there were errors.
  */
-int update_db_tables(unsigned char clear_teams);
+extern int update_db_tables(unsigned char clear_teams);
 
 /**
  * Gets a monster name from it's ID.
@@ -281,7 +810,7 @@ int update_db_tables(unsigned char clear_teams);
  * @param[in] id Monster ID.
  * @param[out] name Monster name.
  */
-void update_get_monster_name(int id, char name[64]);
+extern void update_get_monster_name(int id, char name[UNIT_NAME_LEN]);
 
 /**
  * Updaes the data in the table 'info'.
@@ -289,71 +818,40 @@ void update_get_monster_name(int id, char name[64]);
  * @param[in] id Player ID.
  * @param[in] name Player name.
  * @param[in] level Player level.
- * @return SUCCESS if the info is saved or ERROR_DB_INSERT_INFO on error.
+ * @return {@link SUCCESS} if the info is saved or {@link ERROR_DB_INSERT_INFO}
+ * on error.
  */
-int update_info(const char *id, const char *name, const char *level);
+extern int update_info(const char *id, const char *name, const char *level);
 
 /**
  * Updates the database from a json file.
  *
+ * The file must be JSON, extracted from the game or from Swarfarm. Other JSON
+ * files from other applications may work, but with no guarantees.
+ *
  * @param[in] file Path to the file.
  * @param[in] six_stars Indicator to import only 6* units. Units with runes will
  * be saved anyway.
  * @param[in] with_runes Indicator to import only units with runes.
  * @param[in] clear_teams Indicator to recreate tables teams and units_teams.
  * @param[in] gui Indicator to format output for thr GUI.
- * @return SUCCESS or an error code. See
- * <a href="file:../error/error.h">../error/error.h</a> for a list of error
- * codes.
+ * @return {@link SUCCESS} if the update were performed, or an error defined
+ * in {@link error.h} if there were errors.
  */
-int update_json(
+extern int update_json(
   char file[], unsigned char six_stars,
   unsigned char with_runes, unsigned char clear_teams, unsigned char gui
 );
 
-/**
- * Saves a single rune to the database obtaining data from its json object.
- * 
- * Saves data to the tables 'runes' and 'rune_stats'. In case of error, a
- * description will be printed to stderr.
- * 
- * @param[in] rune_json Rune json fragment.
- * @param[in] unit_id ID of the unit the rune is assigned to. To leave it
- * unassigned, pass an empty string, not NULL.
- * @return The number of stats saved to the database, including the main stat,
- * innate stat (if any), and all the normal stats. -1 incase of error.
- */
-int update_json_rune(json_object *rune_json, char *unit_id);
-
-/**
- * Saves a single unit to the database obtaining data from its json object.
- * 
- * Saves data to the tables 'units'. If the unit has any rune assigned, it will
- * also be saved to 'runes'. In case of error, a description will be printed to
- * stderr.
- * 
- * @param[in] unit_json Unit json fragment.
- * @param[in] six_stars Indicator to import only 6* units. Units with runes will
- * be saved anyway.
- * @param[in] with_runes Indicator to import only units with runes.
- * @param[out] total_runes Cunter for runes. Will be increased for each saved
- * rune.
- * @param[out] total_stats Cunter for rune stats. Will be increased for each
- * stat on each saved rune.
- * @return 1 if the unit was saved to the database. 0 If everything was OK but
- * the unit was not saved because it did not match the criteria. -1 on error.
- */
-int update_json_unit(
-  json_object *unit_json, unsigned char six_stars,
-  unsigned char with_runes, unsigned int *total_runes, unsigned int *total_stats
-);
-
 /**
  * Calculates the total stat values for a rune.
  *
- * @param[in|out] rune Rune to do the calculation on.
+ * For each rune, calculates it's efficiency, max efficiency, and if necesary,
+ * the stats at level 12 and 15.
+ *
+ * @param[in,out] rune Rune to do the calculation on.
  */
-void update_rune_totals(struct DB_Rune *rune);
+extern void update_rune_totals(struct DB_Rune *rune);
 
 /**
  * Calculates the efficiencies of a rune in the database.
@@ -362,18 +860,26 @@ void update_rune_totals(struct DB_Rune *rune);
  *
  * @param[in] id Rune ID.
  * @param[out] efficiency Calculated efficiency.
- * @param[out] efficiency Calculated maximum efficiency.
- * @return SUCCESS, or ERROR_DB_SELECT_RUNE if the rune is not in the
- * database.
+ * @param[out] max_efficiency Calculated maximum efficiency.
+ * @return {@link SUCCESS} if the rune was found and the efficencies calculated,
+ * or {@link ERROR_DB_SELECT_RUNE} if the rune is not in the database.
  */
-int update_efficiency(char *id, float *efficiency, float *max_efficiency);
+extern int update_efficiency(char *id, float *efficiency, float *max_efficiency);
 
 /**
  * Parses the command parameters and calls one of the update functions.
  *
- * @param[in] argc Number of arguments passed to the update command.
- * @param[in] argv Arguments passed to the update command.
- * @return SUCCESS or an error code.
+ * @param[in] argc Number of argument passed to the update command. As a
+ * rule, it must me two less than the argc received by the {@link main}
+ * function of the program.
+ * @param[in] argv Arguments passed to the updater. As a rule, they must be
+ * the same than the argv received by the {@link main} function of the program
+ * without the first two. The first one must be the information source. Other
+ * arguments can be -s or --six-stars to exclude units without runes in a level
+ * lower than 40, -r or --without-runes to import only units with runes, or
+ * -g or --gui to print an output formatted for the GUI.
+ * @return {@link SUCCESS} if the update was succesfully performed, or an error
+ * defined in {@link error.h} if there were errors.
  */
-int cmd_update(int argc, char *argv[]);
+extern int update(int argc, char *argv[]);
 

+ 14 - 4
src/RuneOptimizer/update/update_current_stats.c

@@ -17,11 +17,22 @@
 
 /**
  * @file update_current_stats.c
- * Implementation of update_current_stats.
+ *
+ * Implementation of {@link update_current_stats}.
+ *
+ * This file implements the funciton {@link update_current_stats} declared in
+ * {@link update.h}.
  */
 
-int update_current_stats(){
-    printf("START\n");
+#include <stdio.h>
+#include <string.h>
+#include <sqlite3.h>
+#include "../RuneOptimizer.h"
+#include "../error/error.h"
+#include "../db/db.h"
+#include "update.h"
+
+extern int update_current_stats(){
     sqlite3_stmt *stmt_unit;
     db_query(
       &stmt_unit,
@@ -184,6 +195,5 @@ int update_current_stats(){
         }
     }
     sqlite3_finalize(stmt_unit);
-    printf("END\n");
     return SUCCESS;
 }

+ 11 - 2
src/RuneOptimizer/update/update_db_tables.c

@@ -17,10 +17,19 @@
 
 /**
  * @file update_db_tables.c
- * Implementation of update_db_tables.
+ *
+ * Implementation of {@link update_db_tables}.
+ *
+ * This file implements the funciton {@link update_db_tables} declared in
+ * {@link update.h}.
  */
 
-int update_db_tables(unsigned char clear_teams){
+#include <stdio.h>
+#include <sqlite3.h>
+#include "../error/error.h"
+#include "../db/db.h"
+
+extern int update_db_tables(unsigned char clear_teams){
 
     // Drop all tables
     char table_names[6][11] = {

+ 16 - 2
src/RuneOptimizer/update/update_efficiency.c

@@ -15,7 +15,21 @@
  * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
  */
 
-int update_efficiency(char *id, float *efficiency, float *max_efficiency){
+/**
+ * @file update_efficiency.c
+ *
+ * Implementation of {@link update_efficiency}.
+ *
+ * This file implements the funciton {@link update_efficiency} declared in
+ * {@link update.h}.
+ */
+
+#include <stdio.h>
+#include <sqlite3.h>
+#include "../error/error.h"
+#include "../db/db.h"
+
+extern int update_efficiency(char *id, float *efficiency, float *max_efficiency){
     *efficiency = 0.0f;
     *max_efficiency = 0.0f;
     float eff[5] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
@@ -48,7 +62,7 @@ int update_efficiency(char *id, float *efficiency, float *max_efficiency){
         slot = sqlite3_column_int(stmt_stats, 0);
         stat = sqlite3_column_int(stmt_stats, 1);
         value = sqlite3_column_int(stmt_stats, 2);
-        max_roll_value = stat_roll_max[stat][stars];
+        max_roll_value = STAT_ROLL_MAX[stat][stars];
         eff[slot] += (((float) value) / ((float) max_roll_value));
     }
     sqlite3_finalize(stmt_stats);

+ 8 - 2
src/RuneOptimizer/update/update_get_monster_name.c

@@ -17,10 +17,16 @@
 
 /**
  * @file update_get_monster_name.c
- * Implementation of update_get_monster_name.
+ *
+ * Implementation of {@link update_get_monster_name}.
+ *
+ * This file implements the funciton {@link update_get_monster_name} declared in
+ * {@link update.h}.
  */
 
-void update_get_monster_name(int id, char name[64]){
+#include <string.h>
+
+extern void update_get_monster_name(int id, char name[UNIT_NAME_LEN]){
     
     /*
      * This list is generated from a SWDB database, with the query:

+ 12 - 2
src/RuneOptimizer/update/update_info.c

@@ -17,10 +17,20 @@
 
 /**
  * @file update_info.c
- * Implementation of update_info.
+ *
+ * Implementation of {@link update_info}.
+ *
+ * This file implements the funciton {@link update_info} declared in
+ * {@link update.h}.
  */
 
-int update_info(const char *id, const char *name, const char *level){
+#include <stdio.h>
+#include <sqlite3.h>
+#include <time.h>
+#include "../error/error.h"
+#include "../db/db.h"
+
+extern int update_info(const char *id, const char *name, const char *level){
     time_t t = time(NULL);
     struct tm tm = *localtime(&t);
     char ts[130];

+ 415 - 2
src/RuneOptimizer/update/update_json.c

@@ -17,10 +17,58 @@
 
 /**
  * @file update_json.c
- * Implementation of update_json.
+ *
+ * Implementation of {@link update_json}.
+ *
+ * This file implements the funciton {@link update_json} declared in
+ * {@link update.h}. It also defines and implements some static functions used
+ * by it.
  */
 
-int update_json(
+#include <stdio.h>
+#include <sqlite3.h>
+#include <json-c/json.h>
+#include "../error/error.h"
+#include "../db/db.h"
+
+/**
+ * Saves a single rune to the database obtaining data from its json object.
+ *
+ * Saves data to the tables 'runes' and 'rune_stats'. In case of error, a
+ * description will be printed to stderr.
+ *
+ * @param[in] rune_json Rune json fragment.
+ * @param[in] unit_id ID of the unit the rune is assigned to. To leave it
+ * unassigned, pass an empty string, not NULL.
+ * @return The number of stats saved to the database, including the main stat,
+ * innate stat (if any), and all the normal stats. -1 in case of error.
+ */
+static int update_json_rune(json_object *rune_json, char *unit_id);
+
+/**
+ * Saves a single unit to the database obtaining data from its json object.
+ *
+ * Saves data to the tables 'units'. If the unit has any rune assigned, it will
+ * also be saved to 'runes'. In case of error, a description will be printed to
+ * stderr.
+ *
+ * @param[in] unit_json Unit json fragment.
+ * @param[in] six_stars Indicator to import only 6* units. Units with runes will
+ * be saved anyway.
+ * @param[in] with_runes Indicator to import only units with runes.
+ * @param[out] total_runes Cunter for runes. Will be increased for each saved
+ * rune.
+ * @param[out] total_stats Cunter for rune stats. Will be increased for each
+ * stat on each saved rune.
+ * @return 1 if the unit was saved to the database. 0 If everything was OK but
+ * the unit was not saved because it did not match the criteria. -1 on error.
+ */
+static int update_json_unit(
+  json_object *unit_json, unsigned char six_stars,
+  unsigned char with_runes, unsigned int *total_runes, unsigned int *total_stats
+);
+
+extern int update_json(
   char file[], unsigned char six_stars,
   unsigned char with_runes, unsigned char clear_teams, unsigned char gui
 ){
@@ -95,3 +143,368 @@ int update_json(
 
     return(SUCCESS);
 }
+
+static int update_json_rune(json_object *rune_json, char *unit_id){
+    int total_stats = 0;
+    DB_Rune rune;
+    char *query_parameters[43];
+    for (int i = 1; i < 43; i ++) query_parameters[i] = malloc(5);
+    // Rune ID
+    json_object *rune_id = json_object_object_get(rune_json, "rune_id");
+    strcpy(rune.id, json_object_get_string(rune_id));
+    // Rune unit
+    strcpy(rune.unit, unit_id);
+    // Rune slot
+    json_object *slot_no = json_object_object_get(rune_json, "slot_no");
+    rune.slot = json_object_get_int(slot_no);
+    // Rune quality (extra)
+    json_object *extra = json_object_object_get(rune_json, "extra");
+    rune.quality = json_object_get_int(extra);
+    // Rune stars (class)
+    json_object *class = json_object_object_get(rune_json, "class");
+    rune.stars = json_object_get_int(class);
+    // Ancient runes have stars + 10.
+    if (rune.stars > 10) rune.stars -= 10;
+    // Rune set
+    json_object *set_id = json_object_object_get(rune_json, "set_id");
+    rune.set = json_object_get_int(set_id);
+    // Rune level (upgrade_curr)
+    json_object *upgrade_curr =
+      json_object_object_get(rune_json, "upgrade_curr");
+    rune.level = json_object_get_int(upgrade_curr);
+    // Rune value
+    json_object *base_value = json_object_object_get(rune_json, "base_value");
+    rune.buy_value = json_object_get_int(base_value);
+    // Rune sell value
+    json_object *sell_value = json_object_object_get(rune_json, "sell_value");
+    rune.sell_value = json_object_get_int(sell_value);
+    // Main stat
+    json_object *pri_eff = json_object_object_get(rune_json, "pri_eff");
+    json_object *pri_stat = json_object_array_get_idx(pri_eff, 0);
+    rune.main.stat = json_object_get_int(pri_stat);
+    json_object *pri_value = json_object_array_get_idx(pri_eff, 1);
+    rune.main.value = json_object_get_int(pri_value);
+    // Innate stat
+    json_object *prefix_eff = json_object_object_get(rune_json, "prefix_eff");
+    json_object *prefix_stat = json_object_array_get_idx(prefix_eff, 0);
+    rune.innate.stat = json_object_get_int(prefix_stat);
+    json_object *prefix_value = json_object_array_get_idx(prefix_eff, 1);
+    rune.innate.value = json_object_get_int(prefix_value);
+    json_object *sec_eff = json_object_object_get(rune_json, "sec_eff");
+    // Loop stats
+    int stat_count = json_object_array_length(sec_eff);
+    json_object *stat_json;
+    rune.stat_count = 0;
+    for (int i = 0; i < stat_count && i < 4; i++){
+        rune.stat_count ++;
+        stat_json = json_object_array_get_idx(sec_eff, i);
+        json_object *stat = json_object_array_get_idx(stat_json, 0);
+        rune.stats[i].stat = json_object_get_int(stat);
+        json_object *value = json_object_array_get_idx(stat_json, 1);
+        rune.stats[i].value = json_object_get_int(value);
+        json_object *enchant = json_object_array_get_idx(stat_json, 2);
+        rune.stats[i].enchant = json_object_get_int(enchant);
+        json_object *grind = json_object_array_get_idx(stat_json, 3);
+        rune.stats[i].grind = json_object_get_int(grind);
+    }
+
+    // All the rune info has been loaded. Now, calculate the rest of stats
+    update_rune_totals(&rune);
+
+    // Insert the rune into the database
+    query_parameters[0] = rune.id;
+    query_parameters[1] = unit_id;
+    sprintf(query_parameters[2], "%d", rune.set);
+    sprintf(query_parameters[3], "%d", rune.slot);
+    sprintf(query_parameters[4], "%d", rune.stars);
+    sprintf(query_parameters[5], "%d", rune.level);
+    sprintf(query_parameters[6], "%d", rune.quality);
+    sprintf(query_parameters[7], "%d", rune.efficiency);
+    sprintf(query_parameters[8], "%d", rune.max_efficiency);
+    sprintf(query_parameters[9], "%d", rune.main.stat);
+    sprintf(query_parameters[10], "%d", rune.current_hp_percent);
+    sprintf(query_parameters[11], "%d", rune.current_atk_percent);
+    sprintf(query_parameters[12], "%d", rune.current_def_percent);
+    sprintf(query_parameters[13], "%d", rune.current_hp_flat);
+    sprintf(query_parameters[14], "%d", rune.current_atk_flat);
+    sprintf(query_parameters[15], "%d", rune.current_def_flat);
+    sprintf(query_parameters[16], "%d", rune.current_spd);
+    sprintf(query_parameters[17], "%d", rune.current_crr);
+    sprintf(query_parameters[18], "%d", rune.current_crd);
+    sprintf(query_parameters[19], "%d", rune.current_acc);
+    sprintf(query_parameters[20], "%d", rune.current_res);
+    sprintf(query_parameters[21], "%d", rune.lv12_hp_percent);
+    sprintf(query_parameters[22], "%d", rune.lv12_atk_percent);
+    sprintf(query_parameters[23], "%d", rune.lv12_def_percent);
+    sprintf(query_parameters[24], "%d", rune.lv12_hp_flat);
+    sprintf(query_parameters[25], "%d", rune.lv12_atk_flat);
+    sprintf(query_parameters[26], "%d", rune.lv12_def_flat);
+    sprintf(query_parameters[27], "%d", rune.lv12_spd);
+    sprintf(query_parameters[28], "%d", rune.lv12_crr);
+    sprintf(query_parameters[29], "%d", rune.lv12_crd);
+    sprintf(query_parameters[30], "%d", rune.lv12_acc);
+    sprintf(query_parameters[31], "%d", rune.lv12_res);
+    sprintf(query_parameters[32], "%d", rune.lv15_hp_percent);
+    sprintf(query_parameters[33], "%d", rune.lv15_atk_percent);
+    sprintf(query_parameters[34], "%d", rune.lv15_def_percent);
+    sprintf(query_parameters[35], "%d", rune.lv15_hp_flat);
+    sprintf(query_parameters[36], "%d", rune.lv15_atk_flat);
+    sprintf(query_parameters[37], "%d", rune.lv15_def_flat);
+    sprintf(query_parameters[38], "%d", rune.lv15_spd);
+    sprintf(query_parameters[39], "%d", rune.lv15_crr);
+    sprintf(query_parameters[40], "%d", rune.lv15_crd);
+    sprintf(query_parameters[41], "%d", rune.lv15_acc);
+    sprintf(query_parameters[42], "%d", rune.lv15_res);
+    if (
+      SUCCESS !=
+      db_execute(
+        "INSERT INTO runes ("
+        "  id,                  unit,               type,"
+        "  slot,                stars,              level,"
+        "  quality,             efficiency,         max_efficiency,"
+        "  main_stat,           current_hp_percent, current_atk_percent,"
+        "  current_def_percent, current_hp_flat,    current_atk_flat,"
+        "  current_def_flat,    current_spd,        current_crr,"
+        "  current_crd,         current_acc,        current_res,"
+        "  lv12_hp_percent,     lv12_atk_percent,   lv12_def_percent,"
+        "  lv12_hp_flat,        lv12_atk_flat,      lv12_def_flat,"
+        "  lv12_spd,            lv12_crr,           lv12_crd,"
+        "  lv12_acc,            lv12_res,           lv15_hp_percent,"
+        "  lv15_atk_percent,    lv15_def_percent,   lv15_hp_flat,"
+        "  lv15_atk_flat,       lv15_def_flat,      lv15_spd,"
+        "  lv15_crr,            lv15_crd,           lv15_acc,"
+        "  lv15_res"
+        ") VALUES ("
+        "  ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,"
+        "  ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
+        ")",
+        query_parameters
+      )
+    ){
+        fprintf(stderr, "Unable to insert rune: %s\n", sqlite3_errmsg(db));
+        return(-1);
+    }
+
+    // Insert main stat
+    total_stats ++;
+    //query_parameters[0] = rune.id; // No need, already has id
+    query_parameters[1] = "-1"; // Main stat
+    sprintf(query_parameters[2], "%d", rune.main.stat);
+    sprintf(query_parameters[3], "%d", rune.main.value);
+    query_parameters[4] = "0"; // Mains can't be grinded.
+    query_parameters[5] = "0"; // Mains can't be enchanted.
+    if (
+      SUCCESS !=
+      db_execute(
+        "INSERT INTO rune_stats(rune, slot, stat, value, grind, enchant) "
+        "VALUES (?, ?, ?, ?, ?, ?)",
+      query_parameters
+      )
+    ){
+        fprintf(
+          stderr, "Unable to insert rune main stat: %s\n", sqlite3_errmsg(db)
+        );
+        return(-1);
+    }
+
+    // Insert innate stat
+    if (rune.innate.stat != 0){
+        total_stats ++;
+        //query_parameters[0] = rune.id; // No need, already has id
+        query_parameters[1] = "0"; // Main stat
+        sprintf(query_parameters[2], "%d", rune.innate.stat);
+        sprintf(query_parameters[3], "%d", rune.innate.value);
+        query_parameters[4] = "0"; // Innates can't be grinded.
+        query_parameters[5] = "0"; // Innates can't be enchanted.
+        if (
+          SUCCESS !=
+          db_execute(
+            "INSERT INTO rune_stats "
+            "(rune, slot, stat, value, grind, enchant) "
+            "VALUES (?, ?, ?, ?, ?, ?)",
+          query_parameters
+          )
+        ){
+            fprintf(
+              stderr,
+              "Unable to insert rune innate stat: %s\n", sqlite3_errmsg(db)
+            );
+            return(-1);
+        }
+    }
+
+    // Insert normal stats
+    for (int s = 0; s < rune.stat_count; s ++){
+        total_stats ++;
+        //query_parameters[0] = rune.id; // No need, already has id
+        query_parameters[1] = malloc(5);
+        sprintf(query_parameters[1], "%d", s + 1); // 1-4
+        query_parameters[2] = malloc(5);
+        sprintf(query_parameters[2], "%d", rune.stats[s].stat);
+        sprintf(query_parameters[3], "%d", rune.stats[s].value);
+        query_parameters[4] = malloc(5);
+        sprintf(query_parameters[4], "%d", rune.stats[s].grind);
+        query_parameters[5] = malloc(5);
+        sprintf(query_parameters[5], "%d", rune.stats[s].enchant);
+        if (
+          SUCCESS !=
+          db_execute(
+            "INSERT INTO rune_stats"
+            "(rune, slot, stat, value, grind, enchant) "
+            "VALUES (?, ?, ?, ?, ?, ?)",
+          query_parameters
+          )
+        ){
+            fprintf(
+              stderr, "Unable to insert rune stat: %s\n", sqlite3_errmsg(db)
+            );
+            return(-1);
+        }
+
+    }
+
+    // Now that everything is in the database, I can calculate efficiencies
+    float efficiency = 0.0f;
+    float max_efficiency = 0.0f;
+    update_efficiency(query_parameters[0], &efficiency, &max_efficiency);
+    strcpy(query_parameters[2], query_parameters[0]); //ID
+    sprintf(query_parameters[0], "%6.2f", efficiency);
+    sprintf(query_parameters[1], "%6.2f", max_efficiency);
+    if (
+      SUCCESS !=
+      db_execute(
+        "UPDATE runes SET efficiency = ?, max_efficiency = ? WHERE id = ?",
+        query_parameters
+      )
+    ){
+        fprintf(
+          stderr, "Unable to update rune efficiency: %s\n", sqlite3_errmsg(db)
+        );
+        return(-1);
+    }
+
+    return(total_stats);
+}
+
+static int update_json_unit(
+  json_object *unit_json, unsigned char six_stars,
+  unsigned char with_runes, unsigned int *total_runes, unsigned int *total_stats
+){
+    int ret_val = 0;
+    unsigned char unit_has_runes = FALSE;
+    struct DB_Unit unit;
+    char *query_parameters[23];
+    for (int i = 1; i < 23; i ++) query_parameters[i] = malloc(5);
+    // Unit ID
+    json_object *unit_id = json_object_object_get(unit_json, "unit_id");
+    strcpy(unit.id, json_object_get_string(unit_id));
+    // Unit monster ID
+    json_object *unit_master_id =
+      json_object_object_get(unit_json, "unit_master_id");
+    unit.monster= json_object_get_int(unit_master_id);
+    // Unit name
+    update_get_monster_name(unit.monster, unit.name);
+    json_object *unit_level = json_object_object_get(unit_json, "unit_level");
+    unit.level = json_object_get_int(unit_level);
+    // Unit stars (class)
+    json_object *class = json_object_object_get(unit_json, "class");
+    unit.stars = json_object_get_int(class);
+    // Unit base HP (con * 15)
+    json_object *con = json_object_object_get(unit_json, "con");
+    unit.base_hp = json_object_get_int(con) * 15;
+    // Unit base ATK
+    json_object *atk = json_object_object_get(unit_json, "atk");
+    unit.base_atk = json_object_get_int(atk);
+    // Unit base DEF
+    json_object *def = json_object_object_get(unit_json, "def");
+    unit.base_def = json_object_get_int(def);
+    // Unit base SPD
+    json_object *spd = json_object_object_get(unit_json, "spd");
+    unit.base_spd = json_object_get_int(spd);
+    // Unit base RES
+    json_object *resist = json_object_object_get(unit_json, "resist");
+    unit.base_res = json_object_get_int(resist);
+    // Unit base ACC
+    json_object *accuracy = json_object_object_get(unit_json, "accuracy");
+    unit.base_acc = json_object_get_int(accuracy);
+    // Unit base CRR
+    json_object *critical_rate =
+      json_object_object_get(unit_json, "critical_rate");
+    unit.base_crr = json_object_get_int(critical_rate);
+    // Unit base CRD
+    json_object *critical_damage =
+      json_object_object_get(unit_json, "critical_damage");
+    unit.base_crd = json_object_get_int(critical_damage);
+    // Homunculus name (if is Homunculus)
+    json_object *homunculus_name =
+      json_object_object_get(unit_json, "homunculus_name");
+    if (strlen(json_object_get_string(homunculus_name)) > 0){
+        strcpy(unit.name, json_object_get_string(homunculus_name));
+    }
+
+    // Parse unit runes
+    json_object *unit_runes = json_object_object_get(unit_json, "runes");
+    int rune_count = json_object_array_length(unit_runes);
+    json_object *idx;
+    for (int i = 0; i < rune_count; i++){
+        unit_has_runes = TRUE;
+        *total_runes ++;
+        idx = json_object_array_get_idx(unit_runes, i);
+        int status = update_json_rune(idx, unit.id);
+        if (status != -1) *total_stats += status;
+    }
+
+    // Insert unit, depending on flags and status
+    if (
+        unit_has_runes == TRUE ||
+        (six_stars == FALSE && with_runes == FALSE) ||
+        (six_stars == TRUE && unit.stars == TRUE)
+    ){
+        ret_val = 1;
+        query_parameters[0] = unit.id;
+        query_parameters[1] = unit.name;
+        sprintf(query_parameters[2], "%d", unit.stars);
+        sprintf(query_parameters[3], "%d", unit.level);
+        sprintf(query_parameters[4], "%d", unit.base_hp);
+        sprintf(query_parameters[5], "%d", unit.base_atk);
+        sprintf(query_parameters[6], "%d", unit.base_def);
+        sprintf(query_parameters[7], "%d", unit.base_spd);
+        sprintf(query_parameters[8], "%d", unit.base_crr);
+        sprintf(query_parameters[9], "%d", unit.base_crd);
+        sprintf(query_parameters[10], "%d", unit.base_res);
+        sprintf(query_parameters[11], "%d", unit.base_acc);
+        // Insert current stats as base stats.
+        // They will be updated later.
+        sprintf(query_parameters[12], "%d", unit.base_hp);
+        sprintf(query_parameters[13], "%d", unit.base_atk);
+        sprintf(query_parameters[14], "%d", unit.base_def);
+        sprintf(query_parameters[15], "%d", unit.base_spd);
+        sprintf(query_parameters[16], "%d", unit.base_crr);
+        sprintf(query_parameters[17], "%d", unit.base_crd);
+        sprintf(query_parameters[18], "%d", unit.base_res);
+        sprintf(query_parameters[19], "%d", unit.base_acc);
+        // TODO: Get storage status. But how??
+        sprintf(query_parameters[20], "%d", 0);
+        sprintf(query_parameters[21], "%d", unit.monster);
+        if (
+          SUCCESS !=
+          db_execute(
+            "INSERT INTO units ("
+            "  id,          name,        stars,       level,"
+            "  base_hp,     base_atk,    base_def,    base_spd,"
+            "  base_crr,    base_crd,    base_res,    base_acc,"
+            "  current_hp,  current_atk, current_def, current_spd,"
+            "  current_crr, current_crd, current_res, current_acc,"
+            "  storage, monster"
+            ") VALUES ("
+            "  ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
+            ")",
+          query_parameters
+          )
+        ){
+            fprintf(stderr, "Unable to insert unit: %s\n", sqlite3_errmsg(db));
+            return(-1);
+        }
+    }
+    return(ret_val);
+}

+ 0 - 263
src/RuneOptimizer/update/update_json_rune.c

@@ -1,263 +0,0 @@
-/*
- * This file is part of RuneOptimizer.
- *
- * RuneOptimizer is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @file update_json_rune.c
- * Implementation of update_json_rune.
- */
-
-int update_json_rune(json_object *rune_json, char *unit_id){
-    int total_stats = 0;
-    DB_Rune rune;
-    char *query_parameters[43];
-    for (int i = 1; i < 43; i ++) query_parameters[i] = malloc(5);
-    // Rune ID
-    json_object *rune_id = json_object_object_get(rune_json, "rune_id");
-    strcpy(rune.id, json_object_get_string(rune_id));
-    // Rune unit
-    strcpy(rune.unit, unit_id);
-    // Rune slot
-    json_object *slot_no = json_object_object_get(rune_json, "slot_no");
-    rune.slot = json_object_get_int(slot_no);
-    // Rune quality (extra)
-    json_object *extra = json_object_object_get(rune_json, "extra");
-    rune.quality = json_object_get_int(extra);
-    // Rune stars (class)
-    json_object *class = json_object_object_get(rune_json, "class");
-    rune.stars = json_object_get_int(class);
-    // Ancient runes have stars + 10.
-    if (rune.stars > 10) rune.stars -= 10;
-    // Rune set
-    json_object *set_id = json_object_object_get(rune_json, "set_id");
-    rune.set = json_object_get_int(set_id);
-    // Rune level (upgrade_curr)
-    json_object *upgrade_curr =
-      json_object_object_get(rune_json, "upgrade_curr");
-    rune.level = json_object_get_int(upgrade_curr);
-    // Rune value
-    json_object *base_value = json_object_object_get(rune_json, "base_value");
-    rune.buy_value = json_object_get_int(base_value);
-    // Rune sell value
-    json_object *sell_value = json_object_object_get(rune_json, "sell_value");
-    rune.sell_value = json_object_get_int(sell_value);
-    // Main stat
-    json_object *pri_eff = json_object_object_get(rune_json, "pri_eff");
-    json_object *pri_stat = json_object_array_get_idx(pri_eff, 0);
-    rune.main.stat = json_object_get_int(pri_stat);
-    json_object *pri_value = json_object_array_get_idx(pri_eff, 1);
-    rune.main.value = json_object_get_int(pri_value);
-    // Innate stat
-    json_object *prefix_eff = json_object_object_get(rune_json, "prefix_eff");
-    json_object *prefix_stat = json_object_array_get_idx(prefix_eff, 0);
-    rune.innate.stat = json_object_get_int(prefix_stat);
-    json_object *prefix_value = json_object_array_get_idx(prefix_eff, 1);
-    rune.innate.value = json_object_get_int(prefix_value);
-    json_object *sec_eff = json_object_object_get(rune_json, "sec_eff");
-    // Loop stats
-    int stat_count = json_object_array_length(sec_eff);
-    json_object *stat_json;
-    rune.stat_count = 0;
-    for (int i = 0; i < stat_count && i < 4; i++){
-        rune.stat_count ++;
-        stat_json = json_object_array_get_idx(sec_eff, i);
-        json_object *stat = json_object_array_get_idx(stat_json, 0);
-        rune.stats[i].stat = json_object_get_int(stat);
-        json_object *value = json_object_array_get_idx(stat_json, 1);
-        rune.stats[i].value = json_object_get_int(value);
-        json_object *enchant = json_object_array_get_idx(stat_json, 2);
-        rune.stats[i].enchant = json_object_get_int(enchant);
-        json_object *grind = json_object_array_get_idx(stat_json, 3);
-        rune.stats[i].grind = json_object_get_int(grind);
-    }
-
-    // All the rune info has been loaded. Now, calculate the rest of stats
-    update_rune_totals(&rune);
-
-    // Insert the rune into the database
-    query_parameters[0] = rune.id;
-    query_parameters[1] = unit_id;
-    sprintf(query_parameters[2], "%d", rune.set);
-    sprintf(query_parameters[3], "%d", rune.slot);
-    sprintf(query_parameters[4], "%d", rune.stars);
-    sprintf(query_parameters[5], "%d", rune.level);
-    sprintf(query_parameters[6], "%d", rune.quality);
-    sprintf(query_parameters[7], "%d", rune.efficiency);
-    sprintf(query_parameters[8], "%d", rune.max_efficiency);
-    sprintf(query_parameters[9], "%d", rune.main.stat);
-    sprintf(query_parameters[10], "%d", rune.current_hp_percent);
-    sprintf(query_parameters[11], "%d", rune.current_atk_percent);
-    sprintf(query_parameters[12], "%d", rune.current_def_percent);
-    sprintf(query_parameters[13], "%d", rune.current_hp_flat);
-    sprintf(query_parameters[14], "%d", rune.current_atk_flat);
-    sprintf(query_parameters[15], "%d", rune.current_def_flat);
-    sprintf(query_parameters[16], "%d", rune.current_spd);
-    sprintf(query_parameters[17], "%d", rune.current_crr);
-    sprintf(query_parameters[18], "%d", rune.current_crd);
-    sprintf(query_parameters[19], "%d", rune.current_acc);
-    sprintf(query_parameters[20], "%d", rune.current_res);
-    sprintf(query_parameters[21], "%d", rune.lv12_hp_percent);
-    sprintf(query_parameters[22], "%d", rune.lv12_atk_percent);
-    sprintf(query_parameters[23], "%d", rune.lv12_def_percent);
-    sprintf(query_parameters[24], "%d", rune.lv12_hp_flat);
-    sprintf(query_parameters[25], "%d", rune.lv12_atk_flat);
-    sprintf(query_parameters[26], "%d", rune.lv12_def_flat);
-    sprintf(query_parameters[27], "%d", rune.lv12_spd);
-    sprintf(query_parameters[28], "%d", rune.lv12_crr);
-    sprintf(query_parameters[29], "%d", rune.lv12_crd);
-    sprintf(query_parameters[30], "%d", rune.lv12_acc);
-    sprintf(query_parameters[31], "%d", rune.lv12_res);
-    sprintf(query_parameters[32], "%d", rune.lv15_hp_percent);
-    sprintf(query_parameters[33], "%d", rune.lv15_atk_percent);
-    sprintf(query_parameters[34], "%d", rune.lv15_def_percent);
-    sprintf(query_parameters[35], "%d", rune.lv15_hp_flat);
-    sprintf(query_parameters[36], "%d", rune.lv15_atk_flat);
-    sprintf(query_parameters[37], "%d", rune.lv15_def_flat);
-    sprintf(query_parameters[38], "%d", rune.lv15_spd);
-    sprintf(query_parameters[39], "%d", rune.lv15_crr);
-    sprintf(query_parameters[40], "%d", rune.lv15_crd);
-    sprintf(query_parameters[41], "%d", rune.lv15_acc);
-    sprintf(query_parameters[42], "%d", rune.lv15_res);
-    if (
-      SUCCESS !=
-      db_execute(
-        "INSERT INTO runes ("
-        "  id,                  unit,               type,"
-        "  slot,                stars,              level,"
-        "  quality,             efficiency,         max_efficiency,"
-        "  main_stat,           current_hp_percent, current_atk_percent,"
-        "  current_def_percent, current_hp_flat,    current_atk_flat,"
-        "  current_def_flat,    current_spd,        current_crr,"
-        "  current_crd,         current_acc,        current_res,"
-        "  lv12_hp_percent,     lv12_atk_percent,   lv12_def_percent,"
-        "  lv12_hp_flat,        lv12_atk_flat,      lv12_def_flat,"
-        "  lv12_spd,            lv12_crr,           lv12_crd,"
-        "  lv12_acc,            lv12_res,           lv15_hp_percent,"
-        "  lv15_atk_percent,    lv15_def_percent,   lv15_hp_flat,"
-        "  lv15_atk_flat,       lv15_def_flat,      lv15_spd,"
-        "  lv15_crr,            lv15_crd,           lv15_acc,"
-        "  lv15_res"
-        ") VALUES ("
-        "  ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,"
-        "  ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
-        ")",
-        query_parameters
-      )
-    ){
-        fprintf(stderr, "Unable to insert rune: %s\n", sqlite3_errmsg(db));
-        return(-1);
-    }
-
-    // Insert main stat
-    total_stats ++;
-    //query_parameters[0] = rune.id; // No need, already has id
-    query_parameters[1] = "-1"; // Main stat
-    sprintf(query_parameters[2], "%d", rune.main.stat);
-    sprintf(query_parameters[3], "%d", rune.main.value);
-    query_parameters[4] = "0"; // Mains can't be grinded.
-    query_parameters[5] = "0"; // Mains can't be enchanted.
-    if (
-      SUCCESS !=
-      db_execute(
-        "INSERT INTO rune_stats(rune, slot, stat, value, grind, enchant) "
-        "VALUES (?, ?, ?, ?, ?, ?)",
-      query_parameters
-      )
-    ){
-        fprintf(
-          stderr, "Unable to insert rune main stat: %s\n", sqlite3_errmsg(db)
-        );
-        return(-1);
-    }
-
-    // Insert innate stat
-    if (rune.innate.stat != 0){
-        total_stats ++;
-        //query_parameters[0] = rune.id; // No need, already has id
-        query_parameters[1] = "0"; // Main stat
-        sprintf(query_parameters[2], "%d", rune.innate.stat);
-        sprintf(query_parameters[3], "%d", rune.innate.value);
-        query_parameters[4] = "0"; // Innates can't be grinded.
-        query_parameters[5] = "0"; // Innates can't be enchanted.
-        if (
-          SUCCESS !=
-          db_execute(
-            "INSERT INTO rune_stats "
-            "(rune, slot, stat, value, grind, enchant) "
-            "VALUES (?, ?, ?, ?, ?, ?)",
-          query_parameters
-          )
-        ){
-            fprintf(
-              stderr,
-              "Unable to insert rune innate stat: %s\n", sqlite3_errmsg(db)
-            );
-            return(-1);
-        }
-    }
-
-    // Insert normal stats
-    for (int s = 0; s < rune.stat_count; s ++){
-        total_stats ++;
-        //query_parameters[0] = rune.id; // No need, already has id
-        query_parameters[1] = malloc(5);
-        sprintf(query_parameters[1], "%d", s + 1); // 1-4
-        query_parameters[2] = malloc(5);
-        sprintf(query_parameters[2], "%d", rune.stats[s].stat);
-        sprintf(query_parameters[3], "%d", rune.stats[s].value);
-        query_parameters[4] = malloc(5);
-        sprintf(query_parameters[4], "%d", rune.stats[s].grind);
-        query_parameters[5] = malloc(5);
-        sprintf(query_parameters[5], "%d", rune.stats[s].enchant);
-        if (
-          SUCCESS !=
-          db_execute(
-            "INSERT INTO rune_stats"
-            "(rune, slot, stat, value, grind, enchant) "
-            "VALUES (?, ?, ?, ?, ?, ?)",
-          query_parameters
-          )
-        ){
-            fprintf(
-              stderr, "Unable to insert rune stat: %s\n", sqlite3_errmsg(db)
-            );
-            return(-1);
-        }
-
-    }
-
-    // Now that everything is in the database, I can calculate efficiencies
-    float efficiency = 0.0f;
-    float max_efficiency = 0.0f;
-    update_efficiency(query_parameters[0], &efficiency, &max_efficiency);
-    strcpy(query_parameters[2], query_parameters[0]); //ID
-    sprintf(query_parameters[0], "%6.2f", efficiency);
-    sprintf(query_parameters[1], "%6.2f", max_efficiency);
-    if (
-      SUCCESS !=
-      db_execute(
-        "UPDATE runes SET efficiency = ?, max_efficiency = ? WHERE id = ?",
-        query_parameters
-      )
-    ){
-        fprintf(
-          stderr, "Unable to update rune efficiency: %s\n", sqlite3_errmsg(db)
-        );
-        return(-1);
-    }
-
-    return(total_stats);
-}

+ 0 - 144
src/RuneOptimizer/update/update_json_unit.c

@@ -1,144 +0,0 @@
-/*
- * This file is part of RuneOptimizer.
- *
- * RuneOptimizer is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @file update_json_unit.c
- * Implementation of update_json_unit.
- */
-
-int update_json_unit(
-  json_object *unit_json, unsigned char six_stars,
-  unsigned char with_runes, unsigned int *total_runes, unsigned int *total_stats
-){
-    int ret_val = 0;
-    unsigned char unit_has_runes = FALSE;
-    struct DB_Unit unit;
-    char *query_parameters[23];
-    for (int i = 1; i < 23; i ++) query_parameters[i] = malloc(5);
-    // Unit ID
-    json_object *unit_id = json_object_object_get(unit_json, "unit_id");
-    strcpy(unit.id, json_object_get_string(unit_id));
-    // Unit monster ID
-    json_object *unit_master_id =
-      json_object_object_get(unit_json, "unit_master_id");
-    unit.monster= json_object_get_int(unit_master_id);
-    // Unit name
-    update_get_monster_name(unit.monster, unit.name);
-    json_object *unit_level = json_object_object_get(unit_json, "unit_level");
-    unit.level = json_object_get_int(unit_level);
-    // Unit stars (class)
-    json_object *class = json_object_object_get(unit_json, "class");
-    unit.stars = json_object_get_int(class);
-    // Unit base HP (con * 15)
-    json_object *con = json_object_object_get(unit_json, "con");
-    unit.base_hp = json_object_get_int(con) * 15;
-    // Unit base ATK
-    json_object *atk = json_object_object_get(unit_json, "atk");
-    unit.base_atk = json_object_get_int(atk);
-    // Unit base DEF
-    json_object *def = json_object_object_get(unit_json, "def");
-    unit.base_def = json_object_get_int(def);
-    // Unit base SPD
-    json_object *spd = json_object_object_get(unit_json, "spd");
-    unit.base_spd = json_object_get_int(spd);
-    // Unit base RES
-    json_object *resist = json_object_object_get(unit_json, "resist");
-    unit.base_res = json_object_get_int(resist);
-    // Unit base ACC
-    json_object *accuracy = json_object_object_get(unit_json, "accuracy");
-    unit.base_acc = json_object_get_int(accuracy);
-    // Unit base CRR
-    json_object *critical_rate =
-      json_object_object_get(unit_json, "critical_rate");
-    unit.base_crr = json_object_get_int(critical_rate);
-    // Unit base CRD
-    json_object *critical_damage =
-      json_object_object_get(unit_json, "critical_damage");
-    unit.base_crd = json_object_get_int(critical_damage);
-    // Homunculus name (if is Homunculus)
-    json_object *homunculus_name =
-      json_object_object_get(unit_json, "homunculus_name");
-    if (strlen(json_object_get_string(homunculus_name)) > 0){
-        strcpy(unit.name, json_object_get_string(homunculus_name));
-    }
-
-    // Parse unit runes
-    json_object *unit_runes = json_object_object_get(unit_json, "runes");
-    int rune_count = json_object_array_length(unit_runes);
-    json_object *idx;
-    for (int i = 0; i < rune_count; i++){
-        unit_has_runes = TRUE;
-        *total_runes ++;
-        idx = json_object_array_get_idx(unit_runes, i);
-        int status = update_json_rune(idx, unit.id);
-        if (status != -1) *total_stats += status;
-    }
-
-    // Insert unit, depending on flags and status
-    if (
-        unit_has_runes == TRUE ||
-        (six_stars == FALSE && with_runes == FALSE) ||
-        (six_stars == TRUE && unit.stars == TRUE)
-    ){
-        ret_val = 1;
-        query_parameters[0] = unit.id;
-        query_parameters[1] = unit.name;
-        sprintf(query_parameters[2], "%d", unit.stars);
-        sprintf(query_parameters[3], "%d", unit.level);
-        sprintf(query_parameters[4], "%d", unit.base_hp);
-        sprintf(query_parameters[5], "%d", unit.base_atk);
-        sprintf(query_parameters[6], "%d", unit.base_def);
-        sprintf(query_parameters[7], "%d", unit.base_spd);
-        sprintf(query_parameters[8], "%d", unit.base_crr);
-        sprintf(query_parameters[9], "%d", unit.base_crd);
-        sprintf(query_parameters[10], "%d", unit.base_res);
-        sprintf(query_parameters[11], "%d", unit.base_acc);
-        // Insert current stats as base stats.
-        // They will be updated later.
-        sprintf(query_parameters[12], "%d", unit.base_hp);
-        sprintf(query_parameters[13], "%d", unit.base_atk);
-        sprintf(query_parameters[14], "%d", unit.base_def);
-        sprintf(query_parameters[15], "%d", unit.base_spd);
-        sprintf(query_parameters[16], "%d", unit.base_crr);
-        sprintf(query_parameters[17], "%d", unit.base_crd);
-        sprintf(query_parameters[18], "%d", unit.base_res);
-        sprintf(query_parameters[19], "%d", unit.base_acc);
-        // TODO: Get storage status. But how??
-        sprintf(query_parameters[20], "%d", 0);
-        sprintf(query_parameters[21], "%d", unit.monster);
-        if (
-          SUCCESS !=
-          db_execute(
-            "INSERT INTO units ("
-            "  id,          name,        stars,       level,"
-            "  base_hp,     base_atk,    base_def,    base_spd,"
-            "  base_crr,    base_crd,    base_res,    base_acc,"
-            "  current_hp,  current_atk, current_def, current_spd,"
-            "  current_crr, current_crd, current_res, current_acc,"
-            "  storage, monster"
-            ") VALUES ("
-            "  ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
-            ")",
-          query_parameters
-          )
-        ){
-            fprintf(stderr, "Unable to insert unit: %s\n", sqlite3_errmsg(db));
-            return(-1);
-        }
-    }
-    return(ret_val);
-}

+ 34 - 24
src/RuneOptimizer/update/update_rune_totals.c

@@ -17,10 +17,20 @@
 
 /**
  * @file update_rune_totals.c
- * Implementation of update_rune_totals.
+ *
+ * Implementation of {@link update_rune_totals}.
+ *
+ * This file implements the funciton {@link update_rune_totals} declared in
+ * {@link update.h}.
  */
 
-void update_rune_totals(struct DB_Rune *rune){
+#include <sqlite3.h>
+#include "../error/error.h"
+#include "../db/db.h"
+#include "../RuneOptimizer.h"
+#include "update.h"
+
+extern void update_rune_totals(struct DB_Rune *rune){
     rune->efficiency = 0.0f;
     rune->max_efficiency = 0.0f;
     rune->current_hp_flat = 0;
@@ -64,10 +74,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_hp_flat +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_hp_flat +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case HP_PERCENT:
             rune->current_hp_percent += rune->main.value;
@@ -76,10 +86,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_hp_percent +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_hp_percent +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case ATK_FLAT:
             rune->current_atk_flat += rune->main.value;
@@ -88,10 +98,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_atk_flat +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_atk_flat +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case ATK_PERCENT:
             rune->current_atk_percent += rune->main.value;
@@ -100,10 +110,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_atk_percent +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_atk_percent +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case DEF_FLAT:
             rune->current_def_flat += rune->main.value;
@@ -112,10 +122,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_def_flat +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_def_flat +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case DEF_PERCENT:
             rune->current_def_percent += rune->main.value;
@@ -124,10 +134,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_def_percent +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_def_percent +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case SPD:
             rune->current_spd += rune->main.value;
@@ -136,10 +146,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_spd +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_spd +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case CRR:
             rune->current_crr += rune->main.value;
@@ -148,10 +158,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_crr +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_crr +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case CRD:
             rune->current_crd += rune->main.value;
@@ -160,10 +170,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_crd +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_crd +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case RES:
             rune->current_res += rune->main.value;
@@ -172,10 +182,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_res +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_res +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
         case ACC:
             rune->current_acc += rune->main.value;
@@ -184,10 +194,10 @@ void update_rune_totals(struct DB_Rune *rune){
             }
             else{
                 rune->lv12_acc +=
-                  main_stats_values[rune->main.stat][rune->stars][0];
+                  MAIN_STATS_VALUES[rune->main.stat][rune->stars][0];
             }
             rune->lv15_acc +=
-              main_stats_values[rune->main.stat][rune->stars][1];
+              MAIN_STATS_VALUES[rune->main.stat][rune->stars][1];
             break;
     }
     switch (rune->innate.stat){

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott