Compare commits

...

29 Commits

Author SHA1 Message Date
25c196a563 Merge pull request 'DynamicItemDescriptions Review' (#79) from DynamicItemDescriptions into master
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 6m48s
Reviewed-on: #79
2025-05-15 11:12:34 -05:00
f962e90cad Additional fixes. Finalized branch build. Ready for PR.
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 7m10s
2025-05-15 12:02:31 -04:00
2fea77c66c Fix tests for GetAllEnchantsAffectingAbility. Release Build 12194.
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Has been cancelled
2025-05-15 10:57:47 -05:00
38d72e24a1 Add AllEnchantsAffectingAbility() unit tests.
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 6m53s
2025-05-15 09:58:00 -04:00
67ca0d168d Add new test config files. Add in test to read enchant modifiers for function GetModifiers(). Release Build 12193.
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 6m41s
2025-05-15 02:17:25 -05:00
bee8d6d306 Add StringToClass and ClassToString unit tests. Release Build 12192.
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 6m49s
2025-05-15 00:38:25 -05:00
08ec6b7ed4 Merge branch 'DynamicItemDescriptions' of http://sig.projectdivar.com/sigonasr2/AdventuresInLestoria into DynamicItemDescriptions
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 6m46s
2025-05-15 00:14:06 -05:00
fab7f34afa Add a const at version for datafile getters. Retrieve values from actual datafile provided instead of assuming the variable is from base ability with the data translation function. Fix names not properly spacing/appending. Add in unit tests for GetNameWithPlayerModifiers() and GetDescriptionWithPlayerModifiers(). Applied towards PR #79. Release Build 12191. 2025-05-15 00:14:05 -05:00
ae6e5af5f6 Merge branch 'master' into DynamicItemDescriptions
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 7m13s
2025-05-12 19:26:21 -05:00
b9994242dd Fix incorrect damage display for Multi-Multishot's tooltip. (Suggestion to rework the calculation for the ability and tie the actual damage mult to its damage and just divide by number of arrows.)
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Has been cancelled
2025-05-12 19:22:34 -05:00
b43e6e5bf1 Add dynamic item description parsing and modifying based on ability enchantments for ability tooltips. Fixed bug with the transparency of drawn text not being preserved when using HTML color codes in text with alpha transparency. Release Build 12186.
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Has been cancelled
2025-05-12 19:18:07 -05:00
cb3f38e07c Fix parsing of ability descriptions to use owning strings and to retrieve from the proper keys. (Except for non-enchants.)
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 7m47s
2025-05-12 09:41:14 -05:00
93298e05d3 Create variable parser. Need to fix up when it parses the name and description and all references for its arguments.
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Failing after 1m25s
2025-05-09 17:12:14 -05:00
62ef4d2815 Fix name and description displays for abilities on hover. Release Build 12161.
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 6m51s
2025-05-09 15:46:55 -05:00
1d1cb7170c Fixes issues with retrieving name and description of enhanced abilities. Regular abilities do not display their name proper atm. Release Build 12159.
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 7m7s
2025-05-09 15:38:17 -05:00
8c8567017c Fixed constness of std::vector<std::reference_wrapper<const ItemEnchantInfo>> for GetAllEnchantsAffectingAbility() function.
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 7m8s
2025-05-08 12:06:40 -04:00
2447a6bbb1 Dynamically determine and append all prefix and suffix names and descriptions and name/description replacements for all enhancements that affect abilities.
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Failing after 3m50s
2025-05-07 16:34:15 -04:00
dcb31a01e1 Add changes to parse enchants affecting abilities.
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Failing after 1m31s
2025-05-07 14:06:00 -05:00
9722695e5b Setting up for revealing modified descriptions and names all put together.
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Failing after 1m44s
2025-05-06 16:32:25 -04:00
7308a7e37b Fix up missing Ranger item descriptions 2025-05-06 14:43:39 -04:00
0f012faf36 Add multiple threads to autobuild.
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 6m45s
2025-05-06 14:32:58 -04:00
8d8534c90b Build should be multi-threaded.
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Failing after 1m18s
2025-05-06 12:33:26 -04:00
5a4e7fb53b Add in Gitea workflow for remote auto-build.
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Has been cancelled
2025-05-06 12:30:54 -04:00
1dd3e31735 Add in libs to git staging. 2025-04-24 15:51:59 -04:00
97820bf52b Add ring enchant descriptions for Ranger enchants. Fix up test configuration. 2025-04-23 14:48:22 -04:00
a6e121cbaa Merge branch 'DynamicItemDescriptions' of http://sig.projectdivar.com/sigonasr2/AdventuresInLestoria into DynamicItemDescriptions 2025-04-23 10:05:19 -04:00
c91130eded Fast-forward to 'master' branch 2025-04-23 10:05:12 -04:00
6da5e5b98b Merge branch 'master' into DynamicItemDescriptions 2025-04-23 10:01:49 -04:00
1fe27dce95 Pirate's Treasure Locked state added. Begin populating new item description and enchant structures. 2025-03-26 21:54:47 -05:00
30 changed files with 547 additions and 38 deletions

View File

@ -47,7 +47,7 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Unit Testing|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(ProjectDir)..\AdventuresInLestoria\Adventures in Lestoria;$(ProjectDir)..\AdventuresInLestoria\Adventures in Lestoria\include;$(IncludePath)</IncludePath>
<IncludePath>C:\Users\LabUser\source\repos\AdventuresInLestoria\Adventures in Lestoria\include;C:\Users\LabUser\source\repos\AdventuresInLestoria\Adventures in Lestoria;$(SolutionDir)Adventures in Lestoria;$(SolutionDir)Adventures in Lestoria\include$(SolutionDir);$(IncludePath)</IncludePath>
<OutDir>..\x64\Unit Testing</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Unit Testing|Win32'">
@ -58,7 +58,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>J:\AdventuresInLestoria\Adventures in Lestoria\steam;J:\AdventuresInLestoria\Adventures in Lestoria\discord-files;C:\Users\niconiconii\source\repos\AdventuresInLestoria\Adventures in Lestoria\steam;C:\Users\sigon\source\repos\AdventuresInLestoria\Adventures in Lestoria\steam;C:\Users\niconiconii\source\repos\AdventuresInLestoria\Adventures in Lestoria\discord-files;C:\Users\sigon\source\repos\AdventuresInLestoria\Adventures in Lestoria\discord-files;C:\Users\niconiconii\OneDrive\Documents\include;C:\Users\sigon\OneDrive\Documents\include;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\Users\LabUser\source\repos\AdventuresInLestoria\Adventures in Lestoria\include;J:\AdventuresInLestoria\Adventures in Lestoria\steam;J:\AdventuresInLestoria\Adventures in Lestoria\discord-files;C:\Users\niconiconii\source\repos\AdventuresInLestoria\Adventures in Lestoria\steam;C:\Users\LabUser\source\repos\AdventuresInLestoria\Adventures in Lestoria\steam;C:\Users\sigon\source\repos\AdventuresInLestoria\Adventures in Lestoria\steam;C:\Users\niconiconii\source\repos\AdventuresInLestoria\Adventures in Lestoria\discord-files;C:\Users\LabUser\source\repos\AdventuresInLestoria\Adventures in Lestoria\discord-files;C:\Users\sigon\source\repos\AdventuresInLestoria\Adventures in Lestoria\discord-files;C:\Users\niconiconii\OneDrive\Documents\include;C:\Users\LabUser\OneDrive\Documents\include;C:\Users\sigon\OneDrive\Documents\include;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<PrecompiledHeaderFile>

View File

@ -113,6 +113,49 @@ namespace EnchantTests
testGame->OnUserUpdate(0.f);
testGame.reset();
}
TEST_METHOD(AbilityNameWithPlayerModifiersWorks){
Game::ChangeClass(player,RANGER);
Assert::AreEqual("Rapid Fire",player->GetAbility1().GetNameWithPlayerModifiers().c_str(),L"Ability name should be unmodified with no modifiers applied.");
Assert::AreEqual("Shoots #45F9FFfour#FFFFFF arrows rapidly. Total Damage: #45F9FF52#FFFFFF.",player->GetAbility1().GetDescriptionWithPlayerModifiers().c_str(),L"Ability descriptions should be unmodified with no modifiers applied.");
Game::GiveAndEquipEnchantedRing("Extreme Rapid Fire");
Assert::AreEqual("Extreme Rapid Fire",player->GetAbility1().GetNameWithPlayerModifiers().c_str(),L"Ability name should be modified with appropriate modifier applied.");
Assert::AreEqual("Shoots #45F9FFnine#FFFFFF arrows rapidly. Total Damage: #45F9FF117#FFFFFF.",player->GetAbility1().GetDescriptionWithPlayerModifiers().c_str(),L"Ability description should be modified with appropriate modifier applied.");
Inventory::UnequipItem(EquipSlot::RING1);
Assert::AreEqual("Rapid Fire",player->GetAbility1().GetNameWithPlayerModifiers().c_str(),L"After unequipping Ability name should be back to normal with no modifiers applied.");
Assert::AreEqual("Shoots #45F9FFfour#FFFFFF arrows rapidly. Total Damage: #45F9FF52#FFFFFF.",player->GetAbility1().GetDescriptionWithPlayerModifiers().c_str(),L"After unequipping Ability descriptions should be back to normal with no modifiers applied.");
}
TEST_METHOD(AbilityDescriptionModifiersPopulateProperly){
ItemEnchantInfo::AbilityDescriptionModifiers modifiers{"Test Enchant"_ENC.GetModifiers()};
Assert::AreEqual("Test",(*modifiers.preName).c_str(),L"Pre-name reads in properly");
Assert::AreEqual("Enchant",(*modifiers.newName).c_str(),L"Replacement name reads in properly");
Assert::IsFalse(modifiers.postName.has_value(),L"Post-name should not have a value.");
Assert::AreEqual("Pre test",(*modifiers.preDescription).c_str(),L"Pre-description reads in properly");
Assert::AreEqual("My Description",(*modifiers.newDescription).c_str(),L"Replacement description reads in properly");
Assert::AreEqual("Post test",(*modifiers.postDescription).c_str(),L"Post-description reads in properly");
}
TEST_METHOD(AllEnchantsAffectingAbilityTest){
for(int classBits{int(Class::WARRIOR)};classBits<=int(Class::WITCH);classBits<<=1){
const Class cl{Class(classBits)};
Game::ChangeClass(player,cl);
for(const Ability&ability:player->GetAbilities()){
Assert::AreEqual(size_t(0),ItemEnchantInfo::GetAllEnchantsAffectingAbility(ability.GetName()).size(),util::wformat("There should be no enchants affecting ability {} by default.",ability.GetName()).c_str());
}
}
Game::GiveAndEquipEnchantedRing("Heavy Guard");
Assert::AreEqual(size_t(1),ItemEnchantInfo::GetAllEnchantsAffectingAbility("Block").size(),L"There should be 1 enchant affecting ability Block.");
Game::GiveAndEquipEnchantedRing("Advance Shield",EquipSlot::RING2);
Assert::AreEqual(size_t(2),ItemEnchantInfo::GetAllEnchantsAffectingAbility("Block").size(),L"There should be 2 enchants affecting ability Block.");
Inventory::UnequipItem(EquipSlot::RING1);
Assert::AreEqual(size_t(1),ItemEnchantInfo::GetAllEnchantsAffectingAbility("Block").size(),L"There should be 1 enchant affecting ability Block.");
Game::GiveAndEquipEnchantedRing("Advance Shield");
Assert::AreEqual(size_t(1),ItemEnchantInfo::GetAllEnchantsAffectingAbility("Block").size(),L"With two of the same enchant, there should only be 1 enchant enchants affecting ability Block.");
Inventory::UnequipItem(EquipSlot::RING2);
Assert::AreEqual(size_t(1),ItemEnchantInfo::GetAllEnchantsAffectingAbility("Block").size(),L"There should be 1 enchant affecting ability Block.");
Inventory::UnequipItem(EquipSlot::RING1);
Assert::AreEqual(size_t(0),ItemEnchantInfo::GetAllEnchantsAffectingAbility("Block").size(),L"There should be no enchants affecting ability Block by default.");
}
TEST_METHOD(HealthBoostCheck){
Assert::AreEqual(100,player->GetMaxHealth(),L"Player starts with 100 health.");
std::weak_ptr<Item>nullRing{Game::GiveAndEquipEnchantedRing("Aura of the Beast")};

View File

@ -174,5 +174,21 @@ namespace EngineTests
Assert::AreEqual(200.f,util::map_range<float>(100.f,50,100,100,200),L"100 in input range 50-100 output range 100-200 maps to 200");
Assert::AreEqual(100.f,util::map_range<float>(50.f,50,100,100,200),L"50 in input range 50-100 output range 100-200 maps to 100");
}
TEST_METHOD(ClassUtilTest){
Assert::AreEqual(int(Class::WARRIOR),int(classutils::StringToClass("Warrior")),L"Expected Warrior to return the warrior class.");
Assert::AreEqual(int(Class::WIZARD),int(classutils::StringToClass("Wizard")),L"Expected Wizard to return the wizard class.");
Assert::AreEqual(int(Class::RANGER),int(classutils::StringToClass("Ranger")),L"Expected Ranger to return the ranger class.");
Assert::AreEqual(int(Class::THIEF),int(classutils::StringToClass("Thief")),L"Expected Thief to return the thief class.");
Assert::AreEqual(int(Class::WITCH),int(classutils::StringToClass("Witch")),L"Expected Witch to return the witch class.");
Assert::AreEqual(int(Class::TRAPPER),int(classutils::StringToClass("Trapper")),L"Expected Trapper to return the trapper class.");
Assert::AreEqual("Warrior",classutils::ClassToString(Class::WARRIOR).c_str(),L"Expected class to string to convert properly");
Assert::AreEqual("Wizard",classutils::ClassToString(Class::WIZARD).c_str(),L"Expected class to string to convert properly");
Assert::AreEqual("Ranger",classutils::ClassToString(Class::RANGER).c_str(),L"Expected class to string to convert properly");
Assert::AreEqual("Thief",classutils::ClassToString(Class::THIEF).c_str(),L"Expected class to string to convert properly");
Assert::AreEqual("Witch",classutils::ClassToString(Class::WITCH).c_str(),L"Expected class to string to convert properly");
Assert::AreEqual("Trapper",classutils::ClassToString(Class::TRAPPER).c_str(),L"Expected class to string to convert properly");
}
};
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -68,10 +68,148 @@ const bool Ability::operator==(const Ability&a)const{
return name==a.name&&isOriginalAbility==a.isOriginalAbility;
}
const std::string Ability::GetName()const{
return std::format("{}",name);
const std::string&Ability::GetName()const{
return name;
}
const std::string_view Ability::GetDescription()const{
return description;
}
const std::string Ability::GetNameWithPlayerModifiers()const{
std::string prefixName{};
std::string newName{name};
std::string suffixName{};
for(const auto&enchant:ItemEnchantInfo::GetAllEnchantsAffectingAbility(name)){
const ItemEnchantInfo::AbilityDescriptionModifiers&modifiers{enchant.get().GetModifiers()};
if(prefixName.length()>0&&modifiers.preName)prefixName+=" ";
prefixName+=modifiers.preName.value_or("");
if(modifiers.newName)newName=modifiers.newName.value();
if(suffixName.length()>0&&modifiers.preName)suffixName+=" ";
suffixName+=modifiers.postName.value_or("");
}
std::string finalName{prefixName};
if(finalName.length()>0&&newName.length()>0)finalName+=' ';
finalName+=newName;
if(finalName.length()>0&&suffixName.length()>0)finalName+=' ';
finalName+=suffixName;
return finalName;
}
const std::string Ability::GetDescriptionWithPlayerModifiers()const{
using SpecialKey=std::string;
using TranslateFunc=std::function<std::string(const datafile&data,const std::string&val)>;
std::unordered_map<SpecialKey,TranslateFunc>specialPrefixes{
#define TranslateFunc [&](const datafile&data,const std::string&val)->std::string
{"DamageMult",TranslateFunc{
float damageMult{stof(data.at(val).GetString())};
int finalDmg{int(damageMult*game->GetPlayer()->GetAttack())};
return std::format("{}",finalDmg);
}},
};
const Pixel specialValCol{69,249,255};
const auto ParseVariables=[&](const std::string_view abilityText)->std::string{
std::string finalText{};
size_t marker{};
std::string variableName{};
bool bracesFound{false};
const auto FindAndParse=[&finalText,&bracesFound,&variableName,&specialPrefixes,&specialValCol](datafile&data)->bool{
if(data.HasProperty(variableName)){
finalText+=specialValCol.toHTMLColorCode()+data.GetProperty(variableName).GetFullString()+WHITE.toHTMLColorCode();
bracesFound=false;
variableName="";
return true;
}else if(size_t separatorMarker{std::string::npos};(separatorMarker=variableName.find(':'))!=std::string::npos){
std::string separatorKey{variableName.substr(0,separatorMarker)};
std::string separatorVal{variableName.substr(separatorMarker+1)};
if(!specialPrefixes.count(separatorKey))ERR(std::format("Could not find translation function for key {} inside special prefixes map!",separatorKey))
else {
finalText+=specialValCol.toHTMLColorCode()+specialPrefixes[separatorKey](data,separatorVal)+WHITE.toHTMLColorCode();
bracesFound=false;
return true;
}
}
return false;
};
while(marker<abilityText.length()){
const char c{abilityText[marker]};
if(!bracesFound&&c=='{')bracesFound=true;
else if(bracesFound&&c=='}'){ //Parse the variable.
if(!FindAndParse((*abilityConfig).get()))
ERR(std::format("Could not find variable {} for Ability {}",variableName,GetName()));
}else if(bracesFound)variableName+=c;
else finalText+=c;
marker++;
}
return finalText;
};
std::string prefixDescription{};
std::string newDescription{ParseVariables(description)};
std::string suffixDescription{};
bool descriptionHasBeenModifiedAgain{false};
for(const auto&enchant:ItemEnchantInfo::GetAllEnchantsAffectingAbility(name)){
const ItemEnchantInfo::AbilityDescriptionModifiers&modifiers{enchant.get().GetModifiers()};
if(prefixDescription.length()>0&&modifiers.preDescription)prefixDescription+=" ";
prefixDescription+=modifiers.preDescription.value_or("");
if(modifiers.newDescription)newDescription=*modifiers.newDescription;
if(suffixDescription.length()>0&&modifiers.preDescription)suffixDescription+=" ";
suffixDescription+=modifiers.postDescription.value_or("");
const auto ParseVariablesForEnchant=[&](const std::string_view abilityText)->std::string{
std::string finalText{};
size_t marker{};
std::string variableName{};
bool bracesFound{false};
const auto FindAndParse=[&finalText,&bracesFound,&variableName,&specialPrefixes,&specialValCol](datafile&data)->bool{
if(data.HasProperty(variableName)){
finalText+=specialValCol.toHTMLColorCode()+data.GetProperty(variableName).GetFullString()+WHITE.toHTMLColorCode();
bracesFound=false;
variableName="";
return true;
}else if(size_t separatorMarker{std::string::npos};(separatorMarker=variableName.find(':'))!=std::string::npos){
std::string separatorKey{variableName.substr(0,separatorMarker)};
std::string separatorVal{variableName.substr(separatorMarker+1)};
if(!specialPrefixes.count(separatorKey))ERR(std::format("Could not find translation function for key {} inside special prefixes map!",separatorKey))
else {
finalText+=specialValCol.toHTMLColorCode()+specialPrefixes[separatorKey](data,separatorVal)+WHITE.toHTMLColorCode();
bracesFound=false;
return true;
}
}
return false;
};
while(marker<abilityText.length()){
const char c{abilityText[marker]};
if(!bracesFound&&c=='{')bracesFound=true;
else if(bracesFound&&c=='}'){ //Parse the variable.
if(!FindAndParse(enchant.get().GetData()["Ability Settings"]))
if(!FindAndParse(enchant.get().GetData()))
if(!FindAndParse((*(*enchant.get().GetAbility())->abilityConfig).get()))
ERR(std::format("Could not find variable {} for enchant Ability Settings of enchantment {}",variableName,enchant.get().Name()));
}else if(bracesFound)variableName+=c;
else finalText+=c;
marker++;
}
return finalText;
};
prefixDescription=ParseVariablesForEnchant(prefixDescription);
if(!descriptionHasBeenModifiedAgain){
descriptionHasBeenModifiedAgain=true;
newDescription=description;
}
newDescription=ParseVariablesForEnchant(newDescription);
suffixDescription=ParseVariablesForEnchant(suffixDescription);
}
std::string finalDescription{prefixDescription};
if(finalDescription.length()>0&&newDescription.length()>0)finalDescription+=' ';
finalDescription+=newDescription;
if(finalDescription.length()>0&&suffixDescription.length()>0)finalDescription+=' ';
finalDescription+=suffixDescription;
return finalDescription;
}

View File

@ -37,8 +37,8 @@ All rights reserved.
#pragma endregion
#pragma once
#include "Key.h"
#include "olcPixelGameEngine.h"
#include <string_view>
#include "olcUTIL_DataFile.h"
class InputGroup;
@ -90,10 +90,14 @@ struct Ability{
static std::string tooltipText;
static std::string tooltipTitle;
static Pixel tooltipTitleCol;
std::optional<std::reference_wrapper<datafile>>abilityConfig;
constexpr static float MAX_DESCRIPTION_HOVER_TIME{0.3f};
Ability();
//NOTE: icon expects the actual name relative to the "Ability Icons" directory for this constructor!
Ability(std::string name,std::string shortName,std::string description,float cooldownTime,int manaCost,InputGroup*input,std::string icon,Pixel barColor1=VERY_DARK_RED,Pixel barColor2=DARK_RED,PrecastData precastInfo={},bool canCancelCast=false);
const std::string GetName()const;
const std::string&GetName()const;
const std::string_view GetDescription()const;
const std::string GetNameWithPlayerModifiers()const;
const std::string GetDescriptionWithPlayerModifiers()const;
};

View File

@ -1314,6 +1314,12 @@
<None Include="steam\steam_api.json" />
</ItemGroup>
<ItemGroup>
<Text Include="..\x64\Unit Testing\assets\config\items\Accessories-test.txt" />
<Text Include="..\x64\Unit Testing\assets\config\items\Equipment-test.txt" />
<Text Include="..\x64\Unit Testing\assets\config\items\ItemDatabase-test.txt" />
<Text Include="..\x64\Unit Testing\assets\config\items\ItemEnchants-test.txt" />
<Text Include="..\x64\Unit Testing\assets\config\items\items-test.txt" />
<Text Include="..\x64\Unit Testing\assets\config\items\ItemSets-test.txt" />
<Text Include="..\x64\Unit Testing\debug.log" />
<Text Include="assets\config\Achievements.txt" />
<Text Include="assets\config\audio\audio.txt" />

View File

@ -106,6 +106,9 @@
<Filter Include="Debug">
<UniqueIdentifier>{c4119802-3fc8-4555-9013-a7a3ac9b204d}</UniqueIdentifier>
</Filter>
<Filter Include="Configurations\Items\Test Configurations">
<UniqueIdentifier>{354b389b-2ec1-4cf6-ace0-6597b14edfab}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="olcPixelGameEngine.h">
@ -711,12 +714,12 @@
<ClInclude Include="Arc.h">
<Filter>Header Files\Utils</Filter>
</ClInclude>
<ClInclude Include="Entity.h">
<Filter>Header Files\Utils</Filter>
</ClInclude>
<ClInclude Include="State_Arena.h">
<Filter>Header Files\State</Filter>
</ClInclude>
<ClInclude Include="Entity.h">
<Filter>Header Files\State</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Player.cpp">
@ -1583,6 +1586,24 @@
<Text Include="Chapter_3_FinalBoss.txt">
<Filter>Documentation\Mechanics</Filter>
</Text>
<Text Include="..\x64\Unit Testing\assets\config\items\Accessories-test.txt">
<Filter>Configurations\Items\Test Configurations</Filter>
</Text>
<Text Include="..\x64\Unit Testing\assets\config\items\Equipment-test.txt">
<Filter>Configurations\Items\Test Configurations</Filter>
</Text>
<Text Include="..\x64\Unit Testing\assets\config\items\ItemDatabase-test.txt">
<Filter>Configurations\Items\Test Configurations</Filter>
</Text>
<Text Include="..\x64\Unit Testing\assets\config\items\ItemEnchants-test.txt">
<Filter>Configurations\Items\Test Configurations</Filter>
</Text>
<Text Include="..\x64\Unit Testing\assets\config\items\ItemSets-test.txt">
<Filter>Configurations\Items\Test Configurations</Filter>
</Text>
<Text Include="..\x64\Unit Testing\assets\config\items\items-test.txt">
<Filter>Configurations\Items\Test Configurations</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<Image Include="assets\heart.ico">

View File

@ -179,7 +179,7 @@ AiL::AiL(bool testingMode){
utils::datafile::Read(DATA,ITEM_SET_CONFIG,',',datafile::OverwriteMode::OVERWRITE);
auto keys=DATA.GetProperty("ItemConfiguration");
for(auto&[key,value]:keys){
std::string config=DATA["ItemConfiguration"][key].GetString();
std::string config=DATA["ItemConfiguration"][key].GetString();
utils::datafile::Read(DATA,CONFIG_PATH + "item_directory"_S + config,',',datafile::OverwriteMode::OVERWRITE);
}
}
@ -2183,8 +2183,8 @@ void AiL::RenderCooldowns(){
if(HasEnchantWithAbilityAffected)abilityTitleCol=Pixel{0xFFCD00};
if(a.itemAbility)abilityTitleCol=Pixel{0xA2FF00};
Ability::tooltipTitleCol=abilityTitleCol;
Ability::tooltipTitle=std::format("{}",a.GetName());
Ability::tooltipText=std::format("{}",a.GetDescription());
Ability::tooltipTitle=std::format("{}",a.GetNameWithPlayerModifiers());
Ability::tooltipText=std::format("{}",a.GetDescriptionWithPlayerModifiers());
}
}else heldDownAnyAbilityKey=true;
#pragma endregion
@ -3011,6 +3011,11 @@ void AiL::InitializeClasses(){
Trapper::CreateOriginalCopies();
Wizard::CreateOriginalCopies();
Witch::CreateOriginalCopies();
for(int classBitCount{0b1};const std::string&cl:DATA["class_list"].GetValues()){
classutils::classList[Class(classBitCount)]=cl;
classBitCount<<=1;
}
}
std::string AiL::GetString(std::string key){

View File

@ -56,6 +56,7 @@ enum Class{
};
namespace classutils{//Classes have bit-wise operator capabilities.
inline std::unordered_map<Class,std::string>classList;
static inline Class StringToClass(std::string className){
const std::vector<std::string>&classList=DATA["class_list"].GetValues();
auto it=std::find(classList.begin(),classList.end(),className);
@ -63,4 +64,7 @@ namespace classutils{//Classes have bit-wise operator capabilities.
int element=int(std::distance(classList.begin(),it));
return Class(1<<element); //Yes...It's bitwise flags, who in god's name knows why I did this.
};
static inline std::string ClassToString(const Class&cl){
return classList.at(cl);
}
};

View File

@ -117,7 +117,20 @@ void ItemEnchantInfo::Initialize(){
newEnchant.abilitySlot=affectSlots.at(affectStr);
}
auto IsRequiredKey=[](const std::string_view key){return key=="Description"||key=="Affects"||key.starts_with("Stat Modifier[");};
ItemEnchantInfo::AbilityDescriptionModifiers modifiers;
if(enchant.HasProperty("Ability Settings")){
for(const auto&[key,size]:enchant["Ability Settings"]){
if(key=="Pre-Name")modifiers.preName=enchant["Ability Settings"][key].GetFullString();
else if(key=="Post-Name")modifiers.postName=enchant["Ability Settings"][key].GetFullString();
else if(key=="Name")modifiers.newName=enchant["Ability Settings"][key].GetFullString();
else if(key=="Pre-Description")modifiers.preDescription=enchant["Ability Settings"][key].GetFullString();
else if(key=="Post-Description")modifiers.postDescription=enchant["Ability Settings"][key].GetFullString();
else if(key=="Description")modifiers.newDescription=enchant["Ability Settings"][key].GetFullString();
}
}
auto IsRequiredKey=[](const std::string_view key){return key=="Description"||key=="Affects"||key.starts_with("Stat Modifier[")||key.starts_with("Ability Settings");};
for(auto&[key,size]:enchant){
if(IsRequiredKey(key))continue;
@ -143,6 +156,7 @@ void ItemEnchantInfo::Initialize(){
}
newEnchant.description=enchantDescription;
newEnchant.modifiers=modifiers;
return newEnchant;
};
@ -181,7 +195,7 @@ ItemEnchant::ItemEnchant(const std::string_view enchantName)
}
}
const ItemEnchantInfo&ItemEnchantInfo::GetEnchant(const std::string_view enchantName){
ItemEnchantInfo&ItemEnchantInfo::GetEnchant(const std::string_view enchantName){
return ENCHANT_LIST.at(std::string(enchantName));
}
@ -350,4 +364,30 @@ const bool ItemEnchant::HasAttributes()const{
const std::optional<Class>&ItemEnchant::GetClass()const{
return ItemEnchantInfo::GetEnchant(Name()).GetClass();
}
const std::vector<std::reference_wrapper<ItemEnchantInfo>>ItemEnchantInfo::GetAllEnchantsAffectingAbility(const std::string_view ability){
std::vector<std::reference_wrapper<ItemEnchantInfo>>enchantsAffectingList{};
for(const auto&enchantName:game->GetPlayer()->GetEnchants()){
ItemEnchantInfo&enchant{ItemEnchantInfo::GetEnchant(enchantName)};
if(enchant.GetAbility()&&(*enchant.GetAbility())->GetName()==ability)enchantsAffectingList.emplace_back(std::ref(enchant));
}
return enchantsAffectingList;
}
const ItemEnchantInfo::AbilityDescriptionModifiers ItemEnchantInfo::GetModifiers()const{
return modifiers;
}
datafile&ItemEnchantInfo::GetData(){
switch(Category()){
case ItemEnchantCategory::CLASS:{
return DATA["Item Enchants"]["Class Enchants"][classutils::ClassToString(*GetClass())][Name()];
}break;
case ItemEnchantCategory::GENERAL:{
return DATA["Item Enchants"]["General Enchants"];
}break;
case ItemEnchantCategory::UNIQUE:{
return DATA["Item Enchants"]["Unique Enchants"];
}break;
}
ERR(std::format("An undefined return path was reached for some reason while trying to retrieve data! Category: {}",int(Category())));
return DATA;
}

View File

@ -64,10 +64,19 @@ public:
ABILITY_3,
};
struct AbilityDescriptionModifiers{
std::optional<std::string>preName;
std::optional<std::string>postName;
std::optional<std::string>newName;
std::optional<std::string>preDescription;
std::optional<std::string>postDescription;
std::optional<std::string>newDescription;
};
const static Pixel enchantAttributeCol;
static void Initialize();
const static ItemEnchantInfo&GetEnchant(const std::string_view enchantName);
static ItemEnchantInfo&GetEnchant(const std::string_view enchantName);
const static std::unordered_map<std::string,ItemEnchantInfo>&GetEnchants();
static std::unordered_map<ItemEnchantCategory,Pixel>enchantTextDisplayCol;
@ -78,8 +87,11 @@ public:
const std::optional<AbilitySlot>&GetAbilitySlot()const;
const std::optional<Ability*>GetAbility()const; //Get the ability this enchant is tied to.
const Pixel&DisplayCol()const;
const float GetConfigValue(const std::string_view keyName)const;
const float GetConfigValue(const std::string_view keyName)const;
const float operator[](const std::string&name)const;
const AbilityDescriptionModifiers GetModifiers()const;
static const std::vector<std::reference_wrapper<ItemEnchantInfo>>GetAllEnchantsAffectingAbility(const std::string_view ability);
datafile&GetData();
private:
class ItemEnchantCategoryData{
friend class ItemEnchantInfo;
@ -98,6 +110,7 @@ private:
std::unordered_map<std::string,float>config;
static std::unordered_map<std::string,ItemEnchantInfo>ENCHANT_LIST;
static std::unordered_map<ItemEnchantCategory,ItemEnchantCategoryData>ENCHANT_CATEGORIES;
AbilityDescriptionModifiers modifiers;
};
class Item;

View File

@ -42,12 +42,25 @@ All rights reserved.
INCLUDE_game
void Monster::STRATEGY::PIRATES_TREASURE(Monster&m,float fElapsedTime,std::string strategy){
const float distToPlayer{util::distance(game->GetPlayer()->GetPos(),m.GetPos())};
if(distToPlayer<=ConfigFloat("Open Distance"))m.PerformAnimation("OPEN");
else m.PerformIdleAnimation();
if(m.B(Attribute::COLLIDED_WITH_PLAYER)&&game->GetPlayer()->HasBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN)){
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_PRECURSE);
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN);
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT);
enum Phase{
NORMAL,
LOCKED,
};
switch(PHASE()){
case NORMAL:{
const float distToPlayer{util::distance(game->GetPlayer()->GetPos(),m.GetPos())};
if(distToPlayer<=ConfigFloat("Open Distance"))m.PerformAnimation("OPEN");
else m.PerformIdleAnimation();
if(m.B(Attribute::COLLIDED_WITH_PLAYER)&&game->GetPlayer()->HasBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN)){
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_PRECURSE);
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN);
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT);
}
}break;
case LOCKED:{
m.PerformAnimation("LOCKED");
m.SetCollisionRadius(m.GetOriginalCollisionRadius()+12);
}break;
}
}

View File

@ -2322,4 +2322,8 @@ const bool Player::CoveredInInk()const{
}
const vf2d&Player::GetPreviousPos()const{
return previousPos;
}
const std::unordered_set<std::string>&Player::GetEnchants()const{
return enchantList;
}

View File

@ -340,6 +340,7 @@ public:
void SetTestScreenAimingLocation(vf2d forcedAimingLoc);
const bool CoveredInInk()const;
const vf2d&GetPreviousPos()const; //The position the player was at on the last frame, can be used for comparison purposes to predict where the player may be next.
const std::unordered_set<std::string>&GetEnchants()const; //Get all enchants currently affecting the player.
private:
static std::vector<std::reference_wrapper<Ability>>ABILITY_LIST;
const int SHIELD_CAPACITY{32};
@ -774,6 +775,7 @@ private:
{#class".Right Click Ability.Precast Time"_F,#class".Right Click Ability.Casting Range"_I/100.f*24,#class".Right Click Ability.Casting Size"_I/100.f*24}, \
bool( #class".Right Click Ability.CancelCast"_I ) \
}; \
class::rightClickAbility.abilityConfig=std::ref(DATA.GetProperty(#class".Right Click Ability")); \
class::ability1={ \
#class".Ability 1.Name"_S, \
#class".Ability 1.Short Name"_S, \
@ -787,6 +789,7 @@ private:
{#class".Ability 1.Precast Time"_F,#class".Ability 1.Casting Range"_I/100.f*24,#class".Ability 1.Casting Size"_I/100.f*24}, \
bool(#class".Ability 1.CancelCast"_I) \
}; \
class::ability1.abilityConfig=std::ref(DATA.GetProperty(#class".Ability 1")); \
class::ability2={ \
#class".Ability 2.Name"_S, \
#class".Ability 2.Short Name"_S, \
@ -800,6 +803,7 @@ private:
{#class".Ability 2.Precast Time"_F,#class".Ability 2.Casting Range"_I/100.f*24,#class".Ability 2.Casting Size"_I/100.f*24}, \
bool(#class".Ability 2.CancelCast"_I) \
}; \
class::ability2.abilityConfig=std::ref(DATA.GetProperty(#class".Ability 2")); \
class::ability3={ \
#class".Ability 3.Name"_S, \
#class".Ability 3.Short Name"_S, \
@ -813,6 +817,7 @@ private:
{#class".Ability 3.Precast Time"_F,#class".Ability 3.Casting Range"_I/100.f*24,#class".Ability 3.Casting Size"_I/100.f*24}, \
bool(#class".Ability 3.CancelCast"_I) \
}; \
class::ability3.abilityConfig=std::ref(DATA.GetProperty(#class".Ability 3")); \
class::ability4; \
Player::ABILITY_LIST.emplace_back(class::original_rightClickAbility); \
Player::ABILITY_LIST.emplace_back(class::original_ability1); \

View File

@ -21,4 +21,9 @@ Adding new class animations
Player.txt contains animation names the player has to have loaded.
<className>.cpp contains walk and idle animation references that must be loaded in the Initialize() function.
Animation.cpp contains the SetupClassWalkIdleAnimations() function which all classes need to implement with their spritesheet and class name (all caps) to create the WALK and IDLE animations in the animation database.
All other custom player class animations must be added here too.
All other custom player class animations must be added here too.
Silly Large Purple Wizard Cloak
Peace sign on finishing a stage (wink)
Kitty Headband
Zombie Heart Eyes

View File

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_PATCH 0
#define VERSION_BUILD 12140
#define VERSION_BUILD 12194
#define stringify(a) stringify_(a)
#define stringify_(a) #a

View File

@ -1887,7 +1887,7 @@ Monsters
Strategy = Pirate's Treasure
#Size of each animation frame
SheetFrameSize = 24,24
SheetFrameSize = 36,36
# Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST
4-Way Spritesheet = False
@ -1899,7 +1899,7 @@ Monsters
# The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
IDLE = 1, 1.0, OneShot
WALK = 1, 1.0, OneShot
SLASHING = 1, 1.0, OneShot
LOCKED = 1, 1.0, OneShot
OPEN = 1, 1.0, OneShot
}

View File

@ -64,7 +64,9 @@ Ranger
# Whether or not this ability cancels casts.
CancelCast = 0
Description = Shoots five arrows rapidly at a target location.
Description = Shoots {ARROW COUNT} arrows rapidly. Total Damage: {DamageMult:TotalDamageMult}.
ARROW COUNT = four
#RGB Values. Color 1 is the circle at full cooldown, Color 2 is the color at empty cooldown.
Cooldown Bar Color 1 = 64, 0, 0, 192
@ -88,6 +90,8 @@ Ranger
# Hitbox radius of the arrows
ArrowRadius = 100
TotalDamageMult = 4.0x
Sound = Ranger Rapid Fire
}
Ability 2
@ -100,7 +104,7 @@ Ranger
# Whether or not this ability cancels casts.
CancelCast = 0
Description = Fires an ultrasonic arrow towards a location, piercing everything it comes in contact with.
Description = Fires an ultrasonic arrow towards a location, piercing everything it comes in contact with. Deals {DamageMult:DamageMult} damage.
#RGB Values. Color 1 is the circle at full cooldown, Color 2 is the color at empty cooldown.
Cooldown Bar Color 1 = 64, 0, 0, 192
@ -134,7 +138,7 @@ Ranger
# Whether or not this ability cancels casts.
CancelCast = 0
Description = The Ranger prepares and fires a fan of densely packed arrows.
Description = Prepares and fires a fan of {ArrowCount} packed arrows. Total Damage: {DamageMult:TotalDamageMult}.
#RGB Values. Color 1 is the circle at full cooldown, Color 2 is the color at empty cooldown.
Cooldown Bar Color 1 = 64, 0, 0, 192
@ -148,7 +152,8 @@ Ranger
DamageMult = 1.0
# Number of arrows in the shot spread.
ArrowCount = 6
# How far the shot spread in one angle is. For example, if the value here is set to 18.375, then Multi shot divides the arrows evenly from a span of -18.375 degrees to the left to 18.375 degrees to the right of the player.
TotalDamageMult = 6.0
# How far the shot spread in one angle is. For example, if the value here is set to 18.375, then Multishot divides the arrows evenly from a span of -18.375 degrees to the left to 18.375 degrees to the right of the player.
MultiShotSpread = 18.375
# Speed of arrows that Rapid Fire shoots out.
ArrowSpd = 300

View File

@ -52,7 +52,7 @@ theme_img_directory = themes/
# Path to class configuration files
class_directory = classes/
# Class list to be loaded into the game.
# Class list to be loaded into the game. SHOULD BE IN ORDER BASED ON Class.h
class_list = Warrior, Thief, Ranger, Trapper, Wizard, Witch
# Items Config

View File

@ -93,6 +93,17 @@ Item Enchants
# Stat, Lowest, Highest Value
# Stat Modifier[0] = ..., 0, 0
Ability Settings
{
# Add variables here to modify what the ability's original description might state.
# Use "Pre-Description" and "Post-Description" keys to add to the front or back of a current description string.
# Use "Description" key to completely overwrite the default description (be careful of conflicts with another modification!)
# Use "Pre-Name" and "Post-Name" keys to add to the front or back of a current ability name.
# Use "Name" to completely overwrite the default ability name (be careful of conflicts with another modification!)
Pre-Name = Stealthy
Post-Description = "Invulnerability time increased by {INVULNERABILITY INCREASE} seconds"
}
}
Poisonous Arrow
{
@ -115,6 +126,18 @@ Item Enchants
# Stat, Lowest, Highest Value
# Stat Modifier[0] = ..., 0, 0
Ability Settings
{
# Add variables here to modify what the ability's original description might state.
# Use "Pre-Description" and "Post-Description" keys to add to the front or back of a current description string.
# Use "Description" key to completely overwrite the default description (be careful of conflicts with another modification!)
# Use "Pre-Name" and "Post-Name" keys to add to the front or back of a current ability name.
# Use "Name" to completely overwrite the default ability name (be careful of conflicts with another modification!)
Pre-Name = Extreme
ARROW COUNT = nine
TotalDamageMult = 9.0x
}
}
Charge Beam
{
@ -125,17 +148,40 @@ Item Enchants
# Stat, Lowest, Highest Value
# Stat Modifier[0] = ..., 0, 0
Ability Settings
{
# Add variables here to modify what the ability's original description might state.
# Use "Pre-Description" and "Post-Description" keys to add to the front or back of a current description string.
# Use "Description" key to completely overwrite the default description (be careful of conflicts with another modification!)
# Use "Pre-Name" and "Post-Name" keys to add to the front or back of a current ability name.
# Use "Name" to completely overwrite the default ability name (be careful of conflicts with another modification!)
Name = "Charge Beam"
Post-Description = "Width is massively increased."
}
}
Mega Charged Shot
{
Description = "Charged Shot's cast time increases by {CAST TIME INCREASE} seconds. Now deals {DAMAGE INCREASE MULT}x more damage."
Affects = Ability 2
CAST TIME INCREASE = 1.5s
DAMAGE INCREASE MULT = 2x
CAST TIME INCREASE = 1.5
DAMAGE INCREASE MULT = 2
# Stat, Lowest, Highest Value
# Stat Modifier[0] = ..., 0, 0
Ability Settings
{
# Add variables here to modify what the ability's original description might state.
# Use "Pre-Description" and "Post-Description" keys to add to the front or back of a current description string.
# Use "Description" key to completely overwrite the default description (be careful of conflicts with another modification!)
# Use "Pre-Name" and "Post-Name" keys to add to the front or back of a current ability name.
# Use "Name" to completely overwrite the default ability name (be careful of conflicts with another modification!)
Pre-Name = "Mega"
DamageMult = 5.0
Post-Description = Cast time increased by {CAST TIME INCREASE} seconds.
}
}
Multi-Multishot
{
@ -147,6 +193,17 @@ Item Enchants
# Stat, Lowest, Highest Value
# Stat Modifier[0] = ..., 0, 0
Ability Settings
{
# Add variables here to modify what the ability's original description might state.
# Use "Pre-Description" and "Post-Description" keys to add to the front or back of a current description string.
# Use "Description" key to completely overwrite the default description (be careful of conflicts with another modification!)
# Use "Pre-Name" and "Post-Name" keys to add to the front or back of a current ability name.
# Use "Name" to completely overwrite the default ability name (be careful of conflicts with another modification!)
Pre-Name = "Multi-"
Post-Description = "Holds up to {EXTRA CHARGE COUNT} charges. Cooldown Reduced by {COOLDOWN REDUCTION PCT}."
}
}
}
Thief

View File

@ -7,6 +7,9 @@ ItemConfiguration
Equipment = Equipment.txt
Weapons = Weapons.txt
Accessories = Accessories.txt
# Item enchants unit testing config
Item Enchants Test Config = ItemEnchants-test.txt
}
Item
{

View File

@ -3574,7 +3574,7 @@ namespace olc
else if (c=='#')
{
skip=6;
textCol=BLACK;
textCol={0,0,0,col.a};
for(int i=1;i<7;i++){
if(i<3){
textCol.r*=16;
@ -3687,7 +3687,7 @@ namespace olc
else if (c=='#')
{
skip=6;
textCol=BLACK;
textCol={0,0,0,col.a};
for(int i=1;i<7;i++){
if(i<3){
textCol.r*=16;
@ -4256,7 +4256,7 @@ namespace olc
else if (c=='#')
{
skip=6;
textCol=BLACK;
textCol={0,0,0,col.a};
for(int i=1;i<7;i++){
if(i<3){
textCol.r*=16;
@ -4491,7 +4491,7 @@ namespace olc
else if (c=='#')
{
skip=6;
textCol=BLACK;
textCol={0,0,0,col.a};
for(int i=1;i<7;i++){
if(i<3){
textCol.r*=16;

View File

@ -546,6 +546,10 @@ namespace olc::utils
return m_vecObjects[m_mapObjects[name]].second;
}
inline const datafile&at(const std::string&name)const{
return m_vecObjects.at(m_mapObjects.at(name)).second;
}
inline auto begin(){
return GetKeys().begin();
}

View File

@ -0,0 +1,88 @@
Fragment Description = "A small piece of concentrated material from broken down jewelry."
# Number of fragments earned when breaking down an accessory.
Fragment Disassemble Gain Amount = 1
# Number of fragments and gold required to Refine an accessory.
Fragment Refine Cost = 1, 20g
# Number of fragments and gold required to Enchant an accessory.
Fragment Enchant Cost = 3, 35g
# How much to increase refined stats by with each refinement. (Ex. if the value is 20%, it takes 5 refinements at most from an item with the lowest possible stat to the max stat with 20% increments.)
Refine Stat Increase Amount = 20%
Equipment
{
Ring of the Slime King
{
Slot = Ring1,Ring2
ItemCategory = Accessories
Fragment Name = Slime King Ring Fragment
# Uncomment to specify a custom icon for this fragment. Otherwise uses the default fragment icon with auto-detected color sampling.
#Fragment Icon = MyIcon.png
# See ItemStats.txt for valid stat names
StatValues = Health,Mana,Move Spd %
MinStats = 5,1,1
MaxStats = 20,4,3
SellValue = 90
Equip Sound = Equip Accessory
}
Ring of the Bear
{
Slot = Ring1,Ring2
ItemCategory = Accessories
Fragment Name = Bear Ring Fragment
# See ItemStats.txt for valid stat names
StatValues = Health,Attack,Mana
MinStats = 4,1,1
MaxStats = 10,4,3
SellValue = 75
Equip Sound = Equip Accessory
}
Stone Ring
{
Slot = Ring1,Ring2
ItemCategory = Accessories
Fragment Name = Stone Ring Fragment
# See ItemStats.txt for valid stat names
StatValues = Defense,Health,Health %
MinStats = 5,10,1
MaxStats = 15,25,3
SellValue = 130
Equip Sound = Equip Accessory
}
Bird's Treasure
{
Slot = Ring1,Ring2
ItemCategory = Accessories
Fragment Name = Bird's Treasure Fragment
# See ItemStats.txt for valid stat names
StatValues = Move Spd %,Crit Rate,Mana
MinStats = 1,1,2
MaxStats = 5,3,5
SellValue = 110
Equip Sound = Equip Accessory
}
Null Ring
{
Slot = Ring1,Ring2
ItemCategory = Accessories
Fragment Name = Null Ring Fragment
SellValue = 110
Equip Sound = Equip Accessory
}
}

View File

@ -0,0 +1,35 @@
Item Enchants
{
General Enchants
{
}
Class Enchants
{
Ranger
{
Test Enchant
{
Description = "A test enchant"
Affects = Ability 1
Ability Settings
{
# Add variables here to modify what the ability's original description might state.
# Use "Pre-Description" and "Post-Description" keys to add to the front or back of a current description string.
# Use "Description" key to completely overwrite the default description (be careful of conflicts with another modification!)
# Use "Pre-Name" and "Post-Name" keys to add to the front or back of a current ability name.
# Use "Name" to completely overwrite the default ability name (be careful of conflicts with another modification!)
Pre-Name = Test
Name = Enchant
Pre-Description = "Pre test"
Description = "My Description"
Post-Description = "Post test"
}
}
}
}
Unique Enchants
{
}
}