diff --git a/data/Banners.json b/data/Banners.json index 1aaf39cb7..17e720e65 100644 --- a/data/Banners.json +++ b/data/Banners.json @@ -6,7 +6,9 @@ "prefabPath": "GachaShowPanel_A022", "previewPrefabPath": "UI_Tab_GachaShowPanel_A022", "titlePath": "UI_GACHA_SHOW_PANEL_A022_TITLE", - "costItem": 224, + "costItemId": 224, + "costItemAmount": 1, + "costItemAmount10": 10, "beginTime": 0, "endTime": 1924992000, "sortId": 1000, @@ -21,7 +23,7 @@ "prefabPath": "GachaShowPanel_A079", "previewPrefabPath": "UI_Tab_GachaShowPanel_A079", "titlePath": "UI_GACHA_SHOW_PANEL_A048_TITLE", - "costItem": 223, + "costItemId": 223, "beginTime": 0, "endTime": 1924992000, "sortId": 9998, @@ -37,7 +39,7 @@ "prefabPath": "GachaShowPanel_A080", "previewPrefabPath": "UI_Tab_GachaShowPanel_A080", "titlePath": "UI_GACHA_SHOW_PANEL_A021_TITLE", - "costItem": 223, + "costItemId": 223, "beginTime": 0, "endTime": 1924992000, "sortId": 9997, @@ -47,6 +49,7 @@ "rateUpItems4": [11401, 12402, 13407, 14401, 15401], "rateUpItems5": [11509, 12504], "fallbackItems5Pool1": [], + "weights4": [[1,600], [7,600], [8, 6600], [10,12600]], "weights5": [[1,100], [62,100], [73, 7800], [80,10000]] } ] diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java index 3c97e671c..1586198c2 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java @@ -6,6 +6,7 @@ import emu.grasscutter.utils.Utils; import static emu.grasscutter.Configuration.*; +import emu.grasscutter.Grasscutter; import emu.grasscutter.data.common.ItemParamData; public class GachaBanner { @@ -145,25 +146,26 @@ public class GachaBanner { + "/gacha/details?s=" + sessionKey + "&gachaType=" + gachaType; // Grasscutter.getLogger().info("record = " + record); + ItemParamData costItem1 = this.getCost(1); + ItemParamData costItem10 = this.getCost(10); GachaInfo.Builder info = GachaInfo.newBuilder() .setGachaType(this.getGachaType()) .setScheduleId(this.getScheduleId()) .setBeginTime(this.getBeginTime()) .setEndTime(this.getEndTime()) - .setCostItemId(this.getCostItem()) - .setCostItemNum(1) + .setCostItemId(costItem1.getId()) + .setCostItemNum(costItem1.getCount()) + .setTenCostItemId(costItem10.getId()) + .setTenCostItemNum(costItem10.getCount()) .setGachaPrefabPath(this.getPrefabPath()) .setGachaPreviewPrefabPath(this.getPreviewPrefabPath()) .setGachaProbUrl(details) .setGachaProbUrlOversea(details) .setGachaRecordUrl(record) .setGachaRecordUrlOversea(record) - .setTenCostItemId(this.getCostItem()) - .setTenCostItemNum(10) .setLeftGachaTimes(Integer.MAX_VALUE) .setGachaTimesLimit(Integer.MAX_VALUE) .setGachaSortId(this.getSortId()); - if (this.getTitlePath() != null) { info.setGachaTitlePath(this.getTitlePath()); } diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java b/src/main/java/emu/grasscutter/game/gacha/GachaManager.java index a0337be7f..4cbfde094 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaManager.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.FileReader; import java.nio.file.*; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -46,6 +47,8 @@ public class GachaManager { private static final int starglitterId = 221; private static final int stardustId = 222; + private int[] fallbackItems4Pool2Default = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405}; + private int[] fallbackItems5Pool2Default = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502}; public GachaManager(GameServer server) { this.server = server; @@ -156,16 +159,16 @@ public class GachaManager { // Simple weighted selection with an upper bound for the roll that cuts off trailing entries // All weights must be >= 0 int total = 0; - for (int i : weights) { - if (i < 0) { + for (int weight : weights) { + if (weight < 0) { throw new IllegalArgumentException("Weights must be non-negative!"); } - total += i; + total += weight; } int roll = ThreadLocalRandom.current().nextInt((total < cutoff)? total : cutoff); int subTotal = 0; - for (int i : weights) { - subTotal += i; + for (int i=0; i 0) - && (gachaInfo.getFailedFeaturedItemPulls(rarity) >= 1) - || (this.randomRange(1, 100) <= banner.getEventChance(rarity))) { + boolean pullFeatured = (gachaInfo.getFailedFeaturedItemPulls(rarity) >= 1) // Lost previous coinflip + || (this.randomRange(1, 100) <= banner.getEventChance(rarity)); // Won this coinflip + if (pullFeatured && (featured.length > 0)) { itemId = getRandom(featured); gachaInfo.setFailedFeaturedItemPulls(rarity, 0); } else { gachaInfo.addFailedFeaturedItemPulls(rarity, 1); if (fallback1.length < 1) { - itemId = getRandom(fallback2); // Don't ever run an empty fallback2 btw - } else { + if (fallback2.length < 1) { + itemId = getRandom((rarity==5)? fallbackItems5Pool2Default : fallbackItems4Pool2Default); + } else { + itemId = getRandom(fallback2); + } + } else if (fallback2.length < 1) { + itemId = getRandom(fallback1); + } else { // Both pools are possible, use the pool balancer int pityPool1 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 1)); int pityPool2 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 2)); int chosenPool = switch ((pityPool1 >= pityPool2)? 1 : 0) { // Larger weight must come first for the hard cutoff to function correctly @@ -245,6 +254,7 @@ public class GachaManager { // Spend currency ItemParamData cost = banner.getCost(times); if (cost.getCount() > 0 && !inventory.payItem(cost)) { + player.sendPacket(new PacketDoGachaRsp()); return; } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketDoGachaRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketDoGachaRsp.java index 9144c0d8e..6d8b9ddd9 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketDoGachaRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketDoGachaRsp.java @@ -2,6 +2,7 @@ package emu.grasscutter.server.packet.send; import java.util.List; +import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.game.gacha.GachaBanner; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; @@ -14,16 +15,18 @@ public class PacketDoGachaRsp extends BasePacket { public PacketDoGachaRsp(GachaBanner banner, List list) { super(PacketOpcodes.DoGachaRsp); + ItemParamData costItem = banner.getCost(1); + ItemParamData costItem10 = banner.getCost(10); DoGachaRsp p = DoGachaRsp.newBuilder() .setGachaType(banner.getGachaType()) .setGachaScheduleId(banner.getScheduleId()) .setGachaTimes(list.size()) .setNewGachaRandom(12345) .setLeftGachaTimes(Integer.MAX_VALUE) - .setCostItemId(banner.getCostItem()) - .setCostItemNum(1) - .setTenCostItemId(banner.getCostItem()) - .setTenCostItemNum(10) + .setCostItemId(costItem.getId()) + .setCostItemNum(costItem.getCount()) + .setTenCostItemId(costItem10.getId()) + .setTenCostItemNum(costItem10.getCount()) .addAllGachaItemList(list) .build();