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
11 changes: 10 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,16 @@ jobs:

- name: Publish XPRising.ClientUI to Thunderstore
run: tcli publish --config-path ./ClientUI/thunderstore.toml --token ${{ secrets.THUNDERSTORE_KEY }} --file ./dist/XPRising-ClientUI-${RELEASE_TAG:1}.zip


update_latest_release:
# required to allow release to be updated
permissions:
contents: write
env:
RELEASE_TAG: ${{ github.event.inputs.tag_name || github.event.release.tag_name }}
runs-on: ubuntu-latest

steps:
- name: Set release as latest
run: gh release edit ${{ env.RELEASE_TAG }} --draft=false --latest
env:
Expand Down
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.10] - 2025-06-04

### Added

- Added support for allowing all mastery gain to reduce as mastery increase (separate from prestige mechanics). The `Mastery Gain Reduction` configuration option in `GlobalMasteryConfig.cfg` can be used to allow a linear mastery gain (across 0-100%) to having the mastery gain reduced to 0 as the mastery reaches 100%.

### Fixed

- Fixed XP gain on mobs that should get 0 XP
- Updated support for ambush mobs so that Bloodcraft will treat them as normal mobs and give an appropriate amount of XP

## [0.4.9] - 2025-05-30

### Changed
Expand Down
3 changes: 3 additions & 0 deletions XPRising/Configuration/GlobalMasteryConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public static void Initialize()
GlobalMasterySystem.DecaySubSystemEnabled = _configFile.Bind("Global Mastery", "Enable Decay Subsystem", false, "Enables the Decay Mastery subsystem. This will decay mastery over time. Decay rate is set via 'globalMasteryConfig.json'").Value;
GlobalMasterySystem.MasteryThreshold = _configFile.Bind("Global Mastery", "Mastery Threshold", 0.0, "Threshold level the mastery must reach before the mastery can be reset.").Value;
GlobalMasterySystem.DecayInterval = _configFile.Bind("Global Mastery", "Decay Tick Interval", 60, "Amount of seconds per decay tick.").Value;
var gainReduction = _configFile.Bind("Global Mastery", "Mastery Gain Reduction", 0f, "Used to change the mastery gain from linear to quadratic. This will reduce the mastery gain as mastery approaches 100%.\n" +
"Value is clamped from 0 to 100. Set to 0 to have a linear mastery gain. Set to 100 to reduce mastery gain to 0 as mastery approaches 100%.").Value;
GlobalMasterySystem.MasteryGainReductionMultiplier = Math.Clamp(gainReduction, 0, 100)*0.000001;

// Weapon mastery specific config
WeaponMasterySystem.MasteryGainMultiplier = _configFile.Bind("Mastery - Weapon", "Mastery Gain Multiplier", 1.0, "Multiply the gained mastery value by this amount.").Value;
Expand Down
31 changes: 19 additions & 12 deletions XPRising/Hooks/UnitSpawnerHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using XPRising.Systems;
using XPRising.Utils;
using XPRising.Utils.Prefabs;
using XPShared;
using Faction = ProjectM.Faction;
using Prefabs = XPRising.Utils.Prefabs;

Expand Down Expand Up @@ -65,28 +66,34 @@ public static void Postfix(Dictionary<Entity, (int, SpawnUnit.SpawnFaction)> __s
var em = Plugin.Server.EntityManager;
foreach (var data in __state)
{
if (data.Value.Item2 == SpawnUnit.SpawnFaction.VampireHunters &&
em.TryGetComponentData<FactionReference>(data.Key, out var factionReference))
var entity = data.Key;
var intendedLevel = data.Value.Item1;
var faction = data.Value.Item2;
if (faction == SpawnUnit.SpawnFaction.VampireHunters)
{
Plugin.Log(Plugin.LogSystem.SquadSpawn, LogLevel.Info, "Attempting to set faction vampire hunters");
factionReference.FactionGuid._Value = new PrefabGUID((int)Prefabs.Faction.VampireHunters);
em.SetComponentData(data.Key, factionReference);
entity.With((ref FactionReference factionReference) =>
{
factionReference.FactionGuid._Value = new PrefabGUID((int)Prefabs.Faction.VampireHunters);
});
}

if (em.TryGetComponentData<UnitLevel>(data.Key, out var unitLevel))
Plugin.Log(Plugin.LogSystem.SquadSpawn, LogLevel.Info, "Attempting to set level");
entity.With((ref UnitLevel unitLevel) =>
{
Plugin.Log(Plugin.LogSystem.SquadSpawn, LogLevel.Info, "Attempting to set level");
unitLevel.Level._Value = data.Value.Item1;
em.SetComponentData(data.Key, unitLevel);
}
unitLevel.Level._Value = intendedLevel;
});

// If they get disabled (ie, the user runs far away), just mark them to be destroyed.
em.AddComponent<DestroyWhenDisabled>(data.Key);
entity.Add<DestroyWhenDisabled>();
// Remove "Minion" component as none of these should be acting as minions and this will better allow these
// units to be valid for full XP in Bloodcraft.
entity.TryRemoveComponent<Minion>();

if (data.Value.Item2 is SpawnUnit.SpawnFaction.WantedUnit or SpawnUnit.SpawnFaction.VampireHunters)
if (faction is SpawnUnit.SpawnFaction.WantedUnit or SpawnUnit.SpawnFaction.VampireHunters)
{
// Add the entity to our list of spawned entities so we can match them as reducing heat when killed
WantedSystem.AddAmbushingEntity(data.Key, currentTime);
WantedSystem.AddAmbushingEntity(entity, currentTime);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions XPRising/Systems/ExperienceSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ public static bool IsPlayerLoggingExperience(ulong steamId)
public static void ExpMonitor(List<Alliance.ClosePlayer> closeAllies, PrefabGUID victimPrefab, int victimLevel, bool isVBlood)
{
var multiplier = ExpValueMultiplier(victimPrefab, isVBlood);
// Early exit to entirely stop XP calculations when the multiplier is 0.
if (multiplier == 0) return;

var sumGroupLevel = closeAllies.Sum(x => x.playerLevel);
var avgGroupLevel = (int)Math.Floor(closeAllies.Average(x => x.playerLevel));
Expand Down
5 changes: 4 additions & 1 deletion XPRising/Systems/GlobalMasterySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public static class GlobalMasterySystem
public static bool DecaySubSystemEnabled = false;
public static bool SpellMasteryRequiresUnarmed = false;
public static int DecayInterval = 60;
public static double MasteryGainReductionMultiplier = 0f;
public static readonly string CustomPreset = "custom";
public const string NonePreset = "none";

Expand Down Expand Up @@ -410,7 +411,9 @@ private static double ModMastery(ulong steamID, LazyDictionary<MasteryType, Mast
{
var mastery = playerMastery[type];
var currentMastery = mastery.Mastery;
mastery.Mastery += mastery.CalculateBaseMasteryGrowth(changeInMastery);
// Calculate a potential reduction in mastery gain. This should result in a value [1,0]
var masteryGainReductionMultiplier = (1 - currentMastery * currentMastery * MasteryGainReductionMultiplier);
mastery.Mastery += mastery.CalculateBaseMasteryGrowth(changeInMastery) * masteryGainReductionMultiplier;
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
Expand Down