From 3eafaaada1b445be78bd23f42249ffc958053d08 Mon Sep 17 00:00:00 2001 From: Macarthur Inbody <133794m3r@gmail.com> Date: Sat, 1 May 2021 10:25:09 -0400 Subject: [PATCH 1/7] BUG FIXED! WINDOWS IS WEIRD AGAIN! --- classes/containers/inventory.hxx | 2 +- menus/battle.hxx | 2 +- menus/inventory_menu.hxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/containers/inventory.hxx b/classes/containers/inventory.hxx index 714e33d..ae64d03 100755 --- a/classes/containers/inventory.hxx +++ b/classes/containers/inventory.hxx @@ -31,7 +31,7 @@ class Inventory { //The list of items contained in this object. std::unordered_map items; //the number of items that are contained. - std::unordered_map item_quantity; + std::unordered_map item_quantity; //the indexes of the items as they are held in memory std::deque item_indexes; unsigned short num_items; diff --git a/menus/battle.hxx b/menus/battle.hxx index 91939d8..11d85a2 100644 --- a/menus/battle.hxx +++ b/menus/battle.hxx @@ -68,7 +68,7 @@ std::string update_potions(std::vector< std::pair(4)); + unsigned int max = std::min(potions.size(), static_cast(4)); for (unsigned int i = 0; i < max; i++) { potions_opt += diff --git a/menus/inventory_menu.hxx b/menus/inventory_menu.hxx index 9392234..c69ee3e 100644 --- a/menus/inventory_menu.hxx +++ b/menus/inventory_menu.hxx @@ -24,7 +24,7 @@ class InventoryMenu: public Menu{ void update_shown_items(bool forward=true){ this->menu_string = ""; std::string padding_string(53,' '); - unsigned int end_idx = std::min(this->items.size() - this->current_idx,static_cast(3)); + unsigned int end_idx = std::min(this->items.size() - this->current_idx,static_cast(3)); unsigned int i =this->current_idx; for(;iitems[i].item_quantity); From 44451c2317e20be538b7f6515289cc1d6a114e8c Mon Sep 17 00:00:00 2001 From: Macarthur Inbody <133794m3r@gmail.com> Date: Sat, 1 May 2021 10:53:35 -0400 Subject: [PATCH 2/7] MORE FIXES --- CMakeLists.txt | 11 ++++++++++- classes/containers/inventory.hxx | 2 +- main.cpp | 12 ++++++++++++ main.hxx | 12 ++++++++++++ tests/load_save_test.cpp | 32 ++++++++++++++++++++++++-------- 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2216e0..c6d695b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,7 +192,7 @@ add_executable(save_demo demos/load_save_demo.cpp ) -add_executable(save_test +add_executable(test_save $ $ $ @@ -239,6 +239,11 @@ if(MSVC) #shop Module add_test(NAME "Shop_Module" COMMAND test_shop.exe) + + #save system + add_test(NAME "Shop_Module" + COMMAND test_save) + else() #Test the battle system add_test(NAME "Battle_Module" @@ -255,4 +260,8 @@ else() add_test(NAME "Shop_Module" COMMAND ./test_shop) + + add_test(NAME "Save_System" + COMMAND ./test_save) + endif() diff --git a/classes/containers/inventory.hxx b/classes/containers/inventory.hxx index ae64d03..eb4b304 100755 --- a/classes/containers/inventory.hxx +++ b/classes/containers/inventory.hxx @@ -226,7 +226,7 @@ class Inventory { ss << "Inventory ["; unsigned int i=0; for(auto el: this->items){ - ss << "{" << el.second->get_name() << ", " << this->item_quantity.at(el.first) << "}"; + ss << "{" << el.second->get_name() << ", " << std::to_string(this->item_quantity.at(el.first)) << "}"; if(++i < this->num_items){ ss << ", "; } diff --git a/main.cpp b/main.cpp index 753dbcd..6a65992 100644 --- a/main.cpp +++ b/main.cpp @@ -18,6 +18,18 @@ int main(int argc, char *argv[]) { std::string player_name; std::cout << "Enter your name: "; std::cin >> player_name; + if(player_name.size() > 50){ + move_and_clear_up(1); + while(player_name.size() > 50 && !player_name.empty()){ + std::cout << "Name is too long! Max is 50 characters\n"; + std::cout << "Reenter your name: "; + std::cin >> player_name; + move_and_clear_up(3); + } + } + if(player_name.empty()){ + exit(0); + } Player player(player_name); InventoryMenu player_inv(&player); TutorialMenu tutorial(player, player_inv); diff --git a/main.hxx b/main.hxx index 6157315..b79db65 100644 --- a/main.hxx +++ b/main.hxx @@ -102,6 +102,10 @@ void __add_items(Player &p, const std::string& item_tokens){ * @return A freshly created player object with all of their data. */ Player load_game(const std::string &save_file_name){ + if(!save_file_name.find("_save_file.dat")){ + std::cout << "\x1b[" << BRIGHT_RED_TXT << "mNOT A VALID SAVE FILE!"; + exit(1); + } std::ifstream save_file(save_file_name); //make sure we can read the file. if(!save_file.is_open()){ @@ -117,6 +121,10 @@ Player load_game(const std::string &save_file_name){ std::string token; save_file >> save_string; size_t split = save_string.find(':')+1; + if(split == std::string::npos){ + std::cerr << "\x1b[" << BRIGHT_RED_TXT << "mNO HASH FOUND!\x1b[0m"; + exit(2); + } //check the hash unsigned long ck_hash = std::stoul(save_string.substr(split),nullptr,16); unsigned long hash = gen_hash(save_string.substr(0,split-1)); @@ -144,6 +152,10 @@ Player load_game(const std::string &save_file_name){ token = save_string.substr(tok_start,split-tok_start); switch(current_idx){ case 0: + if(split-tok_start > 50){ + std::cout << "Name's too long"; + exit(1); + } player_name = token; break; case 1: diff --git a/tests/load_save_test.cpp b/tests/load_save_test.cpp index 0e7e801..ed4ea1d 100644 --- a/tests/load_save_test.cpp +++ b/tests/load_save_test.cpp @@ -8,15 +8,31 @@ #include "../classes/items/item_base.hxx" #include "../classes/items/weapon.hxx" #include "../classes/items/armor.hxx" -#include "../classes/items/potion.hxx"; +#include "../classes/items/potion.hxx" #include "../data/items.hxx" #include "../classes/fighters/player.hxx" #include "../main.hxx" -int main(){ - Player player("zzz_test_user"); - player.add_item(stick); - save_game(player); - Player player2 = load_game("zzz_test_user_save_file.dat"); - std::cout << (std::string) player2 << std::endl; - int i =1; +int main(int argc, char *argv[]){ + if(argc == 1) { + Player player("zzz_test_user"); + player.add_item(stick); + save_game(player); + Player player2 = load_game("zzz_test_user_save_file.dat"); + std::cout << "Save file creation/loading test....\n"; + unsigned int tests_passed = 0; + unsigned int tests_failed = 0; + + if ((std::string) player == (std::string) player2) { + std::cout << "Test passed\n"; + tests_passed++; + } + else { + std::cout << "Test failed\n Expected '" << (std::string) player << "' but we got '" << (std::string) player2 + << "'\n"; + tests_failed++; + } + } + //test that we can't pass the hash test obviously. + std::ofstream junk_file("zzy_junk_save_file.dat"); + junk_file << "Jimbo,0,0,[0,],0,1:35"; } \ No newline at end of file From 78ef19ab38fb5cc35826c4c8070b4d8dc09b67ea Mon Sep 17 00:00:00 2001 From: Macarthur Inbody <133794m3r@gmail.com> Date: Sat, 1 May 2021 13:47:53 -0400 Subject: [PATCH 3/7] Built some tests for the save system. Including some invalid saves that it should catch. Added them to the test suite. Now all that's left is to figure out the windows issue. --- classes/fighters/actor.hxx | 2 + classes/fighters/player.hxx | 5 +- main.cpp | 24 +++- main.hxx | 116 +++++++++++++++----- test_data/bad_hash_save_file.dat | 1 + test_data/bad_name.csv | 1 + test_data/bad_number_of_items_save_file.dat | 1 + tests/load_save_test.cpp | 108 +++++++++++++++--- 8 files changed, 213 insertions(+), 45 deletions(-) create mode 100644 test_data/bad_hash_save_file.dat create mode 100644 test_data/bad_name.csv create mode 100644 test_data/bad_number_of_items_save_file.dat diff --git a/classes/fighters/actor.hxx b/classes/fighters/actor.hxx index 4c730dd..34247bc 100644 --- a/classes/fighters/actor.hxx +++ b/classes/fighters/actor.hxx @@ -42,6 +42,7 @@ class Actor { Armor *armor_equipped; //the constructors, public methods, and getters. public: + explicit Actor(std::string name="Actor", unsigned short level=1, double bonus_hp = 0.0, double bonus_str = 0.0, double bonus_def = 0.0,unsigned int hp = 15, unsigned int str = 5, unsigned int def = 3,unsigned short type=0) @@ -200,6 +201,7 @@ class Actor { // } void equip_weapon(Weapon &weapon){ + this->weapon_held = &weapon; this->str_ += weapon.get_damage(); } diff --git a/classes/fighters/player.hxx b/classes/fighters/player.hxx index 536f21d..5332900 100755 --- a/classes/fighters/player.hxx +++ b/classes/fighters/player.hxx @@ -227,11 +227,10 @@ class Player: public Actor { friend InventoryMenu; friend void save_game(const Player &); - friend Player load_game(const std::string& save_file); + friend int load_game(const std::string& save_file,Player &); friend void __add_items(Player &, const std::string&); }; -void save_game(const Player &player); -Player load_game(const std::string& save_file); + void show_all_stats(Player &player){ std::cout << "Name:'" << player.name_ + "' hp:" << player.base_hp_ << " str: " diff --git a/main.cpp b/main.cpp index 6a65992..e67e9c6 100644 --- a/main.cpp +++ b/main.cpp @@ -6,12 +6,27 @@ #include "main.hxx" int main(int argc, char *argv[]) { clear_and_move_top(); - redraw_main(); unsigned int option; + int result; if(argc == 2){ - load_game(argv[1]); - std::cout << "Thanks for playing but the game isn't ready yet."; + if(strncmp(argv[1],"-h",2) == 0){ + std::cout << "\nprogram use " << argv[0]; + std::cout << " {SAVE_FILE_TO_LOAD}. Or -h to see this message. If no argument is given it'll immediately go into the game loading.\n The game does basic checks to make sure it's loading a valid save file but the rest is up to you.\n\n"; + return 0; + } + else { + Player player; + result = load_game(argv[1], player); + if (result != 0) { + std::cout << "Thanks for playing but the game isn't ready yet.\n"; + return 0; + } + else { + return result; + } + } } + redraw_main(); std::cout << "\x1b[1mSelection\x1b[22m: "; option = valid_option(1,3); if(option == 1) { @@ -42,7 +57,8 @@ int main(int argc, char *argv[]) { std::cout << "Enter your character's name: "; std::string filename; std::cin >> filename; - load_game(filename+"_save_file.dat"); + Player player; + load_game(filename+"_save_file.dat",player); std::cout << "Your file loaded correctly but the game isn't ready yet, so please try again later!"; return 0; } diff --git a/main.hxx b/main.hxx index b79db65..779d0ee 100644 --- a/main.hxx +++ b/main.hxx @@ -10,6 +10,7 @@ #define ITP298_CAPSTONE_MAIN_HXX #include #include +#include #include "terminal.hxx" #include "includes.hxx" @@ -41,6 +42,16 @@ void save_game(const Player &player){ //first we get their name, the xp, gold, hp, base hp, base str, base def ss << player.name_ << ',' << player.lvl_ << ',' << player.xp_ << ',' << player.gold_ << ',' << player.hp_ << ',' << player.bonus_hp_ << ',' << player.bonus_str_ << ',' << player.bonus_def_ << ',' << player.current_game_level; + ss << ','; + if(player.weapon_held == nullptr) + ss << "null"; + else + ss << player.weapon_held->get_id(); + ss << ','; + if(player.armor_equipped == nullptr) + ss << "null"; + else + ss << player.armor_equipped->get_id(); //then we get their inventory it is delmited by a [ to seperate it from the other part of the save file ss << ",["; @@ -89,6 +100,12 @@ void __add_items(Player &p, const std::string& item_tokens){ item_tuple = item_tokens.substr(tok_start,split-tok_start); idx = item_tuple.find(';'); item_id = std::stoul(item_tuple.substr(0,idx)); + //bail before we get any real issuses. + if(item_id > ALL_ITEMS_.size()){ + std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID ITEM ID!\n"; + //the test suite will never attempt this. + exit(255); + } item_number = std::stoul(item_tuple.substr(idx+1)); p.add_item(*ALL_ITEMS_[item_id], item_number); tok_start = split; @@ -99,39 +116,41 @@ void __add_items(Player &p, const std::string& item_tokens){ /** * Load the player's game * @param save_file_name The file name that stores it. - * @return A freshly created player object with all of their data. + * @param player The player object to operate on + * @return the return code. 0 for everything worked. */ -Player load_game(const std::string &save_file_name){ - if(!save_file_name.find("_save_file.dat")){ - std::cout << "\x1b[" << BRIGHT_RED_TXT << "mNOT A VALID SAVE FILE!"; - exit(1); +int load_game(const std::string &save_file_name,Player &player){ + if(save_file_name.find("_save_file.dat") == std::string::npos){ + std::cout << "\n\x1b[" << BRIGHT_RED_TXT << "mNOT A VALID SAVE FILE!\x1b[0m\n"; + return 1; } std::ifstream save_file(save_file_name); //make sure we can read the file. if(!save_file.is_open()){ - std::cerr << "\x1b[" << BRIGHT_RED_TXT << "mFile doesn't exist" << "\x1b[0m"; - exit(1); + std::cerr << "\n\x1b[" << BRIGHT_RED_TXT << "mFile doesn't exist" << "\x1b[0m\n"; + return 2; } else if(save_file.fail()){ - std::cerr << "\x1b[" << BRIGHT_RED_TXT << "mFile can't be read\x1b[0m"; - exit(2); + std::cerr << "\n\x1b[" << BRIGHT_RED_TXT << "mFile can't be read\x1b[0m\n"; + return 2; } //now we start std::string save_string; std::string token; save_file >> save_string; - size_t split = save_string.find(':')+1; + size_t split = save_string.find(':'); if(split == std::string::npos){ - std::cerr << "\x1b[" << BRIGHT_RED_TXT << "mNO HASH FOUND!\x1b[0m"; - exit(2); + std::cerr << "\n\x1b[" << BRIGHT_RED_TXT << "mNO HASH FOUND!\x1b[0m\n"; + return 5; } + split++; //check the hash unsigned long ck_hash = std::stoul(save_string.substr(split),nullptr,16); unsigned long hash = gen_hash(save_string.substr(0,split-1)); //bail if(ck_hash != hash){ - std::cerr << "Invalid checksum. Save file is corrupted. Can't load from this file!\n"; - exit(1); + std::cerr << "\n\x1b[" << BRIGHT_RED_TXT << "mInvalid checksum. Save file is corrupted. Can't load from this file!\x1b[0m\n"; + return 5; } std::string player_name; unsigned int xp=0; @@ -147,14 +166,16 @@ Player load_game(const std::string &save_file_name){ size_t tok_start = 0; split = save_string.find(','); unsigned int current_idx = 0; + Weapon *weapon_held = nullptr; + Armor *armor_equip = nullptr; //iterate over all of the options till we get all of the values we need. while(split != std::string::npos){ token = save_string.substr(tok_start,split-tok_start); switch(current_idx){ case 0: if(split-tok_start > 50){ - std::cout << "Name's too long"; - exit(1); + std::cout << "\nName's too long"; + return 7; } player_name = token; break; @@ -190,6 +211,36 @@ Player load_game(const std::string &save_file_name){ //current_game_level current_game_level = std::stoul(token); break; + case 9: + //weeapon equipped + if(strcmp(token.c_str(),"null") != 0){ + unsigned short weapon_id = std::stoul(token); + if(weapon_id > ALL_ITEMS_.size()){ + std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID WEAPON!\n"; + return 255; + } + weapon_held = dynamic_cast(ALL_ITEMS_[std::stoul(token)]); + if(weapon_held->get_type() != 1){ + std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID WEAPON\n"; + return 255; + } + } + break; + case 10: + //equipped armor + if(strcmp(token.c_str(),"null") != 0){ + unsigned short weapon_id = std::stoul(token); + if(weapon_id > ALL_ITEMS_.size()){ + std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID ARMOR!\x1b[0m\n"; + return 255; + } + armor_equip = dynamic_cast(ALL_ITEMS_[std::stoul(token)]); + if(armor_equip->get_type() != 1){ + std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID ARMOR\x1b[0m\n"; + return 255; + } + } + break; default: //should never get here. break; @@ -201,26 +252,41 @@ Player load_game(const std::string &save_file_name){ //find next token substring split = save_string.find(',',split+1); //we're done with the normal items. - if(current_idx == 9) + if(current_idx == 11) break; } //somehow we broke out early - if(current_idx != 9){ - std::cerr << "\x1b[" << BRIGHT_RED_TXT << "mSOMETHING IS BROKEN JIM!\x1b[0m" << std::endl; - exit(1); + if(current_idx != 11){ + std::cerr << "\n\x1b[" << BRIGHT_RED_TXT << "mSOMETHING IS BROKEN JIM!\x1b[0m" << std::endl; + return 6; } //get the string minus the hash split = save_string.find(':'); - Player p(player_name, lvl,bonus_hp,bonus_str,bonus_def,xp,gold,current_game_level); - if(p.get_hp() > hp){ - p.damage((hp-p.get_hp())+p.get_def()); + //ugly hack till I implement copy constructor + player.bonus_hp_ = bonus_hp; + player.bonus_def_ = bonus_def; + player.bonus_str_ = bonus_str; + player.xp_ = xp; + player.gold_ = gold; + player.current_game_level = current_game_level; + player.set_level(lvl); + player.name_ = player_name; + //end of ugly hack + if(weapon_held != nullptr) + player.equip_weapon(*weapon_held); + if(armor_equip != nullptr) + player.equip_armor(*armor_equip); + //if their current hp is less than what the default is at that level + if(player.get_hp() > hp){ + //remove some. + player.damage((hp-player.get_hp())+player.get_def()); } //get the item token substring token = save_string.substr(tok_start+1,split-tok_start-2); //add the items - __add_items(p,token); + __add_items(player,token); //return teh player object - return p; + return 0; } /** diff --git a/test_data/bad_hash_save_file.dat b/test_data/bad_hash_save_file.dat new file mode 100644 index 0000000..f8110b5 --- /dev/null +++ b/test_data/bad_hash_save_file.dat @@ -0,0 +1 @@ +zzz_test_user,1,0,100,20,0.05,0.05,0.05,0,[1,0;1]:62acdbe diff --git a/test_data/bad_name.csv b/test_data/bad_name.csv new file mode 100644 index 0000000..4ae1209 --- /dev/null +++ b/test_data/bad_name.csv @@ -0,0 +1 @@ +zzz_test_user,1,0,100,20,0.05,0.05,0.05,0,[1,0;1]:62acdbf \ No newline at end of file diff --git a/test_data/bad_number_of_items_save_file.dat b/test_data/bad_number_of_items_save_file.dat new file mode 100644 index 0000000..d4672d5 --- /dev/null +++ b/test_data/bad_number_of_items_save_file.dat @@ -0,0 +1 @@ +zzz_test_user,1,0,20,0.05,0.05,0.05[1,0;1]:cceadf0 diff --git a/tests/load_save_test.cpp b/tests/load_save_test.cpp index ed4ea1d..8b2a1db 100644 --- a/tests/load_save_test.cpp +++ b/tests/load_save_test.cpp @@ -12,16 +12,22 @@ #include "../data/items.hxx" #include "../classes/fighters/player.hxx" #include "../main.hxx" -int main(int argc, char *argv[]){ - if(argc == 1) { - Player player("zzz_test_user"); - player.add_item(stick); - save_game(player); - Player player2 = load_game("zzz_test_user_save_file.dat"); - std::cout << "Save file creation/loading test....\n"; - unsigned int tests_passed = 0; - unsigned int tests_failed = 0; - +int main(){ + Player player("zzz_test_user"); + player.add_item(stick); + player.equip_weapon(stick); + save_game(player); + Player player2; + int res = load_game("zzz_test_user_save_file.dat",player2); + std::cout << "\x1b[1mSAVE TESTS\x1b[0m\n"; + std::cout << "Save file creation/loading test....\n"; + unsigned int tests_passed = 0; + unsigned int tests_failed = 0; + if(res != 0){ + std::cout << "Test failed. Wasn't able to load file!"; + tests_failed++; + } + else { if ((std::string) player == (std::string) player2) { std::cout << "Test passed\n"; tests_passed++; @@ -32,7 +38,83 @@ int main(int argc, char *argv[]){ tests_failed++; } } - //test that we can't pass the hash test obviously. - std::ofstream junk_file("zzy_junk_save_file.dat"); - junk_file << "Jimbo,0,0,[0,],0,1:35"; + std::cout << std::endl; + + std::cout << "Invalid save format tests\n"; + std::cout << "Bad Hash Test -- "; + int result = load_game("../test_data/bad_hash_save_file.dat",player2); + if(result != 5 ){ + tests_failed++; + std::cout << "Expected code: 5 but we got " << result; + } + else{ + std::cout << "Test passed."; + tests_passed++; + } + std::cout << std::endl; + + //bad hash + std::cout << "No hash Test -- "; + result = load_game("../test_data/no_hash_save_file.dat",player2); + if(result != 5 ){ + tests_failed++; + std::cout << "Expected code: 5 but we got " << result; + } + else{ + std::cout << "Test passed."; + tests_passed++; + } + std::cout << std::endl; + + //no file + std::cout << "No File test --"; + result = load_game("../test_data/..._save_file.dat",player2); + if(result != 2 ){ + tests_failed++; + std::cout << "Expected code: 2 but we got " << result; + } + else{ + std::cout << "Test passed."; + tests_passed++; + } + std::cout << std::endl; + + //bad name + result = load_game("../test_data/bad_name.csv",player2); + if(result != 1 ){ + tests_failed++; + std::cout << "Expected code: 5 but we got " << result; + } + else{ + std::cout << "Test passed."; + tests_passed++; + } + std::cout << std::endl; + + //bad number of items + result = load_game("../test_data/bad_number_of_items_save_file.dat",player2); + if(result != 6 ){ + tests_failed++; + std::cout << "Expected code: 6 but we got " << result; + } + else{ + std::cout << "Test passed."; + tests_passed++; + } + std::cout << std::endl; + + //has equipped item + result = load_game("../test_data/equipped_armor_save_file.dat",player2); + if(result != 0 ){ + tests_failed++; + std::cout << "Expected code: 0 but we got " << result; + } + else{ + std::cout << "Test passed."; + tests_passed++; + } + std::cout << std::endl; + + std::cout << "\n\x1b[1mResult\x1b[0m\n\x1b[" << BRIGHT_GREEN_TXT << "mPASSED:" << tests_passed << " \x1b[" << BRIGHT_RED_TXT << "mFAILED: " << tests_failed << "\x1b[0m out of " << (tests_passed+tests_failed) << " total tests.\n" << std::endl; + return (tests_failed != 0)?1:0; } \ No newline at end of file From 2af394b5e5e5ea1d0bf5ac349aaddf8640174540 Mon Sep 17 00:00:00 2001 From: Macarthur Inbody <133794m3r@gmail.com> Date: Sat, 1 May 2021 16:05:19 -0400 Subject: [PATCH 4/7] Now everything should be good to go except windows stuff. --- classes/containers/inventory.hxx | 12 ++++-- classes/containers/loot_table.hxx | 27 ++++++-------- classes/containers/shop_inventory.hxx | 1 + classes/fighters/actor.hxx | 22 ++++++----- classes/fighters/mob.hxx | 49 ++++++++++++------------ classes/fighters/player.hxx | 17 ++++----- classes/items/item_base.cpp | 7 ---- classes/items/item_base.hxx | 3 +- classes/items/potion.hxx | 2 +- classes/items/weapon.cpp | 4 +- classes/items/weapon.hxx | 4 +- classes/shop_keeper.hxx | 12 +++--- data/mobs.hxx | 1 - demos/battle_demo.cpp | 10 ----- demos/load_save_demo.cpp | 14 ++++--- includes.hxx | 2 +- main.cpp | 2 + main.hxx | 54 +++++++++++++++++---------- menus/battle.hxx | 17 ++++++--- menus/inventory_menu.hxx | 31 ++++++++------- menus/shop.hxx | 13 +------ tests/load_save_test.cpp | 8 +--- 22 files changed, 157 insertions(+), 155 deletions(-) diff --git a/classes/containers/inventory.hxx b/classes/containers/inventory.hxx index eb4b304..4b9e029 100755 --- a/classes/containers/inventory.hxx +++ b/classes/containers/inventory.hxx @@ -76,13 +76,17 @@ class Inventory { * @param item the item to add * @param number The number to add */ - void add_item(Item &item, unsigned short number=1){ + void add_item(Item &item, unsigned char number=1){ //if it already exists if(this->items.count(item.get_id()) != 0){ //add to it that number this->item_quantity[item.get_id()]+=number; } else { + //shouldn't be able to have more than 255 items. type is short due to std::cout issues. + if(this->num_items > 255) + return; + //otherwise add an item to the hashtables/such. this->items[item.get_id()] = &item; this->item_quantity[item.get_id()] = number; @@ -182,17 +186,17 @@ class Inventory { /** * Get an item based upon an index * @param idx - * @return + * @return get the id of the item in that index */ unsigned short get_item_id(unsigned short idx) const{ return this->item_indexes[idx]; } /** - * Get an item based upon it's id + * Get an item's quantity based upon it's id * * @param item_id - * @return + * @return the amount of the item they have */ unsigned int get_quantity(unsigned short item_id) const{ return this->item_quantity.at(item_id); diff --git a/classes/containers/loot_table.hxx b/classes/containers/loot_table.hxx index 2dfb605..2e55b9d 100755 --- a/classes/containers/loot_table.hxx +++ b/classes/containers/loot_table.hxx @@ -15,37 +15,34 @@ class LootTable:public Inventory { private: - std::vector chances; + std::vector chances; public: - explicit LootTable(std::vector items={}, std::vector counts={},const std::vector& probs = {}) - :Inventory(std::move(items),std::move(counts)){ - this->chances.reserve(probs.size()); - for(double prob:probs){ - this->chances.push_back(std::lround(prob*4294967295)); - } + explicit LootTable(const std::vector& items={}, std::vector counts={},const std::vector& probs = {}) + :Inventory(items,std::move(counts)){ + this->chances = probs; } - std::vector > award_items(){ + std::vector > award_items(){ //create a temporary vector - std::vector> rewards; - unsigned int res = 0; - unsigned short item_id = 0; + std::vector> rewards; + double res; + unsigned short item_id; //see which items we'll give them for(unsigned int i=0;iitem_indexes.size();i++){ - res = xorshift128(0,4294967295); + res = xorshift128(0.00,1.00); //if it's less than the probability we award it. if(res <= this->chances[i]){ //first have to get the item's id. item_id = this->item_indexes[i]; //then we add a std::pair to the vector - rewards.push_back(std::make_pair(this->items[item_id],this->item_quantity[item_id])); + rewards.emplace_back(this->items[item_id],this->item_quantity[item_id]); } } return rewards; } - void add_item(Item &item,unsigned int quantity,double probability){ - this->chances.push_back(std::lround(probability*4294967295)); + void add_item(Item &item,unsigned short quantity,double probability){ + this->chances.push_back(probability); Inventory::add_item(item,quantity); } }; diff --git a/classes/containers/shop_inventory.hxx b/classes/containers/shop_inventory.hxx index c276a2f..c0bd56b 100644 --- a/classes/containers/shop_inventory.hxx +++ b/classes/containers/shop_inventory.hxx @@ -16,6 +16,7 @@ class ShopInventory: public Inventory { const std::vector &quantity = {}):Inventory(items,quantity){ } + /** * The cost to buy amount of the items. * @param item_id The item we're going to be using. diff --git a/classes/fighters/actor.hxx b/classes/fighters/actor.hxx index 34247bc..fe30a85 100644 --- a/classes/fighters/actor.hxx +++ b/classes/fighters/actor.hxx @@ -31,9 +31,9 @@ class Actor { unsigned int base_str_; unsigned int base_def_; //then we store the actual values. Since they may be debuffed or if they're damaged. This way we can have stats reset. - unsigned int hp_; - unsigned int str_; - unsigned int def_; + unsigned int hp_{}; + unsigned int str_{}; + unsigned int def_{}; //level can never be <0 so unsigned value. unsigned short lvl_ = 0; @@ -53,6 +53,9 @@ class Actor { this->base_hp_ = hp; this->base_str_ = str; this->base_def_ = def; + this->hp_ = hp; + this->str_ = str; + this->def_ = def; //these are used when leveling up to give a bonus upon that levelup beyond just their level. this->bonus_hp_ = bonus_hp; this->bonus_str_ = bonus_str; @@ -160,7 +163,7 @@ class Actor { * @param the target actor to damage. Uses this object's strength. * @return int the amount of damage carried out. */ - unsigned int attack(Actor &target){ + unsigned int attack(Actor &target) const{ return target.damage(this->base_str_); } @@ -170,7 +173,7 @@ class Actor { */ virtual void set_level(unsigned short level){ - int dif = 0; + int dif; //if it's the same just do nothing. if(level == this->lvl_) dif = this->lvl_ - 1; @@ -189,7 +192,7 @@ class Actor { } //Check if the actor is still alive. If HP is 0 then it means they're dead. - bool is_alive(){ + bool is_alive() const{ return this->hp_ > 0; } @@ -221,14 +224,15 @@ class Actor { this->def_ += armor.get_defense(); } - Item *equipped_weapon(){ + Item *equipped_weapon() const{ return this->weapon_held; } - Item *equipped_armor(){ + Item *equipped_armor() const{ return this->armor_equipped; } - virtual operator std::string() const{ + + virtual explicit operator std::string() const{ std::stringstream ss; ss << "id: " << this->id << " " << this->name_ << " hp:" <hp_ << "/" << this->base_hp_ << " str:" << this->str_ << "/" << this->base_str_ << " def:" << this->def_ << "/" << this->base_def_; return ss.str(); diff --git a/classes/fighters/mob.hxx b/classes/fighters/mob.hxx index a9cf2da..d077416 100644 --- a/classes/fighters/mob.hxx +++ b/classes/fighters/mob.hxx @@ -12,7 +12,7 @@ struct MobRewards{ unsigned int gold = 0; unsigned int xp = 0; - std::vector> items; + std::vector> items; }; #include "actor.hxx" @@ -20,7 +20,7 @@ struct MobRewards{ class Mob : public Actor { private: //the xp to be awarded and gold be awarded upon death. - unsigned long xp_; + unsigned int xp_; unsigned int gold_; //the tier strings const static std::string tier_str[7]; @@ -48,49 +48,50 @@ class Mob : public Actor { */ void set_gold(){ unsigned int dl = this->lvl_ + 1; - double gm = 1.9; + double gm = 1.90; double glm; double bvm; if(dl < 10){ - gm = 5.9; - glm = 1.9; - bvm = 6.8; + gm = 5.90; + glm = 1.90; + bvm = 6.80; } else if(dl < 40){ - gm = 6.0; + gm = 6.00; glm = 1.85; - bvm = 7.0; + bvm = 7.00; } else if(dl < 91){ gm = 1.95; glm = 2.0; - bvm = 50; + bvm = 50.00; } else if(dl < 151){ - glm = 2.2; - bvm = 70.0; + glm = 2.20; + bvm = 70.00; } else if(dl < 199){ - glm = 2.4; - bvm = 100.0; + glm = 2.40; + bvm = 100.00; } else{ - glm = 4.0; - bvm = 120.0; + glm = 4.00; + bvm = 120.00; } - this->gold_ = static_cast((((this->xp_*glm)-((dl / gm) * bvm))) * 0.5); + this->gold_ = static_cast((this->xp_ * glm - ((dl / gm) * bvm)) * (0.50 + (this->tier_-1 / 3.00))); } public: //initialize the Mob class. Explicit since it can be called with just 1 parameter. Also initialize properties with parent class' constructor. explicit Mob(std::string name="Mob",unsigned short tier=1, unsigned short level=1, double bonus_hp=0.00, double bonus_str=0.0, double bonus_def=0.0) - :Actor(std::move(name),level,bonus_hp+((tier-1.0)/20), - bonus_str+((tier-1.0)/100),bonus_def+((tier-1.0)/80),16,6,3,1) { + :Actor(std::move(name),level,bonus_hp+((tier-1.0)/20.00), + bonus_str+((tier-1.0)/100.00),bonus_def+((tier-1.0)/80.00),16,6,3,1) { unsigned int tmp = this->lvl_ + 1; //based on other formulas this should make the curve OK. //tier will modify the two formulas below eventually - this->xp_ = std::lround( tmp* ((tmp*0.79 )+1.2)); + this->xp_ = std::lround(tmp * (tmp * (0.79 + (tier - 1 / 3.00)) + 2.00)); + this->gold_ = 0; this->set_gold(); this->tier_ = tier; this->set_level(level); @@ -111,11 +112,11 @@ class Mob : public Actor { dif = level - this->lvl_; else dif = this->lvl_ - level; - dif += (this->tier_-1)/6; + dif += (this->tier_-1.00)/6.00; //when they modify the level change the stats to the proper values. - this->base_hp_ += std::lround( (this->bonus_hp_+1.0)*13.1*modifier*dif)+(this->tier_-1); - this->base_str_ += std::lround( ((this->bonus_str_+1.0)*4.0*modifier*dif)+((this->tier_)*2)); - this->base_def_ += std::lround( ((this->bonus_def_+1.0)*3.125*modifier*dif)+((this->tier_-1)/3)); + this->base_hp_ += std::lround( (this->bonus_hp_+1.0)*13.1*modifier*dif)+(this->tier_-1.00); + this->base_str_ += std::lround( ((this->bonus_str_+1.0)*4.0*modifier*dif)+((this->tier_)*2.00)); + this->base_def_ += std::lround( ((this->bonus_def_+1.0)*3.125*modifier*dif)+((this->tier_-1.00)/3.00)); //then set the current stats from the base. this->hp_ = this->base_hp_; this->str_ = this->base_str_; @@ -171,7 +172,7 @@ class Mob : public Actor { * * @return The object stringified. */ - operator std::string(){ + explicit operator std::string(){ std::stringstream ss; ss << "id: " << this->id << " " << this->name_ << " hp:" <hp_ << "/" << this->base_hp_ << " str:" << this->str_ << "/" << this->base_str_ << " def:" << this->def_ << "/" diff --git a/classes/fighters/player.hxx b/classes/fighters/player.hxx index 5332900..163d99d 100755 --- a/classes/fighters/player.hxx +++ b/classes/fighters/player.hxx @@ -52,7 +52,7 @@ class Player: public Actor { */ void set_level(unsigned short level) override{ - int dif = 0; + int dif; //if it's the same just do nothing. if(level == this->lvl_) dif = this->lvl_ - 1; @@ -112,8 +112,8 @@ class Player: public Actor { */ bool add_xp(unsigned int xp){ //might make this just be a one-time calculation and store the value as a property but that's up in the air. - double dl = static_cast(this->lvl_+1); - unsigned int mkxp = std::lround((dl * ((dl*0.79)*1.2) )); + auto dl = static_cast(this->lvl_+1); + unsigned long mkxp = std::lround((dl * ((dl*0.79)*1.2) )); unsigned int xp_lvl = std::lround( ( (dl*1.125) * mkxp )*1.6); this->xp_ += xp; if(this->xp_ > xp_lvl){ @@ -128,7 +128,7 @@ class Player: public Actor { //add HP to the player unsigned short add_hp(unsigned short hp){ - unsigned short restored = 0; + unsigned short restored; if(hp > (this->base_hp_ - this->hp_)) { restored = this->base_hp_ - this->hp_; this->hp_ = this->base_hp_; @@ -140,16 +140,16 @@ class Player: public Actor { return restored; } //item removal functions - void remove_item(unsigned short item_id, unsigned int num = 1){ + void remove_item(unsigned short item_id, unsigned short num = 1){ this->player_inventory.remove_item(item_id, num); } - void remove_item(Item &item, unsigned int num = 1){ + void remove_item(Item &item, unsigned short num = 1){ this->player_inventory.remove_item(item, num); } //add an item. Has to have an actual item in case it doesn't already exist in inventory. - void add_item(Item &item, unsigned int num = 1){ + void add_item(Item &item, unsigned short num = 1){ this->player_inventory.add_item(item,num); } @@ -228,10 +228,9 @@ class Player: public Actor { friend void save_game(const Player &); friend int load_game(const std::string& save_file,Player &); - friend void __add_items(Player &, const std::string&); + friend void _add_items(Player &, const std::string&); }; - void show_all_stats(Player &player){ std::cout << "Name:'" << player.name_ + "' hp:" << player.base_hp_ << " str: " << player.base_str_ << " def:" << player.base_def_ << " level:" << std::to_string(player.lvl_) << diff --git a/classes/items/item_base.cpp b/classes/items/item_base.cpp index a9e59c7..7b5387d 100644 --- a/classes/items/item_base.cpp +++ b/classes/items/item_base.cpp @@ -9,13 +9,6 @@ #include "item_base.hxx" -//Private functions -void Item::generate() -{ - -} - - //Constructors / Destructors Item::Item(std::string name, diff --git a/classes/items/item_base.hxx b/classes/items/item_base.hxx index 765490f..1805bd5 100644 --- a/classes/items/item_base.hxx +++ b/classes/items/item_base.hxx @@ -28,8 +28,7 @@ protected: unsigned int value; //the value of the item - //private functions - void generate(); //item generation function + //item generation function public: diff --git a/classes/items/potion.hxx b/classes/items/potion.hxx index c8786d9..0e72f71 100644 --- a/classes/items/potion.hxx +++ b/classes/items/potion.hxx @@ -20,7 +20,7 @@ class Potion:public Item { explicit Potion(std::string name="Junk", unsigned short level=1, unsigned short tier=1):Item(std::move(name)+" Pot",3,tier,level){ this->power_ = std::lround((level*16.00)*((tier+1.00)/4.00)); } - unsigned short get_power(){ + unsigned short get_power() const{ return this->power_; } }; diff --git a/classes/items/weapon.cpp b/classes/items/weapon.cpp index 1a92bca..a93975a 100644 --- a/classes/items/weapon.cpp +++ b/classes/items/weapon.cpp @@ -5,13 +5,15 @@ * Date: 4/5/21 * Purpose: Weapon class for our currently Untitled RPG.This subclass inherits properties from Item in order to produce weapons */ +#include + #include "weapon.hxx" Weapon::Weapon( std::string name, unsigned int tier, unsigned int level) - :Item(name, 1, tier, level) //base item constructor + :Item(std::move(name), 1, tier, level) //base item constructor { unsigned int damage = std::lround((level * 3.00 + level)+(level*((tier-1.00)/4.00))); this->damage = damage; //sets max damage value diff --git a/classes/items/weapon.hxx b/classes/items/weapon.hxx index 588c707..4542e2e 100644 --- a/classes/items/weapon.hxx +++ b/classes/items/weapon.hxx @@ -19,7 +19,7 @@ private: unsigned int tier = 1, unsigned int level = 1); - virtual ~Weapon(); + ~Weapon() override; //Accessors inline int get_damage() const { return this->damage;} //gets the damage value of a weapon @@ -27,7 +27,7 @@ private: //functions Weapon* clone() const; //creates a clone of a weapon - std::string toString(); + std::string toString() override; }; diff --git a/classes/shop_keeper.hxx b/classes/shop_keeper.hxx index 52642e1..a45a168 100644 --- a/classes/shop_keeper.hxx +++ b/classes/shop_keeper.hxx @@ -32,7 +32,7 @@ class ShopKeeper { * @param quantity how many to purchase * @return if the player was able to purchase said item. */ - bool purchase_item(unsigned short item_id,unsigned int quantity=1){ + bool purchase_item(unsigned short item_id,unsigned short quantity=1){ //if there's not yet a player bail b4 sigint/sigfault/etc. if(player_ == nullptr) return false; @@ -55,7 +55,7 @@ class ShopKeeper { * utility function to give me ids of all items. * @return the ids of all items in tehs hop */ - const std::deque list_inventory() const{ + std::deque list_inventory() const{ return this->shop_inventory_.get_item_ids(); } @@ -106,16 +106,14 @@ class ShopKeeper { * @param amount The amount to sell. * @return Whether they could or not. */ - bool sell_item(unsigned short item_id, unsigned int amount=1){ + bool sell_item(unsigned short item_id, unsigned short amount=1){ //bail if(this->player_ == nullptr) return false; //if they don't have the item - if(!this->player_->player_inventory.contains(item_id)) - return false; - //if they try to sell more than they have - else if(this->player_->player_inventory.get_quantity(item_id) < amount) + if(!this->player_->player_inventory.contains(item_id) || + this->player_->player_inventory.get_quantity(item_id) < amount) return false; //ok let's figure out how much to award them for the sale. diff --git a/data/mobs.hxx b/data/mobs.hxx index 46346e3..4e2e358 100644 --- a/data/mobs.hxx +++ b/data/mobs.hxx @@ -10,5 +10,4 @@ #define ITP298_CAPSTONE_MOBS_HXX Mob rat("Rat",0,1); Mob rat_king("Rat King",5,1); -unsigned short xx = 1+1; #endif //ITP298_CAPSTONE_MOBS_HXX diff --git a/demos/battle_demo.cpp b/demos/battle_demo.cpp index 3995870..faceb69 100644 --- a/demos/battle_demo.cpp +++ b/demos/battle_demo.cpp @@ -19,16 +19,6 @@ int main(){ player.add_item(potion,2); player.equip_armor(cloth_shirt); player.equip_weapon(rusty_sword); -// std::cout << "p atk m " << player.get_str() - boss.get_def() << "\n"; -// std::cout << "m atk p " << boss.get_str() - player.get_def() << "\n"; -// pause(); -// std::cout << player << std::endl << mob << std::endl; -// std::cout << (std::string) player << std::endl; -// pause(); -// show_all_stats(boss); -// show_all_stats(mob); -// show_all_stats(player); -// pause(); battle(player,mob); show_all_stats(player); return 0; diff --git a/demos/load_save_demo.cpp b/demos/load_save_demo.cpp index c37ab00..fef4a05 100644 --- a/demos/load_save_demo.cpp +++ b/demos/load_save_demo.cpp @@ -5,17 +5,19 @@ * Created on 4/30/21. * */ -#include "../classes/items/item_base.hxx" -#include "../classes/items/weapon.hxx" -#include "../classes/items/armor.hxx" -#include "../classes/items/potion.hxx" -#include "../data/items.hxx" #include "../classes/fighters/player.hxx" +#include "../data/items.hxx" #include "../main.hxx" int main(){ Player player("zzz_test_user"); player.add_item(stick); save_game(player); - Player player2 = load_game("zzz_test_user_save_file.dat"); + Player player2; + int res = load_game("zzz_test_user_save_file.dat",player2); + if(res != 0){ + std::cout << "something's broken"; + return 1; + } std::cout << (std::string) player2 << std::endl; + return 0; } \ No newline at end of file diff --git a/includes.hxx b/includes.hxx index 4d5d778..15da9e8 100644 --- a/includes.hxx +++ b/includes.hxx @@ -37,7 +37,7 @@ template std::enable_if_t::value,unsigned long> g unsigned long h = 0; unsigned long t = 0; unsigned long i = 0; - unsigned long long num = static_cast(x); + auto num = static_cast(x); while(num > 0){ h = (h*multiplier + i) % prime; num >>=(t*8); diff --git a/main.cpp b/main.cpp index e67e9c6..5b86bc1 100644 --- a/main.cpp +++ b/main.cpp @@ -46,6 +46,8 @@ int main(int argc, char *argv[]) { exit(0); } Player player(player_name); + //make sure they're ready for the fight. + player.add_gold(200); InventoryMenu player_inv(&player); TutorialMenu tutorial(player, player_inv); tutorial.enter(); diff --git a/main.hxx b/main.hxx index 779d0ee..a4e2741 100644 --- a/main.hxx +++ b/main.hxx @@ -81,15 +81,15 @@ void save_game(const Player &player){ * @param p The player object * @param item_tokens the token string representing their inventory */ -void __add_items(Player &p, const std::string& item_tokens){ - size_t split = 0; - size_t tok_start = 0; +void _add_items(Player &p, const std::string& item_tokens){ + size_t split; + size_t tok_start; split = item_tokens.find(','); //find the number of items - unsigned short num_items = std::stoul(item_tokens.substr(0,split)); + unsigned short num_items = static_cast(std::stoul(item_tokens.substr(0, split))); if(num_items == 0) return; - unsigned int idx; + unsigned long idx; unsigned short item_id; unsigned short item_number; std::string item_tuple; @@ -99,14 +99,14 @@ void __add_items(Player &p, const std::string& item_tokens){ while(tok_start != std::string::npos){ item_tuple = item_tokens.substr(tok_start,split-tok_start); idx = item_tuple.find(';'); - item_id = std::stoul(item_tuple.substr(0,idx)); + item_id = static_cast(std::stoul(item_tuple.substr(0, idx))); //bail before we get any real issuses. if(item_id > ALL_ITEMS_.size()){ std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID ITEM ID!\n"; //the test suite will never attempt this. exit(255); } - item_number = std::stoul(item_tuple.substr(idx+1)); + item_number = static_cast(std::stoul(item_tuple.substr(idx + 1))); p.add_item(*ALL_ITEMS_[item_id], item_number); tok_start = split; split = item_tokens.find(',',split+1); @@ -181,15 +181,15 @@ int load_game(const std::string &save_file_name,Player &player){ break; case 1: //lvl - lvl = std::stoul(token); + lvl = static_cast(std::stoul(token)); break; case 2: //xp - xp = std::stoul(token); + xp = static_cast(std::stoul(token)); break; case 3: //gold - gold = std::stoul(token); + gold = static_cast(std::stoul(token)); break; case 4: //hp @@ -209,36 +209,48 @@ int load_game(const std::string &save_file_name,Player &player){ break; case 8: //current_game_level - current_game_level = std::stoul(token); + current_game_level = static_cast(std::stoul(token)); break; case 9: //weeapon equipped + //if it's the string null then it's blank if(strcmp(token.c_str(),"null") != 0){ - unsigned short weapon_id = std::stoul(token); + //get the id + unsigned short weapon_id = static_cast(std::stoul(token)); + //if it's more than the total items we have die. if(weapon_id > ALL_ITEMS_.size()){ std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID WEAPON!\n"; return 255; } - weapon_held = dynamic_cast(ALL_ITEMS_[std::stoul(token)]); - if(weapon_held->get_type() != 1){ + //it's not actually a weapon bail + if(ALL_ITEMS_[weapon_id]->get_type() != 1){ std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID WEAPON\n"; return 255; } + else { + //convert the pointer + weapon_held = dynamic_cast(ALL_ITEMS_[weapon_id]); + } } break; case 10: //equipped armor if(strcmp(token.c_str(),"null") != 0){ - unsigned short weapon_id = std::stoul(token); + unsigned short weapon_id = static_cast(std::stoul(token)); + //id is more than we have time to bail if(weapon_id > ALL_ITEMS_.size()){ std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID ARMOR!\x1b[0m\n"; return 255; } - armor_equip = dynamic_cast(ALL_ITEMS_[std::stoul(token)]); - if(armor_equip->get_type() != 1){ + //not actually armor so bail + if(ALL_ITEMS_[weapon_id]->get_type() != 2){ std::cout << "\x1b[" << BRIGHT_RED_TXT << "mINVALID ARMOR\x1b[0m\n"; return 255; } + else { + //convert the pointer to armor type + armor_equip = dynamic_cast(ALL_ITEMS_[std::stoul(token)]); + } } break; default: @@ -262,6 +274,7 @@ int load_game(const std::string &save_file_name,Player &player){ } //get the string minus the hash split = save_string.find(':'); + //ugly hack till I implement copy constructor player.bonus_hp_ = bonus_hp; player.bonus_def_ = bonus_def; @@ -272,19 +285,22 @@ int load_game(const std::string &save_file_name,Player &player){ player.set_level(lvl); player.name_ = player_name; //end of ugly hack + + //make sure we are trying to equip something if(weapon_held != nullptr) player.equip_weapon(*weapon_held); if(armor_equip != nullptr) player.equip_armor(*armor_equip); + //if their current hp is less than what the default is at that level if(player.get_hp() > hp){ //remove some. - player.damage((hp-player.get_hp())+player.get_def()); + player.damage(static_cast((hp - player.get_hp()) + player.get_def())); } //get the item token substring token = save_string.substr(tok_start+1,split-tok_start-2); //add the items - __add_items(player,token); + _add_items(player,token); //return teh player object return 0; } diff --git a/menus/battle.hxx b/menus/battle.hxx index 11d85a2..21734a8 100644 --- a/menus/battle.hxx +++ b/menus/battle.hxx @@ -68,8 +68,8 @@ std::string update_potions(std::vector< std::pair(4)); - for (unsigned int i = 0; i < max; i++) { + const size_t max = std::min(potions.size(), static_cast(4)); + for (size_t i = 0; i < max; i++) { potions_opt += std::to_string(i+1) + ")" + potions[i].first.item_name + "x" + std::to_string(potions[i].first.item_quantity) + @@ -103,7 +103,7 @@ bool battle(Player &player,Mob mob){ option.append(14-option.size(),' '); } //the forward declaration of the options. - unsigned int option = 0; + unsigned int option; unsigned int mob_opt; unsigned int dmg; @@ -215,7 +215,7 @@ If enemy's HP is over 4 digits then we make it be ????. //the only other option is 3. case 3: //see if they have any potions to use. - if(potions.size() != 0){ + if(potions.empty()){ //if their HP is at max don't let them use one. if(player.get_hp() == player.get_base_hp()){ message = "Using a potion now wouldn't do any good!"; @@ -229,7 +229,7 @@ If enemy's HP is over 4 digits then we make it be ????. show_battle_message(potions_opt); //show the prompt std::cout << "\x1b[1mSelection\x1b[22m: "; - option = valid_option(1,potions.size()+1); + option = valid_option(1, static_cast(potions.size() + 1)); //they want to use a potion if(option <= potions.size()){ //make sure they want to use that potion @@ -239,7 +239,8 @@ If enemy's HP is over 4 digits then we make it be ????. //they do. if(option == 1){ //add this much hp - unsigned short added = player.add_hp(potions[option-1].first.item_value); + unsigned short added = player.add_hp( + static_cast(potions[option - 1].first.item_value)); //remove it from their inventory player.remove_item(potions[option-1].second); //redraw the hp UI @@ -256,6 +257,10 @@ If enemy's HP is over 4 digits then we make it be ????. //can't use what you don't have message = player.get_name() + " doesn't have any potions!"; } + break; + default: + message = "It won't ever happen."; + break; } //show the message from their turn. show_battle_message(message); diff --git a/menus/inventory_menu.hxx b/menus/inventory_menu.hxx index c69ee3e..f2901d9 100644 --- a/menus/inventory_menu.hxx +++ b/menus/inventory_menu.hxx @@ -24,11 +24,15 @@ class InventoryMenu: public Menu{ void update_shown_items(bool forward=true){ this->menu_string = ""; std::string padding_string(53,' '); - unsigned int end_idx = std::min(this->items.size() - this->current_idx,static_cast(3)); - unsigned int i =this->current_idx; + size_t end_idx = std::min(this->items.size() - this->current_idx,static_cast(3)); + size_t i =this->current_idx; for(;iitems[i].item_quantity); - this->menu_string += std::to_string(i+1) +')' + this->items[i].item_name + tmp + padding_string.substr(0,std::floor(15 - (this->items[i].item_name.size()+tmp.size()))) + ';'; + this->menu_string += std::to_string(i+1) + ')' + this->items[i].item_name + tmp + padding_string.substr(0, + static_cast(std::floor( + 15 - + (this->items[i].item_name.size() + + tmp.size())))) + ';'; } i++; @@ -50,7 +54,7 @@ class InventoryMenu: public Menu{ this->current_idx+= end_idx; else this->current_idx-=end_idx; - this->max_op = i; + this->max_op = static_cast(i); } public: @@ -60,6 +64,8 @@ class InventoryMenu: public Menu{ this->item_ids = this->player_->player_inventory.get_item_ids(); this->prev = false; this->next = false; + this->current_idx = 0; + this->max_op = 0; } void enter(){ @@ -76,7 +82,7 @@ class InventoryMenu: public Menu{ unsigned short choice; std::cout << "\x1b[1mSelection\x1b[22m: "; while(true){ - choice = valid_option(1,this->max_op); + choice = valid_option(static_cast(1),this->max_op); if(choice == this->max_op) break; @@ -96,32 +102,29 @@ class InventoryMenu: public Menu{ } else{ choice--; - if(this->next) - choice--; - else if(this->prev) - choice--; + choice -= (this->prev || this->next)?1:0; if(this->current_idx > 3) choice += 3; auto *item = this->player_->player_inventory.get_item(this->item_ids[choice]); - unsigned short type = item->get_type(); + unsigned short type = static_cast(item->get_type()); if(type == 1) { - Weapon *weapon = dynamic_cast(item); + auto *weapon = dynamic_cast(item); this->player_->unequip_weapon(); this->player_->equip_weapon(*weapon); } else if(type == 2){ - Armor *armor = dynamic_cast(item); + auto *armor = dynamic_cast(item); this->player_->unequip_armor(); this->player_->equip_armor(*armor); } else if(type == 3){ if(player_->get_hp() < player_->get_base_hp()){ - Potion *potion = dynamic_cast(item); + auto *potion = dynamic_cast(item); move_cursor(7,1); std::cout << "Would you like to use " << potion->get_name() << " to restore " << potion->get_power() <<" HP?"; this->show_menu_message("1) Yes 2) No "); std::cout << "\x1b[1mSelection\x1b[22m: "; - choice = valid_option(1,2); + choice = static_cast(valid_option(1, 2)); if(choice == 1){ this->player_->add_hp(potion->get_power()); std::cout << "Hp restored!\n"; diff --git a/menus/shop.hxx b/menus/shop.hxx index 172193c..c90a057 100644 --- a/menus/shop.hxx +++ b/menus/shop.hxx @@ -90,15 +90,6 @@ class ShopMenu:public Menu { std::to_string(this->player_items.size() + 2) + ")Exit Shop ;"; } - //still not done yet - void update_shop_items(){ - - } - //ditto here - void update_player_items(){ - - } - public: //constructor ShopMenu(ShopKeeper &shop_keeper, Player &player) @@ -202,7 +193,7 @@ class ShopMenu:public Menu { } //exit loop else { - return choice - this->shop_items.size(); + return static_cast(choice - this->shop_items.size()); } } } @@ -264,7 +255,7 @@ class ShopMenu:public Menu { } } else{ - return choice - this->player_items.size(); + return static_cast(choice - this->player_items.size()); } } } diff --git a/tests/load_save_test.cpp b/tests/load_save_test.cpp index 8b2a1db..6750067 100644 --- a/tests/load_save_test.cpp +++ b/tests/load_save_test.cpp @@ -5,12 +5,8 @@ * Created on 4/30/21. * */ -#include "../classes/items/item_base.hxx" -#include "../classes/items/weapon.hxx" -#include "../classes/items/armor.hxx" -#include "../classes/items/potion.hxx" -#include "../data/items.hxx" #include "../classes/fighters/player.hxx" +#include "../data/items.hxx" #include "../main.hxx" int main(){ Player player("zzz_test_user"); @@ -115,6 +111,6 @@ int main(){ } std::cout << std::endl; - std::cout << "\n\x1b[1mResult\x1b[0m\n\x1b[" << BRIGHT_GREEN_TXT << "mPASSED:" << tests_passed << " \x1b[" << BRIGHT_RED_TXT << "mFAILED: " << tests_failed << "\x1b[0m out of " << (tests_passed+tests_failed) << " total tests.\n" << std::endl; + std::cout << "\n\x1b[1mResult\x1b[0m\n\x1b[" << BRIGHT_GREEN_TXT << "mPASSED:" << tests_passed << " \x1b[" << BRIGHT_RED_TXT << "mFAILED:" << tests_failed << "\x1b[0m out of " << (tests_passed+tests_failed) << " total tests.\n" << std::endl; return (tests_failed != 0)?1:0; } \ No newline at end of file From dbd35f8a2fe04342339814bcc751efa47e0b54f3 Mon Sep 17 00:00:00 2001 From: Macarthur Inbody <133794m3r@gmail.com> Date: Sat, 1 May 2021 16:34:25 -0400 Subject: [PATCH 5/7] Mobs are scaled according to tiers. And also updated the tests accordingly. --- classes/fighters/mob.hxx | 4 ++-- tests/actor_test.cpp | 46 ++++++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/classes/fighters/mob.hxx b/classes/fighters/mob.hxx index d077416..4638986 100644 --- a/classes/fighters/mob.hxx +++ b/classes/fighters/mob.hxx @@ -78,7 +78,7 @@ class Mob : public Actor { glm = 4.00; bvm = 120.00; } - this->gold_ = static_cast((this->xp_ * glm - ((dl / gm) * bvm)) * (0.50 + (this->tier_-1 / 3.00))); + this->gold_ = static_cast((this->xp_ * glm - ((dl / gm) * bvm)) * 0.50); } public: @@ -90,7 +90,7 @@ class Mob : public Actor { unsigned int tmp = this->lvl_ + 1; //based on other formulas this should make the curve OK. //tier will modify the two formulas below eventually - this->xp_ = std::lround(tmp * (tmp * (0.79 + (tier - 1 / 3.00)) + 2.00)); + this->xp_ = std::lround((tmp * (tmp * 0.79) *(1+ (tier - 1.00 / 3.25))+ 2.00)); this->gold_ = 0; this->set_gold(); this->tier_ = tier; diff --git a/tests/actor_test.cpp b/tests/actor_test.cpp index 64213d2..32f6ee9 100644 --- a/tests/actor_test.cpp +++ b/tests/actor_test.cpp @@ -25,38 +25,38 @@ int main(){ //test the first actor build if( "id: 0 Test hp:15/15 str:5/5 def:3/3" != (std::string) base_actor){ std::cout << "Base actor test failed. got '" << (std::string) base_actor; - std::cout << "\nbut we expected 'id: 0 Test hp:15/15 str:5/5 def:3/3'" << std::endl; + std::cout << "\nbut we expected 'id: 0 Test hp:15/15 str:5/5 def:3/3'\n"; tests_failed++; } else - std::cout << "Base actor test succeeded." << std::endl; + std::cout << "Base actor test succeeded.\n"; //same with the player if("id: 65535 Player hp:20/20 str:5/5 def:4/4 xp:0 g:100" != (std::string) tmp_player){ std::cout << "player creation test failed\n"; std::cout << "Expected 'id: 65535 Player hp:20/20 str:5/5 def:4/4 xp:0 g:100' but we got '"; - std::cout << (std::string) tmp_player << std::endl; + std::cout << (std::string) tmp_player << '\n'; tests_failed++; } else - std::cout << "Player creation test Passed" << std::endl; + std::cout << "Player creation test Passed\n"; //and mob - if( "id: 2 Spawn of Death hp:16/16 str:8/8 def:3/3 xp:6 g:4 tier: 1 / normal" != (std::string) tmp_mob){ + if( "id: 2 Spawn of Death hp:16/16 str:8/8 def:3/3 xp:7 g:5 tier: 1 / normal" != (std::string) tmp_mob){ std::cout << "mob creation test failed \n"; - std::cout << "Expected 'id: 2 Spawn of Death hp:16/16 str:8/8 def:3/3 xp:6 g:4 tier: 1 / normal' but we got '"; - std::cout << (std::string) tmp_mob << std::endl; + std::cout << "Expected 'id: 2 Spawn of Death hp:16/16 str:8/8 def:3/3 xp:7 g:5 tier: 1 / normal' but we got '"; + std::cout << (std::string) tmp_mob << '\n'; tests_failed++; } else - std::cout << "Mob creation test passed" << std::endl; + std::cout << "Mob creation test passed\n"; //test the damage method base_actor.damage(22); //should've killed them. if(!base_actor.is_alive()) { - std::cout << "Actor death test succeeded" << std::endl; + std::cout << "Actor death test succeeded\n"; } else { - std::cout << "Actor death test failed" << std::endl; + std::cout << "Actor death test failed\n"; tests_failed++; } @@ -65,7 +65,7 @@ int main(){ unsigned int expected_hp = tmp_mob_hp - (tmp_player.get_str() - tmp_mob.get_def()); std::cout << "Actor targetting mob test "; if(tmp_mob.get_hp() != expected_hp ){ - std::cout << "failed. Mob HP wrong expected " << expected_hp << " but got " << tmp_mob.get_hp() << std::endl; + std::cout << "failed. Mob HP wrong expected " << expected_hp << " but got " << tmp_mob.get_hp() <<'\n'; tests_failed++; } else{ @@ -77,29 +77,33 @@ int main(){ expected_hp = (tmp_player_hp - (tmp_mob.get_str() - tmp_player.get_def()) ); std::cout << "Mob targeting player test "; if(tmp_player.get_hp() != expected_hp ){ - std::cout << "failed. Expected " << expected_hp << " but got " << tmp_player.get_hp() << std::endl; + std::cout << "failed. Expected " << expected_hp << " but got " << tmp_player.get_hp() << '\n'; tests_failed++; } else{ - std::cout << "passed." << std::endl; + std::cout << "passed.\n"; } //test the tiers and scaling. Mob boss("Bossman",6,5); std::cout << "Boss creation/scaling/tier test "; - if((std::string) boss != "id: 3 Bossman hp:99/99 str:38/38 def:20/20 xp:36 g:30 tier: 6 / boss"){ - std::cout << "failed. Expected 'id: 3 Bossman hp:99/99 str:38/38 def:20/20 xp:36 g:30 tier: 6 / boss' but we got '" << (std::string) boss << "'" << std::endl; + if((std::string) boss != "id: 3 Bossman hp:115/115 str:42/42 def:24/24 xp:192 g:178 tier: 6 / boss"){ + std::cout << "failed. Expected 'id: 3 Bossman hp:115/115 str:42/42 def:24/24 xp:192 g:178 tier: 6 / boss' but we got '" << (std::string) boss << "'\n"; tests_failed++; } else - std::cout << "passed." << std::endl; + std::cout << "passed.\n"; - std::cout << "Passed " << 6 - tests_failed << "/6" << std::endl; - Player tmp_act("jon",6); - if(tests_failed != 0){ - return 1; + std::cout << "Junk Mob creation test\n"; + Mob junk_mob("Junk",0); + if((std::string) junk_mob != "id: 4 Junk hp:13/13 str:5/5 def:2/2 xp:4 g:2 tier: 0 / trash"){ + std::cout << "Test failed: Expected 'id: 4 Junk hp:13/13 str:5/5 def:2/2 xp:4 g:2 tier: 0 / trash' but we got " << (std::string) junk_mob << '\n'; + tests_failed++; } + std::cout << "Passed " << 7 - tests_failed << "/7" << std::endl; + + if(tests_failed != 0) + return 1; else return 0; - } From 7d1df773942a18f4865bc8026a4eff4da75424c0 Mon Sep 17 00:00:00 2001 From: Macarthur Inbody <133794m3r@gmail.com> Date: Sat, 1 May 2021 16:37:06 -0400 Subject: [PATCH 6/7] Added save files test folders now contains all fo the save files to test it so that cmake can actually be run with the build actions on all OSes. --- test_data/equipped_armor_save_file.dat | 1 + test_data/no_hash_save_file.dat | 1 + 2 files changed, 2 insertions(+) create mode 100644 test_data/equipped_armor_save_file.dat create mode 100644 test_data/no_hash_save_file.dat diff --git a/test_data/equipped_armor_save_file.dat b/test_data/equipped_armor_save_file.dat new file mode 100644 index 0000000..41a325c --- /dev/null +++ b/test_data/equipped_armor_save_file.dat @@ -0,0 +1 @@ +zzz_test_user,1,0,100,20,0.05,0.05,0.05,0,0,null,[1,0;1]:cca4876 diff --git a/test_data/no_hash_save_file.dat b/test_data/no_hash_save_file.dat new file mode 100644 index 0000000..6661066 --- /dev/null +++ b/test_data/no_hash_save_file.dat @@ -0,0 +1 @@ +zzz_test_user,1,0,100,20,0.05,0.05,0.05,0,[1,0;1] From 07e5eec2fa080da7b7a7006e45b9795476b5a94e Mon Sep 17 00:00:00 2001 From: Macarthur Inbody <133794m3r@gmail.com> Date: Sat, 1 May 2021 17:57:43 -0400 Subject: [PATCH 7/7] Make sure to not allow them to put more items than are allowed into the inventory no matter what. --- main.hxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main.hxx b/main.hxx index a4e2741..42a2b69 100644 --- a/main.hxx +++ b/main.hxx @@ -87,16 +87,17 @@ void _add_items(Player &p, const std::string& item_tokens){ split = item_tokens.find(','); //find the number of items unsigned short num_items = static_cast(std::stoul(item_tokens.substr(0, split))); - if(num_items == 0) + if(num_items == 0 || num_items > 255) return; unsigned long idx; unsigned short item_id; unsigned short item_number; + unsigned short current_items=0; std::string item_tuple; tok_start = split+1; split = item_tokens.find(',',split+1); //now iterate over it adding items. - while(tok_start != std::string::npos){ + while(tok_start != std::string::npos || current_items > num_items){ item_tuple = item_tokens.substr(tok_start,split-tok_start); idx = item_tuple.find(';'); item_id = static_cast(std::stoul(item_tuple.substr(0, idx))); @@ -110,6 +111,7 @@ void _add_items(Player &p, const std::string& item_tokens){ p.add_item(*ALL_ITEMS_[item_id], item_number); tok_start = split; split = item_tokens.find(',',split+1); + current_items++; } }