Updated cost logic and default weights

This commit is contained in:
AnimeGitB 2022-05-12 02:23:51 +09:30 committed by Melledy
parent 736ca85300
commit 420801b49e
4 changed files with 40 additions and 22 deletions

View File

@ -6,7 +6,9 @@
"prefabPath": "GachaShowPanel_A022", "prefabPath": "GachaShowPanel_A022",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A022", "previewPrefabPath": "UI_Tab_GachaShowPanel_A022",
"titlePath": "UI_GACHA_SHOW_PANEL_A022_TITLE", "titlePath": "UI_GACHA_SHOW_PANEL_A022_TITLE",
"costItem": 224, "costItemId": 224,
"costItemAmount": 1,
"costItemAmount10": 10,
"beginTime": 0, "beginTime": 0,
"endTime": 1924992000, "endTime": 1924992000,
"sortId": 1000, "sortId": 1000,
@ -21,7 +23,7 @@
"prefabPath": "GachaShowPanel_A079", "prefabPath": "GachaShowPanel_A079",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A079", "previewPrefabPath": "UI_Tab_GachaShowPanel_A079",
"titlePath": "UI_GACHA_SHOW_PANEL_A048_TITLE", "titlePath": "UI_GACHA_SHOW_PANEL_A048_TITLE",
"costItem": 223, "costItemId": 223,
"beginTime": 0, "beginTime": 0,
"endTime": 1924992000, "endTime": 1924992000,
"sortId": 9998, "sortId": 9998,
@ -37,7 +39,7 @@
"prefabPath": "GachaShowPanel_A080", "prefabPath": "GachaShowPanel_A080",
"previewPrefabPath": "UI_Tab_GachaShowPanel_A080", "previewPrefabPath": "UI_Tab_GachaShowPanel_A080",
"titlePath": "UI_GACHA_SHOW_PANEL_A021_TITLE", "titlePath": "UI_GACHA_SHOW_PANEL_A021_TITLE",
"costItem": 223, "costItemId": 223,
"beginTime": 0, "beginTime": 0,
"endTime": 1924992000, "endTime": 1924992000,
"sortId": 9997, "sortId": 9997,
@ -47,6 +49,7 @@
"rateUpItems4": [11401, 12402, 13407, 14401, 15401], "rateUpItems4": [11401, 12402, 13407, 14401, 15401],
"rateUpItems5": [11509, 12504], "rateUpItems5": [11509, 12504],
"fallbackItems5Pool1": [], "fallbackItems5Pool1": [],
"weights4": [[1,600], [7,600], [8, 6600], [10,12600]],
"weights5": [[1,100], [62,100], [73, 7800], [80,10000]] "weights5": [[1,100], [62,100], [73, 7800], [80,10000]]
} }
] ]

View File

@ -6,6 +6,7 @@ import emu.grasscutter.utils.Utils;
import static emu.grasscutter.Configuration.*; import static emu.grasscutter.Configuration.*;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
public class GachaBanner { public class GachaBanner {
@ -145,25 +146,26 @@ public class GachaBanner {
+ "/gacha/details?s=" + sessionKey + "&gachaType=" + gachaType; + "/gacha/details?s=" + sessionKey + "&gachaType=" + gachaType;
// Grasscutter.getLogger().info("record = " + record); // Grasscutter.getLogger().info("record = " + record);
ItemParamData costItem1 = this.getCost(1);
ItemParamData costItem10 = this.getCost(10);
GachaInfo.Builder info = GachaInfo.newBuilder() GachaInfo.Builder info = GachaInfo.newBuilder()
.setGachaType(this.getGachaType()) .setGachaType(this.getGachaType())
.setScheduleId(this.getScheduleId()) .setScheduleId(this.getScheduleId())
.setBeginTime(this.getBeginTime()) .setBeginTime(this.getBeginTime())
.setEndTime(this.getEndTime()) .setEndTime(this.getEndTime())
.setCostItemId(this.getCostItem()) .setCostItemId(costItem1.getId())
.setCostItemNum(1) .setCostItemNum(costItem1.getCount())
.setTenCostItemId(costItem10.getId())
.setTenCostItemNum(costItem10.getCount())
.setGachaPrefabPath(this.getPrefabPath()) .setGachaPrefabPath(this.getPrefabPath())
.setGachaPreviewPrefabPath(this.getPreviewPrefabPath()) .setGachaPreviewPrefabPath(this.getPreviewPrefabPath())
.setGachaProbUrl(details) .setGachaProbUrl(details)
.setGachaProbUrlOversea(details) .setGachaProbUrlOversea(details)
.setGachaRecordUrl(record) .setGachaRecordUrl(record)
.setGachaRecordUrlOversea(record) .setGachaRecordUrlOversea(record)
.setTenCostItemId(this.getCostItem())
.setTenCostItemNum(10)
.setLeftGachaTimes(Integer.MAX_VALUE) .setLeftGachaTimes(Integer.MAX_VALUE)
.setGachaTimesLimit(Integer.MAX_VALUE) .setGachaTimesLimit(Integer.MAX_VALUE)
.setGachaSortId(this.getSortId()); .setGachaSortId(this.getSortId());
if (this.getTitlePath() != null) { if (this.getTitlePath() != null) {
info.setGachaTitlePath(this.getTitlePath()); info.setGachaTitlePath(this.getTitlePath());
} }

View File

@ -4,6 +4,7 @@ import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.nio.file.*; import java.nio.file.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@ -46,6 +47,8 @@ public class GachaManager {
private static final int starglitterId = 221; private static final int starglitterId = 221;
private static final int stardustId = 222; 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) { public GachaManager(GameServer server) {
this.server = 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 // Simple weighted selection with an upper bound for the roll that cuts off trailing entries
// All weights must be >= 0 // All weights must be >= 0
int total = 0; int total = 0;
for (int i : weights) { for (int weight : weights) {
if (i < 0) { if (weight < 0) {
throw new IllegalArgumentException("Weights must be non-negative!"); throw new IllegalArgumentException("Weights must be non-negative!");
} }
total += i; total += weight;
} }
int roll = ThreadLocalRandom.current().nextInt((total < cutoff)? total : cutoff); int roll = ThreadLocalRandom.current().nextInt((total < cutoff)? total : cutoff);
int subTotal = 0; int subTotal = 0;
for (int i : weights) { for (int i=0; i<weights.length; i++) {
subTotal += i; subTotal += weights[i];
if (roll < subTotal) { if (roll < subTotal) {
return i; return i;
} }
@ -176,16 +179,22 @@ public class GachaManager {
private synchronized int doRarePull(int[] featured, int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) { private synchronized int doRarePull(int[] featured, int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) {
int itemId = 0; int itemId = 0;
if ( (featured.length > 0) boolean pullFeatured = (gachaInfo.getFailedFeaturedItemPulls(rarity) >= 1) // Lost previous coinflip
&& (gachaInfo.getFailedFeaturedItemPulls(rarity) >= 1) || (this.randomRange(1, 100) <= banner.getEventChance(rarity)); // Won this coinflip
|| (this.randomRange(1, 100) <= banner.getEventChance(rarity))) { if (pullFeatured && (featured.length > 0)) {
itemId = getRandom(featured); itemId = getRandom(featured);
gachaInfo.setFailedFeaturedItemPulls(rarity, 0); gachaInfo.setFailedFeaturedItemPulls(rarity, 0);
} else { } else {
gachaInfo.addFailedFeaturedItemPulls(rarity, 1); gachaInfo.addFailedFeaturedItemPulls(rarity, 1);
if (fallback1.length < 1) { if (fallback1.length < 1) {
itemId = getRandom(fallback2); // Don't ever run an empty fallback2 btw if (fallback2.length < 1) {
} else { 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 pityPool1 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 1));
int pityPool2 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 2)); 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 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 // Spend currency
ItemParamData cost = banner.getCost(times); ItemParamData cost = banner.getCost(times);
if (cost.getCount() > 0 && !inventory.payItem(cost)) { if (cost.getCount() > 0 && !inventory.payItem(cost)) {
player.sendPacket(new PacketDoGachaRsp());
return; return;
} }

View File

@ -2,6 +2,7 @@ package emu.grasscutter.server.packet.send;
import java.util.List; import java.util.List;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.game.gacha.GachaBanner; import emu.grasscutter.game.gacha.GachaBanner;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
@ -14,16 +15,18 @@ public class PacketDoGachaRsp extends BasePacket {
public PacketDoGachaRsp(GachaBanner banner, List<GachaItem> list) { public PacketDoGachaRsp(GachaBanner banner, List<GachaItem> list) {
super(PacketOpcodes.DoGachaRsp); super(PacketOpcodes.DoGachaRsp);
ItemParamData costItem = banner.getCost(1);
ItemParamData costItem10 = banner.getCost(10);
DoGachaRsp p = DoGachaRsp.newBuilder() DoGachaRsp p = DoGachaRsp.newBuilder()
.setGachaType(banner.getGachaType()) .setGachaType(banner.getGachaType())
.setGachaScheduleId(banner.getScheduleId()) .setGachaScheduleId(banner.getScheduleId())
.setGachaTimes(list.size()) .setGachaTimes(list.size())
.setNewGachaRandom(12345) .setNewGachaRandom(12345)
.setLeftGachaTimes(Integer.MAX_VALUE) .setLeftGachaTimes(Integer.MAX_VALUE)
.setCostItemId(banner.getCostItem()) .setCostItemId(costItem.getId())
.setCostItemNum(1) .setCostItemNum(costItem.getCount())
.setTenCostItemId(banner.getCostItem()) .setTenCostItemId(costItem10.getId())
.setTenCostItemNum(10) .setTenCostItemNum(costItem10.getCount())
.addAllGachaItemList(list) .addAllGachaItemList(list)
.build(); .build();