feat(pack): accrue gacha points on /pack/open (skip tutorial)
This commit is contained in:
@@ -246,6 +246,7 @@ public class PackController : SVSimController
|
|||||||
|
|
||||||
var viewer = await _db.Viewers
|
var viewer = await _db.Viewers
|
||||||
.Include(v => v.PackOpenCounts)
|
.Include(v => v.PackOpenCounts)
|
||||||
|
.Include(v => v.GachaPointBalances)
|
||||||
.Include(v => v.MissionData)
|
.Include(v => v.MissionData)
|
||||||
.Include(v => v.Items).ThenInclude(i => i.Item)
|
.Include(v => v.Items).ThenInclude(i => i.Item)
|
||||||
.AsSplitQuery()
|
.AsSplitQuery()
|
||||||
@@ -318,6 +319,13 @@ public class PackController : SVSimController
|
|||||||
var draw = _opener.Draw(pack, _pools, drawCount, request.ExcludeCardIds, _rng);
|
var draw = _opener.Draw(pack, _pools, drawCount, request.ExcludeCardIds, _rng);
|
||||||
var grant = await _acquisition.GrantManyAsync(viewerId, draw.Cards.Select(c => c.CardId));
|
var grant = await _acquisition.GrantManyAsync(viewerId, draw.Cards.Select(c => c.CardId));
|
||||||
|
|
||||||
|
// Accrue gacha points (skip tutorial path — the starter pack isn't a real open).
|
||||||
|
if (!isTutorialPath)
|
||||||
|
{
|
||||||
|
_gachaPoint.Accrue(viewer, pack, child, drawCount);
|
||||||
|
await _db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
// Build reward_list. The service produces the type=5 (Card) entries with post-state counts
|
// Build reward_list. The service produces the type=5 (Card) entries with post-state counts
|
||||||
// plus any cosmetic grants. Currency entry (type=2 Crystals or type=9 Rupy) stays in the
|
// plus any cosmetic grants. Currency entry (type=2 Crystals or type=9 Rupy) stays in the
|
||||||
// controller — it's a pack-purchase concern, not a card-grant concern. The client's
|
// controller — it's a pack-purchase concern, not a card-grant concern. The client's
|
||||||
|
|||||||
@@ -464,4 +464,125 @@ public class PackControllerOpenTests
|
|||||||
});
|
});
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task PackOpen_accrues_gacha_points_per_pack_drawn()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
long viewerId = await factory.SeedViewerAsync();
|
||||||
|
using (var scope = factory.Services.CreateScope())
|
||||||
|
{
|
||||||
|
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||||
|
db.Classes.Add(new ClassEntry { Id = 0, Name = "Neutral" });
|
||||||
|
var set = new ShadowverseCardSetEntry { Id = 10008, IsInRotation = true };
|
||||||
|
db.CardSets.Add(set);
|
||||||
|
// Need a pool that can draw 8 cards across the 4 default rarities.
|
||||||
|
for (int i = 0; i < 30; i++)
|
||||||
|
{
|
||||||
|
set.Cards.Add(new ShadowverseCardEntry
|
||||||
|
{
|
||||||
|
Id = 10804_1010 + i,
|
||||||
|
Name = $"c{i}",
|
||||||
|
Rarity = (Rarity)((i % 4) + 1), // Bronze..Legendary
|
||||||
|
Class = db.Classes.Local.First(),
|
||||||
|
IsFoil = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
db.Packs.Add(new PackConfigEntry
|
||||||
|
{
|
||||||
|
Id = 10008, BasePackId = 10008, PackCategory = PackCategory.LegendCardPack,
|
||||||
|
CommenceDate = DateTime.UtcNow.AddDays(-1), CompleteDate = DateTime.UtcNow.AddDays(30),
|
||||||
|
GachaType = 1,
|
||||||
|
GachaPointConfig = new PackGachaPointConfig { ExchangeablePoint = 400, IncreaseGachaPoint = 1 },
|
||||||
|
ChildGachas =
|
||||||
|
{
|
||||||
|
new PackChildGachaEntry
|
||||||
|
{
|
||||||
|
GachaId = 100087, TypeDetail = 7, Cost = 100, CardCount = 8,
|
||||||
|
OverrideIncreaseGachaPoint = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
var viewer = await db.Viewers.FirstAsync(v => v.Id == viewerId);
|
||||||
|
viewer.Currency.Rupees = 10000;
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||||
|
var body = new StringContent(
|
||||||
|
"""{"parent_gacha_id":10008,"gacha_id":100087,"gacha_type":1,"pack_number":3,"exclude_card_ids":[],"viewer_id":"0","steam_id":0,"steam_session_ticket":""}""",
|
||||||
|
System.Text.Encoding.UTF8, "application/json");
|
||||||
|
var response = await client.PostAsync("/pack/open", body);
|
||||||
|
var text = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK), text);
|
||||||
|
|
||||||
|
using var scope2 = factory.Services.CreateScope();
|
||||||
|
var db2 = scope2.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||||
|
var v = await db2.Viewers
|
||||||
|
.Include(x => x.GachaPointBalances)
|
||||||
|
.FirstAsync(x => x.Id == viewerId);
|
||||||
|
Assert.That(v.GachaPointBalances.Single().Points, Is.EqualTo(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TutorialPackOpen_does_not_accrue_gacha_points()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
long viewerId = await factory.SeedViewerAsync();
|
||||||
|
// Seed the starter pack 99047 with a GachaPointConfig set — the tutorial-path skip
|
||||||
|
// must hold even when the pack is technically point-eligible.
|
||||||
|
using (var scope = factory.Services.CreateScope())
|
||||||
|
{
|
||||||
|
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||||
|
db.Classes.Add(new ClassEntry { Id = 0, Name = "Neutral" });
|
||||||
|
var set = new ShadowverseCardSetEntry { Id = 99047, IsInRotation = true };
|
||||||
|
db.CardSets.Add(set);
|
||||||
|
for (int i = 0; i < 30; i++)
|
||||||
|
{
|
||||||
|
set.Cards.Add(new ShadowverseCardEntry
|
||||||
|
{
|
||||||
|
Id = 99047_1010 + i, Name = $"c{i}",
|
||||||
|
Rarity = (Rarity)((i % 4) + 1),
|
||||||
|
Class = db.Classes.Local.First(), IsFoil = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
db.Items.Add(new ItemEntry { Id = 90001, Name = "starter-ticket" });
|
||||||
|
db.Packs.Add(new PackConfigEntry
|
||||||
|
{
|
||||||
|
Id = 99047, BasePackId = 99047, PackCategory = PackCategory.LegendCardPack,
|
||||||
|
CommenceDate = DateTime.UtcNow.AddDays(-1), CompleteDate = DateTime.UtcNow.AddDays(30),
|
||||||
|
GachaType = 1,
|
||||||
|
GachaPointConfig = new PackGachaPointConfig { ExchangeablePoint = 400, IncreaseGachaPoint = 1 },
|
||||||
|
ChildGachas =
|
||||||
|
{
|
||||||
|
new PackChildGachaEntry
|
||||||
|
{
|
||||||
|
GachaId = 990475, TypeDetail = 5, Cost = 0, CardCount = 8,
|
||||||
|
ItemId = 90001,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
var viewer = await db.Viewers
|
||||||
|
.Include(v => v.Items).ThenInclude(i => i.Item)
|
||||||
|
.FirstAsync(v => v.Id == viewerId);
|
||||||
|
viewer.Items.Add(new OwnedItemEntry { Item = db.Items.Local.First(), Count = 1, Viewer = viewer });
|
||||||
|
viewer.MissionData.TutorialState = 41; // pre-END so the tutorial path is allowed
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||||
|
var body = new StringContent(
|
||||||
|
"""{"parent_gacha_id":99047,"gacha_id":990475,"gacha_type":1,"pack_number":1,"exclude_card_ids":[],"viewer_id":"0","steam_id":0,"steam_session_ticket":""}""",
|
||||||
|
System.Text.Encoding.UTF8, "application/json");
|
||||||
|
var response = await client.PostAsync("/tutorial/pack_open", body);
|
||||||
|
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK),
|
||||||
|
await response.Content.ReadAsStringAsync());
|
||||||
|
|
||||||
|
using var scope2 = factory.Services.CreateScope();
|
||||||
|
var db2 = scope2.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||||
|
var v = await db2.Viewers
|
||||||
|
.Include(x => x.GachaPointBalances)
|
||||||
|
.FirstAsync(x => x.Id == viewerId);
|
||||||
|
Assert.That(v.GachaPointBalances, Is.Empty, "tutorial path must not accrue gacha points");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user