Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ jobs:
run: tcli publish --config-path ./ClientUI/thunderstore.toml --token ${{ secrets.THUNDERSTORE_KEY }} --file ./dist/XPRising-ClientUI-${RELEASE_TAG:1}.zip

- name: Set release as latest
run: gh release edit ${{ env.RELEASE_TAG }} --draft=false --latest
run: gh release edit ${{ env.RELEASE_TAG }} --draft=false --latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.

## [0.4.9] - 2025-05-30

### Changed

- Updated documentation for bloodline mastery to make it match current behaviour and describe it clearer

### Fixed

- Fixed issue that would double apply growth reduction for bloodline mastery when feeding on V Bloods
- Fixed configuration folder normalisation to ensure folder paths are more consistent/usable

## [0.4.8] - 2025-05-30

### Changed
Expand Down
19 changes: 13 additions & 6 deletions Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,19 @@ Weapon/spell mastery will increase when the weapon/spell is used to damage a cre

### Blood Mastery
Feeding on enemies will progress the mastery of that bloodline. If the feeding is cancelled, to kill your victim, a smaller amount of mastery is granted.
Note that your victim will need to have a higher quality of blood than your mastery level to gain mastery.

Bloodline mastery for blood types that don't match your current blood will still be applied at a greatly reduced amount.
V Bloods will give increased mastery improvements. There is configuration to have this apply to X number of random bloodlines, all bloodlines, or just the current player bloodline.

To enable being able to gain mastery on all kills, not just feeding kills, you will need to disable `Merciless bloodlines`. When this is disabled: players will get extra bloodline mastery when making a feeding kill as the mob death will generate a base amount in addition to the standard feeding mastery gain.
V Bloods will give increase mastery improvements.

#### Configuration

| Option | Value | Documentation |
|-------------------------------|-------|-----------------------------------------------------------------------------------------------------------------|
| Merciless Bloodlines | true | Victim blood quality needs to be of a higher value than blood mastery to gain mastery |
| | false | Mastery always improves when the level is less than 100% |
| V Blood improves X bloodlines | 0 | Player's current blood type is used to determine what blood mastery to increase when feeding on a V Blood |
| | 10 | All blood types gain mastery when feeding on a V Blood |
| | X | X randomly chosen blood types gain mastery when feeding on a V Blood (for who knows what the V Blood contains?) |
| Mastery Gain Multiplier | X | Mastery gain is multiplied by this value. Can be used to increase/decrease mastery gain. |
| VBlood Mastery Multiplier | X | Bonus V Blood mastery multiplier (this applies to weapon mastery as well) |

### Mastery buff configuration
The buffs provided by the mastery system can be configured two ways: there are some preset options for quick configuration, or there is the custom configuration which allows great flexibility.
Expand Down
1 change: 1 addition & 0 deletions XPRising/Configuration/DebugLoggingConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class DebugLoggingConfig
public static void Initialize()
{
var configPath = AutoSaveSystem.ConfirmFile(AutoSaveSystem.ConfigPath, "DebugLoggingConfig.cfg");
Plugin.Log(Plugin.LogSystem.Core, LogLevel.Info, $"config folder path: \"{AutoSaveSystem.ConfigPath}\"");
_configFile = new ConfigFile(configPath, true);

// Currently, we are never updating and saving the config file in game, so just load the values.
Expand Down
2 changes: 1 addition & 1 deletion XPRising/Configuration/GlobalMasteryConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static void Initialize()
WeaponMasterySystem.MasteryGainMultiplier = _configFile.Bind("Mastery - Weapon", "Mastery Gain Multiplier", 1.0, "Multiply the gained mastery value by this amount.").Value;

// Blood mastery specific config
BloodlineSystem.MercilessBloodlines = _configFile.Bind("Mastery - Blood", "Merciless Bloodlines", BloodlineSystem.MercilessBloodlines, "Causes blood mastery to only grow when you kill something with a matching blood type of that has a quality higher than the current blood mastery").Value;
BloodlineSystem.MercilessBloodlines = _configFile.Bind("Mastery - Blood", "Merciless Bloodlines", BloodlineSystem.MercilessBloodlines, "Causes blood mastery to only grow when you kill something that has a quality higher than the current blood mastery. V Bloods count as 100% quality.").Value;
BloodlineSystem.VBloodAddsXTypes = _configFile.Bind("Mastery - Blood", "V Blood improves X bloodlines", BloodlineSystem.BloodTypeCount, "Causes consuming a V Blood to improve X random blood masteries. Default value is \"all\" bloodlines. Set to 0 to only do the current bloodline.").Value;
BloodlineSystem.MasteryGainMultiplier = _configFile.Bind("Mastery - Blood", "Mastery Gain Multiplier", 1.0, "Multiply the gained mastery value by this amount.").Value;
}
Expand Down
4 changes: 1 addition & 3 deletions XPRising/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,7 @@ public static void Initialize()
// Pre-initialise some constants
Helper.Initialise();

var configFolderName = string.Join("_",
("XPRising_" + SettingsManager.ServerHostSettings.Name).Split(Path.GetInvalidFileNameChars()));
AutoSaveSystem.ConfigFolder = configFolderName;
AutoSaveSystem.ConfigFolder = AutoSaveSystem.NormaliseConfigFolder(SettingsManager.ServerHostSettings.Name);

// Ensure that internal settings are consistent with server settings
var serverSettings = Plugin.Server.GetExistingSystemManaged<ServerGameSettingsSystem>();
Expand Down
37 changes: 24 additions & 13 deletions XPRising/Systems/BloodlineSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,40 +61,43 @@ public static void UpdateBloodline(Entity killer, Entity victim, bool killOnly)
GlobalMasterySystem.MasteryType victimBloodType;
float victimBloodQuality;
bool isVBlood;
var growthModifier = killOnly ? 0.4 : 1.0;
if (_em.TryGetComponentData<BloodConsumeSource>(victim, out var victimBlood)) {
victimBloodQuality = victimBlood.BloodQuality;
isVBlood = Helper.IsVBlood(victimBlood);
if (isVBlood)
{
victimBloodQuality = 100f;
growthModifier = VBloodMultiplier;
// When running the kill only step for VBloods, only add to the current bloodline, not multi-bloodlines
if (VBloodAddsXTypes > 0 && !killOnly)
{
var baseGrowthVal = growthVal * 0.05 * MasteryGainMultiplier * VBloodMultiplier;
var pmd = Database.PlayerMastery[steamID];
if (VBloodAddsXTypes >= BloodTypeCount)
{
Plugin.Log(LogSystem.Bloodline, LogLevel.Info, $"Adding V Blood bonus ({baseGrowthVal}) to all blood types");
Plugin.Log(LogSystem.Bloodline, LogLevel.Info, () => $"Adding V Blood bonus to all blood types.");
foreach (var bloodType in BuffToBloodTypeMap.Values)
{
GlobalMasterySystem.BankMastery(steamID, victim, bloodType, baseGrowthVal * pmd[killerBloodType].Growth);
var bloodTypeGrowth = growthVal * BloodGrowthMultiplier(growthModifier, victimBloodQuality);
GlobalMasterySystem.BankMastery(steamID, victim, bloodType, ApplyMasteryMultiplier(bloodType, bloodTypeGrowth));
}
}
else
{
var selectedBloodTypes =
BuffToBloodTypeMap.Values.OrderBy(x => _random.Next()).Take(VBloodAddsXTypes);
Plugin.Log(LogSystem.Bloodline, LogLevel.Info, () => $"Adding V Blood bonus ({baseGrowthVal}) to {VBloodAddsXTypes} blood types: {string.Join(",", selectedBloodTypes)}");
Plugin.Log(LogSystem.Bloodline, LogLevel.Info, () => $"Adding V Blood bonus to {VBloodAddsXTypes} blood types: {string.Join(",", selectedBloodTypes)}");
foreach (var bloodType in selectedBloodTypes)
{
GlobalMasterySystem.BankMastery(steamID, victim, bloodType, baseGrowthVal * pmd[killerBloodType].Growth);
var bloodTypeGrowth = growthVal * BloodGrowthMultiplier(growthModifier, victimBloodQuality);
GlobalMasterySystem.BankMastery(steamID, victim, bloodType, ApplyMasteryMultiplier(bloodType, bloodTypeGrowth));
}
}
return;
}
else
{
victimBloodType = killerBloodType;
victimBloodQuality = 100f;
}
}
else
Expand All @@ -114,11 +117,9 @@ public static void UpdateBloodline(Entity killer, Entity victim, bool killOnly)
return;
}

var growthModifier = killOnly ? 0.4 : isVBlood ? VBloodMultiplier : 1.0;

var playerMasterydata = Database.PlayerMastery[steamID];
var bloodlineMastery = playerMasterydata[victimBloodType];
growthVal *= bloodlineMastery.Growth * growthModifier * (victimBloodQuality * 0.01f);
growthVal *= BloodGrowthMultiplier(growthModifier, victimBloodQuality);

if (MercilessBloodlines && victimBloodQuality <= bloodlineMastery.Mastery)
{
Expand Down Expand Up @@ -146,10 +147,8 @@ public static void UpdateBloodline(Entity killer, Entity victim, bool killOnly)

Plugin.Log(LogSystem.Bloodline, LogLevel.Info, $"Bonus bloodline mastery {bonusMastery:F3}]");
}

Plugin.Log(LogSystem.Bloodline, LogLevel.Info,
() => $"Blood growth {Enum.GetName(victimBloodType)}: [{growthVal:F3} * 0.05 * {MasteryGainMultiplier:F3} => {growthVal * 0.05 * MasteryGainMultiplier:F3}]");
growthVal *= 0.05 * MasteryGainMultiplier;

growthVal = ApplyMasteryMultiplier(victimBloodType, growthVal);

GlobalMasterySystem.BankMastery(steamID, victim, victimBloodType, growthVal);
}
Expand Down Expand Up @@ -177,5 +176,17 @@ private static bool GuidToBloodType(PrefabGUID guid, out GlobalMasterySystem.Mas
bloodType = (GlobalMasterySystem.MasteryType)guid.GuidHash;
return true;
}

private static double BloodGrowthMultiplier(double modifier, double quality)
{
return modifier * quality * 0.01f;
}

private static double ApplyMasteryMultiplier(GlobalMasterySystem.MasteryType bloodType, double mastery)
{
Plugin.Log(LogSystem.Bloodline, LogLevel.Info,
() => $"Blood growth {Enum.GetName(bloodType)}: [{mastery:F3} * 0.05 * {MasteryGainMultiplier:F3} => {mastery * 0.05 * MasteryGainMultiplier:F3}]");
return mastery * 0.05 * MasteryGainMultiplier;
}
}
}
4 changes: 2 additions & 2 deletions XPRising/Systems/GlobalMasterySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,7 @@ public static void ExitCombat(ulong steamID)
{
if (!_masteryBank.TryRemove(steamID, out var data)) return;

var lostMastery = data.Aggregate(0d, (a, b) => a + b.Value.Aggregate(0d, (c, d) => c + d.Value));
Plugin.Log(Plugin.LogSystem.Mastery, LogLevel.Info, $"Mastery lost on combat exit: {steamID}: {lostMastery}");
Plugin.Log(Plugin.LogSystem.Mastery, LogLevel.Info, () => $"Mastery lost on combat exit: {steamID}: {data.Aggregate(0d, (a, b) => a + b.Value.Aggregate(0d, (c, d) => c + d.Value))}");
}

/// <summary>
Expand All @@ -414,6 +413,7 @@ private static double ModMastery(ulong steamID, LazyDictionary<MasteryType, Mast
mastery.Mastery += mastery.CalculateBaseMasteryGrowth(changeInMastery);
playerMastery[type] = mastery;

// Calculating it this way, rather than using the result of `CalculateBaseMasteryGrowth` as `Mastery()` clamps the result appropriately so we can't go over max
var actualMasteryChange = mastery.Mastery - currentMastery;
Plugin.Log(Plugin.LogSystem.Mastery, LogLevel.Info, $"Mastery changed: {steamID}: {Enum.GetName(type)}: {mastery.Mastery:F4}(+{actualMasteryChange:F4})");

Expand Down
8 changes: 8 additions & 0 deletions XPRising/Utils/AutoSaveSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using Stunlock.Core;
Expand All @@ -19,6 +20,8 @@ public static class AutoSaveSystem
public static string ConfigPath => Path.Combine(BasePath, ConfigFolder);
public static string SavesPath => Path.Combine(BasePath, ConfigFolder, "Data");
public static string BackupsPath => Path.Combine(BasePath, ConfigFolder, SavesPath, "Backup");

private static Regex _folderValidation = new Regex(@"([^\w]+)");

// Config files
private const string PowerUpJson = "powerUp.json";
Expand Down Expand Up @@ -67,6 +70,11 @@ public static class AutoSaveSystem
}
};

public static string NormaliseConfigFolder(string serverName)
{
return _folderValidation.Replace("XPRising_" + serverName.Trim(), "_");
}

private enum LoadMethod
{
Both,
Expand Down