mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-22 17:51:53 +00:00
Update Epitomized Path (#1254)
* Update Epitomized Path * Update Epitomized Path * Update Epitomized Path * Refactor doRarePull * Update Epitomized Path Co-authored-by: AnimeGitUserB <AnimeGitUserB@bigblueball.in>
This commit is contained in:
parent
bb07d9ea41
commit
2624f48a84
@ -1,5 +1,8 @@
|
|||||||
package emu.grasscutter.game.gacha;
|
package emu.grasscutter.game.gacha;
|
||||||
|
|
||||||
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
|
import emu.grasscutter.game.Account;
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
|
import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo;
|
||||||
import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo;
|
import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
@ -44,6 +47,7 @@ public class GachaBanner {
|
|||||||
private int[] rateUpItems2 = {};
|
private int[] rateUpItems2 = {};
|
||||||
private int eventChance = -1;
|
private int eventChance = -1;
|
||||||
private int costItem = 0;
|
private int costItem = 0;
|
||||||
|
private int wishMaxProgress = 2;
|
||||||
|
|
||||||
public int getGachaType() {
|
public int getGachaType() {
|
||||||
return gachaType;
|
return gachaType;
|
||||||
@ -108,6 +112,11 @@ public class GachaBanner {
|
|||||||
public boolean getRemoveC6FromPool() {return removeC6FromPool;}
|
public boolean getRemoveC6FromPool() {return removeC6FromPool;}
|
||||||
public boolean getAutoStripRateUpFromFallback() {return autoStripRateUpFromFallback;}
|
public boolean getAutoStripRateUpFromFallback() {return autoStripRateUpFromFallback;}
|
||||||
|
|
||||||
|
public int getWishMaxProgress() {return wishMaxProgress;}
|
||||||
|
|
||||||
|
public boolean hasEpitomized() {
|
||||||
|
return bannerType.equals(BannerType.WEAPON);
|
||||||
|
}
|
||||||
|
|
||||||
public int getWeight(int rarity, int pity) {
|
public int getWeight(int rarity, int pity) {
|
||||||
return switch(rarity) {
|
return switch(rarity) {
|
||||||
@ -166,6 +175,17 @@ public class GachaBanner {
|
|||||||
.setLeftGachaTimes(Integer.MAX_VALUE)
|
.setLeftGachaTimes(Integer.MAX_VALUE)
|
||||||
.setGachaTimesLimit(Integer.MAX_VALUE)
|
.setGachaTimesLimit(Integer.MAX_VALUE)
|
||||||
.setGachaSortId(this.getSortId());
|
.setGachaSortId(this.getSortId());
|
||||||
|
|
||||||
|
if(hasEpitomized() && !sessionKey.isEmpty()) {
|
||||||
|
Account account = DatabaseHelper.getAccountBySessionKey(sessionKey);
|
||||||
|
Player player = Grasscutter.getGameServer().getPlayerByAccountId(account.getId());
|
||||||
|
PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this);
|
||||||
|
|
||||||
|
info.setWishItemId(gachaInfo.getWishItemId())
|
||||||
|
.setWishProgress(gachaInfo.getFailedChosenItemPulls())
|
||||||
|
.setWishMaxProgress(this.getWishMaxProgress());
|
||||||
|
}
|
||||||
|
|
||||||
if (this.getTitlePath() != null) {
|
if (this.getTitlePath() != null) {
|
||||||
info.setTitleTextmap(this.getTitlePath());
|
info.setTitleTextmap(this.getTitlePath());
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
|||||||
import emu.grasscutter.server.game.GameServer;
|
import emu.grasscutter.server.game.GameServer;
|
||||||
import emu.grasscutter.server.game.GameServerTickEvent;
|
import emu.grasscutter.server.game.GameServerTickEvent;
|
||||||
import emu.grasscutter.server.packet.send.PacketDoGachaRsp;
|
import emu.grasscutter.server.packet.send.PacketDoGachaRsp;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketGachaWishRsp;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
@ -182,38 +183,59 @@ public class GachaManager {
|
|||||||
return 0; // This should only be reachable if total==0
|
return 0; // This should only be reachable if total==0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized int doFallbackRarePull(int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) {
|
||||||
|
if (fallback1.length < 1) {
|
||||||
|
if (fallback2.length < 1) {
|
||||||
|
return getRandom((rarity==5)? fallbackItems5Pool2Default : fallbackItems4Pool2Default);
|
||||||
|
} else {
|
||||||
|
return getRandom(fallback2);
|
||||||
|
}
|
||||||
|
} else if (fallback2.length < 1) {
|
||||||
|
return 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
|
||||||
|
case 1 -> 1 + drawRoulette(new int[] {pityPool1, pityPool2}, 10000);
|
||||||
|
default -> 2 - drawRoulette(new int[] {pityPool2, pityPool1}, 10000);
|
||||||
|
};
|
||||||
|
return switch (chosenPool) {
|
||||||
|
case 1:
|
||||||
|
gachaInfo.setPityPool(rarity, 1, 0);
|
||||||
|
yield getRandom(fallback1);
|
||||||
|
default:
|
||||||
|
gachaInfo.setPityPool(rarity, 2, 0);
|
||||||
|
yield getRandom(fallback2);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
boolean pullFeatured = (gachaInfo.getFailedFeaturedItemPulls(rarity) >= 1) // Lost previous coinflip
|
boolean epitomized = (banner.hasEpitomized()) && (rarity == 5) && (gachaInfo.getWishItemId() != 0);
|
||||||
|| (this.randomRange(1, 100) <= banner.getEventChance(rarity)); // Won this coinflip
|
boolean pityEpitomized = (gachaInfo.getFailedChosenItemPulls() >= banner.getWishMaxProgress()); // Maximum fate points reached
|
||||||
if (pullFeatured && (featured.length > 0)) {
|
boolean pityFeatured = (gachaInfo.getFailedFeaturedItemPulls(rarity) >= 1); // Lost previous coinflip
|
||||||
itemId = getRandom(featured);
|
boolean rollFeatured = (this.randomRange(1, 100) <= banner.getEventChance(rarity)); // Won this coinflip
|
||||||
gachaInfo.setFailedFeaturedItemPulls(rarity, 0);
|
boolean pullFeatured = pityFeatured || rollFeatured;
|
||||||
|
|
||||||
|
if (epitomized && pityEpitomized) { // Auto pick item when epitomized points reached
|
||||||
|
gachaInfo.setFailedFeaturedItemPulls(rarity, 0); // Epitomized item will always be a featured one
|
||||||
|
itemId = gachaInfo.getWishItemId();
|
||||||
} else {
|
} else {
|
||||||
gachaInfo.addFailedFeaturedItemPulls(rarity, 1);
|
if (pullFeatured && (featured.length > 0)) {
|
||||||
if (fallback1.length < 1) {
|
gachaInfo.setFailedFeaturedItemPulls(rarity, 0);
|
||||||
if (fallback2.length < 1) {
|
itemId = getRandom(featured);
|
||||||
itemId = getRandom((rarity==5)? fallbackItems5Pool2Default : fallbackItems4Pool2Default);
|
} else {
|
||||||
} else {
|
gachaInfo.addFailedFeaturedItemPulls(rarity, 1); // This could be moved into doFallbackRarePull but having it here makes it clearer
|
||||||
itemId = getRandom(fallback2);
|
itemId = doFallbackRarePull(fallback1, fallback2, rarity, banner, gachaInfo);
|
||||||
}
|
}
|
||||||
} else if (fallback2.length < 1) {
|
}
|
||||||
itemId = getRandom(fallback1);
|
|
||||||
} else { // Both pools are possible, use the pool balancer
|
if (epitomized) {
|
||||||
int pityPool1 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 1));
|
if(itemId == gachaInfo.getWishItemId()) { // Reset epitomized points when got wished item
|
||||||
int pityPool2 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 2));
|
gachaInfo.setFailedChosenItemPulls(0);
|
||||||
int chosenPool = switch ((pityPool1 >= pityPool2)? 1 : 0) { // Larger weight must come first for the hard cutoff to function correctly
|
} else { // Add epitomized points if not get wished item
|
||||||
case 1 -> 1 + drawRoulette(new int[] {pityPool1, pityPool2}, 10000);
|
gachaInfo.addFailedChosenItemPulls(1);
|
||||||
default -> 2 - drawRoulette(new int[] {pityPool2, pityPool1}, 10000);
|
|
||||||
};
|
|
||||||
itemId = switch (chosenPool) {
|
|
||||||
case 1:
|
|
||||||
gachaInfo.setPityPool(rarity, 1, 0);
|
|
||||||
yield getRandom(fallback1);
|
|
||||||
default:
|
|
||||||
gachaInfo.setPityPool(rarity, 2, 0);
|
|
||||||
yield getRandom(fallback2);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return itemId;
|
return itemId;
|
||||||
@ -356,7 +378,7 @@ public class GachaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Packets
|
// Packets
|
||||||
player.sendPacket(new PacketDoGachaRsp(banner, list));
|
player.sendPacket(new PacketDoGachaRsp(banner, list, gachaInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void startWatcher(GameServer server) {
|
private synchronized void startWatcher(GameServer server) {
|
||||||
|
@ -12,6 +12,9 @@ public class PlayerGachaBannerInfo {
|
|||||||
private int pity5Pool2 = 0;
|
private int pity5Pool2 = 0;
|
||||||
private int pity4Pool1 = 0;
|
private int pity4Pool1 = 0;
|
||||||
private int pity4Pool2 = 0;
|
private int pity4Pool2 = 0;
|
||||||
|
|
||||||
|
private int failedChosenItemPulls = 0;
|
||||||
|
private int wishItemId = 0;
|
||||||
|
|
||||||
public int getPity5() {
|
public int getPity5() {
|
||||||
return pity5;
|
return pity5;
|
||||||
@ -36,6 +39,26 @@ public class PlayerGachaBannerInfo {
|
|||||||
public void addPity4(int amount) {
|
public void addPity4(int amount) {
|
||||||
this.pity4 += amount;
|
this.pity4 += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getWishItemId() {
|
||||||
|
return wishItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWishItemId(int wishItemId) {
|
||||||
|
this.wishItemId = wishItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFailedChosenItemPulls() {
|
||||||
|
return failedChosenItemPulls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFailedChosenItemPulls(int amount) {
|
||||||
|
failedChosenItemPulls = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFailedChosenItemPulls(int amount) {
|
||||||
|
failedChosenItemPulls += amount;
|
||||||
|
}
|
||||||
|
|
||||||
public int getFailedFeaturedItemPulls(int rarity) {
|
public int getFailedFeaturedItemPulls(int rarity) {
|
||||||
return switch (rarity) {
|
return switch (rarity) {
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.gacha.GachaBanner;
|
||||||
|
import emu.grasscutter.game.gacha.PlayerGachaBannerInfo;
|
||||||
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.GachaWishReqOuterClass.GachaWishReq;
|
||||||
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketGachaWishRsp;
|
||||||
|
|
||||||
|
@Opcodes(PacketOpcodes.GachaWishReq)
|
||||||
|
public class HandlerGachaWishReq extends PacketHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
|
GachaWishReq req = GachaWishReq.parseFrom(payload);
|
||||||
|
|
||||||
|
GachaBanner banner = session.getServer().getGachaManager().getGachaBanners().get(req.getGachaScheduleId());
|
||||||
|
PlayerGachaBannerInfo gachaInfo = session.getPlayer().getGachaInfo().getBannerInfo(banner);
|
||||||
|
|
||||||
|
gachaInfo.setFailedChosenItemPulls(0);
|
||||||
|
gachaInfo.setWishItemId(req.getItemId());
|
||||||
|
|
||||||
|
session.send(new PacketGachaWishRsp(req.getGachaType(), req.getGachaScheduleId(), req.getItemId(), 0, banner.getWishMaxProgress()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,9 +1,12 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.gacha.GachaBanner;
|
||||||
|
import emu.grasscutter.game.gacha.PlayerGachaBannerInfo;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketGachaWishRsp;
|
||||||
import emu.grasscutter.server.packet.send.PacketGetGachaInfoRsp;
|
import emu.grasscutter.server.packet.send.PacketGetGachaInfoRsp;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.GetGachaInfoReq)
|
@Opcodes(PacketOpcodes.GetGachaInfoReq)
|
||||||
|
@ -4,6 +4,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import emu.grasscutter.data.common.ItemParamData;
|
import emu.grasscutter.data.common.ItemParamData;
|
||||||
import emu.grasscutter.game.gacha.GachaBanner;
|
import emu.grasscutter.game.gacha.GachaBanner;
|
||||||
|
import emu.grasscutter.game.gacha.PlayerGachaBannerInfo;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.DoGachaRspOuterClass.DoGachaRsp;
|
import emu.grasscutter.net.proto.DoGachaRspOuterClass.DoGachaRsp;
|
||||||
@ -13,12 +14,12 @@ import emu.grasscutter.net.proto.RetcodeOuterClass;
|
|||||||
|
|
||||||
public class PacketDoGachaRsp extends BasePacket {
|
public class PacketDoGachaRsp extends BasePacket {
|
||||||
|
|
||||||
public PacketDoGachaRsp(GachaBanner banner, List<GachaItem> list) {
|
public PacketDoGachaRsp(GachaBanner banner, List<GachaItem> list, PlayerGachaBannerInfo gachaInfo) {
|
||||||
super(PacketOpcodes.DoGachaRsp);
|
super(PacketOpcodes.DoGachaRsp);
|
||||||
|
|
||||||
ItemParamData costItem = banner.getCost(1);
|
ItemParamData costItem = banner.getCost(1);
|
||||||
ItemParamData costItem10 = banner.getCost(10);
|
ItemParamData costItem10 = banner.getCost(10);
|
||||||
DoGachaRsp p = DoGachaRsp.newBuilder()
|
DoGachaRsp.Builder rsp = DoGachaRsp.newBuilder()
|
||||||
.setGachaType(banner.getGachaType())
|
.setGachaType(banner.getGachaType())
|
||||||
.setGachaScheduleId(banner.getScheduleId())
|
.setGachaScheduleId(banner.getScheduleId())
|
||||||
.setGachaTimes(list.size())
|
.setGachaTimes(list.size())
|
||||||
@ -28,10 +29,15 @@ public class PacketDoGachaRsp extends BasePacket {
|
|||||||
.setCostItemNum(costItem.getCount())
|
.setCostItemNum(costItem.getCount())
|
||||||
.setTenCostItemId(costItem10.getId())
|
.setTenCostItemId(costItem10.getId())
|
||||||
.setTenCostItemNum(costItem10.getCount())
|
.setTenCostItemNum(costItem10.getCount())
|
||||||
.addAllGachaItemList(list)
|
.addAllGachaItemList(list);
|
||||||
.build();
|
|
||||||
|
if(banner.hasEpitomized()) {
|
||||||
|
rsp.setWishItemId(gachaInfo.getWishItemId())
|
||||||
|
.setWishProgress(gachaInfo.getFailedChosenItemPulls())
|
||||||
|
.setWishMaxProgress(banner.getWishMaxProgress());
|
||||||
|
}
|
||||||
|
|
||||||
this.setData(p);
|
this.setData(rsp.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketDoGachaRsp() {
|
public PacketDoGachaRsp() {
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.GachaWishRspOuterClass.GachaWishRsp;
|
||||||
|
|
||||||
|
public class PacketGachaWishRsp extends BasePacket {
|
||||||
|
|
||||||
|
public PacketGachaWishRsp(int gachaType, int scheduleId, int itemId, int progress, int maxProgress) {
|
||||||
|
super(PacketOpcodes.GachaWishRsp);
|
||||||
|
|
||||||
|
GachaWishRsp proto = GachaWishRsp.newBuilder()
|
||||||
|
.setGachaType(gachaType)
|
||||||
|
.setGachaScheduleId(scheduleId)
|
||||||
|
.setWishItemId(itemId)
|
||||||
|
.setWishProgress(progress)
|
||||||
|
.setWishMaxProgress(maxProgress)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user