mirror of
https://github.com/Melledy/Nebula.git
synced 2026-09-19 17:19:58 +02:00
* Fix some grammar warning * Reimplement gacha * Update GachaResult#toSpinResp declaration --------- Co-authored-by: Yostarcc <lubenwei7758258@gmail.com>
195 lines
6.5 KiB
Java
195 lines
6.5 KiB
Java
package emu.nebula.game.gacha;
|
|
|
|
import emu.nebula.data.GameData;
|
|
import emu.nebula.game.inventory.ItemAcquireMap;
|
|
import emu.nebula.game.inventory.ItemParamMap;
|
|
import emu.nebula.game.inventory.ItemType;
|
|
import emu.nebula.game.player.Player;
|
|
import emu.nebula.game.player.PlayerChangeInfo;
|
|
import emu.nebula.proto.Public.Transform;
|
|
import it.unimi.dsi.fastutil.ints.IntList;
|
|
|
|
import java.util.function.IntPredicate;
|
|
|
|
public final class GachaRewardResolver {
|
|
private static final int MAX_DISC_COUNT = 6;
|
|
private static final int ITEM_ID_TRAVEL_PERMIT = 23;
|
|
private static final int ITEM_ID_EXPERT_PERMIT = 24;
|
|
private static final int EXPERT_PERMIT_PER_DUP_CHAR = 40;
|
|
private static final int TRAVEL_PERMIT_PER_DISC = 100;
|
|
|
|
private GachaRewardResolver() {
|
|
}
|
|
|
|
public static boolean isResolvable(IntList cards) {
|
|
if (cards == null || cards.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
return isResolvable(consumer -> {
|
|
for (int id : cards) {
|
|
if (!consumer.test(id)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public static boolean isResolvable(int[] cards) {
|
|
if (cards == null || cards.length == 0) {
|
|
return false;
|
|
}
|
|
|
|
return isResolvable(consumer -> {
|
|
for (int id : cards) {
|
|
if (!consumer.test(id)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
private static boolean isResolvable(IntPredicateRunner runner) {
|
|
return runner.run(GachaRewardResolver::isResolvableItem);
|
|
}
|
|
|
|
private static boolean isResolvableItem(int itemId) {
|
|
var itemData = GameData.getItemDataTable().get(itemId);
|
|
if (itemData == null) {
|
|
return false;
|
|
}
|
|
|
|
if (itemData.getItemType() == ItemType.Char) {
|
|
var characterData = GameData.getCharacterDataTable().get(itemId);
|
|
return characterData != null;
|
|
}
|
|
|
|
if (itemData.getItemType() == ItemType.Disc) {
|
|
var discData = GameData.getDiscDataTable().get(itemId);
|
|
return discData != null;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static RewardPlan resolve(ItemAcquireMap acquireItems, ItemParamMap baseBonusItems) {
|
|
if (acquireItems == null) {
|
|
return null;
|
|
}
|
|
|
|
var grantItems = new ItemParamMap();
|
|
if (baseBonusItems != null) {
|
|
grantItems.add(baseBonusItems);
|
|
}
|
|
|
|
var transformSrcItems = new ItemParamMap();
|
|
var transformDstItems = new ItemParamMap();
|
|
|
|
int characters = 0;
|
|
|
|
for (var entry : acquireItems.getItems().int2ObjectEntrySet()) {
|
|
int id = entry.getIntKey();
|
|
var acquire = entry.getValue();
|
|
|
|
if (acquire.getType() == ItemType.Char) {
|
|
int count = acquire.getCount();
|
|
int newCharacterCount = acquire.getBegin() == 0 ? 1 : 0;
|
|
int duplicateCount = Math.max(count - newCharacterCount, 0);
|
|
|
|
if (duplicateCount > 0) {
|
|
var characterData = GameData.getCharacterDataTable().get(id);
|
|
if (characterData == null) {
|
|
continue;
|
|
}
|
|
|
|
transformSrcItems.add(id, duplicateCount);
|
|
transformDstItems.add(characterData.getFragmentsId(), characterData.getTransformQty() * duplicateCount);
|
|
transformDstItems.add(ITEM_ID_EXPERT_PERMIT, EXPERT_PERMIT_PER_DUP_CHAR * duplicateCount);
|
|
}
|
|
|
|
if (newCharacterCount > 0) {
|
|
grantItems.add(id, newCharacterCount);
|
|
}
|
|
characters += acquire.getCount();
|
|
} else if (acquire.getType() == ItemType.Disc) {
|
|
int begin = acquire.getBegin();
|
|
int count = acquire.getCount();
|
|
|
|
int newDiscCount = begin == 0 ? 1 : 0;
|
|
int duplicateCount = Math.max(count - newDiscCount, 0);
|
|
int effectiveBegin = begin + newDiscCount;
|
|
|
|
int maxTransformCount = Math.max(MAX_DISC_COUNT - effectiveBegin, 0);
|
|
int transformCount = Math.min(duplicateCount, maxTransformCount);
|
|
int extraCount = Math.max(duplicateCount - transformCount, 0);
|
|
|
|
if (transformCount > 0) {
|
|
var discData = GameData.getDiscDataTable().get(id);
|
|
if (discData == null) {
|
|
continue;
|
|
}
|
|
|
|
transformSrcItems.add(id, transformCount);
|
|
transformDstItems.add(discData.getTransformItemId(), transformCount);
|
|
}
|
|
if (extraCount > 0) {
|
|
transformSrcItems.add(id, extraCount);
|
|
transformDstItems.add(ITEM_ID_TRAVEL_PERMIT, TRAVEL_PERMIT_PER_DISC * extraCount);
|
|
}
|
|
|
|
if (newDiscCount > 0) {
|
|
grantItems.add(id, newDiscCount);
|
|
}
|
|
grantItems.add(ITEM_ID_TRAVEL_PERMIT, TRAVEL_PERMIT_PER_DISC * acquire.getCount());
|
|
} else {
|
|
grantItems.add(id, acquire.getCount());
|
|
}
|
|
}
|
|
|
|
grantItems.add(transformDstItems);
|
|
return new RewardPlan(
|
|
acquireItems,
|
|
grantItems,
|
|
new TransformLog(transformSrcItems, transformDstItems),
|
|
characters
|
|
);
|
|
}
|
|
|
|
public static int apply(Player player, RewardPlan plan, PlayerChangeInfo change) {
|
|
if (player == null || plan == null || change == null) {
|
|
return 0;
|
|
}
|
|
|
|
player.getInventory().addItems(plan.grantItems(), change);
|
|
change.add(plan.acquireItems().toProto());
|
|
|
|
var transform = Transform.newInstance();
|
|
plan.transformLog().srcItems().toItemTemplateStream().forEach(transform::addSrc);
|
|
plan.transformLog().dstItems().toItemTemplateStream().forEach(transform::addDst);
|
|
change.add(transform);
|
|
|
|
return plan.characterCount();
|
|
}
|
|
|
|
@FunctionalInterface
|
|
private interface IntPredicateRunner {
|
|
boolean run(IntPredicate predicate);
|
|
}
|
|
|
|
public record RewardPlan(
|
|
ItemAcquireMap acquireItems,
|
|
ItemParamMap grantItems,
|
|
TransformLog transformLog,
|
|
int characterCount
|
|
) {
|
|
}
|
|
|
|
public record TransformLog(
|
|
ItemParamMap srcItems,
|
|
ItemParamMap dstItems
|
|
) {
|
|
}
|
|
}
|