mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
Updated code calculating passive health, stamina and mana regeneration for characters, based on new UOX.INI settings and bonuses from characters/items/races Added three new Character/Item/Race DFN tags to grant bonus health/stamina/mana regeneration: HEALTHREGENBONUS=# // 10 bonus points equates to 0.01 extra hp regen per second, independent of era STAMINAREGENBONUS=# // 10 bonus points equates to 0.05 extra stamina regen per second MANAREGENBONUS=# // 10 bonus point equates to 0.1 extra mana regen per second ...also available as JS Properties: .healthRegenBonus .staminaRegenBonus .manaRegenBonus Updated get/set JS commands to allow getting/setting regen bonuses for health, stamina and mana Updated races.dfn to include default +2 health regen bonus for humans, and +2 mana regen bonus for gargoyles. Added new UOX.INI settings under [Skills and Stats] section: HEALTHREGENMODE=1 // 0 = no passive health regen, 1 = default passive health regen STAMINAREGENMODE=1 // 0 = no passive stamina regen, 1 = default passive stamina regen (LBR or below), 2 = AoS or beyond, 3 = SA and beyond MANAREGENMODE=1 // 0 = no passive mana regen, 1 = default passive mana regen (LBR or below), 2 = AoS (Pub17), 3 = AoS/SE (Pub18 and beyond), 4 = ML, 5 = KR, 6 = SA and beyond HEALTHREGENCAP=# // Max cap for Health Regeneration Bonus stat per character STAMINAREGENCAP=# // Max cap for Stamina Regeneration Bonus stat per character MANAREGENCAP=# // Max cap for Mana Regeneration Bonus stat per character Added new UOX.INI section ([default race bonuses]) with the following new settings for the 3 default playable races (only used if nothing else specified in races.dfn): HUMANHEALTHREGENBONUS=0 // default health regen bonus for human race (2 from ML expansion onwards) HUMANSTAMINAREGENBONUS=0 // default stamina regen bonus for human race HUMANMANAREGENBONUS=0 // default mana regen bonus for human race ELFHEALTHREGENBONUS=0 // default health regen bonus for elf race ELFSTAMINAREGENBONUS=0 // default stamina regen bonus for elf race ELFMANAREGENBONUS=0 // default mana regen bonus for elf race GARGOYLEHEALTHREGENBONUS=0 // default health regen bonus for gargoyle race GARGOYLESTAMINAREGENBONUS=0 // default stamina regen bonus for gargoyle race GARGOYLEMANAREGENBONUS=0 // default mana regen bonus for gargoyle race (2 from SA expansion onwards) Updated UOX3 Documentation with new feature section on Stat Regeneration with details on stat regeneration rules and recommended settings per UO era Added support for Medable armors (have no effect on meditation skill and/or passive regen of mana when worn) and Mage Armors (can turn non-medable armor into medable armor) These properties are defined per armor piece using the first and second bits of the MORE property: MORE=0x1 0x0 0x0 0x0 // Medable Armor MORE=0x0 0x1 0x0 0x0 // Mage Armor The following armor types have been marked as medable by default: leather armor, leather ninja armor, leather samurai armor, leaf armor, gargish cloth armor, gargish leather armor and all hats and masks Updated JS Method .Defense() to support optional fourth and fifth parameters - excludeMedableArmor (true/false) and includeShield (true/false) Updated CalfDef function to support including shields in the calculations, and updated mana regen code to include shields when checking for equipped armor Updated Meditation skill JS script to exclude medable armor from armor check, include shields, and apply different rules for active meditation depending on mana regen mode Updated stat window to include defensive rating of shields (based on Parrying skill) and/or elemental resistances (if enabled in ini) Added a new property to CRace class, which is automatically set and incremented as UOX3 loads in races from races.dfn: raceID Added new Getters/Setters for CRace class to retrieve ID of a specific Race object Updated JS property .id for Race JS Object to return new race ID instead of iterating through list of races to compare race object and return index Reloading DFNs now also reloads Races
482 lines
12 KiB
C++
482 lines
12 KiB
C++
//
|
|
// StringUtility.cpp
|
|
// Infinity
|
|
//
|
|
//
|
|
|
|
#include "StringUtility.hpp"
|
|
#include <cctype>
|
|
#include <regex>
|
|
#include <locale>
|
|
#include <algorithm>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <filesystem>
|
|
#include <codecvt>
|
|
using namespace std::string_literals;
|
|
|
|
namespace oldstrutil
|
|
{
|
|
//=====================================================================
|
|
// Lowercase the string
|
|
std::string lower( const std::string &value )
|
|
{
|
|
auto rValue = value;
|
|
std::transform( rValue.begin(), rValue.end(), rValue.begin(),
|
|
[]( unsigned char c ){ return std::tolower( c ); } );
|
|
return rValue;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Uppercase the string
|
|
std::string upper( const std::string &value )
|
|
{
|
|
auto rValue = value;
|
|
std::transform( rValue.begin(), rValue.end(), rValue.begin(),
|
|
[]( unsigned char c ){ return std::toupper( c ); } );
|
|
return rValue;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Remove leading whitespace
|
|
std::string ltrim( const std::string &value )
|
|
{
|
|
auto count = 0;
|
|
for( auto it = value.begin(); it != value.end(); it++ )
|
|
{
|
|
if( !isspace( *it ))
|
|
{
|
|
return value.substr( count );
|
|
}
|
|
else
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
return std::string();
|
|
}
|
|
|
|
//=====================================================================
|
|
// Remove trailing whitespace
|
|
std::string rtrim( const std::string &value )
|
|
{
|
|
auto count = 0;
|
|
for( auto it = value.rbegin(); it != value.rend(); it++ )
|
|
{
|
|
if( !isspace( *it ))
|
|
{
|
|
return value.substr( 0, value.size() - count );
|
|
}
|
|
else
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
return std::string();
|
|
}
|
|
|
|
//=====================================================================
|
|
// Remove leading/trailing whitespace
|
|
std::string trim( const std::string &value )
|
|
{
|
|
return rtrim( ltrim( value ));
|
|
}
|
|
|
|
//=====================================================================
|
|
// Remove leading/trailing whitepace, and reduce all other whitespace to one " "
|
|
std::string simplify( const std::string &value )
|
|
{
|
|
auto tvalue = trim( value );
|
|
auto rValue = ""s;
|
|
auto toggle = false;
|
|
for( auto &c : tvalue )
|
|
{
|
|
if( isspace( c ))
|
|
{
|
|
if( !toggle )
|
|
{
|
|
rValue = rValue + c;
|
|
toggle = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
toggle = false;
|
|
rValue = rValue + c;
|
|
}
|
|
}
|
|
return rValue;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Removing everything after a delimiter. Normally "//" for comments
|
|
std::string removeTrailing( const std::string& value, const std::string& delim )
|
|
{
|
|
auto loc = value.find( delim );
|
|
if( loc == std::string::npos )
|
|
{
|
|
return value;
|
|
}
|
|
return value.substr( 0, loc );
|
|
}
|
|
|
|
//=====================================================================
|
|
// Return the values between two delimitors.
|
|
std::string contents( const std::string &value, const std::string& startdelim, const std::string &enddelim, std::string::size_type location )
|
|
{
|
|
auto loc = value.find_first_of( startdelim, location );
|
|
if( loc == std::string::npos )
|
|
{
|
|
return std::string();
|
|
}
|
|
auto start_search = loc + startdelim.size();
|
|
if( start_search >= value.size() )
|
|
{
|
|
return std::string();
|
|
}
|
|
auto end = value.find_first_of( enddelim, start_search );
|
|
if( end == std::string::npos )
|
|
{
|
|
return std::string();
|
|
}
|
|
return value.substr( start_search, end - start_search );
|
|
}
|
|
|
|
//=====================================================================
|
|
// Split a string based on a separator
|
|
std::tuple<std::string, std::string> split( const std::string &value, const std::string &sep )
|
|
{
|
|
auto loc = value.find( sep );
|
|
auto next = loc + sep.size();
|
|
if(( loc == std::string::npos ) || ( next >= value.size() ))
|
|
{
|
|
return std::make_tuple( trim( value ), ""s );
|
|
}
|
|
else
|
|
{
|
|
return std::make_tuple( trim( value.substr( 0, loc )), trim( value.substr( next )));
|
|
}
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++
|
|
std::string format( std::size_t maxsize, const std::string fmtstring, ... )
|
|
{
|
|
|
|
std::va_list argptr;
|
|
va_start( argptr, fmtstring );
|
|
auto test = oldstrutil::format( fmtstring, argptr );
|
|
if( maxsize > 0 )
|
|
{
|
|
if( test.size() > maxsize )
|
|
{
|
|
test = test.substr( 0, maxsize );
|
|
}
|
|
}
|
|
va_end( argptr ); // va_end in same function
|
|
return test;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++
|
|
std::string format( std::size_t maxsize, const std::string fmtstring, va_list& list )
|
|
{
|
|
auto temp = oldstrutil::format( fmtstring, list );
|
|
if( maxsize > 0 )
|
|
{
|
|
if( temp.size() > maxsize )
|
|
{
|
|
temp = temp.substr( 0, maxsize );
|
|
}
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++
|
|
std::string format( const std::string fmtstring, ... )
|
|
{
|
|
std::va_list argptr;
|
|
va_start( argptr, fmtstring );
|
|
std::string result = oldstrutil::format( fmtstring, argptr );
|
|
va_end( argptr ); // va_end in same function
|
|
return result;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++
|
|
std::string format( const std::string fmtstring, va_list& list )
|
|
{
|
|
constexpr std::uintmax_t buffersize = 4096;
|
|
char msg[buffersize];
|
|
std::memset( msg, 0, buffersize );
|
|
std::vsnprintf( msg, buffersize, fmtstring.c_str(), list );
|
|
return std::string( msg );
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++
|
|
std::string formatMessage( const std::string& uformat, const std::string& data )
|
|
{
|
|
auto values = oldstrutil::sections( data, "," );
|
|
auto format = uformat;
|
|
auto pos = format.find_first_of( "%" );
|
|
if( pos == std::string::npos )
|
|
{
|
|
return format;
|
|
}
|
|
size_t index = 0;
|
|
while( pos != std::string::npos )
|
|
{
|
|
if( index >= values.size() )
|
|
{
|
|
break;
|
|
}
|
|
auto temp = values[index];
|
|
index++;
|
|
// now, we assume the formatting was done before the string, so basically we
|
|
// replace the format specifier, with the string
|
|
format.replace( pos, 2, temp );
|
|
pos = format.find_first_of( "%" );
|
|
}
|
|
return format;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++
|
|
std::vector<std::string> sections( const std::string& value, const std::string& sep, std::string::size_type start, std::string::size_type end )
|
|
{
|
|
std::vector<std::string> rValue;
|
|
|
|
auto pos = value.find( sep, start );
|
|
while( pos < end )
|
|
{
|
|
if(( pos - start ) > 0 )
|
|
{
|
|
auto potential = value.substr( start, pos - start );
|
|
rValue.push_back( potential );
|
|
start = pos+sep.size();
|
|
}
|
|
else if( pos == start )
|
|
{
|
|
rValue.push_back( "" );
|
|
start += sep.size();
|
|
}
|
|
pos = value.find( sep, start );
|
|
}
|
|
rValue.push_back( value.substr( start, pos - start ));
|
|
return rValue;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++
|
|
std::uintmax_t sectionCount( const std::string& value, const std::string& sep, std::string::size_type start, std::string::size_type end )
|
|
{
|
|
return oldstrutil::sections( value, sep, start, end ).size();
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++
|
|
std::string indexSection( const std::string& value, std::uintmax_t sectionindex, const std::string& sep, std::string::size_type start, std::string::size_type end )
|
|
{
|
|
auto sec = oldstrutil::sections( value, sep, start, end );
|
|
if( sec.size() <= sectionindex )
|
|
{
|
|
return sec[sectionindex];
|
|
}
|
|
throw std::runtime_error( oldstrutil::format( "Section index %ul exceeded size %ul from sections %s", sectionindex, sec.size(), value.c_str() ));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++
|
|
std::string extractSection( const std::string& value, const std::string& sep, std::string::size_type start, std::string::size_type stop )
|
|
{
|
|
std::string data;
|
|
size_t count = 0;
|
|
size_t startoffset = 0;
|
|
size_t stopoffset = 0;
|
|
bool match = false;
|
|
stopoffset = value.find( sep, startoffset );
|
|
while( startoffset != std::string::npos )
|
|
{
|
|
if( count == start )
|
|
{
|
|
match = true;
|
|
// We dont return the seperator, so jump over it
|
|
size_t tempoffset = startoffset;
|
|
while ( stopoffset != std::string::npos )
|
|
{
|
|
if( count == stop )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
tempoffset = stopoffset + sep.length();
|
|
stopoffset = value.find( sep, tempoffset );
|
|
count++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
else
|
|
{
|
|
if( stopoffset != std::string::npos )
|
|
{
|
|
startoffset = stopoffset + sep.length();
|
|
}
|
|
else
|
|
{
|
|
startoffset = static_cast<size_t>( std::string::npos );
|
|
}
|
|
stopoffset = value.find( sep, startoffset );
|
|
}
|
|
count++;
|
|
}
|
|
if( match )
|
|
{
|
|
size_t length = stopoffset - startoffset;
|
|
if( stopoffset == std::string::npos )
|
|
{
|
|
length = value.length() - startoffset;
|
|
}
|
|
data = value.substr( startoffset, length );
|
|
}
|
|
return data;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++
|
|
std::vector<std::string> breakSize( std::size_t maxsize, const std::string& input )
|
|
{
|
|
auto working = input;
|
|
std::vector<std::string> total;
|
|
while( working.size() > maxsize )
|
|
{
|
|
auto portion = working.substr( 0, maxsize );
|
|
working.replace( 0, maxsize, "" );
|
|
total.push_back( portion );
|
|
}
|
|
if( !working.empty() )
|
|
{
|
|
total.push_back( working );
|
|
}
|
|
return total;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++
|
|
std::string fixDirectory( const std::string& base )
|
|
{
|
|
std::string value = "\\";
|
|
std::string::size_type index = 0;
|
|
auto data = trim( base );
|
|
while(( index = data.find( value, index )) != std::string::npos )
|
|
{
|
|
data = data.replace( index, 1, "/" );
|
|
}
|
|
if( data.find_last_of( "/" ) != data.size() - 1 )
|
|
{
|
|
data = data + "/";
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++
|
|
std::string replaceSlash( std::string& data )
|
|
{
|
|
std::string value = "\\";
|
|
std::string::size_type index = 0;
|
|
|
|
while(( index = data.find( value, index )) != std::string::npos )
|
|
{
|
|
data = data.replace( index, 1, "/" );
|
|
}
|
|
return data;
|
|
}
|
|
|
|
std::string number( char n, int base )
|
|
{
|
|
std::stringstream conversion;
|
|
auto value = static_cast<std::int16_t>( n );
|
|
|
|
switch( base )
|
|
{
|
|
case 10:
|
|
conversion << std::dec << value;
|
|
break;
|
|
case 16:
|
|
conversion << std::hex << value << std::dec;
|
|
break;
|
|
case 8:
|
|
conversion << std::oct << value << std::dec;
|
|
break;
|
|
default:
|
|
conversion << std::dec << value;
|
|
break;
|
|
}
|
|
|
|
return conversion.str();
|
|
}
|
|
std::string number( unsigned char n, int base )
|
|
{
|
|
std::stringstream conversion;
|
|
auto value = static_cast<std::uint16_t>( n );
|
|
|
|
switch( base )
|
|
{
|
|
case 10:
|
|
conversion << std::dec << value;
|
|
break;
|
|
case 16:
|
|
conversion << std::hex << value << std::dec;
|
|
break;
|
|
case 8:
|
|
conversion << std::oct << value << std::dec;
|
|
break;
|
|
default:
|
|
conversion << std::dec << value;
|
|
break;
|
|
}
|
|
|
|
return conversion.str();
|
|
}
|
|
|
|
#if defined( _MSC_VER )
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4996)
|
|
#endif
|
|
// Decode a UTF8 string into a wstring
|
|
std::wstring stringToWstring( const std::string& t_str )
|
|
{
|
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
|
|
|
|
// use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
|
|
try
|
|
{
|
|
auto rValue = converter.from_bytes( t_str );
|
|
return rValue;
|
|
}
|
|
catch( ... )
|
|
{
|
|
return L"";
|
|
}
|
|
}
|
|
#if defined( _MSC_VER )
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
// "Encode" a wstring into UTF8, while retaining any special wide characters
|
|
std::string wStringToString( const std::wstring& t_str )
|
|
{
|
|
const size_t stringLen = t_str.size();
|
|
|
|
std::string resultString;
|
|
for( size_t i = 0; i < stringLen; ++i )
|
|
{
|
|
resultString.push_back( static_cast<char>( t_str[i] ));
|
|
}
|
|
|
|
return resultString;
|
|
}
|
|
|
|
// Convert from string to wstring and back to string
|
|
std::string stringToWstringToString( const std::string& t_str )
|
|
{
|
|
return wStringToString( stringToWstring( t_str ));
|
|
}
|
|
}
|