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