|
|
@@ -19,174 +19,7 @@
|
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
|
#include <sqlite3.h>
|
|
|
-
|
|
|
-// Rune set definitions
|
|
|
-#define ENERGY 1
|
|
|
-#define GUARD 2
|
|
|
-#define SWIFT 3
|
|
|
-#define BLADE 4
|
|
|
-#define RAGE 5
|
|
|
-#define FOCUS 6
|
|
|
-#define ENDURE 7
|
|
|
-#define FATAL 8
|
|
|
-#define DESPAIR 10
|
|
|
-#define VAMPIRE 11
|
|
|
-#define VIOLENT 13
|
|
|
-#define NEMESIS 14
|
|
|
-#define WILL 15
|
|
|
-#define SHIELD 16
|
|
|
-#define REVENGE 17
|
|
|
-#define DESTROY 18
|
|
|
-#define FIGHT 19
|
|
|
-#define DETERMINATION 20
|
|
|
-#define ENHANCE 21
|
|
|
-#define ACCURACY 22
|
|
|
-#define TOLERANCE 23
|
|
|
-
|
|
|
-// Rune stat definitions
|
|
|
-#define HP_FLAT 1
|
|
|
-#define HP_PERCENT 2
|
|
|
-#define ATK_FLAT 3
|
|
|
-#define ATK_PERCENT 4
|
|
|
-#define DEF_FLAT 5
|
|
|
-#define DEF_PERCENT 6
|
|
|
-#define SPD 8
|
|
|
-#define CRR 9
|
|
|
-#define CRD 10
|
|
|
-#define RES 11
|
|
|
-#define ACC 12
|
|
|
-
|
|
|
-struct Unit {
|
|
|
- unsigned char id[12];
|
|
|
- unsigned char name[50];
|
|
|
- unsigned short 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 short 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;
|
|
|
-};
|
|
|
-
|
|
|
-struct Rune {
|
|
|
- unsigned char id[12];
|
|
|
- unsigned char slot;
|
|
|
- unsigned char set;
|
|
|
- unsigned char unit[12];
|
|
|
- unsigned char hp_percent;
|
|
|
- unsigned char atk_percent;
|
|
|
- unsigned char def_percent;
|
|
|
- unsigned short hp_flat;
|
|
|
- unsigned char atk_flat;
|
|
|
- unsigned char def_flat;
|
|
|
- unsigned char spd;
|
|
|
- unsigned char crr;
|
|
|
- unsigned char crd;
|
|
|
- unsigned char acc;
|
|
|
- unsigned char res;
|
|
|
-};
|
|
|
-
|
|
|
-struct Stats {
|
|
|
- unsigned short hp;
|
|
|
- unsigned short atk;
|
|
|
- unsigned short def;
|
|
|
- unsigned short spd;
|
|
|
- unsigned short crr;
|
|
|
- unsigned short crd;
|
|
|
- unsigned short acc;
|
|
|
- unsigned short res;
|
|
|
-};
|
|
|
-
|
|
|
-struct Rune_Set_Count {
|
|
|
- unsigned short energy;
|
|
|
- unsigned short guard;
|
|
|
- unsigned short swift;
|
|
|
- unsigned short blade;
|
|
|
- unsigned short rage;
|
|
|
- unsigned short focus;
|
|
|
- unsigned short endure;
|
|
|
- unsigned short fatal;
|
|
|
- unsigned short despair;
|
|
|
- unsigned short vampire;
|
|
|
- unsigned short violent;
|
|
|
- unsigned short nemesis;
|
|
|
- unsigned short will;
|
|
|
- unsigned short shield;
|
|
|
- unsigned short revenge;
|
|
|
- unsigned short destroy;
|
|
|
- unsigned short fight;
|
|
|
- unsigned short determination;
|
|
|
- unsigned short enhance;
|
|
|
- unsigned short accuracy;
|
|
|
- unsigned short tolerance;
|
|
|
-};
|
|
|
-typedef struct Result {
|
|
|
- unsigned char rune_ids[6][12];
|
|
|
- signed int rating;
|
|
|
- struct Stats stats;
|
|
|
-} Result;
|
|
|
-
|
|
|
-char stat_names[][13] = {
|
|
|
- "NULL", "HP_FLAT", "HP", "ATK_FLAT", "ATK", "DEF_FLAT",
|
|
|
- "DEF", "NULL", "SPD", "CRR", "CRD", "RES", "ACC"
|
|
|
-};
|
|
|
-char set_names[][24] = {
|
|
|
- "NULL", "ENERGY", "GUARD", "SWIFT", "BLADE", "RAGE",
|
|
|
- "FOCUS", "ENDURE", "FATAL", "NULL", "DESPAIR", "VAMPIRE",
|
|
|
- "VIOLENT", "NEMESIS", "WILL", "SHIELD", "REVENGE", "DESTROY",
|
|
|
- "FIGHT", "DETERMINATION", "ENHANCE", "ACCURACY", "TOLERANCE"
|
|
|
-};
|
|
|
-/**
|
|
|
- * Displays the help text.
|
|
|
- */
|
|
|
-void show_help();
|
|
|
-
|
|
|
-/**
|
|
|
- * Starts the optimization process.
|
|
|
- *
|
|
|
- * @param argc Argument count.
|
|
|
- * @param argv Argument list.
|
|
|
- * @return 0 on success, other on error.
|
|
|
- */
|
|
|
-int optimize(int argc, char *argv[]);
|
|
|
-
|
|
|
-/**
|
|
|
- * Connects to the database.
|
|
|
- *
|
|
|
- * Initializes the global db.
|
|
|
- *
|
|
|
- * @return 0 on success, other on error.
|
|
|
- */
|
|
|
-int open_databse();
|
|
|
-
|
|
|
-/**
|
|
|
- * Sorts the result array.
|
|
|
- *
|
|
|
- * Sorts them by rating.
|
|
|
- *
|
|
|
- * @param results List of results to sort.
|
|
|
- * @param total Number of results.
|
|
|
- */
|
|
|
-void sort_results(Result results[1000], int total);
|
|
|
-
|
|
|
-/**
|
|
|
- * @var Stores the database error statuses.
|
|
|
- */
|
|
|
-int db_status;
|
|
|
-
|
|
|
-/**
|
|
|
- * @var Database connection.
|
|
|
- */
|
|
|
-sqlite3 *db;
|
|
|
+#include "RuneOptimizer.h"
|
|
|
|
|
|
/**
|
|
|
* Starts the program.
|
|
|
@@ -195,51 +28,53 @@ sqlite3 *db;
|
|
|
*
|
|
|
* @param argc Argument count.
|
|
|
* @param argv Argument list.
|
|
|
- * @return 0 on success, other on error.
|
|
|
+ * @return SUCCESS on success, other on error.
|
|
|
*/
|
|
|
int main(int argc, char *argv[]){
|
|
|
- // Parse the arguments
|
|
|
- if (argc < 2){
|
|
|
- fprintf(stderr, "No options specified\n");
|
|
|
- return 0;
|
|
|
+ // Parse the arguments to find the command (index 1)
|
|
|
+
|
|
|
+ // If no arguments, end here
|
|
|
+ if (argc < 2){
|
|
|
+ fprintf(stderr, "No command specified\n");
|
|
|
+ return ERROR_INPUT_NO_COMMAND;
|
|
|
}
|
|
|
- int command = -1;
|
|
|
+
|
|
|
+ // Update command, TODO
|
|
|
if (strcmp(argv[1], "update") == 0){
|
|
|
fprintf(stderr, "Updating is still unimplemented\n");
|
|
|
- return 0;
|
|
|
+ return UNIMPLEMENTED;
|
|
|
}
|
|
|
+
|
|
|
+ // Optimize command, call the function with all the arguments to be
|
|
|
+ // processed there.
|
|
|
else if (strcmp(argv[1], "optimize") == 0){
|
|
|
- //printf("Starting optimization...\n");
|
|
|
int result = optimize(argc, argv);
|
|
|
- if (result != 0){
|
|
|
- //fprintf(stderr, "Errors in optimization: %d\n", result);
|
|
|
- return result;
|
|
|
- }
|
|
|
+ return result;
|
|
|
}
|
|
|
+
|
|
|
+ // Help command. Call and return
|
|
|
else if (strcmp(argv[1], "help") == 0){
|
|
|
show_help();
|
|
|
- return 0;
|
|
|
+ return SUCCESS;
|
|
|
}
|
|
|
+
|
|
|
+ // Any other command is an error
|
|
|
else{
|
|
|
- fprintf(stderr, "Invalid option specified: %s\n", argv[1]);
|
|
|
- return 0;
|
|
|
+ fprintf(stderr, "Invalid command specified: %s\n", argv[1]);
|
|
|
+ return ERROR_INPUT_INVALID_COMMAND;
|
|
|
}
|
|
|
-
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
int open_database(){
|
|
|
+ // The database location and name is hardcoded in the same directory.
|
|
|
int db_status = sqlite3_open("../data.sqlite", &db);
|
|
|
-
|
|
|
if (db_status != SQLITE_OK) {
|
|
|
-
|
|
|
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
|
|
|
sqlite3_close(db);
|
|
|
-
|
|
|
- return 1;
|
|
|
+ return ERROR_DB_CANT_OPEN;
|
|
|
}
|
|
|
else{
|
|
|
- return 0;
|
|
|
+ return SUCCESS;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -286,16 +121,17 @@ void show_help(){
|
|
|
printf(" Only the selected sets will be included, so this option is\n");
|
|
|
printf(" mandatory. Accepted values the rune net names, lowercase.\n");
|
|
|
printf(" Values must be comma-separated, and up to 3 can be included.\n");
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
int optimize(int argc, char *argv[]){
|
|
|
// Get unit identifier
|
|
|
if (argc < 3){
|
|
|
fprintf(stderr, "No unit specified for optimization\n");
|
|
|
- return -1;
|
|
|
+ return ERROR_INPUT_NO_UNIT;
|
|
|
}
|
|
|
|
|
|
- // Get other data
|
|
|
+ // Initialize values for the data to be read form arguments.
|
|
|
int requested_level = 0;
|
|
|
char requested_level_column[9] = "current_";
|
|
|
int sets[3] = {0, 0, 0};
|
|
|
@@ -313,9 +149,10 @@ int optimize(int argc, char *argv[]){
|
|
|
min_stats.res = 1;
|
|
|
min_stats.acc = 1;
|
|
|
|
|
|
- // Loop argumens
|
|
|
+ // Loop command line arguments
|
|
|
for (int i = 3; i < argc; i ++){
|
|
|
- //printf("ARGUMENT %d: %s\n", i, argv[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){
|
|
|
@@ -331,17 +168,28 @@ int optimize(int argc, char *argv[]){
|
|
|
strcpy(requested_level_column, "lv15_");
|
|
|
}
|
|
|
else{
|
|
|
- fprintf(stderr, "Invalid option for argument %s: %s\nValid options are 'current', '12' or '15'\n", argv[i], argv[i + 1]);
|
|
|
- return -9;
|
|
|
+ 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_INVALID_LEVEL;
|
|
|
}
|
|
|
// Advance one position in argument reading
|
|
|
i ++;
|
|
|
}
|
|
|
else{
|
|
|
- fprintf(stderr, "Argument %s requires a value.\nValid options are 'current', '12' or '15'\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ fprintf(
|
|
|
+ stderr,
|
|
|
+ "Argument %s requires a value.\n"
|
|
|
+ "Valid options are 'current', '12' or '15'\n", argv[i]
|
|
|
+ );
|
|
|
+ return ERROR_INPUT_NO_LEVEL;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // Rune sets argument
|
|
|
else if (strcmp("--sets", argv[i]) == 0 || strcmp("-e", argv[i]) == 0){
|
|
|
if (i < argc - 1){
|
|
|
// Separate string by commas
|
|
|
@@ -417,7 +265,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Unknown rune set %s.\n", token);
|
|
|
- return -10;
|
|
|
+ return ERROR_INPUT_INVALID_SET;
|
|
|
}
|
|
|
token = strtok(NULL, ",");
|
|
|
j ++;
|
|
|
@@ -426,10 +274,16 @@ int optimize(int argc, char *argv[]){
|
|
|
i ++;
|
|
|
}
|
|
|
else{
|
|
|
- fprintf(stderr, "Argument %s requires a list of values separated by commas.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ fprintf(
|
|
|
+ stderr,
|
|
|
+ "Argument %s requires a list of values separated by commas.\n",
|
|
|
+ argv[i]
|
|
|
+ );
|
|
|
+ return ERROR_INPUT_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
|
|
|
@@ -475,7 +329,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Unknown rune stat %s.\n", token);
|
|
|
- return -10;
|
|
|
+ return ERROR_INPUT_INVALID_STAT;
|
|
|
}
|
|
|
token = strtok(NULL, ",");
|
|
|
j ++;
|
|
|
@@ -485,9 +339,11 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Argument %s requires a list of values separated by commas.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ return ERROR_INPUT_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]);
|
|
|
@@ -500,7 +356,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ return ERROR_INPUT_NO_HP;
|
|
|
}
|
|
|
}
|
|
|
else if (strcmp("--min-atk", argv[i]) == 0 || strcmp("-a", argv[i]) == 0){
|
|
|
@@ -515,7 +371,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ return ERROR_INPUT_NO_ATK;
|
|
|
}
|
|
|
}
|
|
|
else if (strcmp("--min-def", argv[i]) == 0 || strcmp("-d", argv[i]) == 0){
|
|
|
@@ -530,7 +386,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ return ERROR_INPUT_NO_DEF;
|
|
|
}
|
|
|
}
|
|
|
else if (strcmp("--min-spd", argv[i]) == 0 || strcmp("-s", argv[i]) == 0){
|
|
|
@@ -545,7 +401,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ return ERROR_INPUT_NO_SPD;
|
|
|
}
|
|
|
}
|
|
|
else if (strcmp("--min-crr", argv[i]) == 0 || strcmp("-c", argv[i]) == 0){
|
|
|
@@ -563,7 +419,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ return ERROR_INPUT_NO_CRR;
|
|
|
}
|
|
|
}
|
|
|
else if (strcmp("--min-crd", argv[i]) == 0 || strcmp("-d", argv[i]) == 0){
|
|
|
@@ -578,7 +434,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ return ERROR_INPUT_NO_CRD;
|
|
|
}
|
|
|
}
|
|
|
else if (strcmp("--min-res", argv[i]) == 0 || strcmp("-r", argv[i]) == 0){
|
|
|
@@ -596,7 +452,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ return ERROR_INPUT_NO_RES;
|
|
|
}
|
|
|
}
|
|
|
else if (strcmp("--min-acc", argv[i]) == 0 || strcmp("-f", argv[i]) == 0){
|
|
|
@@ -614,63 +470,65 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
|
|
|
- return -9;
|
|
|
+ return ERROR_INPUT_NO_ACC;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- // Read the unit from the databse
|
|
|
- open_database();
|
|
|
+ // Now we can open the database.
|
|
|
+ if (SUCCESS != open_database()){
|
|
|
+ return ERROR_DB_CANT_OPEN;
|
|
|
+ }
|
|
|
|
|
|
+ // Read the unit from the databse
|
|
|
sqlite3_stmt *res;
|
|
|
char *sql = "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 "
|
|
|
+ "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 = ?";
|
|
|
db_status = sqlite3_prepare_v2(db, sql, -1, &res, 0);
|
|
|
-
|
|
|
- if (db_status == SQLITE_OK) {
|
|
|
- sqlite3_bind_text(res, 1, argv[2], strlen(argv[2]), NULL);
|
|
|
- sqlite3_bind_text(res, 2, argv[2], strlen(argv[2]), NULL);
|
|
|
- }
|
|
|
- else {
|
|
|
- fprintf(stderr, "Failed to execute statement to select unit: %s\n", sqlite3_errmsg(db));
|
|
|
- return -2;
|
|
|
+ if (db_status != SQLITE_OK) {
|
|
|
+ fprintf(
|
|
|
+ stderr,
|
|
|
+ "Failed to execute statement to select unit: %s\n",
|
|
|
+ sqlite3_errmsg(db)
|
|
|
+ );
|
|
|
+ return ERROR_DB_UNIT;
|
|
|
}
|
|
|
+ sqlite3_bind_text(res, 1, argv[2], strlen(argv[2]), NULL);
|
|
|
+ sqlite3_bind_text(res, 2, argv[2], strlen(argv[2]), NULL);
|
|
|
|
|
|
+ // Fetch just one line
|
|
|
int step = sqlite3_step(res);
|
|
|
|
|
|
+ // Create a unit structure with the red data.
|
|
|
struct Unit unit;
|
|
|
-
|
|
|
-
|
|
|
- if (step == SQLITE_ROW) {
|
|
|
- strcpy(unit.id, sqlite3_column_text(res, 0));
|
|
|
- strcpy(unit.name, sqlite3_column_text(res, 1));
|
|
|
- unit.base_hp = sqlite3_column_int(res, 2);
|
|
|
- unit.base_atk = sqlite3_column_int(res, 3);
|
|
|
- unit.base_def = sqlite3_column_int(res, 4);
|
|
|
- unit.base_spd = sqlite3_column_int(res, 5);
|
|
|
- unit.base_crr = sqlite3_column_int(res, 6);
|
|
|
- unit.base_crd = sqlite3_column_int(res, 7);
|
|
|
- unit.base_res = sqlite3_column_int(res, 8);
|
|
|
- unit.base_acc = sqlite3_column_int(res, 9);
|
|
|
- unit.current_hp = sqlite3_column_int(res, 10);
|
|
|
- unit.current_atk = sqlite3_column_int(res, 11);
|
|
|
- unit.current_def = sqlite3_column_int(res, 12);
|
|
|
- unit.current_spd = sqlite3_column_int(res, 13);
|
|
|
- unit.current_crr = sqlite3_column_int(res, 14);
|
|
|
- unit.current_crd = sqlite3_column_int(res, 15);
|
|
|
- unit.current_res = sqlite3_column_int(res, 16);
|
|
|
- unit.current_acc = sqlite3_column_int(res, 17);
|
|
|
-
|
|
|
- }
|
|
|
- else{
|
|
|
+ if (step != SQLITE_ROW) {
|
|
|
fprintf(stderr, "Unit not found: %s\n", sqlite3_errmsg(db));
|
|
|
- return -3;
|
|
|
+ return ERROR_DB_UNIT_NOF_FOUND;
|
|
|
}
|
|
|
-
|
|
|
+ strcpy(unit.id, sqlite3_column_text(res, 0));
|
|
|
+ strcpy(unit.name, sqlite3_column_text(res, 1));
|
|
|
+ unit.base_hp = sqlite3_column_int(res, 2);
|
|
|
+ unit.base_atk = sqlite3_column_int(res, 3);
|
|
|
+ unit.base_def = sqlite3_column_int(res, 4);
|
|
|
+ unit.base_spd = sqlite3_column_int(res, 5);
|
|
|
+ unit.base_crr = sqlite3_column_int(res, 6);
|
|
|
+ unit.base_crd = sqlite3_column_int(res, 7);
|
|
|
+ unit.base_res = sqlite3_column_int(res, 8);
|
|
|
+ unit.base_acc = sqlite3_column_int(res, 9);
|
|
|
+ unit.current_hp = sqlite3_column_int(res, 10);
|
|
|
+ unit.current_atk = sqlite3_column_int(res, 11);
|
|
|
+ unit.current_def = sqlite3_column_int(res, 12);
|
|
|
+ unit.current_spd = sqlite3_column_int(res, 13);
|
|
|
+ unit.current_crr = sqlite3_column_int(res, 14);
|
|
|
+ unit.current_crd = sqlite3_column_int(res, 15);
|
|
|
+ unit.current_res = sqlite3_column_int(res, 16);
|
|
|
+ unit.current_acc = sqlite3_column_int(res, 17);
|
|
|
+
|
|
|
+ // Min stats that have the value 1 get overriden by the current stats.
|
|
|
if (min_stats.hp == 1){
|
|
|
min_stats.hp = unit.current_hp;
|
|
|
}
|
|
|
@@ -809,15 +667,11 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
}
|
|
|
printf("\n");
|
|
|
-
|
|
|
if (total_requested_runes != 6){
|
|
|
fprintf(stderr, "Invalid rune set combination.\n");
|
|
|
- return -3;
|
|
|
+ return ERROR_INPUT_INCOMPLETE_SETS;
|
|
|
}
|
|
|
|
|
|
- // TODO
|
|
|
- //return 0;
|
|
|
-
|
|
|
// Create queries for each slot
|
|
|
char query_odd[2500] = "SELECT id, unit, type, ";
|
|
|
strcat(query_odd, requested_level_column);
|
|
|
@@ -862,12 +716,6 @@ int optimize(int argc, char *argv[]){
|
|
|
strcat(query_odd, "-1) ");
|
|
|
// TODO: Add team stuff
|
|
|
|
|
|
-
|
|
|
- //printf("- QUERY ODD: %s\n", query_odd);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
char query_even[1500] = "SELECT id, unit, type, ";
|
|
|
strcat(query_even, requested_level_column);
|
|
|
strcat(query_even, "hp_flat, ");
|
|
|
@@ -907,7 +755,6 @@ int optimize(int argc, char *argv[]){
|
|
|
strcat(query_even, ", ");
|
|
|
}
|
|
|
strcat(query_even, "-1) AND main_stat IN (");
|
|
|
-
|
|
|
for (int i = 0; i < 12; i ++){
|
|
|
if (requested_stats[i] != 0){
|
|
|
sprintf(stat_set, "%d", requested_stats[i]);
|
|
|
@@ -918,59 +765,60 @@ int optimize(int argc, char *argv[]){
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
strcat(query_even, "-1) ");
|
|
|
// TODO: Add team stuff
|
|
|
|
|
|
+ // Get data for all the runes from the database.
|
|
|
+ // 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.
|
|
|
sqlite3_stmt *stmt_runes[7];
|
|
|
+ // Im assumming 600 runes per slot is a safe estimate. I hope it doesn't
|
|
|
+ // come back to bite me.
|
|
|
struct Rune runes[7][600];
|
|
|
db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[1], 0);
|
|
|
if (db_status != SQLITE_OK) {
|
|
|
printf("Error getting runes for slot 1: %s\n", sqlite3_errmsg(db));
|
|
|
- return -7;
|
|
|
+ return ERROR_DB_RUNES_SLOT;
|
|
|
}
|
|
|
sqlite3_bind_int(stmt_runes[1], 1, 1);
|
|
|
db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[3], 0);
|
|
|
if (db_status != SQLITE_OK) {
|
|
|
printf("Error getting runes for slot 3: %s\n", sqlite3_errmsg(db));
|
|
|
- return -7;
|
|
|
+ return ERROR_DB_RUNES_SLOT;
|
|
|
}
|
|
|
sqlite3_bind_int(stmt_runes[3], 1, 3);
|
|
|
db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[5], 0);
|
|
|
if (db_status != SQLITE_OK) {
|
|
|
printf("Error getting runes for slot 5: %s\n", sqlite3_errmsg(db));
|
|
|
- return -7;
|
|
|
+ return ERROR_DB_RUNES_SLOT;
|
|
|
}
|
|
|
sqlite3_bind_int(stmt_runes[5], 1, 5);
|
|
|
db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[2], 0);
|
|
|
if (db_status != SQLITE_OK) {
|
|
|
printf("Error getting runes for slot 2: %s\n", sqlite3_errmsg(db));
|
|
|
- return -7;
|
|
|
+ return ERROR_DB_RUNES_SLOT;
|
|
|
}
|
|
|
sqlite3_bind_int(stmt_runes[2], 1, 2);
|
|
|
db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[4], 0);
|
|
|
if (db_status != SQLITE_OK) {
|
|
|
printf("Error getting runes for slot 4: %s\n", sqlite3_errmsg(db));
|
|
|
- return -7;
|
|
|
+ return ERROR_DB_RUNES_SLOT;
|
|
|
}
|
|
|
sqlite3_bind_int(stmt_runes[4], 1, 4);
|
|
|
db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[6], 0);
|
|
|
if (db_status != SQLITE_OK) {
|
|
|
printf("Error getting runes for slot 6: %s\n", sqlite3_errmsg(db));
|
|
|
- return -7;
|
|
|
+ return ERROR_DB_RUNES_SLOT;
|
|
|
}
|
|
|
sqlite3_bind_int(stmt_runes[6], 1, 6);
|
|
|
|
|
|
-
|
|
|
// Get and populate all the runes
|
|
|
int rune_count[7];
|
|
|
for (int i = 1; i < 7; i ++){
|
|
|
int j = 0;
|
|
|
while (1 == 1){
|
|
|
int status = sqlite3_step(stmt_runes[i]);
|
|
|
- //printf("STATUS: %d ", status);
|
|
|
if (status == SQLITE_ROW){
|
|
|
- //printf(" - (%d) Slot %d, Rune ID %s\n", j, i, sqlite3_column_text(stmt_runes[i], 0));
|
|
|
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].set = sqlite3_column_int(stmt_runes[i], 2);
|
|
|
@@ -994,10 +842,11 @@ int optimize(int argc, char *argv[]){
|
|
|
rune_count[i] = j;
|
|
|
}
|
|
|
|
|
|
+ // If any slot doesn't have matching runes, we can stop now.
|
|
|
for (int i = 1; i < 7; i ++){
|
|
|
if (rune_count[i] == 0){
|
|
|
- fprintf(stderr, "\n - No availbale runes for slot %d\n", i);
|
|
|
- return 1;
|
|
|
+ printf("\n - No availbale runes for slot %d\n", i);
|
|
|
+ return SUCCESS;
|
|
|
}
|
|
|
}
|
|
|
printf("\n");
|
|
|
@@ -1009,7 +858,27 @@ int optimize(int argc, char *argv[]){
|
|
|
rune_count[5] *
|
|
|
rune_count[6];
|
|
|
|
|
|
- // Print summary
|
|
|
+ // Print a nice summary before starting the long optimization.
|
|
|
+ // 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% |
|
|
|
+ // -----------------------------------
|
|
|
+ //
|
|
|
+ // Im breaking the 80-characters-line rule here, but only 'cause I'd like
|
|
|
+ // to remain sane.
|
|
|
printf(" ----------------------------------- Requested rune sets:\n");
|
|
|
printf(" | %*s | ", -31, unit.name);
|
|
|
for (int i = 0; i < 3; i ++){
|
|
|
@@ -1050,8 +919,9 @@ int optimize(int argc, char *argv[]){
|
|
|
printf(" | ACC: | %*d\% | %*d\% | %*d\% |\n", 5, unit.base_acc, 5, unit.current_acc, 5, min_stats.acc);
|
|
|
printf(" -----------------------------------\n");
|
|
|
|
|
|
- // Now its time to loop all 6 reels of runes and try to match combos
|
|
|
+ // Now its time to loop all 6 'reels' of runes and try to match combos
|
|
|
printf("\n\n__Optimization progress___________________________\n", max_combinations);
|
|
|
+ // Initialize arrys and some counters
|
|
|
int index[7] = {0, 0, 0, 0, 0, 0};
|
|
|
unsigned long tested_combinations = 0;
|
|
|
unsigned long valid_sets = 0;
|
|
|
@@ -1066,8 +936,13 @@ int optimize(int argc, char *argv[]){
|
|
|
index[6] < rune_count[6]
|
|
|
){
|
|
|
// Progress bar, 50 characters to 100%
|
|
|
- if ((tested_combinations + 1) % (unsigned long)(max_combinations / 50) == 0){
|
|
|
+ if (
|
|
|
+ (tested_combinations + 1) %
|
|
|
+ (unsigned long)(max_combinations / 50)
|
|
|
+ == 0
|
|
|
+ ){
|
|
|
printf("#");
|
|
|
+ // Line buffered! need to flush after every char.
|
|
|
fflush(stdout);
|
|
|
}
|
|
|
|
|
|
@@ -1203,8 +1078,10 @@ int optimize(int argc, char *argv[]){
|
|
|
stats.atk += runes[i][index[i]].atk_flat;
|
|
|
stats.def += runes[i][index[i]].def_flat;
|
|
|
stats.hp += unit.base_hp * runes[i][index[i]].hp_percent / 100;
|
|
|
- stats.atk += unit.base_hp * runes[i][index[i]].atk_percent / 100;
|
|
|
- stats.def += unit.base_hp * runes[i][index[i]].def_percent / 100;
|
|
|
+ stats.atk +=
|
|
|
+ unit.base_hp * runes[i][index[i]].atk_percent / 100;
|
|
|
+ stats.def +=
|
|
|
+ unit.base_hp * runes[i][index[i]].def_percent / 100;
|
|
|
stats.spd += runes[i][index[i]].spd;
|
|
|
stats.crr += runes[i][index[i]].crr;
|
|
|
stats.crd += runes[i][index[i]].crd;
|
|
|
@@ -1223,11 +1100,13 @@ int optimize(int argc, char *argv[]){
|
|
|
stats.acc >= min_stats.acc
|
|
|
){
|
|
|
// This is a valid sets and all stats are above the minimum.
|
|
|
- // Create a result.
|
|
|
+ // Create a result with rune indexes, stats, and rating.
|
|
|
for (int i = 1; i < 7; i ++){
|
|
|
- strcpy(results[result_count].rune_ids[i - 1], runes[i][index[i]].id);
|
|
|
+ strcpy(
|
|
|
+ results[result_count].rune_ids[i - 1],
|
|
|
+ runes[i][index[i]].id
|
|
|
+ );
|
|
|
}
|
|
|
-
|
|
|
results[result_count].stats.hp = stats.hp;
|
|
|
results[result_count].stats.atk = stats.atk;
|
|
|
results[result_count].stats.def = stats.def;
|
|
|
@@ -1237,6 +1116,8 @@ int optimize(int argc, char *argv[]){
|
|
|
results[result_count].stats.res = stats.res;
|
|
|
results[result_count].stats.acc = stats.acc;
|
|
|
|
|
|
+ // One rating point per stat increase over current stats.
|
|
|
+ // Save for HP, with takes 15 for a raing point
|
|
|
results[result_count].rating = 0;
|
|
|
results[result_count].rating += ((stats.hp - unit.current_hp) / 15);
|
|
|
results[result_count].rating += (stats.atk - unit.current_atk);
|
|
|
@@ -1250,7 +1131,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Loop control
|
|
|
+ // Loop control. Rotate the reels 'right to left'
|
|
|
tested_combinations ++;
|
|
|
index[6] ++;
|
|
|
if (index[6] == rune_count[6]){
|
|
|
@@ -1274,23 +1155,21 @@ int optimize(int argc, char *argv[]){
|
|
|
index[1] ++;
|
|
|
}
|
|
|
|
|
|
- // TODO: DEBUG force exit with some results
|
|
|
- if (result_count > 0){
|
|
|
- break;
|
|
|
- }
|
|
|
+ //DEBUG: force exit with some results TODO
|
|
|
+ //if (result_count > 1){
|
|
|
+ // break;
|
|
|
+ //}
|
|
|
}
|
|
|
printf("\n");
|
|
|
|
|
|
if (result_count > 0){
|
|
|
+ // Yay! Some combinations matched te criteria.
|
|
|
printf("\n\n%d results found\n", result_count);
|
|
|
// Sort results
|
|
|
sort_results(results, result_count);
|
|
|
- //for (int i = 0; i < result_count; i ++){
|
|
|
- // printf(" - Sorted option %d rating: %d\n", i, results[i].rating);
|
|
|
- //}
|
|
|
- printf("\nPresenting best option:\n\n");
|
|
|
|
|
|
// Preview the best option
|
|
|
+ printf("\nPresenting best option:\n\n");
|
|
|
printf(" --------------------------\n");
|
|
|
printf(" | %*s |\n", -22, unit.name);
|
|
|
printf(" | ID: %*s |\n", -18, unit.id);
|
|
|
@@ -1307,6 +1186,40 @@ int optimize(int argc, char *argv[]){
|
|
|
printf(" | ACC: | %*d\% | %*d\% |\n", 5, unit.current_acc, 5, results[0].stats.acc);
|
|
|
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 |
|
|
|
+ // ------------------------------ ------------------------------ ------------------------------
|
|
|
+ //
|
|
|
+ // Again, Im breaking the 80-characters-line rule.
|
|
|
+
|
|
|
char present[8][130];
|
|
|
strcpy(present[0], "");
|
|
|
strcpy(present[1], "");
|
|
|
@@ -1332,15 +1245,13 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else {
|
|
|
fprintf(stderr, "Failed to execute statement to select rune: %s\n", sqlite3_errmsg(db));
|
|
|
- return -2;
|
|
|
+ return ERROR_DB_RUNES_RESULT;
|
|
|
}
|
|
|
|
|
|
int step = sqlite3_step(rune_res);
|
|
|
if (step == SQLITE_ROW) {
|
|
|
char tmp[64];
|
|
|
strcpy(tmp, "");
|
|
|
- //strcpy(unit.id, sqlite3_column_text(rune_res, 0));
|
|
|
- //printf("Rune %d (%s)\n", sqlite3_column_int(rune_res, 1), sqlite3_column_text(rune_res, 0));
|
|
|
strcat(present[0], "|");
|
|
|
sprintf(tmp, "%*d", 1, sqlite3_column_int(rune_res, 1));
|
|
|
strcat(present[0], tmp);
|
|
|
@@ -1378,7 +1289,7 @@ int optimize(int argc, char *argv[]){
|
|
|
}
|
|
|
else {
|
|
|
fprintf(stderr, "Failed to execute statement to select rune stats: %s\n", sqlite3_errmsg(db));
|
|
|
- return -2;
|
|
|
+ return ERROR_DB_STATS_RESULT;
|
|
|
}
|
|
|
|
|
|
int curr_slot = -1;
|
|
|
@@ -1409,25 +1320,27 @@ int optimize(int argc, char *argv[]){
|
|
|
strcat(present[curr_slot + 3], tmp);
|
|
|
strcat(present[curr_slot + 3], "| ");
|
|
|
}
|
|
|
- /*else{
|
|
|
- sprintf(tmp, "%d-EMPTY ", curr_slot);
|
|
|
- strcat(present[curr_slot + 3], tmp);
|
|
|
- //curr_slot ++;
|
|
|
- }*/
|
|
|
+
|
|
|
curr_slot ++;
|
|
|
}
|
|
|
else{
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
+ sqlite3_finalize(stats_res);
|
|
|
}
|
|
|
else{
|
|
|
fprintf(stderr, "BAD ROW: %s\n", sqlite3_errmsg(db));
|
|
|
}
|
|
|
sqlite3_finalize(rune_res);
|
|
|
- //printf(present[0]);
|
|
|
|
|
|
// 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){
|
|
|
//printf("-6->1-");
|
|
|
i = 1;
|
|
|
@@ -1502,34 +1415,12 @@ int optimize(int argc, char *argv[]){
|
|
|
printf("No results found\n");
|
|
|
}
|
|
|
|
|
|
- printf("ENDING\n");
|
|
|
-
|
|
|
- sqlite3_finalize(res);
|
|
|
sqlite3_close(db);
|
|
|
-
|
|
|
- /*
|
|
|
-
|
|
|
- rc = sqlite3_exec(db, sql, callback, 0, &err_msg);
|
|
|
-
|
|
|
- if (rc != SQLITE_OK ) {
|
|
|
-
|
|
|
- ffprintf(stderr, "Failed to select data\n");
|
|
|
- ffprintf(stderr, "SQL error: %s\n", err_msg);
|
|
|
-
|
|
|
- sqlite3_free(err_msg);
|
|
|
- sqlite3_close(db);
|
|
|
-
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- sqlite3_close(db);
|
|
|
-
|
|
|
- */
|
|
|
- return 0;
|
|
|
+ return SUCCESS;
|
|
|
}
|
|
|
|
|
|
void sort_results(Result results[1000], int total){
|
|
|
- // Bubble sort
|
|
|
+ // Bubble sort, by descending rating.
|
|
|
int i, j;
|
|
|
Result temp;
|
|
|
|