| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439 |
- /*
- * 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 <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sqlite3.h>
- #include "RuneOptimizer.h"
- /**
- * Starts the program.
- *
- * Reads parameters and runs the appropiate functions.
- *
- * @param argc Argument count.
- * @param argv Argument list.
- * @return SUCCESS on success, other on error.
- */
- int main(int argc, char *argv[]){
- // Parse the arguments to find the command (index 1)
- // If no arguments, end here
- if (argc < 2){
- fprintf(stderr, "No command specified\n");
- return ERROR_INPUT_NO_COMMAND;
- }
- // Update command, TODO
- if (strcmp(argv[1], "update") == 0){
- fprintf(stderr, "Updating is still unimplemented\n");
- return UNIMPLEMENTED;
- }
- // Optimize command, call the function with all the arguments to be
- // processed there.
- else if (strcmp(argv[1], "optimize") == 0){
- int result = optimize(argc, argv);
- return result;
- }
- // Help command. Call and return
- else if (strcmp(argv[1], "help") == 0){
- show_help();
- return SUCCESS;
- }
- // Any other command is an error
- else{
- fprintf(stderr, "Invalid command specified: %s\n", argv[1]);
- return ERROR_INPUT_INVALID_COMMAND;
- }
- }
- int open_database(){
- // The database location and name is hardcoded in the same directory.
- int db_status = sqlite3_open("../data.sqlite", &db);
- if (db_status != SQLITE_OK) {
- fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
- sqlite3_close(db);
- return ERROR_DB_CANT_OPEN;
- }
- else{
- return SUCCESS;
- }
- }
- void show_help(){
- printf("\nRune Optimizer v0.1\n");
- printf("\n Usage:\n");
- printf(" RuneOptimizer [command] [options]\n");
- printf("\n\n Command: helps\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. Currently unimplemented.\n");
- printf("\n\n Command: optimize\n");
- printf("\n Calculates an optimization for a unit.\n");
- printf("\n Usage\n");
- printf(" RuneOptimizer optmize [unit] [options]\n");
- printf("\n [unit] can be a unit ID or a unit name (case sensitive)\n");
- printf("\n Options: \n\n");
- printf(" -h | --min_hp <NUM> Minumum HP to consider in the optimization.\n");
- printf(" It defaults to the unit's current value.\n");
- printf(" -a | --min_atk <NUM> Minumum ATK to consider in the optimization.\n");
- printf(" It defaults to the unit's current value.\n");
- printf(" -d | --min_def <NUM> Minumum DEF to consider in the optimization.\n");
- printf(" It defaults to the unit's current value.\n");
- printf(" -s | --min_spd <NUM> Minumum SPD to consider in the optimization.\n");
- printf(" It defaults to the unit's current value.\n");
- printf(" -c | --min_crr <NUM> Minumum CRIT RATE to consider in the optimization.\n");
- printf(" It defaults to the unit's current value.\n");
- printf(" -d | --min_crd <NUM> Minumum CRIT DAMAGE to consider in the optimization.\n");
- printf(" It defaults to the unit's current value.\n");
- printf(" -r | --min_res <NUM> Minumum RES to consider in the optimization.\n");
- 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(" -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");
- printf(" -t | --stats <ST1>,<ST2>... Stats than can be selected as mains for slots 2, 4 and 6.\n");
- printf(" Only the selected stats will be included, so this option\n");
- printf(" is mandatory. Accepted values are 'hp', 'atk', 'def',\n");
- printf(" 'hpflat', 'atkflat', 'defflat', 'spd', 'crr', 'crd',\n");
- printf(" 'res' and 'acc'. Values must be comma-separated, and up\n");
- printf(" to 12 can be included.\n");
- printf(" -e | --sets <S1>,<S2>... Rune sets that than can be considered during the optimization.\n");
- printf(" Only the selected sets will be included, so this option is\n");
- printf(" mandatory. Accepted values the rune net names, lowercase.\n");
- printf(" Values must be comma-separated, and up to 3 can be included.\n");
- return;
- }
- int optimize(int argc, char *argv[]){
- // Get unit identifier
- if (argc < 3){
- fprintf(stderr, "No unit specified for optimization\n");
- return ERROR_INPUT_NO_UNIT;
- }
- // Initialize values for the data to be read form arguments.
- int requested_level = 0;
- char requested_level_column[9] = "current_";
- int sets[3] = {0, 0, 0};
- int requested_stats[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- struct Stats min_stats;
- // Unsigned, so I cant use -1 as placeholder to check if its modified from
- // arguments. I'm using just 1 (I don't think anybody will input values of
- // 1), and later, if they are still 1, they are changed to 0.
- min_stats.hp = 1;
- min_stats.atk = 1;
- min_stats.def = 1;
- min_stats.spd = 1;
- min_stats.crr = 1;
- min_stats.crd = 1;
- min_stats.res = 1;
- min_stats.acc = 1;
- // Loop command line arguments
- for (int i = 3; i < argc; i ++){
- // Rune level arguments
- if (strcmp("--level", argv[i]) == 0 || strcmp("-l", argv[i]) == 0){
- if (i < argc - 1){
- if (strcmp("current", argv[i + 1]) == 0){
- requested_level = 0;
- strcpy(requested_level_column, "current_");
- }
- else if (strcmp("12", argv[i + 1]) == 0){
- requested_level = 12;
- strcpy(requested_level_column, "lv12_");
- }
- else if (strcmp("15", argv[i + 1]) == 0){
- requested_level = 15;
- strcpy(requested_level_column, "lv15_");
- }
- else{
- fprintf(
- stderr,
- "Invalid option for argument %s: %s\n"
- "Valid options are 'current', '12' or '15'\n",
- argv[i], argv[i + 1]
- );
- return ERROR_INPUT_INVALID_LEVEL;
- }
- // Advance one position in argument reading
- i ++;
- }
- else{
- fprintf(
- stderr,
- "Argument %s requires a value.\n"
- "Valid options are 'current', '12' or '15'\n", argv[i]
- );
- return ERROR_INPUT_NO_LEVEL;
- }
- }
- // Rune sets argument
- else if (strcmp("--sets", argv[i]) == 0 || strcmp("-e", argv[i]) == 0){
- if (i < argc - 1){
- // Separate string by commas
- int j = 0;
- // Returns first token
- char *token = strtok(argv[i + 1], ",");
- // Keep printing tokens while one of the
- // delimiters present in the list, or until its complete
- while (token != NULL && j < 3){
- if (strcmp(token, "energy") == 0){
- sets[j] = ENERGY;
- }
- else if (strcmp(token, "guard") == 0){
- sets[j] = GUARD;
- }
- else if (strcmp(token, "swift") == 0){
- sets[j] = SWIFT;
- }
- else if (strcmp(token, "blade") == 0){
- sets[j] = BLADE;
- }
- else if (strcmp(token, "rage") == 0){
- sets[j] = RAGE;
- }
- else if (strcmp(token, "focus") == 0){
- sets[j] = FOCUS;
- }
- else if (strcmp(token, "endure") == 0){
- sets[j] = ENDURE;
- }
- else if (strcmp(token, "fatal") == 0){
- sets[j] = FATAL;
- }
- else if (strcmp(token, "despair") == 0){
- sets[j] = DESPAIR;
- }
- else if (strcmp(token, "vampire") == 0){
- sets[j] = VAMPIRE;
- }
- else if (strcmp(token, "violent") == 0){
- sets[j] = VIOLENT;
- }
- else if (strcmp(token, "nemesis") == 0){
- sets[j] = NEMESIS;
- }
- else if (strcmp(token, "will") == 0){
- sets[j] = WILL;
- }
- else if (strcmp(token, "shield") == 0){
- sets[j] = SHIELD;
- }
- else if (strcmp(token, "revenge") == 0){
- sets[j] = REVENGE;
- }
- else if (strcmp(token, "destroy") == 0){
- sets[j] = DESTROY;
- }
- else if (strcmp(token, "fight") == 0){
- sets[j] = FIGHT;
- }
- else if (strcmp(token, "determination") == 0){
- sets[j] = DETERMINATION;
- }
- else if (strcmp(token, "enhance") == 0){
- sets[j] = ENHANCE;
- }
- else if (strcmp(token, "accuracy") == 0){
- sets[j] = ACCURACY;
- }
- else if (strcmp(token, "tolerance") == 0){
- sets[j] = TOLERANCE;
- }
- else{
- fprintf(stderr, "Unknown rune set %s.\n", token);
- return ERROR_INPUT_INVALID_SET;
- }
- token = strtok(NULL, ",");
- j ++;
- }
- // Advance one position in argument reading
- i ++;
- }
- else{
- fprintf(
- stderr,
- "Argument %s requires a list of values separated by commas.\n",
- argv[i]
- );
- return ERROR_INPUT_NO_SET;
- }
- }
- // Accepted stats arguments
- else if (strcmp("--stats", argv[i]) == 0 || strcmp("-t", argv[i]) == 0){
- if (i < argc - 1){
- // Separate string by commas
- int j = 0;
- // Returns first token
- char *token = strtok(argv[i + 1], ",");
- // Keep printing tokens while one of the
- // delimiters present in the list, or until its complete
- while (token != NULL && j < 3){
- if (strcmp(token, "hp") == 0){
- requested_stats[j] = HP_PERCENT;
- }
- else if (strcmp(token, "atk") == 0){
- requested_stats[j] = ATK_PERCENT;
- }
- else if (strcmp(token, "def") == 0){
- requested_stats[j] = DEF_PERCENT;
- }
- else if (strcmp(token, "hpflat") == 0){
- requested_stats[j] = HP_FLAT;
- }
- else if (strcmp(token, "atkflat") == 0){
- requested_stats[j] = ATK_FLAT;
- }
- else if (strcmp(token, "defflat") == 0){
- requested_stats[j] = DEF_FLAT;
- }
- else if (strcmp(token, "spd") == 0){
- requested_stats[j] = SPD;
- }
- else if (strcmp(token, "crr") == 0){
- requested_stats[j] = CRR;
- }
- else if (strcmp(token, "crd") == 0){
- requested_stats[j] = CRD;
- }
- else if (strcmp(token, "res") == 0){
- requested_stats[j] = RES;
- }
- else if (strcmp(token, "acc") == 0){
- requested_stats[j] = ACC;
- }
- else{
- fprintf(stderr, "Unknown rune stat %s.\n", token);
- return ERROR_INPUT_INVALID_STAT;
- }
- token = strtok(NULL, ",");
- j ++;
- }
- // Advance one position in argument reading
- i ++;
- }
- else{
- fprintf(stderr, "Argument %s requires a list of values separated by commas.\n", argv[i]);
- return ERROR_INPUT_NO_STAT;
- }
- }
- // Minimum stats arguments.
- else if (strcmp("--min-hp", argv[i]) == 0 || strcmp("-h", argv[i]) == 0){
- if (i < argc - 1){
- unsigned short stat_tmp = atoi(argv[i + 1]);
- if (stat_tmp == 1){
- stat_tmp = 0;
- }
- min_stats.hp = 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_HP;
- }
- }
- else if (strcmp("--min-atk", argv[i]) == 0 || strcmp("-a", argv[i]) == 0){
- if (i < argc - 1){
- unsigned short stat_tmp = atoi(argv[i + 1]);
- if (stat_tmp == 1){
- stat_tmp = 0;
- }
- min_stats.atk = 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_ATK;
- }
- }
- else if (strcmp("--min-def", argv[i]) == 0 || strcmp("-d", argv[i]) == 0){
- if (i < argc - 1){
- unsigned short stat_tmp = atoi(argv[i + 1]);
- if (stat_tmp == 1){
- stat_tmp = 0;
- }
- min_stats.def = 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_DEF;
- }
- }
- else if (strcmp("--min-spd", argv[i]) == 0 || strcmp("-s", argv[i]) == 0){
- if (i < argc - 1){
- unsigned short stat_tmp = atoi(argv[i + 1]);
- if (stat_tmp == 1){
- stat_tmp = 0;
- }
- min_stats.spd = 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_SPD;
- }
- }
- else if (strcmp("--min-crr", argv[i]) == 0 || strcmp("-c", argv[i]) == 0){
- if (i < argc - 1){
- unsigned short stat_tmp = atoi(argv[i + 1]);
- if (stat_tmp == 1){
- stat_tmp = 0;
- }
- else if (stat_tmp > 100){
- stat_tmp = 100;
- }
- min_stats.crr = 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_CRR;
- }
- }
- else if (strcmp("--min-crd", argv[i]) == 0 || strcmp("-d", argv[i]) == 0){
- if (i < argc - 1){
- unsigned short stat_tmp = atoi(argv[i + 1]);
- if (stat_tmp == 1){
- stat_tmp = 0;
- }
- min_stats.crd = 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_CRD;
- }
- }
- else if (strcmp("--min-res", argv[i]) == 0 || strcmp("-r", argv[i]) == 0){
- if (i < argc - 1){
- unsigned short stat_tmp = atoi(argv[i + 1]);
- if (stat_tmp == 1){
- stat_tmp = 0;
- }
- else if (stat_tmp > 100){
- stat_tmp = 100;
- }
- min_stats.atk = 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_RES;
- }
- }
- else if (strcmp("--min-acc", argv[i]) == 0 || strcmp("-f", argv[i]) == 0){
- if (i < argc - 1){
- unsigned short stat_tmp = atoi(argv[i + 1]);
- if (stat_tmp == 1){
- stat_tmp = 0;
- }
- else if (stat_tmp > 85){
- stat_tmp = 85;
- }
- min_stats.acc = 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_ACC;
- }
- }
- }
- // Now we can open the database.
- if (SUCCESS != open_database()){
- return ERROR_DB_CANT_OPEN;
- }
- // Read the unit from the databse
- sqlite3_stmt *res;
- char *sql = "SELECT "
- "id, name, base_hp, base_atk, base_def, base_spd, base_crr, base_crd, "
- "base_res, base_acc, current_hp, current_atk, current_def, current_spd, "
- "current_crr, current_crd, current_res, current_acc "
- "FROM units WHERE id = ? OR name = ?";
- db_status = sqlite3_prepare_v2(db, sql, -1, &res, 0);
- if (db_status != SQLITE_OK) {
- fprintf(
- stderr,
- "Failed to execute statement to select unit: %s\n",
- sqlite3_errmsg(db)
- );
- return ERROR_DB_UNIT;
- }
- sqlite3_bind_text(res, 1, argv[2], strlen(argv[2]), NULL);
- sqlite3_bind_text(res, 2, argv[2], strlen(argv[2]), NULL);
- // Fetch just one line
- int step = sqlite3_step(res);
- // Create a unit structure with the red data.
- struct Unit unit;
- if (step != SQLITE_ROW) {
- fprintf(stderr, "Unit not found: %s\n", sqlite3_errmsg(db));
- return ERROR_DB_UNIT_NOF_FOUND;
- }
- strcpy(unit.id, sqlite3_column_text(res, 0));
- strcpy(unit.name, sqlite3_column_text(res, 1));
- unit.base_hp = sqlite3_column_int(res, 2);
- unit.base_atk = sqlite3_column_int(res, 3);
- unit.base_def = sqlite3_column_int(res, 4);
- unit.base_spd = sqlite3_column_int(res, 5);
- unit.base_crr = sqlite3_column_int(res, 6);
- unit.base_crd = sqlite3_column_int(res, 7);
- unit.base_res = sqlite3_column_int(res, 8);
- unit.base_acc = sqlite3_column_int(res, 9);
- unit.current_hp = sqlite3_column_int(res, 10);
- unit.current_atk = sqlite3_column_int(res, 11);
- unit.current_def = sqlite3_column_int(res, 12);
- unit.current_spd = sqlite3_column_int(res, 13);
- unit.current_crr = sqlite3_column_int(res, 14);
- unit.current_crd = sqlite3_column_int(res, 15);
- unit.current_res = sqlite3_column_int(res, 16);
- unit.current_acc = sqlite3_column_int(res, 17);
- // Min stats that have the value 1 get overriden by the current stats.
- if (min_stats.hp == 1){
- min_stats.hp = unit.current_hp;
- }
- if (min_stats.atk == 1){
- min_stats.atk = unit.current_atk;
- }
- if (min_stats.def == 1){
- min_stats.def = unit.current_def;
- }
- if (min_stats.spd == 1){
- min_stats.spd = unit.current_spd;
- }
- if (min_stats.crr == 1){
- min_stats.crr = unit.current_crr;
- }
- if (min_stats.crd == 1){
- min_stats.crd = unit.current_crd;
- }
- if (min_stats.res == 1){
- min_stats.res = unit.current_res;
- }
- if (min_stats.acc == 1){
- min_stats.acc = unit.current_acc;
- }
- // Calculate required rune count
- struct Rune_Set_Count requested_set_count;
- requested_set_count.energy = 0;
- requested_set_count.guard = 0;
- requested_set_count.swift = 0;
- requested_set_count.blade = 0;
- requested_set_count.rage = 0;
- requested_set_count.focus = 0;
- requested_set_count.endure = 0;
- requested_set_count.fatal = 0;
- requested_set_count.despair = 0;
- requested_set_count.vampire = 0;
- requested_set_count.violent = 0;
- requested_set_count.nemesis = 0;
- requested_set_count.will = 0;
- requested_set_count.shield = 0;
- requested_set_count.revenge = 0;
- requested_set_count.destroy = 0;
- requested_set_count.fight = 0;
- requested_set_count.determination = 0;
- requested_set_count.enhance = 0;
- requested_set_count.accuracy = 0;
- requested_set_count.tolerance = 0;
- char total_requested_runes = 0;
- for (int i = 0; i < 3; i ++){
- switch (sets[i]){
- case ENERGY:
- requested_set_count.energy += 2;
- total_requested_runes += 2;
- break;
- case GUARD:
- requested_set_count.guard += 2;
- total_requested_runes += 2;
- break;
- case SWIFT:
- requested_set_count.swift += 4;
- total_requested_runes += 4;
- break;
- case BLADE:
- requested_set_count.blade += 2;
- total_requested_runes += 2;
- break;
- case RAGE:
- requested_set_count.rage += 4;
- total_requested_runes += 4;
- break;
- case FOCUS:
- requested_set_count.focus += 2;
- total_requested_runes += 2;
- break;
- case ENDURE:
- requested_set_count.endure += 2;
- total_requested_runes += 2;
- break;
- case FATAL:
- requested_set_count.fatal += 4;
- total_requested_runes += 4;
- break;
- case DESPAIR:
- requested_set_count.despair += 2;
- total_requested_runes += 2;
- break;
- case VAMPIRE:
- requested_set_count.vampire += 4;
- total_requested_runes += 4;
- break;
- case VIOLENT:
- requested_set_count.violent += 4;
- total_requested_runes += 4;
- break;
- case NEMESIS:
- requested_set_count.nemesis += 2;
- total_requested_runes += 2;
- break;
- case WILL:
- requested_set_count.will += 2;
- total_requested_runes += 2;
- break;
- case SHIELD:
- requested_set_count.shield += 2;
- total_requested_runes += 2;
- break;
- case REVENGE:
- requested_set_count.revenge += 2;
- total_requested_runes += 2;
- break;
- case DESTROY:
- requested_set_count.destroy += 2;
- total_requested_runes += 2;
- break;
- case FIGHT:
- requested_set_count.fight += 2;
- total_requested_runes += 2;
- break;
- case DETERMINATION:
- requested_set_count.determination += 2;
- total_requested_runes += 2;
- break;
- case ENHANCE:
- requested_set_count.enhance += 2;
- total_requested_runes += 2;
- break;
- case ACCURACY:
- requested_set_count.accuracy += 2;
- total_requested_runes += 2;
- break;
- case TOLERANCE:
- requested_set_count.tolerance += 2;
- total_requested_runes += 2;
- break;
- }
- }
- printf("\n");
- if (total_requested_runes != 6){
- fprintf(stderr, "Invalid rune set combination.\n");
- return ERROR_INPUT_INCOMPLETE_SETS;
- }
- // Create queries for each slot
- char query_odd[2500] = "SELECT id, unit, type, ";
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "hp_flat, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "atk_flat, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "def_flat, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "hp_percent, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "atk_percent, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "def_percent, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "spd, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "crr, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "crd, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "res, ");
- strcat(query_odd, requested_level_column);
- strcat(query_odd, "acc FROM runes WHERE slot = ? AND type IN (");
- char cur_set[2];
- char stat_set[2];
- if (sets[0] != 0){
- sprintf(cur_set, "%d", sets[0]);
- strcat(query_odd, cur_set);
- strcat(query_odd, ", ");
- }
- if (sets[1] != 0){
- sprintf(cur_set, "%d", sets[1]);
- strcat(query_odd, cur_set);
- strcat(query_odd, ", ");
- }
- if (sets[2] != 0){
- sprintf(cur_set, "%d", sets[2]);
- strcat(query_odd, cur_set);
- strcat(query_odd, ", ");
- }
- strcat(query_odd, "-1) ");
- // TODO: Add team stuff
- char query_even[1500] = "SELECT id, unit, type, ";
- strcat(query_even, requested_level_column);
- strcat(query_even, "hp_flat, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "atk_flat, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "def_flat, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "hp_percent, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "atk_percent, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "def_percent, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "spd, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "crr, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "crd, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "res, ");
- strcat(query_even, requested_level_column);
- strcat(query_even, "acc FROM runes WHERE slot = ? AND type IN (");
- if (sets[0] != 0){
- sprintf(cur_set, "%d", sets[0]);
- strcat(query_even, cur_set);
- strcat(query_even, ", ");
- }
- if (sets[1] != 0){
- sprintf(cur_set, "%d", sets[1]);
- strcat(query_even, cur_set);
- strcat(query_even, ", ");
- }
- if (sets[2] != 0){
- sprintf(cur_set, "%d", sets[2]);
- strcat(query_even, cur_set);
- strcat(query_even, ", ");
- }
- strcat(query_even, "-1) AND main_stat IN (");
- for (int i = 0; i < 12; i ++){
- if (requested_stats[i] != 0){
- sprintf(stat_set, "%d", requested_stats[i]);
- strcat(query_even, stat_set);
- strcat(query_even, ", ");
- }
- else{
- break;
- }
- }
- strcat(query_even, "-1) ");
- // TODO: Add team stuff
- // Get data for all the runes from the database.
- // Im using a 7 position array, and the index 0 is ignored. This is
- // is because I REALLY NEED to use 1-indexes to match rune slots.
- sqlite3_stmt *stmt_runes[7];
- // Im assumming 600 runes per slot is a safe estimate. I hope it doesn't
- // come back to bite me.
- struct Rune runes[7][600];
- db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[1], 0);
- if (db_status != SQLITE_OK) {
- printf("Error getting runes for slot 1: %s\n", sqlite3_errmsg(db));
- return ERROR_DB_RUNES_SLOT;
- }
- sqlite3_bind_int(stmt_runes[1], 1, 1);
- db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[3], 0);
- if (db_status != SQLITE_OK) {
- printf("Error getting runes for slot 3: %s\n", sqlite3_errmsg(db));
- return ERROR_DB_RUNES_SLOT;
- }
- sqlite3_bind_int(stmt_runes[3], 1, 3);
- db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[5], 0);
- if (db_status != SQLITE_OK) {
- printf("Error getting runes for slot 5: %s\n", sqlite3_errmsg(db));
- return ERROR_DB_RUNES_SLOT;
- }
- sqlite3_bind_int(stmt_runes[5], 1, 5);
- db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[2], 0);
- if (db_status != SQLITE_OK) {
- printf("Error getting runes for slot 2: %s\n", sqlite3_errmsg(db));
- return ERROR_DB_RUNES_SLOT;
- }
- sqlite3_bind_int(stmt_runes[2], 1, 2);
- db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[4], 0);
- if (db_status != SQLITE_OK) {
- printf("Error getting runes for slot 4: %s\n", sqlite3_errmsg(db));
- return ERROR_DB_RUNES_SLOT;
- }
- sqlite3_bind_int(stmt_runes[4], 1, 4);
- db_status = sqlite3_prepare_v2(db, query_odd, -1, &stmt_runes[6], 0);
- if (db_status != SQLITE_OK) {
- printf("Error getting runes for slot 6: %s\n", sqlite3_errmsg(db));
- return ERROR_DB_RUNES_SLOT;
- }
- sqlite3_bind_int(stmt_runes[6], 1, 6);
- // Get and populate all the runes
- int rune_count[7];
- for (int i = 1; i < 7; i ++){
- int j = 0;
- while (1 == 1){
- int status = sqlite3_step(stmt_runes[i]);
- if (status == SQLITE_ROW){
- strcpy(runes[i][j].id, sqlite3_column_text(stmt_runes[i], 0));
- strcpy(runes[i][j].unit, sqlite3_column_text(stmt_runes[i], 1));
- runes[i][j].set = sqlite3_column_int(stmt_runes[i], 2);
- runes[i][j].hp_flat = sqlite3_column_int(stmt_runes[i], 3);
- runes[i][j].atk_flat = sqlite3_column_int(stmt_runes[i], 4);
- runes[i][j].def_flat = sqlite3_column_int(stmt_runes[i], 5);
- runes[i][j].hp_percent = sqlite3_column_int(stmt_runes[i], 6);
- runes[i][j].atk_percent = sqlite3_column_int(stmt_runes[i], 7);
- runes[i][j].def_percent = sqlite3_column_int(stmt_runes[i], 8);
- runes[i][j].spd = sqlite3_column_int(stmt_runes[i], 9);
- runes[i][j].crr = sqlite3_column_int(stmt_runes[i], 10);
- runes[i][j].crd = sqlite3_column_int(stmt_runes[i], 11);
- runes[i][j].res = sqlite3_column_int(stmt_runes[i], 12);
- runes[i][j].acc = sqlite3_column_int(stmt_runes[i], 13);
- j ++;
- }
- else{
- break;
- }
- }
- rune_count[i] = j;
- }
- // If any slot doesn't have matching runes, we can stop now.
- for (int i = 1; i < 7; i ++){
- if (rune_count[i] == 0){
- printf("\n - No availbale runes for slot %d\n", i);
- return SUCCESS;
- }
- }
- printf("\n");
- unsigned long max_combinations =
- rune_count[1] *
- rune_count[2] *
- rune_count[3] *
- rune_count[4] *
- rune_count[5] *
- rune_count[6];
- // Print a nice summary before starting the long optimization.
- // This is an output example:
- //
- // ----------------------------------- Requested rune sets:
- // | Lushen | RAGE BLADE
- // | ID: 7223811472 |
- // ----------------------------------- Accepted stats:
- // | STAT | BASE | CURR. | MIN. | ATK CRR CRD
- // -----------------------------------
- // | HP: | 9225 | 12262 | 10000 | Considering runes at level 15
- // | ATK: | 900 | 2482 | 2482 |
- // | DEF: | 461 | 703 | 703 | Runes considered by slot:
- // | SPD: | 103 | 159 | 159 | 1: 27 2: 39 3: 25
- // | CRR: | 15% | 79% | 79% | 4: 35 5: 24 6: 32
- // | CRD: | 50% | 188% | 188% |
- // | RES: | 15% | 35% | 35% | Total combinations: 707616000
- // | ACC: | 0% | 11% | 10% |
- // -----------------------------------
- //
- // Im breaking the 80-characters-line rule here, but only 'cause I'd like
- // to remain sane.
- printf(" ----------------------------------- Requested rune sets:\n");
- printf(" | %*s | ", -31, unit.name);
- for (int i = 0; i < 3; i ++){
- if (sets[i] != 0){
- printf(" %s ", set_names[sets[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]]);
- }
- else{
- break;
- }
- }
- 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);
- // Initialize arrys and some counters
- int index[7] = {0, 0, 0, 0, 0, 0};
- unsigned long tested_combinations = 0;
- unsigned long valid_sets = 0;
- unsigned long result_count = 0;
- Result results[1000];
- while(
- index[1] < rune_count[1] &&
- index[2] < rune_count[2] &&
- index[3] < rune_count[3] &&
- index[4] < rune_count[4] &&
- index[5] < rune_count[5] &&
- index[6] < rune_count[6]
- ){
- // Progress bar, 50 characters to 100%
- if (
- (tested_combinations + 1) %
- (unsigned long)(max_combinations / 50)
- == 0
- ){
- printf("#");
- // Line buffered! need to flush after every char.
- fflush(stdout);
- }
- // Calculate rune sets at current indexes.
- struct Rune_Set_Count set_count;
- set_count.energy = 0;
- set_count.guard = 0;
- set_count.swift = 0;
- set_count.blade = 0;
- set_count.rage = 0;
- set_count.focus = 0;
- set_count.endure = 0;
- set_count.fatal = 0;
- set_count.despair = 0;
- set_count.vampire = 0;
- set_count.violent = 0;
- set_count.nemesis = 0;
- set_count.will = 0;
- set_count.shield = 0;
- set_count.revenge = 0;
- set_count.destroy = 0;
- set_count.fight = 0;
- set_count.determination = 0;
- set_count.enhance = 0;
- set_count.accuracy = 0;
- set_count.tolerance = 0;
- for (int i = 1; i < 7; i ++){
- switch (runes[i][index[i]].set){
- case ENERGY:
- set_count.energy ++;
- break;
- case GUARD:
- set_count.guard ++;
- break;
- case SWIFT:
- set_count.swift ++;
- break;
- case BLADE:
- set_count.blade ++;
- break;
- case RAGE:
- set_count.rage ++;
- break;
- case FOCUS:
- set_count.focus ++;
- break;
- case ENDURE:
- set_count.endure ++;
- break;
- case FATAL:
- set_count.fatal ++;
- break;
- case DESPAIR:
- set_count.despair ++;
- break;
- case VAMPIRE:
- set_count.vampire ++;
- break;
- case VIOLENT:
- set_count.violent ++;
- break;
- case NEMESIS:
- set_count.nemesis ++;
- break;
- case WILL:
- set_count.will ++;
- break;
- case SHIELD:
- set_count.shield ++;
- break;
- case REVENGE:
- set_count.revenge ++;
- break;
- case DESTROY:
- set_count.destroy ++;
- break;
- case FIGHT:
- set_count.fight ++;
- break;
- case DETERMINATION:
- set_count.determination ++;
- break;
- case ENHANCE:
- set_count.enhance ++;
- break;
- case ACCURACY:
- set_count.accuracy ++;
- break;
- case TOLERANCE:
- set_count.tolerance ++;
- break;
- }
- }
- // Compare with requested sets
- if (
- set_count.energy >= requested_set_count.energy &&
- set_count.guard >= requested_set_count.guard &&
- set_count.swift >= requested_set_count.swift &&
- set_count.blade >= requested_set_count.blade &&
- set_count.rage >= requested_set_count.rage &&
- set_count.focus >= requested_set_count.focus &&
- set_count.endure >= requested_set_count.endure &&
- set_count.fatal >= requested_set_count.fatal &&
- set_count.despair >= requested_set_count.despair &&
- set_count.vampire >= requested_set_count.vampire &&
- set_count.violent >= requested_set_count.violent &&
- set_count.nemesis >= requested_set_count.nemesis &&
- set_count.will >= requested_set_count.will &&
- set_count.shield >= requested_set_count.shield &&
- set_count.revenge >= requested_set_count.revenge &&
- set_count.destroy >= requested_set_count.destroy &&
- set_count.fight >= requested_set_count.fight &&
- set_count.determination >= requested_set_count.determination &&
- set_count.enhance >= requested_set_count.enhance &&
- set_count.accuracy >= requested_set_count.accuracy &&
- set_count.tolerance >= requested_set_count.tolerance
- ){
- // The current runes form a valid set.
- valid_sets ++;
- // Calculate new stats
- struct Stats stats;
- stats.hp = unit.base_hp;
- stats.atk = unit.base_atk;
- stats.def = unit.base_def;
- stats.spd = unit.base_spd;
- stats.crr = unit.base_crr;
- stats.crd = unit.base_crd;
- stats.res = unit.base_res;
- stats.acc = unit.base_acc;
- for (int i = 1; i < 7; i ++){
- stats.hp += runes[i][index[i]].hp_flat;
- stats.atk += runes[i][index[i]].atk_flat;
- stats.def += runes[i][index[i]].def_flat;
- stats.hp += unit.base_hp * runes[i][index[i]].hp_percent / 100;
- stats.atk +=
- unit.base_hp * runes[i][index[i]].atk_percent / 100;
- stats.def +=
- unit.base_hp * runes[i][index[i]].def_percent / 100;
- stats.spd += runes[i][index[i]].spd;
- stats.crr += runes[i][index[i]].crr;
- stats.crd += runes[i][index[i]].crd;
- stats.res += runes[i][index[i]].res;
- stats.acc += runes[i][index[i]].acc;
- }
- // Compare with minimum requeriments
- if (
- stats.hp >= min_stats.hp &&
- stats.atk >= min_stats.atk &&
- stats.def >= min_stats.def &&
- stats.spd >= min_stats.spd &&
- stats.crr >= min_stats.crr &&
- stats.crd >= min_stats.crd &&
- stats.res >= min_stats.res &&
- stats.acc >= min_stats.acc
- ){
- // This is a valid sets and all stats are above the minimum.
- // Create a result with rune indexes, stats, and rating.
- for (int i = 1; i < 7; i ++){
- strcpy(
- results[result_count].rune_ids[i - 1],
- runes[i][index[i]].id
- );
- }
- results[result_count].stats.hp = stats.hp;
- results[result_count].stats.atk = stats.atk;
- results[result_count].stats.def = stats.def;
- results[result_count].stats.spd = stats.spd;
- results[result_count].stats.crr = stats.crr;
- results[result_count].stats.crd = stats.crd;
- results[result_count].stats.res = stats.res;
- results[result_count].stats.acc = stats.acc;
- // One rating point per stat increase over current stats.
- // Save for HP, with takes 15 for a raing point
- results[result_count].rating = 0;
- results[result_count].rating += ((stats.hp - unit.current_hp) / 15);
- results[result_count].rating += (stats.atk - unit.current_atk);
- results[result_count].rating += (stats.def - unit.current_def);
- results[result_count].rating += (stats.spd - unit.current_spd);
- results[result_count].rating += (stats.crr - unit.current_crr);
- results[result_count].rating += (stats.crd - unit.current_crd);
- results[result_count].rating += (stats.res - unit.current_res);
- results[result_count].rating += (stats.acc - unit.current_acc);
- result_count ++;
- }
- }
- // Loop control. Rotate the reels 'right to left'
- tested_combinations ++;
- index[6] ++;
- if (index[6] == rune_count[6]){
- index[6] = 0;
- index[5] ++;
- }
- if (index[5] == rune_count[5]){
- index[5] = 0;
- index[4] ++;
- }
- if (index[4] == rune_count[4]){
- index[4] = 0;
- index[3] ++;
- }
- if (index[3] == rune_count[3]){
- index[3] = 0;
- index[2] ++;
- }
- if (index[2] == rune_count[2]){
- index[2] = 0;
- index[1] ++;
- }
- //DEBUG: force exit with some results TODO
- //if (result_count > 1){
- // break;
- //}
- }
- printf("\n");
- if (result_count > 0){
- // Yay! Some combinations matched te criteria.
- printf("\n\n%d results found\n", result_count);
- // Sort results
- sort_results(results, result_count);
- // 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;
- }
- 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], "|");
- }
- // 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);
- }
- 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;
- }
- 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{
- printf("No results found\n");
- }
- sqlite3_close(db);
- return SUCCESS;
- }
- void sort_results(Result results[1000], int total){
- // Bubble sort, by descending rating.
- int i, j;
- Result temp;
- for (i = 0; i < total - 1; i++)
- {
- for (j = 0; j < (total - 1-i); j++)
- {
- if (results[j].rating < results[j + 1].rating)
- {
- temp = results[j];
- results[j] = results[j + 1];
- results[j + 1] = temp;
- }
- }
- }
- }
|