/*
* 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);
}