Skip to content

Commit

Permalink
- fixed parsing class list numbers for select and change
Browse files Browse the repository at this point in the history
- fams should no longer get stuck as frequently
- changed command references to '.misc remindme' where applicable
- github workflow shouldn't throw on building DebugLoggerError patch
- removed recipes from small grinder that shouldn't be there (all recipe changes will not be seen on existing stations, must be picked up and placed again)
- pilots snipped again
- previous update fixed majority of burst crashing, this should take care of any remaining that I am aware of
- collision back to the way it was for familiars
- shinies for various golems and robots working again
- durability bonus for legendaries from blacksmithing corrected
- modified class changing for consistency in buff removal and application ('.class passives' to toggle buffs off, '.class c [Class]' to change, then '.class sb' to apply)
- staggered familiar and player experience scrolling text and improved origination
- canning death mage bite angel thing, way more trouble than it's worth especially with 1.1 on the horizon
- small service to keep disabled familiars with their player every so often
- handling for a few instances where stats from bonuses would double until next refreshed, still one or two laying around but very easy for player to self-correct by switching weapons and a variety of other methods, needs a finer approach to completely handle (pending)
- slashers 3rd hit applies stacking bleed, seeeems balanced enough to roll with for now
- mutant grease for fishing profession, 1 per 4 levels
  • Loading branch information
mfoltz committed Feb 24, 2025
1 parent 0ba53a9 commit 898d647
Show file tree
Hide file tree
Showing 38 changed files with 743 additions and 310 deletions.
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,3 @@ dist/
*.env
secrets.json
DevCommands.cs
TestPatches.cs
DebugLoggerPatch.cs
/Patches/DebugLoggerPatch.cs
2 changes: 1 addition & 1 deletion Bloodcraft.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>Bloodcraft</AssemblyName>
<Version>1.6.5</Version>
<Version>1.6.6</Version>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<RestoreSources>
https://api.nuget.org/v3/index.json;
Expand Down
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
`1.6.5`
`1.6.6`
- shinies for golems and robots working again
- reverted changes to familiar collision and should no longer sometimes prevent batform/waygate usage in weird disable loop
- removed some recipes from small grinder that were not supposed to be there
- durability bonus for blacksmithing on legendaries corrected
- modified class change process for consistency in buff removal and application ('.class passives' to toggle buffs off, '.class c [Class]' to change, then '.class sb' to apply)
- added another class command with a long name, now there is one for changing configurations entirely and one for resyncing all existing buffs if needed (best used while server has password under a small maintenance period before then changing class buffs in config then rebooting, can use the global sync after rebooting but still with password or players can just use the personal '.class sb' command)
- small service to keep disabled familiars with their owners instead of where they were last left
- death mage bite stuff removed, you will need to change that buff accordingly if were making use of it
- clearing drop tables more thoroughly to prevent any drops when lingering fams are cleared on server restarts
- handling for various instances of observed stat doubling
- fixed alchemy experience from blood potions and merlots, scales with quality of prisoner
- familar and player experience scrolling text staggered to prevent overlap and improved origination

- `1.6.5`
- tired, check commands list if anything doesn't do what you expect as that's autogenerated and will match whatever is in build
- reduced chances for random seeds per 20 harvesting levels to [2, 4, 6, 8, 10] from [4, 8, 12, 16, 20]
- config option for echoes cost, haven't double checked this yet #testingandtired
Expand Down
113 changes: 59 additions & 54 deletions Commands/ClassCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
using ProjectM;
using Stunlock.Core;
using Unity.Entities;
using UnityEngine.TextCore.Text;
using VampireCommandFramework;
using static Bloodcraft.Systems.Legacies.BloodManager.BloodStats;
using static Bloodcraft.Utilities.Classes;
using static Bloodcraft.Utilities.Misc.PlayerBoolsManager;
using static Il2CppSystem.Xml.Schema.XsdDuration;
using static VCF.Core.Basics.RoleCommands;
using User = ProjectM.Network.User;

Expand All @@ -22,33 +21,27 @@ internal static class ClassCommands
static readonly bool _classes = ConfigService.SoftSynergies || ConfigService.HardSynergies;

[Command(name: "select", shortHand: "s", adminOnly: false, usage: ".class s [Class]", description: "Select class.")]
public static void SelectClassCommand(ChatCommandContext ctx, string className)
public static void SelectClassCommand(ChatCommandContext ctx, string input)
{
if (!_classes)
{
LocalizationService.HandleReply(ctx, "Classes are not enabled.");
return;
}

Entity playerCharacter = ctx.Event.SenderCharacterEntity;
ulong steamId = ctx.Event.User.PlatformId;
PlayerClass playerClass;
PlayerClass? nullablePlayerClass = ParseClassFromInput(ctx, input);

if (int.TryParse(className, out int value))
if (nullablePlayerClass.HasValue)
{
--value;

if (!Enum.IsDefined(typeof(PlayerClass), value))
{
LocalizationService.HandleReply(ctx,
"Invalid class, use '<color=white>.class l</color>' to see options.");
return;
}

playerClass = (PlayerClass)value;
PlayerClass playerClass = nullablePlayerClass.Value;

if (!HasClass(steamId) && steamId.TryGetPlayerClasses(out var classes)) // retrieval methods here could use improving but this is fine for now
{
UpdateClassData(ctx.Event.SenderCharacterEntity, playerClass, classes, steamId);
UpdatePlayerClass(playerClass, classes, steamId);
ApplyClassBuffs(playerCharacter, steamId);

LocalizationService.HandleReply(ctx, $"You've selected {FormatClassName(playerClass)}!");
}
else
Expand All @@ -58,21 +51,7 @@ public static void SelectClassCommand(ChatCommandContext ctx, string className)
}
else
{
if (!TryParseClassName(className, out playerClass))
{
LocalizationService.HandleReply(ctx, "Invalid class, use <color=white>'.class l'</color> to see options.");
return;
}

if (!HasClass(steamId) && steamId.TryGetPlayerClasses(out var classes)) // retrieval methods here could use improving but this is fine for now
{
UpdateClassData(ctx.Event.SenderCharacterEntity, playerClass, classes, steamId);
LocalizationService.HandleReply(ctx, $"You've selected {FormatClassName(playerClass)}!");
}
else
{
LocalizationService.HandleReply(ctx, $"You've already selected {FormatClassName(GetPlayerClass(steamId))}, use <color=white>'.class c [Class]'</color> to change. (<color=#ffd9eb>{new PrefabGUID(ConfigService.ChangeClassItem).GetLocalizedName()}</color>x<color=white>{ConfigService.ChangeClassQuantity}</color>)");
}
LocalizationService.HandleReply(ctx, "Invalid class, use '<color=white>.class l</color>' to see options.");
}
}

Expand Down Expand Up @@ -207,38 +186,47 @@ public static void ChooseClassSpell(ChatCommandContext ctx, int choice)
}

[Command(name: "change", shortHand:"c", adminOnly: false, usage: ".class c [Class]", description: "Change classes.")]
public static void ChangeClassCommand(ChatCommandContext ctx, string className)
public static void ChangeClassCommand(ChatCommandContext ctx, string input)
{
if (!_classes)
{
LocalizationService.HandleReply(ctx, "Classes are not enabled.");
return;
}

if (!TryParseClassName(className, out var parsedClassType))
{
LocalizationService.HandleReply(ctx, "Invalid class, use <color=white>'.class l'</color> to see options.");
return;
}

Entity playerCharacter = ctx.Event.SenderUserEntity;
ulong steamId = ctx.Event.User.PlatformId;
Entity character = ctx.Event.SenderUserEntity;

if (steamId.TryGetPlayerClasses(out var classes) && !HasClass(steamId))
{
LocalizationService.HandleReply(ctx, "You haven't selected a class yet, use <color=white>'.class s [Class]'</color> instead.");
return;
}
PlayerClass? nullablePlayerClass = ParseClassFromInput(ctx, input);

if (ConfigService.ChangeClassItem != 0 && !HandleClassChangeItem(ctx))
if (nullablePlayerClass.HasValue)
{
return;
}
PlayerClass playerClass = nullablePlayerClass.Value;

RemoveClassBuffs(character, steamId);
UpdateClassData(character, parsedClassType, classes, steamId);
if (steamId.TryGetPlayerClasses(out Dictionary<PlayerClass, (List<int>, List<int>)> classes) && !HasClass(steamId))
{
LocalizationService.HandleReply(ctx, "You haven't selected a class yet, use <color=white>'.class s [Class]'</color> instead.");
return;
}

if (GetPlayerBool(steamId, CLASS_BUFFS_KEY))
{
LocalizationService.HandleReply(ctx, "You have class buffs enabled, use <color=white>'.class passives'</color> to disable them before changing classes!");
return;
}

LocalizationService.HandleReply(ctx, $"Class changed to {FormatClassName(parsedClassType)}!");
if (ConfigService.ChangeClassItem != 0 && !HandleClassChangeItem(ctx))
{
return;
}

UpdatePlayerClass(playerClass, classes, steamId);
LocalizationService.HandleReply(ctx, $"Class changed to {FormatClassName(playerClass)}! Use <color=white>'.class sb'</color> at least once after changing.");
}
else
{
LocalizationService.HandleReply(ctx, "Invalid class, use '<color=white>.class l</color>' to see options.");
}
}

[Command(name: "syncbuffs", shortHand: "sb", adminOnly: false, usage: ".class sb", description: "Applies class buffs appropriately if not present.")]
Expand All @@ -252,6 +240,8 @@ public static void SyncClassBuffsCommand(ChatCommandContext ctx)

var steamId = ctx.Event.User.PlatformId;

SetPlayerBool(steamId, CLASS_BUFFS_KEY, true);

if (HasClass(steamId))
{
PlayerClass playerClass = GetPlayerClass(steamId);
Expand Down Expand Up @@ -459,25 +449,40 @@ public static void ClassBuffsToggleCommand(ChatCommandContext ctx)
TogglePlayerBool(steamId, CLASS_BUFFS_KEY);
if (GetPlayerBool(steamId, CLASS_BUFFS_KEY))
{
LocalizationService.HandleReply(ctx, "Class passive buffs <color=green>enabled</color>!");
ApplyClassBuffs(playerCharacter, steamId);

LocalizationService.HandleReply(ctx, "Class passive buffs <color=green>enabled</color>!");
}
else
{
List<PrefabGUID> classBuffs = GetClassBuffs(steamId);
RemoveClassBuffs(playerCharacter, classBuffs);

LocalizationService.HandleReply(ctx, "Class passive buffs <color=red>disabled</color>!");
RemoveClassBuffs(playerCharacter, steamId);
}
}

[Command(name: "iacknowledgethiswillgloballyremovethensyncallclassbuffsonplayersandwantthattohappen", adminOnly: true, usage: ".class iacknowledgethiswillgloballyremovethensyncallclassbuffsonplayersandwantthattohappen", description: "Globally syncs class buffs (removes all then applies from current class) for players if needed.")]
public static void GlobalClassSyncCommand(ChatCommandContext ctx)
{
if (!_classes)
{
LocalizationService.HandleReply(ctx, "Classes are not enabled.");
return;
}

GlobalSyncClassBuffs(ctx).Start();
}

[Command(name: "iacknowledgethiswillremoveallclassbuffsfromplayersandwantthattohappen", adminOnly: true, usage: ".class iacknowledgethiswillremoveallclassbuffsfromplayersandwantthattohappen", description: "Globally removes class buffs from players to then facilitate changing class buffs in config.")]
public static void ClassBuffsPurgeCommand(ChatCommandContext ctx)
public static void GlobalClassPurgeCommand(ChatCommandContext ctx)
{
if (!_classes)
{
LocalizationService.HandleReply(ctx, "Classes are not enabled.");
return;
}

PurgeClassBuffs();
GlobalPurgeClassBuffs(ctx);
}
}
2 changes: 1 addition & 1 deletion Commands/MiscCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,6 @@ public static void ResetMusicCommand(ChatCommandContext ctx)
character.Write(combatMusicListener_Shared);

CombatMusicSystemServer.OnUpdate();
ctx.Reply($"Combat music cleared~");
ctx.Reply($"Combat music cleared!");
}
}
2 changes: 0 additions & 2 deletions Commands/PartyCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,5 @@ public static void ResetPartyCommand(ChatCommandContext ctx)
{
LocalizationService.HandleReply(ctx, $"No parties found that you own or are a member in.");
}

// SavePlayerParties();
}
}
11 changes: 9 additions & 2 deletions Commands/WeaponCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal static class WeaponCommands
static EntityManager EntityManager => Core.EntityManager;
static ServerGameManager ServerGameManager => Core.ServerGameManager;

static readonly bool _classes = ConfigService.SoftSynergies || ConfigService.HardSynergies;
static readonly PrefabGUID _exoFormBuff = new(-31099041);

[Command(name: "get", adminOnly: false, usage: ".wep get", description: "Displays current weapon expertise details.")]
public static void GetExpertiseCommand(ChatCommandContext ctx)
Expand Down Expand Up @@ -405,9 +405,16 @@ public static void LockPlayerSpells(ChatCommandContext ctx)
return;
}

Entity playerCharacter = ctx.Event.SenderCharacterEntity;
User user = ctx.Event.User;
ulong SteamID = user.PlatformId;

if (playerCharacter.HasBuff(_exoFormBuff))
{
LocalizationService.HandleReply(ctx, "Spells cannot be locked when using exoform.");
return;
}

TogglePlayerBool(SteamID, SPELL_LOCK_KEY);

if (GetPlayerBool(SteamID, SPELL_LOCK_KEY))
Expand All @@ -416,7 +423,7 @@ public static void LockPlayerSpells(ChatCommandContext ctx)
}
else
{
LocalizationService.HandleReply(ctx, "Spells set.");
LocalizationService.HandleReply(ctx, "Spells locked.");
}
}
}
19 changes: 17 additions & 2 deletions Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ internal static class Core

static readonly PrefabGUID _wolfBiteCast = new(990205141);

static readonly PrefabGUID _vargulfBleedBuff = new(1581496399);

static readonly HashSet<PrefabGUID> _bearFormBuffs =
[
new(-1569370346), // AB_Shapeshift_Bear_Buff
Expand Down Expand Up @@ -90,7 +92,6 @@ public static void Initialize()
OLD_SHARED_KEY = Convert.FromBase64String(SecretManager.GetOldSharedKey()); // loading these last causes a bad format exception now... oh computers, you so fun
NEW_SHARED_KEY = Convert.FromBase64String(SecretManager.GetNewSharedKey());

// if (_performance) ServerPerformanceLogger();
_ = new PlayerService();
_ = new LocalizationService();

Expand Down Expand Up @@ -120,13 +121,16 @@ public static void Initialize()
DeathEventListenerSystemPatch.OnDeathEventHandler += FamiliarUnlockSystem.OnUpdate;
//DetectSanguis(); want to nail the fun factor and make sure no glaring bugs before adding stakes
_ = new BattleService();
_ = new FamiliarService();
}
if (ConfigService.ProfessionSystem)
{
// uhh definitely remember what I was going to put here? hrm
}

ModifyPrefabs();

SlashersBleedTest();
// MiscLogging();

_initialized = true;
Expand Down Expand Up @@ -176,7 +180,7 @@ static void ModifyPrefabs()
modifyRotation.Type = RotationModificationType.Set;
});
}

/*
if (SystemService.PrefabCollectionSystem._PrefabGuidToEntityMap.TryGetValue(_mapIconCharmed, out Entity mapIconCharmedPrefab))
{
Expand Down Expand Up @@ -265,6 +269,17 @@ static void ModifyPrefabs()
}
}
}
static void SlashersBleedTest()
{
if (SystemService.PrefabCollectionSystem._PrefabGuidToEntityMap.TryGetValue(_vargulfBleedBuff, out Entity bleedBuffPrefab))
{
bleedBuffPrefab.With((ref Buff buff) =>
{
buff.MaxStacks = 5;
buff.IncreaseStacks = true;
});
}
}

static readonly ComponentType[] _prefabGUIDComponent =
[
Expand Down
Loading

0 comments on commit 898d647

Please sign in to comment.