Implement random weighted roll enchant functions. Added unit tests for them. Release Build 11497.

pull/65/head
sigonasr2 5 months ago
parent 773c011eb9
commit a6876f2523
  1. 8
      Adventures in Lestoria Tests/EnchantTests.cpp
  2. 11
      Adventures in Lestoria Tests/GameHelper.h
  3. 19
      Adventures in Lestoria Tests/ItemTests.cpp
  4. 6
      Adventures in Lestoria/Item.cpp
  5. 3
      Adventures in Lestoria/Item.h
  6. 24
      Adventures in Lestoria/ItemEnchant.cpp
  7. 1
      Adventures in Lestoria/ItemEnchant.h
  8. 2
      Adventures in Lestoria/Version.h
  9. BIN
      x64/Release/Adventures in Lestoria.exe

@ -57,14 +57,6 @@ INCLUDE_MONSTER_LIST
extern std::mt19937 rng;
namespace Test
{
template<class T>
inline static void InRange(T initialVal,std::pair<T,T>range,std::wstring_view assertMessage){
Assert::IsTrue(initialVal>=range.first&&initialVal<=range.second,std::format(L"Expected: {}~{} Actual: {} - {}",range.first,range.second,initialVal,assertMessage).c_str());
}
}
namespace EnchantTests
{
TEST_CLASS(EnchantTest)

@ -37,10 +37,13 @@ All rights reserved.
#pragma endregion
#pragma once
#include "CppUnitTest.h"
#include "AdventuresInLestoria.h"
INCLUDE_game
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace Game{
enum class CastWaitProperty{
WAIT_FOR_CAST_TIME,
@ -66,4 +69,12 @@ namespace Game{
nullRing.lock()->EnchantItem(enchantName);
return nullRing;
}
}
namespace Test
{
template<class T>
inline static void InRange(T initialVal,std::pair<T,T>range,std::wstring_view assertMessage){
Assert::IsTrue(initialVal>=range.first&&initialVal<=range.second,std::format(L"Expected: {}~{} Actual: {} - {}",range.first,range.second,initialVal,assertMessage).c_str());
}
}

@ -42,6 +42,7 @@ All rights reserved.
#include <format>
#include "ItemDrop.h"
#include <ranges>
#include "GameHelper.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace olc::utils;
@ -272,5 +273,23 @@ namespace ItemTests
Inventory::UnequipItem(EquipSlot::RING2);
Assert::AreEqual(true,Item::SelectedEquipIsDifferent(extraRing,EquipSlot::RING1),L"The game should allow equipping a ring to either blank slot if they're open.");
}
TEST_METHOD(AccessoryRandomEnchantTest){
std::weak_ptr<Item>extraRing{Inventory::AddItem("Ring of the Slime King"s)};
std::unordered_map<ItemEnchantInfo::ItemEnchantCategory,uint32_t>enchantCounts;
for(int i:std::ranges::iota_view(0,1000)){
ItemEnchantInfo resultEnchant{extraRing.lock()->ApplyRandomEnchant()};
if(resultEnchant.GetClass().has_value())Assert::AreEqual(int(resultEnchant.GetClass().value()),int(player->GetClass()),L"Player's class matches the class of the enchant.");
enchantCounts[resultEnchant.Category()]++;
Assert::AreEqual(true,extraRing.lock()->GetEnchant().has_value(),L"Ring is expected to be enchanted.");
Assert::AreEqual(resultEnchant.Name(),extraRing.lock()->GetEnchant().value().Name(),L"Ring is expected to be enchanted with the same enchant that was selected.");
Assert::AreEqual(false,player->HasEnchant(resultEnchant.Name()),L"Player is not expected to have the same enchant that was selected while the ring is unequipped.");
Inventory::EquipItem(extraRing,EquipSlot::RING1);
Assert::AreEqual(true,player->HasEnchant(resultEnchant.Name()),L"Player is expected to have the same enchant that was selected.");
Inventory::UnequipItem(EquipSlot::RING1);
}
Test::InRange(enchantCounts[ItemEnchantInfo::ItemEnchantCategory::GENERAL],{450U,550U},util::wformat("General enchants % is approx 50%."));
Test::InRange(enchantCounts[ItemEnchantInfo::ItemEnchantCategory::CLASS],{350U,450U},util::wformat("Class enchants % is approx 40%."));
Test::InRange(enchantCounts[ItemEnchantInfo::ItemEnchantCategory::UNIQUE],{50U,150U},util::wformat("Unique enchants % is approx 40%."));
}
};
}

@ -1523,6 +1523,8 @@ const std::optional<std::string>&Item::FragmentIcon()const{
return ITEM_DATA.at(FragmentName()).FragmentIcon();
}
void Item::ApplyRandomEnchant(){
const ItemEnchantInfo Item::ApplyRandomEnchant(){
EnchantName randomEnchantName{ItemEnchant::RollRandomEnchant()};
EnchantItem(randomEnchantName);
return ItemEnchantInfo::GetEnchant(randomEnchantName);
}

@ -57,6 +57,7 @@ class ItemProps;
using ITCategory=std::string;
using EventName=std::string;
using EnchantName=std::string;
using ItemScript=std::function<bool(AiL*,ItemProps)>;
@ -256,7 +257,7 @@ public:
void Lock();
void Unlock();
void EnchantItem(const std::string_view enchantName);
void ApplyRandomEnchant();
const ItemEnchantInfo ApplyRandomEnchant();
std::optional<ItemEnchant>GetEnchant()const;
const bool HasEnchant()const;
friend const bool operator==(std::shared_ptr<Item>lhs,std::shared_ptr<Item>rhs){return lhs->it==rhs->it&&lhs->randomizedStats==rhs->randomizedStats;};

@ -226,7 +226,7 @@ const std::unordered_map<std::string,ItemEnchantInfo>&ItemEnchantInfo::GetEnchan
return ENCHANT_LIST;
}
const std::string ItemEnchant::RollRandomEnchant(){
const std::vector<ItemEnchantInfo>ItemEnchant::GetAvailableEnchants(){
std::vector<ItemEnchantInfo>filteredEnchants;
std::for_each(ItemEnchantInfo::GetEnchants().begin(),ItemEnchantInfo::GetEnchants().end(),[&filteredEnchants](const std::pair<std::string,ItemEnchantInfo>&data){
@ -240,7 +240,27 @@ const std::string ItemEnchant::RollRandomEnchant(){
}
});
return filteredEnchants[util::random()%filteredEnchants.size()].Name();
return filteredEnchants;
}
const std::string ItemEnchant::RollRandomEnchant(){
const std::vector<ItemEnchantInfo>filteredEnchants{GetAvailableEnchants()};
int randomRoll{int(util::random_range(0,100))};
const std::pair<int,int>generalEnchantRange{0,"Item Enchants.General Enchants.Percent Chance"_I};
const std::pair<int,int>classEnchantRange{generalEnchantRange.second,generalEnchantRange.second+"Item Enchants.Class Enchants.Percent Chance"_I};
const std::pair<int,int>uniqueEnchantRange{classEnchantRange.second,classEnchantRange.second+"Item Enchants.Unique Enchants.Percent Chance"_I};
std::vector<ItemEnchantInfo>remainingAvailableEnchants;
if(randomRoll>=generalEnchantRange.first&&randomRoll<generalEnchantRange.second){
std::copy_if(filteredEnchants.begin(),filteredEnchants.end(),std::back_inserter(remainingAvailableEnchants),[](const ItemEnchantInfo&enchant){return enchant.Category()==ItemEnchantInfo::ItemEnchantCategory::GENERAL;});
}else if(randomRoll>=classEnchantRange.first&&randomRoll<classEnchantRange.second){
std::copy_if(filteredEnchants.begin(),filteredEnchants.end(),std::back_inserter(remainingAvailableEnchants),[](const ItemEnchantInfo&enchant){return enchant.Category()==ItemEnchantInfo::ItemEnchantCategory::CLASS;});
}else if(randomRoll>=uniqueEnchantRange.first&&randomRoll<uniqueEnchantRange.second){
std::copy_if(filteredEnchants.begin(),filteredEnchants.end(),std::back_inserter(remainingAvailableEnchants),[](const ItemEnchantInfo&enchant){return enchant.Category()==ItemEnchantInfo::ItemEnchantCategory::UNIQUE;});
}else ERR(std::format("WARNING! Somehow did not pick a value in any of the given ranges. Rolled value was: {}. Ranges were {}-{}, {}-{}, {}-{}",randomRoll,generalEnchantRange.first,generalEnchantRange.second,classEnchantRange.first,classEnchantRange.second,uniqueEnchantRange.first,uniqueEnchantRange.second));
return remainingAvailableEnchants[util::random()%remainingAvailableEnchants.size()].Name();
}
void ItemEnchant::UpdateDescription(){

@ -105,6 +105,7 @@ public:
const std::string_view Description()const;
const ItemEnchantInfo::ItemEnchantCategory&Category()const;
const std::optional<ItemEnchantInfo::AbilitySlot>&AbilitySlot()const;
const static std::vector<ItemEnchantInfo>GetAvailableEnchants();
//Rolls a class-appropriate random enchant.
const static std::string RollRandomEnchant();
void SetAttribute(const std::string_view attr,const float val);

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_PATCH 5
#define VERSION_BUILD 11493
#define VERSION_BUILD 11497
#define stringify(a) stringify_(a)
#define stringify_(a) #a

Loading…
Cancel
Save