From 60851f63c7e26c5e5bebe062b07a865daa9ad2a1 Mon Sep 17 00:00:00 2001 From: Jun <13masj@gmail.com> Date: Sun, 21 Jun 2026 14:44:48 -0700 Subject: [PATCH] Sealed orange chests in BBM can drop BBM jewelry, configurable in JSON, also add isPaidReset to database for tracking --- Arrowgene.Ddon.Database/DdonDatabaseBuilder.cs | 2 +- .../Script/migration_bbm_paid_reset.sql | 1 + Arrowgene.Ddon.Database/IDatabase.cs | 3 ++- .../Core/DdonSqlDbBitterBlackMazeProgress.cs | 15 +++++++++------ .../Migration/00000064_BbmPaidResetMigration.cs | 16 ++++++++++++++++ Arrowgene.Ddon.Database/Sql/SqlDb.cs | 2 +- .../Characters/BitterblackMazeManager.cs | 17 +++++++++++++++++ .../Handler/BattleContentContentResetHandler.cs | 1 + .../Handler/CreateCharacterHandler.cs | 2 +- .../Asset/BitterblackMazeAsset.cs | 1 + .../BitterblackMazeAssetDeserializer.cs | 1 + .../Files/Assets/BitterblackMaze.json | 7 +++++++ .../BattleContent/BitterblackMazeProgress.cs | 1 + .../Database/DatabaseMigratorTest.cs | 2 +- 14 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 Arrowgene.Ddon.Database/Files/Database/Script/migration_bbm_paid_reset.sql create mode 100644 Arrowgene.Ddon.Database/Sql/Core/Migration/00000064_BbmPaidResetMigration.cs diff --git a/Arrowgene.Ddon.Database/DdonDatabaseBuilder.cs b/Arrowgene.Ddon.Database/DdonDatabaseBuilder.cs index 7ed62a56..c693b194 100644 --- a/Arrowgene.Ddon.Database/DdonDatabaseBuilder.cs +++ b/Arrowgene.Ddon.Database/DdonDatabaseBuilder.cs @@ -13,7 +13,7 @@ public static class DdonDatabaseBuilder { private const string DefaultSchemaFile = "Script/schema_sqlite.sql"; - public const uint Version = 63; + public const uint Version = 64; private static readonly ILogger Logger = LogProvider.Logger(typeof(DdonDatabaseBuilder)); public static IDatabase Build(DatabaseSetting settings) diff --git a/Arrowgene.Ddon.Database/Files/Database/Script/migration_bbm_paid_reset.sql b/Arrowgene.Ddon.Database/Files/Database/Script/migration_bbm_paid_reset.sql new file mode 100644 index 00000000..3e8b58d0 --- /dev/null +++ b/Arrowgene.Ddon.Database/Files/Database/Script/migration_bbm_paid_reset.sql @@ -0,0 +1 @@ +ALTER TABLE "ddon_bbm_progress" ADD COLUMN "is_paid_reset" BOOLEAN NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/Arrowgene.Ddon.Database/IDatabase.cs b/Arrowgene.Ddon.Database/IDatabase.cs index fd39f8cf..d7c8c8f6 100644 --- a/Arrowgene.Ddon.Database/IDatabase.cs +++ b/Arrowgene.Ddon.Database/IDatabase.cs @@ -447,7 +447,8 @@ public interface IDatabase BattleContentMode contentMode, uint tier, bool killedDeath, - ulong lastTicketTime + ulong lastTicketTime, + bool isPaidReset ); bool UpdateBBMProgress(uint characterId, BitterblackMazeProgress progress, DbConnection? connectionIn = null); diff --git a/Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbBitterBlackMazeProgress.cs b/Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbBitterBlackMazeProgress.cs index 17c0c30e..50a2c600 100644 --- a/Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbBitterBlackMazeProgress.cs +++ b/Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbBitterBlackMazeProgress.cs @@ -8,7 +8,7 @@ public partial class DdonSqlDb : SqlDb { protected static readonly string[] BitterBlackMazeProgressFields = [ - "character_id", "start_time", "content_id", "content_mode", "tier", "killed_death", "last_ticket_time" + "character_id", "start_time", "content_id", "content_mode", "tier", "killed_death", "last_ticket_time", "is_paid_reset" ]; private readonly string SqlDeleteBBMProgress = "DELETE FROM \"ddon_bbm_progress\" WHERE \"character_id\"=@character_id;"; @@ -20,14 +20,14 @@ public partial class DdonSqlDb : SqlDb private readonly string SqlUpdateBBMProgress = $"UPDATE \"ddon_bbm_progress\" SET {BuildQueryUpdate(BitterBlackMazeProgressFields)} WHERE \"character_id\"=@character_id;"; - public override bool InsertBBMProgress(uint characterId, ulong startTime, uint contentId, BattleContentMode contentMode, uint tier, bool killedDeath, ulong lastTicketTime) + public override bool InsertBBMProgress(uint characterId, ulong startTime, uint contentId, BattleContentMode contentMode, uint tier, bool killedDeath, ulong lastTicketTime, bool isPaidReset) { using DbConnection connection = OpenNewConnection(); - return InsertBBMProgress(connection, characterId, startTime, contentId, contentMode, tier, killedDeath, lastTicketTime); + return InsertBBMProgress(connection, characterId, startTime, contentId, contentMode, tier, killedDeath, lastTicketTime, isPaidReset); } public bool InsertBBMProgress(DbConnection connection, uint characterId, ulong startTime, uint contentId, BattleContentMode contentMode, uint tier, bool killedDeath, - ulong lastTicketTime) + ulong lastTicketTime, bool isPaidReset) { return ExecuteNonQuery(connection, SqlInsertBBMProgress, command => { @@ -38,16 +38,17 @@ public partial class DdonSqlDb : SqlDb AddParameter(command, "tier", tier); AddParameter(command, "killed_death", killedDeath); AddParameter(command, "last_ticket_time", lastTicketTime); + AddParameter(command, "is_paid_reset", isPaidReset); }) == 1; } public override bool UpdateBBMProgress(uint characterId, BitterblackMazeProgress progress, DbConnection? connectionIn = null) { - return UpdateBBMProgress(characterId, progress.StartTime, progress.ContentId, progress.ContentMode, progress.Tier, progress.KilledDeath, progress.LastTicketTime, + return UpdateBBMProgress(characterId, progress.StartTime, progress.ContentId, progress.ContentMode, progress.Tier, progress.KilledDeath, progress.LastTicketTime, progress.IsPaidReset, connectionIn); } - public bool UpdateBBMProgress(uint characterId, ulong startTime, uint contentId, BattleContentMode contentMode, uint tier, bool killedDeath, ulong lastTicketTime, + public bool UpdateBBMProgress(uint characterId, ulong startTime, uint contentId, BattleContentMode contentMode, uint tier, bool killedDeath, ulong lastTicketTime, bool isPaidReset, DbConnection? connectionIn = null) { return ExecuteQuerySafe(connectionIn, connection => @@ -61,6 +62,7 @@ public partial class DdonSqlDb : SqlDb AddParameter(command, "tier", tier); AddParameter(command, "killed_death", killedDeath); AddParameter(command, "last_ticket_time", lastTicketTime); + AddParameter(command, "is_paid_reset", isPaidReset); }) == 1; }); } @@ -98,6 +100,7 @@ public partial class DdonSqlDb : SqlDb result.Tier = GetUInt32(reader, "tier"); result.KilledDeath = GetBoolean(reader, "killed_death"); result.LastTicketTime = GetUInt64(reader, "last_ticket_time"); + result.IsPaidReset = GetBoolean(reader, "is_paid_reset"); } }); }); diff --git a/Arrowgene.Ddon.Database/Sql/Core/Migration/00000064_BbmPaidResetMigration.cs b/Arrowgene.Ddon.Database/Sql/Core/Migration/00000064_BbmPaidResetMigration.cs new file mode 100644 index 00000000..ed897ddf --- /dev/null +++ b/Arrowgene.Ddon.Database/Sql/Core/Migration/00000064_BbmPaidResetMigration.cs @@ -0,0 +1,16 @@ +using System.Data.Common; + +namespace Arrowgene.Ddon.Database.Sql.Core.Migration; + +public class BbmPaidResetMigration(DatabaseSetting databaseSetting) : IMigrationStrategy +{ + public uint From => 63; + public uint To => 64; + + public bool Migrate(IDatabase db, DbConnection conn) + { + string adaptedSchema = DdonDatabaseBuilder.GetAdaptedSchema(databaseSetting, "Script/migration_bbm_paid_reset.sql"); + db.Execute(conn, adaptedSchema, true); + return true; + } +} \ No newline at end of file diff --git a/Arrowgene.Ddon.Database/Sql/SqlDb.cs b/Arrowgene.Ddon.Database/Sql/SqlDb.cs index c223117b..555ade45 100644 --- a/Arrowgene.Ddon.Database/Sql/SqlDb.cs +++ b/Arrowgene.Ddon.Database/Sql/SqlDb.cs @@ -566,7 +566,7 @@ public abstract class SqlDb : IDatabase public abstract bool InsertBBMCharacterId(uint characterId, uint bbmCharacterId); public abstract uint SelectBBMCharacterId(uint characterId, DbConnection? connectionIn = null); public abstract uint SelectBBMNormalCharacterId(uint bbmCharacterId); - public abstract bool InsertBBMProgress(uint characterId, ulong startTime, uint contentId, BattleContentMode contentMode, uint tier, bool killedDeath, ulong lastTicketTime); + public abstract bool InsertBBMProgress(uint characterId, ulong startTime, uint contentId, BattleContentMode contentMode, uint tier, bool killedDeath, ulong lastTicketTime, bool isPaidReset); public abstract bool UpdateBBMProgress(uint characterId, BitterblackMazeProgress progress, DbConnection? connectionIn = null); public abstract BitterblackMazeProgress SelectBBMProgress(uint characterId); public abstract bool RemoveBBMProgress(uint characterId); diff --git a/Arrowgene.Ddon.GameServer/Characters/BitterblackMazeManager.cs b/Arrowgene.Ddon.GameServer/Characters/BitterblackMazeManager.cs index f4568c3a..b24d9d93 100644 --- a/Arrowgene.Ddon.GameServer/Characters/BitterblackMazeManager.cs +++ b/Arrowgene.Ddon.GameServer/Characters/BitterblackMazeManager.cs @@ -464,6 +464,23 @@ namespace Arrowgene.Ddon.GameServer.Characters } else { + //Sealed Orange chests can have a chance at giving an earring/bracelet if the JSON is configured to do so and the character is doing a Paid Reset of BBM + if( character.BbmProgress.IsPaidReset && + chestType == ChestType.Orange && + assets.LootRanges[stageId.Id].SealedChestJewelryChance > 0 && + RollRewardChance(assets.LootRanges[stageId.Id].SealedChestJewelryChance)) + { + uint itemId = (character.BbmProgress.ContentMode == BattleContentMode.Rotunda) + ? BitterblackMazeManager.BitterblackBraceletItemId + : BitterblackMazeManager.BitterblackEarringItemId; + results.Add(new InstancedGatheringItem() + { + ItemId = (ItemId)itemId, + ItemNum = 1, + Quality = 1, + }); + } + uint picks = (uint)Random.Shared.Next(4); for (int i = 0; i < picks; i++) { diff --git a/Arrowgene.Ddon.GameServer/Handler/BattleContentContentResetHandler.cs b/Arrowgene.Ddon.GameServer/Handler/BattleContentContentResetHandler.cs index 3bccc8fd..a321582c 100644 --- a/Arrowgene.Ddon.GameServer/Handler/BattleContentContentResetHandler.cs +++ b/Arrowgene.Ddon.GameServer/Handler/BattleContentContentResetHandler.cs @@ -118,6 +118,7 @@ namespace Arrowgene.Ddon.GameServer.Handler client.Character.BbmProgress.ContentId = 0; client.Character.BbmProgress.Tier = 0; client.Character.BbmProgress.KilledDeath = false; + client.Character.BbmProgress.IsPaidReset = isPaidRequest; Server.Database.UpdateBBMProgress(client.Character.CharacterId, client.Character.BbmProgress, connection); // Update the situation information diff --git a/Arrowgene.Ddon.LoginServer/Handler/CreateCharacterHandler.cs b/Arrowgene.Ddon.LoginServer/Handler/CreateCharacterHandler.cs index 09be64ca..abde010d 100644 --- a/Arrowgene.Ddon.LoginServer/Handler/CreateCharacterHandler.cs +++ b/Arrowgene.Ddon.LoginServer/Handler/CreateCharacterHandler.cs @@ -518,7 +518,7 @@ namespace Arrowgene.Ddon.LoginServer.Handler Logger.Error("Failed to seed first MSQ for player"); } - if (!Database.InsertBBMProgress(character.CharacterId, 0, 0, 0, 0, false, 0)) + if (!Database.InsertBBMProgress(character.CharacterId, 0, 0, 0, 0, false, 0, true)) { Logger.Error("Failed to insert BBM progress"); } diff --git a/Arrowgene.Ddon.Shared/Asset/BitterblackMazeAsset.cs b/Arrowgene.Ddon.Shared/Asset/BitterblackMazeAsset.cs index 7bad8c8b..3ce20cb4 100644 --- a/Arrowgene.Ddon.Shared/Asset/BitterblackMazeAsset.cs +++ b/Arrowgene.Ddon.Shared/Asset/BitterblackMazeAsset.cs @@ -39,6 +39,7 @@ namespace Arrowgene.Ddon.Shared.Asset public (uint Min, uint Max) SealedRange; public double RareChance { get; set; } public double JewelryChance { get; set; } + public double SealedChestJewelryChance { get; set; } public (uint Gold, uint Silver, uint Red) Marks { get; set; } } diff --git a/Arrowgene.Ddon.Shared/AssetReader/BitterblackMazeAssetDeserializer.cs b/Arrowgene.Ddon.Shared/AssetReader/BitterblackMazeAssetDeserializer.cs index de8123a0..349908f7 100644 --- a/Arrowgene.Ddon.Shared/AssetReader/BitterblackMazeAssetDeserializer.cs +++ b/Arrowgene.Ddon.Shared/AssetReader/BitterblackMazeAssetDeserializer.cs @@ -70,6 +70,7 @@ namespace Arrowgene.Ddon.Shared.AssetReader NormalRange = (lootRange.GetProperty("normal").GetProperty("min").GetUInt32(), lootRange.GetProperty("normal").GetProperty("max").GetUInt32()), SealedRange = (lootRange.GetProperty("sealed").GetProperty("min").GetUInt32(), lootRange.GetProperty("sealed").GetProperty("max").GetUInt32()), JewelryChance = lootRange.GetProperty("jewelry_chance").GetDouble(), + SealedChestJewelryChance = lootRange.GetProperty("sealed_chest_jewelry_chance").GetDouble(), RareChance = lootRange.GetProperty("rare_chance").GetDouble(), Marks = (lootRange.GetProperty("marks").GetProperty("gold").GetUInt32(), lootRange.GetProperty("marks").GetProperty("silver").GetUInt32(), lootRange.GetProperty("marks").GetProperty("red").GetUInt32()) }; diff --git a/Arrowgene.Ddon.Shared/Files/Assets/BitterblackMaze.json b/Arrowgene.Ddon.Shared/Files/Assets/BitterblackMaze.json index 94022518..2e5992c6 100644 --- a/Arrowgene.Ddon.Shared/Files/Assets/BitterblackMaze.json +++ b/Arrowgene.Ddon.Shared/Files/Assets/BitterblackMaze.json @@ -1091,6 +1091,7 @@ { "comment": "Rotunda 1", "jewelry_chance": 1.0, + "sealed_chest_jewelry_chance": 0.0, "rare_chance": 0.01, "stage_ids": [ 603, @@ -1115,6 +1116,7 @@ { "comment": "Rotunda 2", "jewelry_chance": 1.0, + "sealed_chest_jewelry_chance": 0.0, "rare_chance": 0.01, "stage_ids": [ 604, @@ -1139,6 +1141,7 @@ { "comment": "Rotunda 3", "jewelry_chance": 1.0, + "sealed_chest_jewelry_chance": 0.0, "rare_chance": 0.01, "stage_ids": [ 605, @@ -1166,6 +1169,7 @@ { "comment": "Abyss 1", "jewelry_chance": 1.0, + "sealed_chest_jewelry_chance": 0.0, "rare_chance": 0.01, "stage_ids": [ 682, @@ -1190,6 +1194,7 @@ { "comment": "Abyss 2", "jewelry_chance": 1.0, + "sealed_chest_jewelry_chance": 0.0, "rare_chance": 0.01, "stage_ids": [ 683, @@ -1214,6 +1219,7 @@ { "comment": "Abyss 3", "jewelry_chance": 1.0, + "sealed_chest_jewelry_chance": 0.0, "rare_chance": 0.01, "stage_ids": [ 684, @@ -1238,6 +1244,7 @@ { "comment": "Abyss 4", "jewelry_chance": 1.0, + "sealed_chest_jewelry_chance": 0.0, "rare_chance": 0.01, "stage_ids": [ 685, diff --git a/Arrowgene.Ddon.Shared/Model/BattleContent/BitterblackMazeProgress.cs b/Arrowgene.Ddon.Shared/Model/BattleContent/BitterblackMazeProgress.cs index b0bec18b..d927e37e 100644 --- a/Arrowgene.Ddon.Shared/Model/BattleContent/BitterblackMazeProgress.cs +++ b/Arrowgene.Ddon.Shared/Model/BattleContent/BitterblackMazeProgress.cs @@ -18,5 +18,6 @@ namespace Arrowgene.Ddon.Shared.Model.BattleContent public uint Tier { get; set; } public bool KilledDeath { get; set; } public ulong LastTicketTime { get; set; } + public bool IsPaidReset { get; set; } } } diff --git a/Arrowgene.Ddon.Test/Database/DatabaseMigratorTest.cs b/Arrowgene.Ddon.Test/Database/DatabaseMigratorTest.cs index e3b78407..c77d86f3 100644 --- a/Arrowgene.Ddon.Test/Database/DatabaseMigratorTest.cs +++ b/Arrowgene.Ddon.Test/Database/DatabaseMigratorTest.cs @@ -428,7 +428,7 @@ namespace Arrowgene.Ddon.Test.Database public bool InsertBBMCharacterId(uint characterId, uint bbmCharacterId) { return false; } public uint SelectBBMCharacterId(uint characterId, DbConnection? connectionIn = null) { return 0; } public uint SelectBBMNormalCharacterId(uint bbmCharacterId) { return 0; } - public bool InsertBBMProgress(uint characterId, ulong startTime, uint contentId, BattleContentMode contentMode, uint tier, bool killedDeath, ulong lastTicketTime) { return true; } + public bool InsertBBMProgress(uint characterId, ulong startTime, uint contentId, BattleContentMode contentMode, uint tier, bool killedDeath, ulong lastTicketTime, bool isPaidReset) { return true; } public bool UpdateBBMProgress(uint characterId, BitterblackMazeProgress progress, DbConnection? connectionIn = null) { return true; } public bool RemoveBBMProgress(uint characterId) { return true; } public BitterblackMazeProgress SelectBBMProgress(uint characterId) { return new BitterblackMazeProgress(); }