Просмотр исходного кода

Unit view functionality. Rune efficiencies calculated on update command. Fixed a path error in the GUI.

Iñigo Valentin 4 лет назад
Родитель
Сommit
71686d4961

+ 3 - 3
RuneOptimizerGUI/RuneOptimizer.py

@@ -55,10 +55,10 @@ for cls in classesToInclude:
 
 # The path to the RuneOptimizer executable. Different in Windows.
 executable_path = \
-  os.path.dirname(os.path.realpath(__file__)) + '/../../RuneOptimizer'
+  os.path.dirname(os.path.realpath(__file__)) + '/../RuneOptimizer'
 if os.name == 'nt':
     executable_path = \
-      os.path.dirname(os.path.realpath(__file__)) + '\..\..\RuneOptimizer.exe'
+      os.path.dirname(os.path.realpath(__file__)) + '\..\RuneOptimizer.exe'
 
 # App information
 app_info = {
@@ -110,7 +110,7 @@ if __name__ == '__main__':
 
     # Open the database
     conn = sqlite3.connect(
-      os.path.dirname(os.path.realpath(__file__)) + '/../../data.sqlite'
+      os.path.dirname(os.path.realpath(__file__)) + '/../data.sqlite'
     )
 
     # Start the GUI

+ 7 - 0
src/RuneOptimizer/RuneOptimizer.c

@@ -30,6 +30,7 @@
 #include "help/help.c"
 #include "optimize/optimize.c"
 #include "team/team.c"
+#include "unit/unit.c"
 #include "update/update.c"
 
 int main(int argc, char *argv[]){
@@ -92,6 +93,12 @@ int main(int argc, char *argv[]){
         return(cmd_team(argc - 2, argv + 2));
     }
 
+    // Unit command.
+    else if (strcmp(argv[1], "unit") == 0){
+        // Pass the rest of the arguments to the team command.
+        return(cmd_unit(argc - 2, argv + 2));
+    }
+
     // Any other command is an error
     else{
         fprintf(stderr, "Invalid command specified: %s\n", argv[1]);

+ 48 - 0
src/RuneOptimizer/RuneOptimizer.h

@@ -252,6 +252,54 @@ typedef struct Rune_Set_Count {
     unsigned short tolerance;
 } Rune_Set_Count;
 
+/**
+ * Names for rune qualities.
+ *
+ * Indexed by Com2Us ID.
+ */
+const char quality_names[][26] = {
+  "NULL",
+  "NORMAL",   "MAGIC",   "RARE",   "HERO",    "LEGEND",  // 1-5
+  "NULL",     "NULL",    "NULL",   "NULL",    "NULL",
+  "A.NORMAL", "A.MAGIC", "A.RARE", "A.HERO",  "A.LEGEND" //11-15
+};
+
+/**
+ * Names for rune stats, .
+ *
+ * Indexed by Com2Us ID.
+ */
+const char stat_names_printable[][13] = {
+  "NULL",
+  "HP  %4d  ", "HP  %4d%% ", "ATK %4d  ", "ATK %4d%% ", "DEF %4d  ", "DEF %4d%% ", // 1-6
+  "NULL",
+  "SPD %4d  ", "CRR %4d%% ", "CRD %4d%% ", "RES %4d%% ", "ACC %4d%% " // 8-12
+};
+
+/**
+ * Max roll values for each stat.
+ *
+ * Indexed by stat ID and rune stars. Works both for initial rolls and
+ * power-ups.
+ *
+ * TODO: For ancient runes, the initial rolls are higher.
+ */
+const int stat_roll_max[13][7] = {
+  {-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%
+  {-1, 4, 5, 8, 10, 15, 20}, // ATK
+  {-1, 2, 3, 5, 6, 7, 8}, // ATK%
+  {-1, 4, 5, 8, 10, 15, 20}, // DEF
+  {-1, 2, 3, 5, 6, 7, 8}, // DEF%
+  {-1, -1, -1, -1, -1, -1, -1}, // NULL (unused)
+  {-1, 1, 2, 3, 4, 5, 6}, // SPD
+  {-1, 1, 2, 3, 4, 5, 6}, // CRR
+  {-1, 2, 3, 4, 5, 5, 7}, // CRD
+  {-1, 2, 3, 4, 5, 7, 8}, // RES
+  {-1, 2, 3, 4, 5, 7, 8} // ACC
+};
+
 /**
  * Starts the program.
  *

+ 10 - 0
src/RuneOptimizer/error/error.h

@@ -185,6 +185,11 @@
  */
 #define ERROR_INPUT_TEAM_DELETE_ARGUMENT_COUNT -131
 
+/**
+ * Error indicating
+ */
+#define ERROR_INPUT_UNIT_NO_ID -132
+
 /**
  * Error indicating 
  */
@@ -369,3 +374,8 @@
  * Error indicating
  */
 #define ERROR_DB_EXECUTE_NO_PARAMETERS -236
+
+/**
+ * Error indicating
+ */
+#define ERROR_DB_RUNE_NOT_FOUND -237

+ 6 - 1
src/RuneOptimizer/help/help.c

@@ -22,7 +22,7 @@ void cmd_help(){
     printf("%s <%s>\n", AUTHOR, MAIL);
     printf("\n  Usage:\n");
     printf("  RuneOptimizer [command] [options]\n");
-    printf("\n\n  Command: helps\n");
+    printf("\n\n  Command: help\n");
     printf("\n    Display this help text and exists. It has no options.\n");
     printf("\n\n  Command: update\n");
     printf("\n    Updates the information and builds a database. Usage.\n");
@@ -38,6 +38,11 @@ void cmd_help(){
     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");

+ 0 - 1
src/RuneOptimizer/optimize/optimize.h

@@ -105,7 +105,6 @@ const char stat_names[][13] = {
   "DEF",  "NULL",    "SPD", "CRR",      "CRD", "RES",      "ACC"
 };
 
-
 /**
  * Names for rune sets.
  * 

+ 27 - 0
src/RuneOptimizer/unit/unit.c

@@ -0,0 +1,27 @@
+/*
+ * 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/>.
+ */
+
+#include "unit.h"
+#include "unit_list.c"
+
+int cmd_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]));
+}

+ 25 - 0
src/RuneOptimizer/unit/unit.h

@@ -0,0 +1,25 @@
+/*
+ * 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/>.
+ */
+
+/**
+ * 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.
+ */
+int unit_list(char *search);

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

@@ -0,0 +1,317 @@
+/*
+ * 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/>.
+ */
+
+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);
+    return(units_found);
+}

+ 1 - 0
src/RuneOptimizer/update/update.c

@@ -24,6 +24,7 @@
 #include "update_json_unit.c"
 #include "update_info.c"
 #include "update_json.c"
+#include "update_efficiency.c"
 
 /**
  * Parses the command parameters and calls one of the update functions.

+ 13 - 0
src/RuneOptimizer/update/update.h

@@ -350,6 +350,19 @@ int update_json_unit(
  */
 void update_rune_totals(struct DB_Rune *rune);
 
+/**
+ * Calculates the efficiencies of a rune in the database.
+ *
+ * It doesn't perform the update in the database.
+ *
+ * @param[in] id Rune ID.
+ * @param[out] efficiency Calculated efficiency.
+ * @param[out] efficiency Calculated maximum efficiency.
+ * @return SUCCESS, or ERROR_DB_RUNE_NOT_FOUND if the rune is not in the
+ * database.
+ */
+int update_efficiency(char *id, float *efficiency, float *max_efficiency);
+
 /**
  * Parses the command parameters and calls one of the update functions.
  *

+ 75 - 0
src/RuneOptimizer/update/update_efficiency.c

@@ -0,0 +1,75 @@
+/*
+ * 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/>.
+ */
+
+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};
+    sqlite3_stmt *stmt_rune;
+    sqlite3_stmt *stmt_stats;
+    char *parameters[1] = {id};
+    db_query(
+      &stmt_rune, "SELECT stars, level FROM runes WHERE id = ?", parameters
+    );
+    if (SQLITE_ROW != sqlite3_step(stmt_rune)) {
+        fprintf(stderr, "Rune not found: %s\n", sqlite3_errmsg(db));
+        sqlite3_finalize(stmt_rune);
+        return(ERROR_DB_RUNE_NOT_FOUND);
+    }
+    int stars = sqlite3_column_int(stmt_rune, 0);
+    int level = sqlite3_column_int(stmt_rune, 1);
+    db_query(
+      &stmt_stats,
+      "SELECT slot, stat, value FROM rune_stats WHERE rune = ? AND slot != -1",
+      parameters
+    );
+
+    // Calculate efficiency for each slot.
+    // Main slot is excluded from the calculation.
+    int slot = -1;
+    int stat = -1;
+    int value = -1;
+    int max_roll_value = -1;
+    while (SQLITE_ROW == sqlite3_step(stmt_stats)){
+        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];
+        eff[slot] += (((float) value) / ((float) max_roll_value));
+    }
+    sqlite3_finalize(stmt_stats);
+    sqlite3_finalize(stmt_rune);
+
+    // Sum  each slot efficiency.
+    // Each roll contributes only 1/9 to the total efficiency.
+    for (int i = 0; i < 5; i ++){
+        eff[i] = eff[i] / 9.0f;
+        *efficiency += eff[i];
+    }
+
+    // Calculate max efficiency. For each power up remaining, add 1/9.
+    *max_efficiency = *efficiency;
+    if (level < 12) *max_efficiency += (1.0f / 9.0f);
+    if (level < 9) *max_efficiency += (1.0f / 9.0f);
+    if (level < 6) *max_efficiency += (1.0f / 9.0f);
+    if (level < 3) *max_efficiency += (1.0f / 9.0f);
+
+    // Multiply by 100 to get a percent value
+    *efficiency *= 100.0f;
+    *max_efficiency *= 100.0f;
+    return(SUCCESS);
+}

+ 31 - 3
src/RuneOptimizer/update/update_json_rune.c

@@ -28,12 +28,14 @@ int update_json_rune(json_object *rune_json, char *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 (rank)
-    json_object *rank = json_object_object_get(rune_json, "rank");
-    rune.quality = json_object_get_int(rank);
+    // 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);
@@ -231,5 +233,31 @@ int update_json_rune(json_object *rune_json, char *unit_id){
         }
 
     }
+
+    // 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);
+    printf("CALCULATED EFF: %f\n", efficiency);
+    //char eff_c[7];
+    //char max_eff_c[7];
+    //sprintf(eff_c, "%6.2f", efficiency);
+    //sprintf(max_eff_c, "%6.2f", 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 - 1
src/RuneOptimizer/update/update_rune_totals.c

@@ -51,7 +51,6 @@ void update_rune_totals(struct DB_Rune *rune){
     rune->current_acc = 0;
     rune->lv12_acc = 0;
     rune->lv15_acc = 0;
-    // TODO: Calculate efficiencies
     switch (rune->main.stat){
         case HP_FLAT:
             rune->current_hp_flat += rune->main.value;