فهرست منبع

Merge branch 'GUI'

Iñigo Valentin 4 سال پیش
والد
کامیت
b6485478df
5فایلهای تغییر یافته به همراه2074 افزوده شده و 280 حذف شده
  1. 5 1
      .gitignore
  2. 2 2
      src/Makefile
  3. 432 273
      src/RuneOptimizer/RuneOptimizer.c
  4. 31 4
      src/RuneOptimizer/RuneOptimizer.h
  5. 1604 0
      src/RuneOptimizerGUI/RuneOptimizer.py

+ 5 - 1
.gitignore

@@ -1,3 +1,7 @@
 data.sqlite
-RuneOptimizer
+*.sqlite
+./RuneOptimizer
 src/util
+src/RuneOptimizer/RuneOptimizer
+RuneOptimizer
+src/RuneOptimizer/util/

+ 2 - 2
src/Makefile

@@ -1,9 +1,9 @@
 CC=gcc
 CFLAGS=
-LIBS=-lsqlite3
+LIBS=-lsqlite3 -lm
 OUT=../RuneOptimizer
 compile :
-	@$(CC) RuneOptimizer.c $(LIBS) -o $(OUT)
+	@$(CC) RuneOptimizer/RuneOptimizer.c $(LIBS) -o $(OUT)
 	@echo Compiled executable $(OUT)
 #RuneOptimizer: RuneOptimizer.c
 #	$(CC) -o makeRO RuneOptimizer.c

+ 432 - 273
src/RuneOptimizer.c → src/RuneOptimizer/RuneOptimizer.c

@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sqlite3.h>
+#include <math.h>
 #include "RuneOptimizer.h"
 
 /**
@@ -67,7 +68,7 @@ int main(int argc, char *argv[]){
 
 int open_database(){
     // The database location and name is hardcoded in the same directory.
-    int db_status = sqlite3_open("../data.sqlite", &db);
+    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);
@@ -108,6 +109,10 @@ void show_help(){
     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");
@@ -121,10 +126,12 @@ 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");
+    printf("        -g | --gui                  Formats the output to be consumed by the GUI.\n");
     return;
 }
 
 int optimize(int argc, char *argv[]){
+
     // Get unit identifier
     if (argc < 3){
         fprintf(stderr, "No unit specified for optimization\n");
@@ -132,7 +139,8 @@ int optimize(int argc, char *argv[]){
     }
 
     // Initialize values for the data to be read form arguments.
-    int requested_level = 0;
+    char requested_level = 0;
+    char gui = 0;
     char requested_level_column[9] = "current_";
     int sets[3] = {0, 0, 0};
     int requested_stats[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -148,6 +156,9 @@ int optimize(int argc, char *argv[]){
     min_stats.crd = 1;
     min_stats.res = 1;
     min_stats.acc = 1;
+    min_stats.ehp = 1;
+    min_stats.dmg = 1;
+
 
     // Loop command line arguments
     for (int i = 3; i < argc; i ++){
@@ -473,6 +484,41 @@ int optimize(int argc, char *argv[]){
                 return ERROR_INPUT_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;
+                }
+                min_stats.ehp = stat_tmp;
+                // Advance one position in argument reading
+                i ++;
+            }
+            else{
+                fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
+                return ERROR_INPUT_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;
+                }
+                min_stats.dmg = stat_tmp;
+                // Advance one position in argument reading
+                i ++;
+            }
+            else{
+                fprintf(stderr, "Argument %s requires a numeric value.\n", argv[i]);
+                return ERROR_INPUT_NO_DMG;
+            }
+        }
+
+        // GUI invoked?
+        else if (strcmp("--gui", argv[i]) == 0 || strcmp("-g", argv[i]) == 0){
+            gui = 1;
+        }
 
     }
 
@@ -519,6 +565,8 @@ int optimize(int argc, char *argv[]){
     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.base_ehp = calculate_ehp(unit.base_hp, unit.base_def);
+    unit.base_dmg = calculate_dmg(unit.base_atk, unit.base_crr, unit.base_crd);
     unit.current_hp = sqlite3_column_int(res, 10);
     unit.current_atk = sqlite3_column_int(res, 11);
     unit.current_def = sqlite3_column_int(res, 12);
@@ -527,6 +575,8 @@ int optimize(int argc, char *argv[]){
     unit.current_crd = sqlite3_column_int(res, 15);
     unit.current_res = sqlite3_column_int(res, 16);
     unit.current_acc = sqlite3_column_int(res, 17);
+    unit.current_ehp = calculate_ehp(unit.current_hp, unit.current_def);
+    unit.current_dmg = calculate_dmg(unit.current_atk, unit.current_crr, unit.current_crd);
 
     // Min stats that have the value 1 get overriden by the current stats.
     if (min_stats.hp == 1){
@@ -553,6 +603,12 @@ int optimize(int argc, char *argv[]){
     if (min_stats.acc == 1){
         min_stats.acc = unit.current_acc;
     }
+    if (min_stats.ehp == 1){
+        min_stats.ehp = 0;
+    }
+    if (min_stats.dmg == 1){
+        min_stats.dmg = 0;
+    }
 
     // Calculate required rune count
     struct Rune_Set_Count requested_set_count;
@@ -666,7 +722,9 @@ int optimize(int argc, char *argv[]){
                 break;
         }
     }
-    printf("\n");
+    if (gui != 1){
+        printf("\n");
+    }
     if (total_requested_runes != 6){
         fprintf(stderr, "Invalid rune set combination.\n");
         return ERROR_INPUT_INCOMPLETE_SETS;
@@ -777,37 +835,37 @@ int optimize(int argc, char *argv[]){
     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));
+        fprintf(stderr, "Error getting runes for slot 1: %s\n", sqlite3_errmsg(db));
         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));
+        fprintf(stderr, "Error getting runes for slot 3: %s\n", sqlite3_errmsg(db));
         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));
+        fprintf(stderr, "Error getting runes for slot 5: %s\n", sqlite3_errmsg(db));
         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));
+        fprintf(stderr, "Error getting runes for slot 2: %s\n", sqlite3_errmsg(db));
         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));
+        fprintf(stderr, "Error getting runes for slot 4: %s\n", sqlite3_errmsg(db));
         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));
+        fprintf(stderr, "Error getting runes for slot 6: %s\n", sqlite3_errmsg(db));
         return ERROR_DB_RUNES_SLOT;
     }
     sqlite3_bind_int(stmt_runes[6], 1, 6);
@@ -845,11 +903,18 @@ int optimize(int argc, char *argv[]){
     // If any slot doesn't have matching runes, we can stop now.
     for (int i = 1; i < 7; i ++){
         if (rune_count[i] == 0){
-            printf("\n  - No availbale runes for slot %d\n", i);
+            if (gui != 1){
+                printf("\n  - No availbale runes for slot %d\n", i);
+            }
+            else{
+                fprintf(stderr, "\n  - No available runes for slot %d\n", i);
+            }
             return SUCCESS;
         }
     }
-    printf("\n");
+    if (gui != 1){
+        printf("\n");
+    }
     unsigned long max_combinations =
       rune_count[1] *
       rune_count[2] *
@@ -879,48 +944,54 @@ int optimize(int argc, char *argv[]){
     //
     // 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 ++){
-        if (sets[i] != 0){
-            printf(" %s ", set_names[sets[i]]);
+    if (gui != 1){
+        printf(" -----------------------------------------    Requested rune sets:\n");
+        printf(" | %*s |      ", -37, unit.name);
+        for (int i = 0; i < 3; i ++){
+            if (sets[i] != 0){
+                printf(" %s ", set_names[sets[i]]);
+            }
+            else{
+                break;
+            }
         }
-        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 < 12; i ++){
+            if (requested_stats[i] != 0){
+                printf(" %s ", stat_names[requested_stats[i]]);
+            }
+            else{
+                break;
+            }
         }
-    }
-    printf("\n");
-    printf(" | ID: %*s |\n", -27, unit.id);
-    printf(" -----------------------------------    Accepted stats:\n");
-    printf(" | STAT | BASE   | CURR.  | MIN.   |      ");
-    for (int i = 0; i < 12; i ++){
-        if (requested_stats[i] != 0){
-            printf(" %s ", stat_names[requested_stats[i]]);
+        printf("\n");
+        printf(" -----------------------------------------\n");
+        printf(" | HP:  | %*d  | %*d  | %*d  |    ", 7, unit.base_hp, 7, unit.current_hp, 7, min_stats.hp);
+        if (requested_level == 0){
+            printf("Using runes at their current level\n");
         }
         else{
-            break;
+            printf("Considering runes at level %d\n", requested_level);
         }
+        printf(" | ATK: | %*d  | %*d  | %*d  |\n", 7, unit.base_atk, 7, unit.current_atk, 7, min_stats.atk);
+        printf(" | DEF: | %*d  | %*d  | %*d  |    Runes considered by slot:\n", 7, unit.base_def, 7, unit.current_def, 7, min_stats.def);
+        printf(" | SPD: | %*d  | %*d  | %*d  |      1:%*d    2:%*d    3:%*d\n", 7, unit.base_spd, 7, unit.current_spd, 7, 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, 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, min_stats.crd);
+        printf(" | RES: | %*d\% | %*d\% | %*d\% |    Total combinations: %d\n", 7, unit.base_res, 7, unit.current_res, 7, min_stats.res, max_combinations);
+        printf(" | ACC: | %*d\% | %*d\% | %*d\% |\n", 7, unit.base_acc, 7, unit.current_acc, 7, min_stats.acc);
+        printf(" | EHP: | %*d  | %*d  | %*d  |\n", 7, unit.base_ehp, 7, unit.current_ehp, 7, min_stats.ehp);
+        printf(" | DMG: | %*d  | %*d  | %*d  |\n", 7, unit.base_dmg, 7, unit.current_dmg, 7, min_stats.dmg);
+        printf(" -----------------------------------------\n");
     }
-    printf("\n");
-    printf(" -----------------------------------\n");
-    printf(" | HP:  | %*d  | %*d  | %*d  |    ", 5, unit.base_hp, 5, unit.current_hp, 5, min_stats.hp);
-    if (requested_level == 0){
-        printf("Using runes at their current level\n");
-    }
-    else{
-        printf("Considering runes at level %d\n", requested_level);
-    }
-    printf(" | ATK: | %*d  | %*d  | %*d  |\n", 5, unit.base_atk, 5, unit.current_atk, 5, min_stats.atk);
-    printf(" | DEF: | %*d  | %*d  | %*d  |    Runes considered by slot:\n", 5, unit.base_def, 5, unit.current_def, 5, min_stats.def);
-    printf(" | SPD: | %*d  | %*d  | %*d  |      1:%*d    2:%*d    3:%*d\n", 5, unit.base_spd, 5, unit.current_spd, 5, 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", 5, unit.base_crr, 5, unit.current_crr, 5, min_stats.crr, 3, rune_count[4], 3, rune_count[5], 3, rune_count[6]);
-    printf(" | CRD: | %*d\% | %*d\% | %*d\% |\n", 5, unit.base_crd, 5, unit.current_crd, 5, min_stats.crd);
-    printf(" | RES: | %*d\% | %*d\% | %*d\% |    Total combinations: %d\n", 5, unit.base_res, 5, unit.current_res, 5, min_stats.res, max_combinations);
-    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
-    printf("\n\n__Optimization progress___________________________\n", max_combinations);
+    if (gui != 1){
+        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;
@@ -937,6 +1008,7 @@ int optimize(int argc, char *argv[]){
     ){
         // Progress bar, 50 characters to 100%
         if (
+          gui != 1 &&
           (tested_combinations + 1) %
           (unsigned long)(max_combinations / 50)
           == 0
@@ -1088,6 +1160,11 @@ int optimize(int argc, char *argv[]){
                 stats.res += runes[i][index[i]].res;
                 stats.acc += runes[i][index[i]].acc;
             }
+
+            // Calculated stats
+            stats.ehp = calculate_ehp(stats.hp, stats.def);
+            stats.dmg = calculate_dmg(stats.atk, stats.crr, stats.crd);
+
             // Compare with minimum requeriments
             if (
                 stats.hp >= min_stats.hp &&
@@ -1097,7 +1174,9 @@ int optimize(int argc, char *argv[]){
                 stats.crr >= min_stats.crr &&
                 stats.crd >= min_stats.crd &&
                 stats.res >= min_stats.res &&
-                stats.acc >= min_stats.acc
+                stats.acc >= min_stats.acc &&
+                stats.ehp >= min_stats.ehp &&
+                stats.dmg >= min_stats.dmg
             ){
                 // This is a valid sets and all stats are above the minimum.
                 // Create a result with rune indexes, stats, and rating.
@@ -1115,6 +1194,8 @@ int optimize(int argc, char *argv[]){
                 results[result_count].stats.crd = stats.crd;
                 results[result_count].stats.res = stats.res;
                 results[result_count].stats.acc = stats.acc;
+                results[result_count].stats.ehp = stats.ehp;
+                results[result_count].stats.dmg = stats.dmg;
 
                 // One rating point per stat increase over current stats.
                 // Save for HP, with takes 15 for a raing point
@@ -1156,263 +1237,325 @@ int optimize(int argc, char *argv[]){
         }
 
         //DEBUG: force exit with some results TODO
-        //if (result_count > 1){
+        //if (result_count > 11){
         //    break;
         //}
     }
-    printf("\n");
+    if (gui != 1){
+        printf("\n");
+    }
 
     if (result_count > 0){
         // Yay! Some combinations matched te criteria.
-        printf("\n\n%d results found\n", result_count);
+        if (gui != 1){
+            printf("\n\n%d results found\n", result_count);
+        }
         // Sort results
         sort_results(results, result_count);
 
         // 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);
-        printf(" --------------------------\n");
-        printf(" | STAT | CURR.  | NEW    |\n");
-        printf(" --------------------------\n");
-        printf(" | HP:  | %*d  | %*d  |\n", 5, unit.current_hp, 5, results[0].stats.hp);
-        printf(" | ATK: | %*d  | %*d  |\n", 5, unit.current_atk, 5, results[0].stats.atk);
-        printf(" | DEF: | %*d  | %*d  |\n", 5, unit.current_def, 5, results[0].stats.def);
-        printf(" | SPD: | %*d  | %*d  |\n", 5, unit.current_spd, 5, results[0].stats.spd);
-        printf(" | CRR: | %*d\% | %*d\% |\n", 5, unit.current_crr, 5, results[0].stats.crr);
-        printf(" | CRD: | %*d\% | %*d\% |\n", 5, unit.current_crd, 5, results[0].stats.crd);
-        printf(" | RES: | %*d\% | %*d\% |\n", 5, unit.current_res, 5, results[0].stats.res);
-        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], "");
-        strcpy(present[2], "");
-        strcpy(present[4], "");
-        strcpy(present[5], "");
-        strcpy(present[6], "");
-        strcpy(present[7], "");
-
-        // Retrieve the rune stats from the database
-        printf("\n");
-        for (int i = 6; i != 0;){
-            char *rune_id = results[0].rune_ids[i - 1];
-            sqlite3_stmt *rune_res;
-            char *sql =
-              "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 = ?";
-            db_status = sqlite3_prepare_v2(db, sql, -1, &rune_res, 0);
-
-            if (db_status == SQLITE_OK) {
-                sqlite3_bind_text(rune_res, 1, results[0].rune_ids[i - 1], strlen(results[0].rune_ids[i - 1]), NULL);
-            }
-            else {
-                fprintf(stderr, "Failed to execute statement to select rune: %s\n", sqlite3_errmsg(db));
-                return ERROR_DB_RUNES_RESULT;
-            }
+        if (gui != 1){
+            printf("\nPresenting best option:\n\n");
+            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, results[0].stats.hp);
+            printf(" | ATK: | %*d  | %*d  |\n", 7, unit.current_atk, 7, results[0].stats.atk);
+            printf(" | DEF: | %*d  | %*d  |\n", 7, unit.current_def, 7, results[0].stats.def);
+            printf(" | SPD: | %*d  | %*d  |\n", 7, unit.current_spd, 7, results[0].stats.spd);
+            printf(" | CRR: | %*d\% | %*d\% |\n", 7, unit.current_crr, 7, results[0].stats.crr);
+            printf(" | CRD: | %*d\% | %*d\% |\n", 7, unit.current_crd, 7, results[0].stats.crd);
+            printf(" | RES: | %*d\% | %*d\% |\n", 7, unit.current_res, 7, results[0].stats.res);
+            printf(" | ACC: | %*d\% | %*d\% |\n", 7, unit.current_acc, 7, results[0].stats.acc);
+            printf(" | EHP: | %*d  | %*d  |\n", 7, unit.current_ehp, 7, results[0].stats.ehp);
+            printf(" | DMG: | %*d  | %*d  |\n", 7, unit.current_dmg, 7, results[0].stats.dmg);
+            printf(" ------------------------------\n");
 
-            int step = sqlite3_step(rune_res);
-            if (step == SQLITE_ROW) {
-                char tmp[64];
-                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], "|");
-                }
+            // 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.
 
-                // Rune level
-                sprintf(tmp, "        +%*s |  ", 2, sqlite3_column_text(rune_res, 5));
-                strcat(present[1], tmp);
+            char present[8][130];
+            strcpy(present[0], "");
+            strcpy(present[1], "");
+            strcpy(present[2], "");
+            strcpy(present[4], "");
+            strcpy(present[5], "");
+            strcpy(present[6], "");
+            strcpy(present[7], "");
 
-                sqlite3_stmt *stats_res;
-                char *sql_stats =
-                  "SELECT rune, slot, stat, value, enchant, grind "
-                  "FROM rune_stats "
-                  "WHERE rune = ?";
-                db_status = sqlite3_prepare_v2(db, sql_stats, -1, &stats_res, 0);
+            // Retrieve the rune stats from the database
+            printf("\n");
+            for (int i = 6; i != 0;){
+                char *rune_id = results[0].rune_ids[i - 1];
+                sqlite3_stmt *rune_res;
+                char *sql =
+                  "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 = ?";
+                db_status = sqlite3_prepare_v2(db, sql, -1, &rune_res, 0);
 
                 if (db_status == SQLITE_OK) {
-                    sqlite3_bind_text(stats_res, 1, sqlite3_column_text(rune_res, 0), strlen(sqlite3_column_text(rune_res, 0)), NULL);
+                    sqlite3_bind_text(rune_res, 1, results[0].rune_ids[i - 1], strlen(results[0].rune_ids[i - 1]), NULL);
                 }
                 else {
-                    fprintf(stderr, "Failed to execute statement to select rune stats: %s\n", sqlite3_errmsg(db));
-                    return ERROR_DB_STATS_RESULT;
+                    fprintf(stderr, "Failed to execute statement to select rune: %s\n", sqlite3_errmsg(db));
+                    return ERROR_DB_RUNES_RESULT;
                 }
 
-                int curr_slot = -1;
-                while (1 == 1){
-                    int status = sqlite3_step(stats_res);
-                    //printf("STATUS:  %d   ", status);
-                    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], "|  ");
-                        }
+                int step = sqlite3_step(rune_res);
+                if (step == SQLITE_ROW) {
+                    char tmp[64];
+                    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);
 
-                        curr_slot ++;
+                    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{
-                        break;
+                        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);
+
+                    sqlite3_stmt *stats_res;
+                    char *sql_stats =
+                      "SELECT rune, slot, stat, value, enchant, grind "
+                      "FROM rune_stats "
+                      "WHERE rune = ?";
+                    db_status = sqlite3_prepare_v2(db, sql_stats, -1, &stats_res, 0);
+
+                    if (db_status == SQLITE_OK) {
+                        sqlite3_bind_text(stats_res, 1, sqlite3_column_text(rune_res, 0), strlen(sqlite3_column_text(rune_res, 0)), NULL);
                     }
+                    else {
+                        fprintf(stderr, "Failed to execute statement to select rune stats: %s\n", sqlite3_errmsg(db));
+                        return ERROR_DB_STATS_RESULT;
+                    }
+
+                    int curr_slot = -1;
+                    while (1 == 1){
+                        int status = sqlite3_step(stats_res);
+                        //printf("STATUS:  %d   ", status);
+                        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;
+                        }
+                    }
+                    sqlite3_finalize(stats_res);
                 }
-                sqlite3_finalize(stats_res);
-            }
-            else{
-                fprintf(stderr, "BAD ROW: %s\n", sqlite3_errmsg(db));
-            }
-            sqlite3_finalize(rune_res);
+                else{
+                    fprintf(stderr, "BAD 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){
-                //printf("-6->1-");
-                i = 1;
-            }
-            else if (i == 1){
-                //printf("-1->2-");
-                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], "");
-                //printf("-2->5-");
-                i = 5;
-            }
-            else if (i == 5){
-                //printf("-5->4-");
-                i = 4;
-            }
-            else if (i == 4){
-                //printf("-4->3-");
-                i = 3;
+                // 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;
+                }
+                else if (i == 1){
+                    //printf("-1->2-");
+                    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], "");
+                    //printf("-2->5-");
+                    i = 5;
+                }
+                else if (i == 5){
+                    //printf("-5->4-");
+                    i = 4;
+                }
+                else if (i == 4){
+                    //printf("-4->3-");
+                    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");
+                    //printf("-3->0-");
+                    i = 0;
+                }
             }
-            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");
-                //printf("-3->0-");
-                i = 0;
+        }
+        else{
+            //Print for GUI
+            char tmp[1000000];
+            strcpy(tmp, "");
+            char json[1000000] = "{\"results\":[";
+            for (int i = 0; i < result_count; i++){
+                //printf("RES LOOP %d\n", i);
+                sprintf(tmp, "{\"rating\":%d,", results[i].rating);
+                strcat(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\n", json);
+                for (int j = 0; j < 5; j++){
+                    //printf("    RUNE LOOP %d\n", j);
+                    sprintf(tmp, "\"%s\",", results[i].rune_ids[j]);
+                    strcat(json, tmp);
+                }
+                //printf("    B %s\n", json);
+                sprintf(tmp, "\"%s\"", results[i].rune_ids[5]);
+                strcat(json, tmp);
+                strcat(json, "]},");
             }
+            // Remove last comma
+            json[strlen(json) - 1] = '\0';
+
+            // End and print
+            strcat(json, "]}\0");
+            printf("%s", json);
         }
     }
     else{
-        printf("No results found\n");
+        if (gui != 1){
+            printf("No results found\n");
+        }
+        else{
+            fprintf(stderr, "No results found\n");
+        }
     }
 
     sqlite3_close(db);
@@ -1437,3 +1580,19 @@ void sort_results(Result results[1000], int total){
         }
     }
 }
+
+unsigned int calculate_ehp(unsigned int hp, unsigned short def){
+    unsigned int ehp = 0;
+    ehp = ceil((((((float) def) * 3.5f) + 1140.0f) * ((float) hp)) / 1000.0f);
+    return ehp;
+}
+
+unsigned short calculate_dmg(unsigned short atk, unsigned short crr, unsigned short crd){
+    unsigned short dmg = 0;
+    float crr_capped = (float) crr;
+    if (crr_capped > 100.0f){
+        crr_capped = 100.0f;
+    }
+    dmg = ceil((((float) atk) * (100.0f - crr_capped) / 100.0f) + ((((float) atk) + (((float) atk) * ((float) crd) / 100.0f)) * crr_capped / 100.0f));
+    return dmg;
+}

+ 31 - 4
src/RuneOptimizer.h → src/RuneOptimizer/RuneOptimizer.h

@@ -54,7 +54,7 @@
 struct Unit {
     unsigned char id[12];
     unsigned char name[50];
-    unsigned short base_hp;
+    unsigned int base_hp;
     unsigned short base_atk;
     unsigned short base_def;
     unsigned short base_spd;
@@ -62,7 +62,9 @@ struct Unit {
     unsigned short base_crd;
     unsigned short base_acc;
     unsigned short base_res;
-    unsigned short current_hp;
+    unsigned int base_ehp;
+    unsigned short base_dmg;
+    unsigned int current_hp;
     unsigned short current_atk;
     unsigned short current_def;
     unsigned short current_spd;
@@ -70,6 +72,8 @@ struct Unit {
     unsigned short current_crd;
     unsigned short current_acc;
     unsigned short current_res;
+    unsigned int current_ehp;
+    unsigned short current_dmg;
 };
 
 struct Rune {
@@ -91,7 +95,7 @@ struct Rune {
 };
 
 struct Stats {
-    unsigned short hp;
+    unsigned int hp;
     unsigned short atk;
     unsigned short def;
     unsigned short spd;
@@ -99,6 +103,8 @@ struct Stats {
     unsigned short crd;
     unsigned short acc;
     unsigned short res;
+    unsigned int ehp;
+    unsigned short dmg;
 };
 
 struct Rune_Set_Count {
@@ -173,6 +179,25 @@ int open_databse();
  */
 void sort_results(Result results[1000], int total);
 
+/**
+ * Calculates efficient HP.
+ *
+ * @param hp HP stat.
+ * @param def DEF stat.
+ * @return Calculated EHP.
+ */
+unsigned int calculate_ehp(unsigned int hp, unsigned short def);
+
+/**
+ * Calculates damage.
+ *
+ * @param atk ATK stat.
+ * @param crr CRR stat.
+ * @param crd CRD stat.
+ * @return Calculated DMG.
+ */
+unsigned short calculate_dmg(unsigned short atk, unsigned short crr, unsigned short crd);
+
 /**
  * @var Stores the database error statuses.
  */
@@ -203,7 +228,9 @@ sqlite3 *db;
 #define ERROR_INPUT_NO_CRD 114
 #define ERROR_INPUT_NO_RES 115
 #define ERROR_INPUT_NO_ACC 116
-#define ERROR_INPUT_INCOMPLETE_SETS 117
+#define ERROR_INPUT_NO_EHP 117
+#define ERROR_INPUT_NO_DMG 118
+#define ERROR_INPUT_INCOMPLETE_SETS 119
 #define ERROR_DB_CANT_OPEN 200
 #define ERROR_DB_UNIT 201
 #define ERROR_DB_UNIT_NOF_FOUND 202

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1604 - 0
src/RuneOptimizerGUI/RuneOptimizer.py


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است