mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-02-09 06:18:20 +08:00
Blossom Implement (#1606)
* Blossom! * rename * delete SpawnBlossomEntry.java * use MAP * use List * use LIST * use List * useCondensedResin * useCondensedResin * fix build * enhance * fix bug * REMOVE BOSS * fix condensed resin * fix condensed resin * use POSITIVE_INFINITY * use RewardPreviewData * fix build * fix resources * add BLOSSOM_MONSTER_FIGHTING_VOLUME * edit monster score * edit monster score * fix bug * fix bug * improve logic * fix monsters level * Deleted comment blocks * nitpick * Fix compilation problems * nitpick * Refactor + nitpick * Clean up overall diff to develop * Clean up other usage of condensed resin * Clean up overall diff to develop * Lombokify Scene.java * Missed an odd getter name * Unhardcode reward previews * EDIT NAME * remove leyline 1 * remove leyline 2 * Update BlossomManager.java Co-authored-by: AnimeGitB <AnimeGitB@bigblueball.in>
This commit is contained in:
parent
957296fa2d
commit
abd1e7569e
@ -113,6 +113,7 @@ public class GameData {
|
|||||||
@Getter private static final Int2ObjectMap<TriggerExcelConfigData> triggerExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
|
@Getter private static final Int2ObjectMap<TriggerExcelConfigData> triggerExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
@Getter private static final Map<String,ScriptSceneData> scriptSceneDataMap = new HashMap<>();
|
@Getter private static final Map<String,ScriptSceneData> scriptSceneDataMap = new HashMap<>();
|
||||||
@Getter private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>();
|
@Getter private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>();
|
||||||
|
@Getter private static final Int2ObjectMap<BlossomRefreshExcelConfigData> blossomRefreshExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter private static final Int2ObjectMap<OpenStateData> openStateDataMap = new Int2ObjectOpenHashMap<>();
|
@Getter private static final Int2ObjectMap<OpenStateData> openStateDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@ -124,7 +125,7 @@ public class GameData {
|
|||||||
|
|
||||||
|
|
||||||
@Getter private static final List<OpenStateData> openStateList = new ArrayList<>();
|
@Getter private static final List<OpenStateData> openStateList = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
public static Int2ObjectMap<?> getMapByResourceDef(Class<?> resourceDefinition) {
|
public static Int2ObjectMap<?> getMapByResourceDef(Class<?> resourceDefinition) {
|
||||||
Int2ObjectMap<?> map = null;
|
Int2ObjectMap<?> map = null;
|
||||||
|
@ -10,10 +10,13 @@ import emu.grasscutter.Grasscutter;
|
|||||||
import emu.grasscutter.data.ResourceLoader.AvatarConfig;
|
import emu.grasscutter.data.ResourceLoader.AvatarConfig;
|
||||||
import emu.grasscutter.data.excels.ReliquaryAffixData;
|
import emu.grasscutter.data.excels.ReliquaryAffixData;
|
||||||
import emu.grasscutter.data.excels.ReliquaryMainPropData;
|
import emu.grasscutter.data.excels.ReliquaryMainPropData;
|
||||||
|
import emu.grasscutter.game.managers.blossom.BlossomConfig;
|
||||||
import emu.grasscutter.game.world.SpawnDataEntry;
|
import emu.grasscutter.game.world.SpawnDataEntry;
|
||||||
import emu.grasscutter.utils.WeightedList;
|
import emu.grasscutter.utils.WeightedList;
|
||||||
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;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
public class GameDepot {
|
public class GameDepot {
|
||||||
public static final int[] BLOCK_SIZE = new int[]{50,500};//Scales
|
public static final int[] BLOCK_SIZE = new int[]{50,500};//Scales
|
||||||
@ -22,8 +25,9 @@ public class GameDepot {
|
|||||||
private static Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>();
|
private static Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>();
|
||||||
private static Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>();
|
private static Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
private static Map<String, AvatarConfig> playerAbilities = new HashMap<>();
|
@Getter @Setter private static Map<String, AvatarConfig> playerAbilities = new HashMap<>();
|
||||||
private static HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists = new HashMap<>();
|
@Getter private static HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists = new HashMap<>();
|
||||||
|
@Getter @Setter private static BlossomConfig blossomConfig;
|
||||||
|
|
||||||
public static void load() {
|
public static void load() {
|
||||||
for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) {
|
for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) {
|
||||||
@ -64,19 +68,7 @@ public class GameDepot {
|
|||||||
return relicAffixDepot.get(depot);
|
return relicAffixDepot.get(depot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> getSpawnLists() {
|
|
||||||
return spawnLists;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSpawnListById(HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> data) {
|
public static void addSpawnListById(HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> data) {
|
||||||
spawnLists.putAll(data);
|
spawnLists.putAll(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setPlayerAbilities(Map<String, AvatarConfig> playerAbilities) {
|
|
||||||
GameDepot.playerAbilities = playerAbilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, AvatarConfig> getPlayerAbilities() {
|
|
||||||
return playerAbilities;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
|
|||||||
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierActionType;
|
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierActionType;
|
||||||
import emu.grasscutter.data.common.PointData;
|
import emu.grasscutter.data.common.PointData;
|
||||||
import emu.grasscutter.data.common.ScenePointConfig;
|
import emu.grasscutter.data.common.ScenePointConfig;
|
||||||
|
import emu.grasscutter.game.managers.blossom.BlossomConfig;
|
||||||
import emu.grasscutter.game.quest.QuestEncryptionKey;
|
import emu.grasscutter.game.quest.QuestEncryptionKey;
|
||||||
import emu.grasscutter.game.world.SpawnDataEntry;
|
import emu.grasscutter.game.world.SpawnDataEntry;
|
||||||
import emu.grasscutter.game.world.SpawnDataEntry.GridBlockId;
|
import emu.grasscutter.game.world.SpawnDataEntry.GridBlockId;
|
||||||
@ -75,6 +76,7 @@ public class ResourceLoader {
|
|||||||
// Load default home layout
|
// Load default home layout
|
||||||
loadHomeworldDefaultSaveData();
|
loadHomeworldDefaultSaveData();
|
||||||
loadNpcBornData();
|
loadNpcBornData();
|
||||||
|
loadBlossomResources();
|
||||||
|
|
||||||
Grasscutter.getLogger().info(translate("messages.status.resources.finish"));
|
Grasscutter.getLogger().info(translate("messages.status.resources.finish"));
|
||||||
loadedAll = true;
|
loadedAll = true;
|
||||||
@ -486,6 +488,12 @@ public class ResourceLoader {
|
|||||||
Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas.");
|
Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private static void loadBlossomResources() {
|
||||||
|
GameDepot.setBlossomConfig(DataLoader.loadClass("BlossomConfig.json", BlossomConfig.class));
|
||||||
|
Grasscutter.getLogger().debug("Loaded BlossomConfig.");
|
||||||
|
}
|
||||||
|
|
||||||
// BinOutput configs
|
// BinOutput configs
|
||||||
|
|
||||||
public static class AvatarConfig {
|
public static class AvatarConfig {
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
package emu.grasscutter.data.excels;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.grasscutter.data.GameResource;
|
||||||
|
import emu.grasscutter.data.ResourceType;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@ResourceType(name = "BlossomRefreshExcelConfigData.json")
|
||||||
|
public class BlossomRefreshExcelConfigData extends GameResource {
|
||||||
|
private int id;
|
||||||
|
// Map details
|
||||||
|
@Getter private long nameTextMapHash;
|
||||||
|
@Getter private long descTextMapHash;
|
||||||
|
@Getter private String icon;
|
||||||
|
@Getter private String clientShowType; // BLOSSOM_SHOWTYPE_CHALLENGE, BLOSSOM_SHOWTYPE_NPCTALK
|
||||||
|
|
||||||
|
// Refresh details
|
||||||
|
@Getter private String refreshType; // Leyline blossoms, magical ore outcrops
|
||||||
|
@Getter private int refreshCount; // Number of entries to spawn at refresh (1 for each leyline type for each city, 4 for magical ore for each city)
|
||||||
|
@Getter private String refreshTime; // Server time-of-day to refresh at
|
||||||
|
@Getter private RefreshCond[] refreshCondVec; // AR requirements etc.
|
||||||
|
|
||||||
|
@Getter private int cityId;
|
||||||
|
@Getter private int blossomChestId; // 1 for mora, 2 for exp
|
||||||
|
@Getter private Drop[] dropVec;
|
||||||
|
|
||||||
|
// Unknown details
|
||||||
|
// @Getter private int reviseLevel;
|
||||||
|
// @Getter private int campUpdateNeedCount; // Always 1 if specified
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Drop {
|
||||||
|
@Getter int dropId;
|
||||||
|
@Getter int previewReward;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RefreshCond {
|
||||||
|
@Getter String type;
|
||||||
|
@Getter List<Integer> param;
|
||||||
|
}
|
||||||
|
}
|
@ -8,12 +8,12 @@ import emu.grasscutter.game.dungeons.DungeonDrop;
|
|||||||
import emu.grasscutter.game.dungeons.DungeonDropEntry;
|
import emu.grasscutter.game.dungeons.DungeonDropEntry;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.inventory.ItemType;
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.ActionReason;
|
import emu.grasscutter.game.props.ActionReason;
|
||||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||||
|
import emu.grasscutter.net.proto.ResinCostTypeOuterClass;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
@ -88,11 +88,12 @@ public class DungeonChallenge extends WorldChallenge {
|
|||||||
|
|
||||||
private void settle() {
|
private void settle() {
|
||||||
if (!stage) {
|
if (!stage) {
|
||||||
getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
|
var scene = this.getScene();
|
||||||
getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE,
|
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(getScene()));
|
||||||
|
scene.getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE,
|
||||||
new ScriptArgs(this.isSuccess() ? 1 : 0));
|
new ScriptArgs(this.isSuccess() ? 1 : 0));
|
||||||
// Battle pass trigger
|
// Battle pass trigger
|
||||||
this.getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON));
|
scene.getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +167,7 @@ public class DungeonChallenge extends WorldChallenge {
|
|||||||
// Get rewards.
|
// Get rewards.
|
||||||
List<GameItem> rewards = new ArrayList<>();
|
List<GameItem> rewards = new ArrayList<>();
|
||||||
|
|
||||||
if (request.getIsUseCondenseResin()) {
|
if (request.getResinCostType() == ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE) {
|
||||||
// Check if condensed resin is usable here.
|
// Check if condensed resin is usable here.
|
||||||
// For this, we use the following logic for now:
|
// For this, we use the following logic for now:
|
||||||
// The normal resin cost of the dungeon has to be 20.
|
// The normal resin cost of the dungeon has to be 20.
|
||||||
@ -174,25 +175,15 @@ public class DungeonChallenge extends WorldChallenge {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the player has condensed resin.
|
// Spend the condensed resin and only proceed if the transaction succeeds.
|
||||||
GameItem condensedResin = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(220007);
|
if (!player.getResinManager().useCondensedResin(1)) return;
|
||||||
if (condensedResin == null || condensedResin.getCount() <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deduct.
|
|
||||||
player.getInventory().removeItem(condensedResin, 1);
|
|
||||||
|
|
||||||
// Roll rewards.
|
// Roll rewards.
|
||||||
rewards.addAll(this.rollRewards(true));
|
rewards.addAll(this.rollRewards(true));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If the player used regular resin, try to deduct.
|
// Spend the resin and only proceed if the transaction succeeds.
|
||||||
// Stop if insufficient resin.
|
if (!player.getResinManager().useResin(resinCost)) return;
|
||||||
boolean success = player.getResinManager().useResin(resinCost);
|
|
||||||
if (!success) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Roll rewards.
|
// Roll rewards.
|
||||||
rewards.addAll(this.rollRewards(false));
|
rewards.addAll(this.rollRewards(false));
|
||||||
|
@ -215,12 +215,15 @@ public abstract class GameEntity {
|
|||||||
|
|
||||||
// Invoke entity damage event.
|
// Invoke entity damage event.
|
||||||
EntityDamageEvent event = new EntityDamageEvent(this, amount, this.getScene().getEntityById(killerId));
|
EntityDamageEvent event = new EntityDamageEvent(this, amount, this.getScene().getEntityById(killerId));
|
||||||
event.call(); if (event.isCanceled()) {
|
event.call();
|
||||||
|
if (event.isCanceled()) {
|
||||||
return; // If the event is canceled, do not damage the entity.
|
return; // If the event is canceled, do not damage the entity.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add negative HP to the current HP property.
|
if(getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) != Float.POSITIVE_INFINITY){
|
||||||
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -(event.getDamage()));
|
// Add negative HP to the current HP property.
|
||||||
|
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -(event.getDamage()));
|
||||||
|
}
|
||||||
|
|
||||||
// Check if dead
|
// Check if dead
|
||||||
boolean isDead = false;
|
boolean isDead = false;
|
||||||
|
@ -2,6 +2,7 @@ package emu.grasscutter.game.entity.gadget;
|
|||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
|
import emu.grasscutter.game.entity.gadget.chest.BossChestInteractHandler;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.LifeState;
|
import emu.grasscutter.game.props.LifeState;
|
||||||
import emu.grasscutter.net.proto.BossChestInfoOuterClass.BossChestInfo;
|
import emu.grasscutter.net.proto.BossChestInfoOuterClass.BossChestInfo;
|
||||||
@ -9,6 +10,7 @@ import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
|||||||
import emu.grasscutter.net.proto.InterOpTypeOuterClass.InterOpType;
|
import emu.grasscutter.net.proto.InterOpTypeOuterClass.InterOpType;
|
||||||
import emu.grasscutter.net.proto.InteractTypeOuterClass;
|
import emu.grasscutter.net.proto.InteractTypeOuterClass;
|
||||||
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||||
|
import emu.grasscutter.net.proto.ResinCostTypeOuterClass;
|
||||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||||
import emu.grasscutter.scripts.constants.ScriptGadgetState;
|
import emu.grasscutter.scripts.constants.ScriptGadgetState;
|
||||||
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
||||||
@ -32,7 +34,13 @@ public class GadgetChest extends GadgetContent {
|
|||||||
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START));
|
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START));
|
||||||
return false;
|
return false;
|
||||||
}else {
|
}else {
|
||||||
var success = handler.onInteract(this, player);
|
boolean success;
|
||||||
|
if(handler instanceof BossChestInteractHandler bossChestInteractHandler){
|
||||||
|
success = bossChestInteractHandler.onInteract(this, player,
|
||||||
|
req.getResinCostType()== ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE);
|
||||||
|
}else{
|
||||||
|
success = handler.onInteract(this, player);
|
||||||
|
}
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3,31 +3,34 @@ package emu.grasscutter.game.entity.gadget;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
|
import emu.grasscutter.game.entity.gadget.worktop.WorktopWorktopOptionHandler;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||||
|
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq;
|
||||||
import emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo;
|
import emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
|
|
||||||
public class GadgetWorktop extends GadgetContent {
|
public class GadgetWorktop extends GadgetContent {
|
||||||
private IntSet worktopOptions;
|
private IntSet worktopOptions;
|
||||||
|
private WorktopWorktopOptionHandler handler;
|
||||||
|
|
||||||
public GadgetWorktop(EntityGadget gadget) {
|
public GadgetWorktop(EntityGadget gadget) {
|
||||||
super(gadget);
|
super(gadget);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntSet getWorktopOptions() {
|
public IntSet getWorktopOptions() {
|
||||||
return worktopOptions;
|
return worktopOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addWorktopOptions(int[] options) {
|
public void addWorktopOptions(int[] options) {
|
||||||
if (this.worktopOptions == null) {
|
if (this.worktopOptions == null) {
|
||||||
this.worktopOptions = new IntOpenHashSet();
|
this.worktopOptions = new IntOpenHashSet();
|
||||||
}
|
}
|
||||||
Arrays.stream(options).forEach(this.worktopOptions::add);
|
Arrays.stream(options).forEach(this.worktopOptions::add);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeWorktopOption(int option) {
|
public void removeWorktopOption(int option) {
|
||||||
if (this.worktopOptions == null) {
|
if (this.worktopOptions == null) {
|
||||||
return;
|
return;
|
||||||
@ -43,11 +46,20 @@ public class GadgetWorktop extends GadgetContent {
|
|||||||
if (this.worktopOptions == null) {
|
if (this.worktopOptions == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WorktopInfo worktop = WorktopInfo.newBuilder()
|
WorktopInfo worktop = WorktopInfo.newBuilder()
|
||||||
.addAllOptionList(this.getWorktopOptions())
|
.addAllOptionList(this.getWorktopOptions())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
gadgetInfo.setWorktop(worktop);
|
gadgetInfo.setWorktop(worktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOnSelectWorktopOptionEvent(WorktopWorktopOptionHandler handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
public boolean onSelectWorktopOption(SelectWorktopOptionReq req) {
|
||||||
|
this.handler.onSelectWorktopOption(this,req.getOptionId());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,17 @@ public class BossChestInteractHandler implements ChestInteractHandler{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onInteract(GadgetChest chest, Player player) {
|
public boolean onInteract(GadgetChest chest, Player player) {
|
||||||
|
return this.onInteract(chest,player,false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onInteract(GadgetChest chest, Player player,boolean useCondensedResin) {
|
||||||
|
var blossomRewards = player.getScene().getBlossomManager().onReward(player,chest.getGadget(),useCondensedResin);
|
||||||
|
if(blossomRewards!=null) {
|
||||||
|
player.getInventory().addItems(blossomRewards, ActionReason.OpenWorldBossChest);
|
||||||
|
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(blossomRewards));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
var worldDataManager = chest.getGadget().getScene().getWorld().getServer().getWorldDataSystem();
|
var worldDataManager = chest.getGadget().getScene().getWorld().getServer().getWorldDataSystem();
|
||||||
var monster = chest.getGadget().getMetaGadget().group.monsters.get(chest.getGadget().getMetaGadget().boss_chest.monster_config_id);
|
var monster = chest.getGadget().getMetaGadget().group.monsters.get(chest.getGadget().getMetaGadget().boss_chest.monster_config_id);
|
||||||
var reward = worldDataManager.getRewardByBossId(monster.monster_id);
|
var reward = worldDataManager.getRewardByBossId(monster.monster_id);
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
package emu.grasscutter.game.entity.gadget.worktop;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
||||||
|
public interface WorktopWorktopOptionHandler {
|
||||||
|
boolean onSelectWorktopOption(GadgetWorktop gadgetWorktop,int option);
|
||||||
|
}
|
@ -52,6 +52,12 @@ public class ResinManager extends BasePlayerManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized boolean useCondensedResin(int amount) {
|
||||||
|
// Don't deduct if resin disabled.
|
||||||
|
if (!GAME_OPTIONS.resinOptions.resinUsage) return true;
|
||||||
|
return this.player.getInventory().payItem(220007, amount);
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void addResin(int amount) {
|
public synchronized void addResin(int amount) {
|
||||||
// Check if resin enabled.
|
// Check if resin enabled.
|
||||||
if (!GAME_OPTIONS.resinOptions.resinUsage) {
|
if (!GAME_OPTIONS.resinOptions.resinUsage) {
|
||||||
|
@ -0,0 +1,135 @@
|
|||||||
|
package emu.grasscutter.game.managers.blossom;
|
||||||
|
|
||||||
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.excels.MonsterData;
|
||||||
|
import emu.grasscutter.data.excels.WorldLevelData;
|
||||||
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
|
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
||||||
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
|
||||||
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
|
import emu.grasscutter.game.world.Scene;
|
||||||
|
import emu.grasscutter.scripts.data.SceneBossChest;
|
||||||
|
import emu.grasscutter.scripts.data.SceneGadget;
|
||||||
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
import emu.grasscutter.utils.Position;
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
public class BlossomActivity {
|
||||||
|
|
||||||
|
private final SceneGroup tempSceneGroup;
|
||||||
|
private final WorldChallenge challenge;
|
||||||
|
private final EntityGadget gadget;
|
||||||
|
private EntityGadget chest;
|
||||||
|
private int step;
|
||||||
|
private final int goal;
|
||||||
|
private int generatedCount;
|
||||||
|
private final int worldLevel;
|
||||||
|
private boolean pass=false;
|
||||||
|
private final List<EntityMonster> activeMonsters = new ArrayList<>();
|
||||||
|
private final Queue<Integer> candidateMonsters = new ArrayDeque<>();
|
||||||
|
private static final int BLOOMING_GADGET_ID = 70210109;
|
||||||
|
public BlossomActivity(EntityGadget entityGadget, List<Integer> monsters, int timeout, int worldLevel) {
|
||||||
|
this.tempSceneGroup = new SceneGroup();
|
||||||
|
this.tempSceneGroup.id = entityGadget.getId();
|
||||||
|
this.gadget=entityGadget;
|
||||||
|
this.step=0;
|
||||||
|
this.goal = monsters.size();
|
||||||
|
this.candidateMonsters.addAll(monsters);
|
||||||
|
this.worldLevel = worldLevel;
|
||||||
|
ArrayList<ChallengeTrigger> challengeTriggers = new ArrayList<>();
|
||||||
|
this.challenge = new WorldChallenge(entityGadget.getScene(),
|
||||||
|
tempSceneGroup,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
List.of(goal, timeout),
|
||||||
|
timeout,
|
||||||
|
goal, challengeTriggers);
|
||||||
|
challengeTriggers.add(new KillMonsterTrigger());
|
||||||
|
//this.challengeTriggers.add(new InTimeTrigger());
|
||||||
|
}
|
||||||
|
public WorldChallenge getChallenge(){
|
||||||
|
return this.challenge;
|
||||||
|
}
|
||||||
|
public void setMonsters(List<EntityMonster> monsters) {
|
||||||
|
this.activeMonsters.clear();
|
||||||
|
this.activeMonsters.addAll(monsters);
|
||||||
|
for(EntityMonster monster : monsters){
|
||||||
|
monster.setGroupId(this.tempSceneGroup.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int getAliveMonstersCount(){
|
||||||
|
int count=0;
|
||||||
|
for(EntityMonster monster: activeMonsters) {
|
||||||
|
if(monster.isAlive()){
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
public boolean getPass(){
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
public void start(){
|
||||||
|
challenge.start();
|
||||||
|
}
|
||||||
|
public void onTick() {
|
||||||
|
Scene scene = gadget.getScene();
|
||||||
|
Position pos = gadget.getPosition();
|
||||||
|
if(getAliveMonstersCount() <= 2){
|
||||||
|
if(generatedCount<goal){
|
||||||
|
step++;
|
||||||
|
|
||||||
|
WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(worldLevel);
|
||||||
|
int worldLevelOverride = 0;
|
||||||
|
if (worldLevelData != null) {
|
||||||
|
worldLevelOverride = worldLevelData.getMonsterLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<EntityMonster> newMonsters = new ArrayList<>();
|
||||||
|
int willSpawn = Utils.randomRange(3,5);
|
||||||
|
if(generatedCount+willSpawn>goal){
|
||||||
|
willSpawn = goal - generatedCount;
|
||||||
|
}
|
||||||
|
generatedCount+=willSpawn;
|
||||||
|
for (int i = 0; i < willSpawn; i++) {
|
||||||
|
MonsterData monsterData = GameData.getMonsterDataMap().get(candidateMonsters.poll());
|
||||||
|
int level = scene.getEntityLevel(1, worldLevelOverride);
|
||||||
|
EntityMonster entity = new EntityMonster(scene, monsterData, pos.nearby2d(40), level);
|
||||||
|
scene.addEntity(entity);
|
||||||
|
newMonsters.add(entity);
|
||||||
|
}
|
||||||
|
setMonsters(newMonsters);
|
||||||
|
}else{
|
||||||
|
if(getAliveMonstersCount() == 0) {
|
||||||
|
this.pass = true;
|
||||||
|
this.challenge.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public EntityGadget getGadget(){
|
||||||
|
return gadget;
|
||||||
|
}
|
||||||
|
public EntityGadget getChest(){
|
||||||
|
if(chest==null) {
|
||||||
|
EntityGadget rewardGadget = new EntityGadget(gadget.getScene(), BLOOMING_GADGET_ID, gadget.getPosition());
|
||||||
|
SceneGadget metaGadget = new SceneGadget();
|
||||||
|
metaGadget.boss_chest = new SceneBossChest();
|
||||||
|
metaGadget.boss_chest.resin = 20;
|
||||||
|
rewardGadget.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, Float.POSITIVE_INFINITY);
|
||||||
|
rewardGadget.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, Float.POSITIVE_INFINITY);
|
||||||
|
rewardGadget.setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, Float.POSITIVE_INFINITY);
|
||||||
|
rewardGadget.setMetaGadget(metaGadget);
|
||||||
|
rewardGadget.buildContent();
|
||||||
|
chest = rewardGadget;
|
||||||
|
}
|
||||||
|
return chest;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package emu.grasscutter.game.managers.blossom;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class BlossomConfig {
|
||||||
|
@Getter private int monsterFightingVolume;
|
||||||
|
// @Getter private Int2ObjectMap<IntList> monsterIdsPerDifficulty; // Need to wrangle Gson for this
|
||||||
|
@Getter private Map<Integer, List<Integer>> monsterIdsPerDifficulty;
|
||||||
|
}
|
@ -0,0 +1,237 @@
|
|||||||
|
package emu.grasscutter.game.managers.blossom;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.grasscutter.Grasscutter;
|
||||||
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.GameDepot;
|
||||||
|
import emu.grasscutter.data.common.ItemParamData;
|
||||||
|
import emu.grasscutter.data.excels.RewardPreviewData;
|
||||||
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
|
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
||||||
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
|
import emu.grasscutter.game.world.Scene;
|
||||||
|
import emu.grasscutter.game.world.SpawnDataEntry;
|
||||||
|
import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
|
||||||
|
import emu.grasscutter.net.proto.BlossomBriefInfoOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.VisionTypeOuterClass;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketBlossomBriefInfoNotify;
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
|
||||||
|
public class BlossomManager {
|
||||||
|
public BlossomManager(Scene scene) {
|
||||||
|
this.scene = scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Scene scene;
|
||||||
|
private final List<BlossomActivity> blossomActivities = new ArrayList<>();
|
||||||
|
private final List<BlossomActivity> activeChests = new ArrayList<>();
|
||||||
|
private final List<EntityGadget> createdEntity = new ArrayList<>();
|
||||||
|
|
||||||
|
private final List<SpawnDataEntry> blossomConsumed = new ArrayList<>();
|
||||||
|
|
||||||
|
public void onTick(){
|
||||||
|
synchronized (blossomActivities){
|
||||||
|
var it = blossomActivities.iterator();
|
||||||
|
while(it.hasNext()){
|
||||||
|
var active = it.next();
|
||||||
|
active.onTick();
|
||||||
|
if (active.getPass()) {
|
||||||
|
EntityGadget chest = active.getChest();
|
||||||
|
scene.addEntity(chest);
|
||||||
|
scene.setChallenge(null);
|
||||||
|
activeChests.add(active);
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recycleGadgetEntity(List<GameEntity> entities){
|
||||||
|
for(var entity : entities){
|
||||||
|
if(entity instanceof EntityGadget gadget){
|
||||||
|
createdEntity.remove(gadget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifyIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initBlossom(EntityGadget gadget){
|
||||||
|
if(createdEntity.contains(gadget)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(blossomConsumed.contains(gadget.getSpawnEntry())){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var id = gadget.getGadgetId();
|
||||||
|
if(BlossomType.valueOf(id)==null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gadget.buildContent();
|
||||||
|
gadget.setState(204);
|
||||||
|
int worldLevel = getWorldLevel();
|
||||||
|
GadgetWorktop gadgetWorktop = ((GadgetWorktop) gadget.getContent());
|
||||||
|
gadgetWorktop.addWorktopOptions(new int[]{187});
|
||||||
|
gadgetWorktop.setOnSelectWorktopOptionEvent((GadgetWorktop context, int option) -> {
|
||||||
|
BlossomActivity activity;
|
||||||
|
EntityGadget entityGadget = context.getGadget();
|
||||||
|
synchronized (blossomActivities) {
|
||||||
|
for (BlossomActivity i : this.blossomActivities) {
|
||||||
|
if (i.getGadget() == entityGadget) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int volume=0;
|
||||||
|
IntList monsters = new IntArrayList();
|
||||||
|
while(true){
|
||||||
|
var remain = GameDepot.getBlossomConfig().getMonsterFightingVolume() - volume;
|
||||||
|
if(remain<=0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var rand = Utils.randomRange(1,100);
|
||||||
|
if(rand>85 && remain>=50){//15% ,generate strong monster
|
||||||
|
monsters.addAll(getRandomMonstersID(2,1));
|
||||||
|
volume+=50;
|
||||||
|
}else if(rand>50 && remain>=20) {//35% ,generate normal monster
|
||||||
|
monsters.addAll(getRandomMonstersID(1,1));
|
||||||
|
volume+=20;
|
||||||
|
}else{//50% ,generate weak monster
|
||||||
|
monsters.addAll(getRandomMonstersID(0,1));
|
||||||
|
volume+=10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Grasscutter.getLogger().info("Blossom Monsters:"+monsters);
|
||||||
|
|
||||||
|
activity = new BlossomActivity(entityGadget, monsters, -1, worldLevel);
|
||||||
|
blossomActivities.add(activity);
|
||||||
|
}
|
||||||
|
entityGadget.updateState(201);
|
||||||
|
scene.setChallenge(activity.getChallenge());
|
||||||
|
scene.removeEntity(entityGadget, VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE);
|
||||||
|
activity.start();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
createdEntity.add(gadget);
|
||||||
|
notifyIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyIcon() {
|
||||||
|
final int wl = getWorldLevel();
|
||||||
|
final int worldLevel = (wl < 0) ? 0 : ((wl > 8) ? 8 : wl);
|
||||||
|
final int monsterLevel = GameData.getWorldLevelDataMap().get(worldLevel).getMonsterLevel();
|
||||||
|
List<BlossomBriefInfoOuterClass.BlossomBriefInfo> blossoms = new ArrayList<>();
|
||||||
|
GameDepot.getSpawnLists().forEach((gridBlockId, spawnDataEntryList) -> {
|
||||||
|
int sceneId = gridBlockId.getSceneId();
|
||||||
|
spawnDataEntryList.stream()
|
||||||
|
.map(SpawnDataEntry::getGroup)
|
||||||
|
.map(SpawnGroupEntry::getSpawns)
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.filter(spawn -> !blossomConsumed.contains(spawn))
|
||||||
|
.filter(spawn -> BlossomType.valueOf(spawn.getGadgetId()) != null)
|
||||||
|
.forEach(spawn -> {
|
||||||
|
var type = BlossomType.valueOf(spawn.getGadgetId());
|
||||||
|
int previewReward = getPreviewReward(type, worldLevel);
|
||||||
|
blossoms.add(BlossomBriefInfoOuterClass.BlossomBriefInfo.newBuilder()
|
||||||
|
.setSceneId(sceneId)
|
||||||
|
.setPos(spawn.getPos().toProto())
|
||||||
|
.setResin(20)
|
||||||
|
.setMonsterLevel(monsterLevel)
|
||||||
|
.setRewardId(previewReward)
|
||||||
|
.setCircleCampId(type.getCircleCampId())
|
||||||
|
.setRefreshId(type.getBlossomChestId()) // TODO: replace when using actual leylines
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
scene.broadcastPacket(new PacketBlossomBriefInfoNotify(blossoms));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldLevel(){
|
||||||
|
return scene.getWorld().getWorldLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Integer getPreviewReward(BlossomType type, int worldLevel) {
|
||||||
|
// TODO: blossoms should be based on their city
|
||||||
|
if (type == null) {
|
||||||
|
Grasscutter.getLogger().error("Illegal blossom type {}",type);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blossomChestId = type.getBlossomChestId();
|
||||||
|
var dataMap = GameData.getBlossomRefreshExcelConfigDataMap();
|
||||||
|
for (var data : dataMap.values()) {
|
||||||
|
if (blossomChestId == data.getBlossomChestId()) {
|
||||||
|
var dropVecList = data.getDropVec();
|
||||||
|
if (worldLevel > dropVecList.length) {
|
||||||
|
Grasscutter.getLogger().error("Illegal world level {}", worldLevel);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return dropVecList[worldLevel].getPreviewReward();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Grasscutter.getLogger().error("Cannot find blossom type {}",type);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RewardPreviewData getRewardList(BlossomType type, int worldLevel) {
|
||||||
|
Integer previewReward = getPreviewReward(type, worldLevel);
|
||||||
|
if (previewReward == null) return null;
|
||||||
|
return GameData.getRewardPreviewDataMap().get((int) previewReward);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GameItem> onReward(Player player, EntityGadget chest, boolean useCondensedResin) {
|
||||||
|
var resinManager = player.getResinManager();
|
||||||
|
synchronized (activeChests) {
|
||||||
|
var it = activeChests.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
var activeChest = it.next();
|
||||||
|
if (activeChest.getChest() == chest) {
|
||||||
|
boolean pay = useCondensedResin ? resinManager.useCondensedResin(1) : resinManager.useResin(20);
|
||||||
|
if (pay) {
|
||||||
|
int worldLevel = getWorldLevel();
|
||||||
|
List<GameItem> items = new ArrayList<>();
|
||||||
|
var gadget = activeChest.getGadget();
|
||||||
|
var type = BlossomType.valueOf(gadget.getGadgetId());
|
||||||
|
RewardPreviewData blossomRewards = getRewardList(type, worldLevel);
|
||||||
|
if (blossomRewards == null) {
|
||||||
|
Grasscutter.getLogger().error("Blossom could not support world level : "+worldLevel);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var rewards = blossomRewards.getPreviewItems();
|
||||||
|
for (ItemParamData blossomReward : rewards) {
|
||||||
|
int rewardCount = blossomReward.getCount();
|
||||||
|
if (useCondensedResin) {
|
||||||
|
rewardCount += blossomReward.getCount(); // Double!
|
||||||
|
}
|
||||||
|
items.add(new GameItem(blossomReward.getItemId(),rewardCount));
|
||||||
|
}
|
||||||
|
it.remove();
|
||||||
|
recycleGadgetEntity(List.of(gadget));
|
||||||
|
blossomConsumed.add(gadget.getSpawnEntry());
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntList getRandomMonstersID(int difficulty,int count){
|
||||||
|
IntList result = new IntArrayList();
|
||||||
|
List<Integer> monsters = GameDepot.getBlossomConfig().getMonsterIdsPerDifficulty().get(difficulty);
|
||||||
|
for(int i=0; i<count; i++){
|
||||||
|
result.add((int) monsters.get(Utils.randomRange(0, monsters.size()-1)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package emu.grasscutter.game.managers.blossom;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public enum BlossomType {
|
||||||
|
GOLD(70360056, 101001001, 1),
|
||||||
|
BLUE(70360057, 101002003, 2);
|
||||||
|
|
||||||
|
@Getter private final int gadgetId;
|
||||||
|
@Getter private final int circleCampId;
|
||||||
|
@Getter private final int blossomChestId;
|
||||||
|
|
||||||
|
BlossomType(int gadgetId, int circleCampId, int blossomChestId) {
|
||||||
|
this.gadgetId = gadgetId;
|
||||||
|
this.circleCampId = circleCampId;
|
||||||
|
this.blossomChestId = blossomChestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Int2ObjectMap<BlossomType> map = new Int2ObjectOpenHashMap<>(
|
||||||
|
Stream.of(values()).collect(Collectors.toMap(x -> x.getGadgetId(), x -> x))
|
||||||
|
);
|
||||||
|
|
||||||
|
public static BlossomType valueOf(int i) {
|
||||||
|
return map.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlossomType random() {
|
||||||
|
BlossomType[] values = values();
|
||||||
|
return values[Utils.randomRange(0, values.length)];
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,8 @@ import emu.grasscutter.data.excels.*;
|
|||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.dungeons.DungeonSettleListener;
|
import emu.grasscutter.game.dungeons.DungeonSettleListener;
|
||||||
import emu.grasscutter.game.entity.*;
|
import emu.grasscutter.game.entity.*;
|
||||||
|
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
||||||
|
import emu.grasscutter.game.managers.blossom.BlossomManager;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.player.TeamInfo;
|
import emu.grasscutter.game.player.TeamInfo;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
@ -17,6 +19,7 @@ import emu.grasscutter.game.quest.QuestGroupSuite;
|
|||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||||
|
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass;
|
||||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||||
import emu.grasscutter.scripts.SceneIndexManager;
|
import emu.grasscutter.scripts.SceneIndexManager;
|
||||||
import emu.grasscutter.scripts.SceneScriptManager;
|
import emu.grasscutter.scripts.SceneScriptManager;
|
||||||
@ -25,6 +28,8 @@ import emu.grasscutter.scripts.data.SceneGadget;
|
|||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -32,25 +37,26 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Scene {
|
public class Scene {
|
||||||
private final World world;
|
@Getter private final World world;
|
||||||
private final SceneData sceneData;
|
@Getter private final SceneData sceneData;
|
||||||
private final List<Player> players;
|
@Getter private final List<Player> players;
|
||||||
private final Map<Integer, GameEntity> entities;
|
@Getter private final Map<Integer, GameEntity> entities;
|
||||||
private final Set<SpawnDataEntry> spawnedEntities;
|
@Getter private final Set<SpawnDataEntry> spawnedEntities;
|
||||||
private final Set<SpawnDataEntry> deadSpawnedEntities;
|
@Getter private final Set<SpawnDataEntry> deadSpawnedEntities;
|
||||||
private final Set<SceneBlock> loadedBlocks;
|
@Getter private final Set<SceneBlock> loadedBlocks;
|
||||||
|
@Getter private final BlossomManager blossomManager;
|
||||||
private Set<SpawnDataEntry.GridBlockId> loadedGridBlocks;
|
private Set<SpawnDataEntry.GridBlockId> loadedGridBlocks;
|
||||||
private boolean dontDestroyWhenEmpty;
|
@Getter @Setter private boolean dontDestroyWhenEmpty;
|
||||||
|
|
||||||
private int autoCloseTime;
|
@Getter @Setter private int autoCloseTime;
|
||||||
private int time;
|
@Getter private int time;
|
||||||
|
|
||||||
private SceneScriptManager scriptManager;
|
@Getter private SceneScriptManager scriptManager;
|
||||||
private WorldChallenge challenge;
|
@Getter @Setter private WorldChallenge challenge;
|
||||||
private List<DungeonSettleListener> dungeonSettleListeners;
|
@Getter private List<DungeonSettleListener> dungeonSettleListeners;
|
||||||
private DungeonData dungeonData;
|
@Getter private DungeonData dungeonData;
|
||||||
private int prevScene; // Id of the previous scene
|
@Getter @Setter private int prevScene; // Id of the previous scene
|
||||||
private int prevScenePoint;
|
@Getter @Setter private int prevScenePoint;
|
||||||
private Set<SceneNpcBornEntry> npcBornEntrySet;
|
private Set<SceneNpcBornEntry> npcBornEntrySet;
|
||||||
public Scene(World world, SceneData sceneData) {
|
public Scene(World world, SceneData sceneData) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
@ -67,36 +73,21 @@ public class Scene {
|
|||||||
this.loadedGridBlocks = new HashSet<>();
|
this.loadedGridBlocks = new HashSet<>();
|
||||||
this.npcBornEntrySet = ConcurrentHashMap.newKeySet();
|
this.npcBornEntrySet = ConcurrentHashMap.newKeySet();
|
||||||
this.scriptManager = new SceneScriptManager(this);
|
this.scriptManager = new SceneScriptManager(this);
|
||||||
|
this.blossomManager = new BlossomManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return sceneData.getId();
|
return sceneData.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public World getWorld() {
|
|
||||||
return world;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SceneData getSceneData() {
|
|
||||||
return this.sceneData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SceneType getSceneType() {
|
public SceneType getSceneType() {
|
||||||
return getSceneData().getSceneType();
|
return getSceneData().getSceneType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Player> getPlayers() {
|
|
||||||
return players;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPlayerCount() {
|
public int getPlayerCount() {
|
||||||
return this.getPlayers().size();
|
return this.getPlayers().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, GameEntity> getEntities() {
|
|
||||||
return entities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameEntity getEntityById(int id) {
|
public GameEntity getEntityById(int id) {
|
||||||
return this.entities.get(id);
|
return this.entities.get(id);
|
||||||
}
|
}
|
||||||
@ -107,72 +98,11 @@ public class Scene {
|
|||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* @return the autoCloseTime
|
|
||||||
*/
|
|
||||||
public int getAutoCloseTime() {
|
|
||||||
return autoCloseTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param autoCloseTime the autoCloseTime to set
|
|
||||||
*/
|
|
||||||
public void setAutoCloseTime(int autoCloseTime) {
|
|
||||||
this.autoCloseTime = autoCloseTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTime() {
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void changeTime(int time) {
|
public void changeTime(int time) {
|
||||||
this.time = time % 1440;
|
this.time = time % 1440;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPrevScene() {
|
|
||||||
return prevScene;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrevScene(int prevScene) {
|
|
||||||
this.prevScene = prevScene;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPrevScenePoint() {
|
|
||||||
return prevScenePoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrevScenePoint(int prevPoint) {
|
|
||||||
this.prevScenePoint = prevPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean dontDestroyWhenEmpty() {
|
|
||||||
return dontDestroyWhenEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDontDestroyWhenEmpty(boolean dontDestroyWhenEmpty) {
|
|
||||||
this.dontDestroyWhenEmpty = dontDestroyWhenEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<SceneBlock> getLoadedBlocks() {
|
|
||||||
return loadedBlocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<SpawnDataEntry> getSpawnedEntities() {
|
|
||||||
return spawnedEntities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<SpawnDataEntry> getDeadSpawnedEntities() {
|
|
||||||
return deadSpawnedEntities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SceneScriptManager getScriptManager() {
|
|
||||||
return scriptManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DungeonData getDungeonData() {
|
|
||||||
return dungeonData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDungeonData(DungeonData dungeonData) {
|
public void setDungeonData(DungeonData dungeonData) {
|
||||||
if (dungeonData == null || this.dungeonData != null || this.getSceneType() != SceneType.SCENE_DUNGEON || dungeonData.getSceneId() != this.getId()) {
|
if (dungeonData == null || this.dungeonData != null || this.getSceneType() != SceneType.SCENE_DUNGEON || dungeonData.getSceneId() != this.getId()) {
|
||||||
return;
|
return;
|
||||||
@ -180,14 +110,6 @@ public class Scene {
|
|||||||
this.dungeonData = dungeonData;
|
this.dungeonData = dungeonData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldChallenge getChallenge() {
|
|
||||||
return challenge;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setChallenge(WorldChallenge challenge) {
|
|
||||||
this.challenge = challenge;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addDungeonSettleObserver(DungeonSettleListener dungeonSettleListener) {
|
public void addDungeonSettleObserver(DungeonSettleListener dungeonSettleListener) {
|
||||||
if (dungeonSettleListeners == null) {
|
if (dungeonSettleListeners == null) {
|
||||||
dungeonSettleListeners = new ArrayList<>();
|
dungeonSettleListeners = new ArrayList<>();
|
||||||
@ -195,10 +117,6 @@ public class Scene {
|
|||||||
dungeonSettleListeners.add(dungeonSettleListener);
|
dungeonSettleListeners.add(dungeonSettleListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DungeonSettleListener> getDungeonSettleObservers() {
|
|
||||||
return dungeonSettleListeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isInScene(GameEntity entity) {
|
public boolean isInScene(GameEntity entity) {
|
||||||
return this.entities.containsKey(entity.getId());
|
return this.entities.containsKey(entity.getId());
|
||||||
}
|
}
|
||||||
@ -241,7 +159,7 @@ public class Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Deregister scene if not in use
|
// Deregister scene if not in use
|
||||||
if (this.getPlayerCount() <= 0 && !this.dontDestroyWhenEmpty()) {
|
if (this.getPlayerCount() <= 0 && !this.dontDestroyWhenEmpty) {
|
||||||
this.getWorld().deregisterScene(this);
|
this.getWorld().deregisterScene(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -434,6 +352,8 @@ public class Scene {
|
|||||||
challenge.onCheckTimeOut();
|
challenge.onCheckTimeOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blossomManager.onTick();
|
||||||
|
|
||||||
checkNpcGroup();
|
checkNpcGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,11 +447,12 @@ public class Scene {
|
|||||||
}
|
}
|
||||||
gadget.buildContent();
|
gadget.buildContent();
|
||||||
|
|
||||||
gadget.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, 99999);
|
gadget.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, Float.POSITIVE_INFINITY);
|
||||||
gadget.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 99999);
|
gadget.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, Float.POSITIVE_INFINITY);
|
||||||
gadget.setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, 99999);
|
gadget.setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, Float.POSITIVE_INFINITY);
|
||||||
|
|
||||||
entity = gadget;
|
entity = gadget;
|
||||||
|
blossomManager.initBlossom(gadget);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity == null) continue;
|
if (entity == null) continue;
|
||||||
@ -557,6 +478,7 @@ public class Scene {
|
|||||||
if (toRemove.size() > 0) {
|
if (toRemove.size() > 0) {
|
||||||
toRemove.stream().forEach(this::removeEntityDirectly);
|
toRemove.stream().forEach(this::removeEntityDirectly);
|
||||||
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE));
|
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE));
|
||||||
|
blossomManager.recycleGadgetEntity(toRemove);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,4 +747,20 @@ public class Scene {
|
|||||||
scriptManager.addGroupSuite(group, suite);
|
scriptManager.addGroupSuite(group, suite);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void selectWorktopOptionWith(SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq req) {
|
||||||
|
GameEntity entity = getEntityById(req.getGadgetEntityId());
|
||||||
|
if (entity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Handle
|
||||||
|
if (entity instanceof EntityGadget gadget) {
|
||||||
|
if (gadget.getContent() instanceof GadgetWorktop worktop) {
|
||||||
|
boolean shouldDelete = worktop.onSelectWorktopOption(req);
|
||||||
|
if (shouldDelete) {
|
||||||
|
entity.getScene().removeEntity(entity, VisionType.VISION_TYPE_REMOVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,62 +5,20 @@ import java.util.Objects;
|
|||||||
|
|
||||||
import emu.grasscutter.data.GameDepot;
|
import emu.grasscutter.data.GameDepot;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
public class SpawnDataEntry {
|
public class SpawnDataEntry {
|
||||||
private transient SpawnGroupEntry group;
|
@Getter @Setter private transient SpawnGroupEntry group;
|
||||||
private int monsterId;
|
@Getter private int monsterId;
|
||||||
private int gadgetId;
|
@Getter private int gadgetId;
|
||||||
private int configId;
|
@Getter private int configId;
|
||||||
private int level;
|
@Getter private int level;
|
||||||
private int poseId;
|
@Getter private int poseId;
|
||||||
private int gatherItemId;
|
@Getter private int gatherItemId;
|
||||||
private int gadgetState;
|
@Getter private int gadgetState;
|
||||||
private Position pos;
|
@Getter private Position pos;
|
||||||
private Position rot;
|
@Getter private Position rot;
|
||||||
|
|
||||||
public SpawnGroupEntry getGroup() {
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGroup(SpawnGroupEntry group) {
|
|
||||||
this.group = group;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMonsterId() {
|
|
||||||
return monsterId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGadgetId() {
|
|
||||||
return gadgetId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGadgetState() {
|
|
||||||
return gadgetState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getConfigId() {
|
|
||||||
return configId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLevel() {
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPoseId() {
|
|
||||||
return poseId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGatherItemId() {
|
|
||||||
return gatherItemId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Position getPos() {
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Position getRot() {
|
|
||||||
return rot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GridBlockId getBlockId() {
|
public GridBlockId getBlockId() {
|
||||||
int scale = GridBlockId.getScale(gadgetId);
|
int scale = GridBlockId.getScale(gadgetId);
|
||||||
@ -71,37 +29,17 @@ public class SpawnDataEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class SpawnGroupEntry {
|
public static class SpawnGroupEntry {
|
||||||
private int sceneId;
|
@Getter private int sceneId;
|
||||||
private int groupId;
|
@Getter private int groupId;
|
||||||
private int blockId;
|
@Getter private int blockId;
|
||||||
private List<SpawnDataEntry> spawns;
|
@Getter @Setter private List<SpawnDataEntry> spawns;
|
||||||
|
|
||||||
public int getSceneId() {
|
|
||||||
return sceneId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGroupId() {
|
|
||||||
return groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBlockId() {
|
|
||||||
return blockId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBlockId(int blockId) {
|
|
||||||
this.blockId = blockId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<SpawnDataEntry> getSpawns() {
|
|
||||||
return spawns;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class GridBlockId {
|
public static class GridBlockId {
|
||||||
int sceneId;
|
@Getter private int sceneId;
|
||||||
int scale;
|
@Getter private int scale;
|
||||||
int x;
|
@Getter private int x;
|
||||||
int z;
|
@Getter private int z;
|
||||||
|
|
||||||
public GridBlockId(int sceneId, int scale, int x, int z) {
|
public GridBlockId(int sceneId, int scale, int x, int z) {
|
||||||
this.sceneId = sceneId;
|
this.sceneId = sceneId;
|
||||||
|
@ -13,20 +13,20 @@ import emu.grasscutter.server.packet.send.PacketSelectWorktopOptionRsp;
|
|||||||
|
|
||||||
@Opcodes(PacketOpcodes.SelectWorktopOptionReq)
|
@Opcodes(PacketOpcodes.SelectWorktopOptionReq)
|
||||||
public class HandlerSelectWorktopOptionReq extends PacketHandler {
|
public class HandlerSelectWorktopOptionReq extends PacketHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
SelectWorktopOptionReq req = SelectWorktopOptionReq.parseFrom(payload);
|
SelectWorktopOptionReq req = SelectWorktopOptionReq.parseFrom(payload);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GameEntity entity = session.getPlayer().getScene().getEntityById(req.getGadgetEntityId());
|
GameEntity entity = session.getPlayer().getScene().getEntityById(req.getGadgetEntityId());
|
||||||
|
|
||||||
if (entity == null || !(entity instanceof EntityGadget)) {
|
if (!(entity instanceof EntityGadget)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
session.getPlayer().getScene().selectWorktopOptionWith(req);
|
||||||
session.getPlayer().getScene().getScriptManager().callEvent(
|
session.getPlayer().getScene().getScriptManager().callEvent(
|
||||||
EventType.EVENT_SELECT_OPTION,
|
EventType.EVENT_SELECT_OPTION,
|
||||||
new ScriptArgs(entity.getConfigId(), req.getOptionId())
|
new ScriptArgs(entity.getConfigId(), req.getOptionId())
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.BlossomBriefInfoNotifyOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.BlossomBriefInfoOuterClass;
|
||||||
|
|
||||||
|
public class PacketBlossomBriefInfoNotify extends BasePacket {
|
||||||
|
public PacketBlossomBriefInfoNotify(Iterable<BlossomBriefInfoOuterClass.BlossomBriefInfo> blossoms) {
|
||||||
|
super(PacketOpcodes.BlossomBriefInfoNotify);
|
||||||
|
this.setData(BlossomBriefInfoNotifyOuterClass.BlossomBriefInfoNotify.newBuilder().addAllBriefInfoList(blossoms));
|
||||||
|
}
|
||||||
|
}
|
@ -10,28 +10,28 @@ import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
|||||||
@Entity
|
@Entity
|
||||||
public class Position implements Serializable {
|
public class Position implements Serializable {
|
||||||
private static final long serialVersionUID = -2001232313615923575L;
|
private static final long serialVersionUID = -2001232313615923575L;
|
||||||
|
|
||||||
@SerializedName(value="x", alternate={"_x", "X"})
|
@SerializedName(value="x", alternate={"_x", "X"})
|
||||||
private float x;
|
private float x;
|
||||||
|
|
||||||
@SerializedName(value="y", alternate={"_y", "Y"})
|
@SerializedName(value="y", alternate={"_y", "Y"})
|
||||||
private float y;
|
private float y;
|
||||||
|
|
||||||
@SerializedName(value="z", alternate={"_z", "Z"})
|
@SerializedName(value="z", alternate={"_z", "Z"})
|
||||||
private float z;
|
private float z;
|
||||||
|
|
||||||
public Position() {
|
public Position() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position(float x, float y) {
|
public Position(float x, float y) {
|
||||||
set(x, y);
|
set(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position(float x, float y, float z) {
|
public Position(float x, float y, float z) {
|
||||||
set(x, y, z);
|
set(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position(String p) {
|
public Position(String p) {
|
||||||
String[] split = p.split(",");
|
String[] split = p.split(",");
|
||||||
if (split.length >= 2) {
|
if (split.length >= 2) {
|
||||||
@ -42,7 +42,7 @@ public class Position implements Serializable {
|
|||||||
this.z = Float.parseFloat(split[2]);
|
this.z = Float.parseFloat(split[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position(Vector vector) {
|
public Position(Vector vector) {
|
||||||
this.set(vector);
|
this.set(vector);
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ public class Position implements Serializable {
|
|||||||
public void setZ(float z) {
|
public void setZ(float z) {
|
||||||
this.z = z;
|
this.z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getY() {
|
public float getY() {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
@ -74,22 +74,22 @@ public class Position implements Serializable {
|
|||||||
public void setY(float y) {
|
public void setY(float y) {
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position set(float x, float y) {
|
public Position set(float x, float y) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deep copy
|
// Deep copy
|
||||||
public Position set(Position pos) {
|
public Position set(Position pos) {
|
||||||
return this.set(pos.getX(), pos.getY(), pos.getZ());
|
return this.set(pos.getX(), pos.getY(), pos.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position set(Vector pos) {
|
public Position set(Vector pos) {
|
||||||
return this.set(pos.getX(), pos.getY(), pos.getZ());
|
return this.set(pos.getX(), pos.getY(), pos.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position set(float x, float y, float z) {
|
public Position set(float x, float y, float z) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
@ -103,17 +103,17 @@ public class Position implements Serializable {
|
|||||||
this.z += add.getZ();
|
this.z += add.getZ();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position addX(float d) {
|
public Position addX(float d) {
|
||||||
this.x += d;
|
this.x += d;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position addY(float d) {
|
public Position addY(float d) {
|
||||||
this.y += d;
|
this.y += d;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position addZ(float d) {
|
public Position addZ(float d) {
|
||||||
this.z += d;
|
this.z += d;
|
||||||
return this;
|
return this;
|
||||||
@ -125,7 +125,7 @@ public class Position implements Serializable {
|
|||||||
this.z -= sub.getZ();
|
this.z -= sub.getZ();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** In radians
|
/** In radians
|
||||||
* */
|
* */
|
||||||
public Position translate(float dist, float angle) {
|
public Position translate(float dist, float angle) {
|
||||||
@ -149,13 +149,20 @@ public class Position implements Serializable {
|
|||||||
double detZ = getZ()-b.getZ();
|
double detZ = getZ()-b.getZ();
|
||||||
return Math.sqrt(detX*detX+detY*detY+detZ*detZ);
|
return Math.sqrt(detX*detX+detY*detY+detZ*detZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Position nearby2d(int range){
|
||||||
|
Position position = clone();
|
||||||
|
position.z += (float)Utils.randomRange(-range,range)/10;
|
||||||
|
position.x += (float)Utils.randomRange(-range,range)/10;
|
||||||
|
return position;
|
||||||
|
}
|
||||||
public Position translateWithDegrees(float dist, float angle) {
|
public Position translateWithDegrees(float dist, float angle) {
|
||||||
angle = (float) Math.toRadians(angle);
|
angle = (float) Math.toRadians(angle);
|
||||||
this.x += dist * Math.sin(angle);
|
this.x += dist * Math.sin(angle);
|
||||||
this.y += -dist * Math.cos(angle);
|
this.y += -dist * Math.cos(angle);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Position clone() {
|
public Position clone() {
|
||||||
return new Position(x, y, z);
|
return new Position(x, y, z);
|
||||||
@ -165,7 +172,7 @@ public class Position implements Serializable {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "(" + this.getX() + ", " + this.getY() + ", " + this.getZ() + ")";
|
return "(" + this.getX() + ", " + this.getY() + ", " + this.getZ() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector toProto() {
|
public Vector toProto() {
|
||||||
return Vector.newBuilder()
|
return Vector.newBuilder()
|
||||||
.setX(this.getX())
|
.setX(this.getX())
|
||||||
|
8
src/main/resources/defaults/data/BlossomConfig.json
Normal file
8
src/main/resources/defaults/data/BlossomConfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"monsterFightingVolume": 100,
|
||||||
|
"monsterIdsPerDifficulty": {
|
||||||
|
"0": [21010101, 20010101, 20010201, 20010202, 20010301, 20010401, 20010403, 20010501, 20010601, 20010604, 20010701, 20010702, 20010801, 20010802, 20010901, 20010902, 20010904, 20011001, 20011101, 20011103, 20011601, 20011701, 20011801, 20011901, 20050201, 20050202, 20050203, 20050301, 20050302, 20050401, 20050402, 20050403, 20050501, 20050502, 20050601, 20050602, 20050603, 20050701, 20050702, 20050703, 20050801, 20050802, 20050901, 21010201, 21010301, 21010401, 21010402, 21010501, 21010502, 21010601, 21010603, 21010701, 21010901, 21010902, 21011001, 21011002, 21011201, 21011301, 21011302, 21011401, 21011403, 21011501, 21011601, 21011602, 20011201, 20011202, 20011301, 20011304, 20011401, 20011501, 20011502, 25010101, 25010102, 25010103, 25010104, 25010105, 25010106, 25010201, 25010203, 25010204, 25010205, 25010206, 25010207, 25010208, 25010701, 25020101, 25020102, 25020201, 25020204, 25030101, 25030102, 25030103, 25030201, 25030301, 25040101, 25040102, 25040103, 25050101, 25050201, 25050301, 25050401, 25050402, 25050501, 25050502, 25060101, 25060102, 25070101, 25070201, 25070202, 21010102, 20010302, 20010402, 20010502, 20010602, 20010703, 20010803, 20010903, 20011002, 20011102, 21010302, 21010702, 21011202, 21011402, 20011203, 20011302, 20011402, 20011503, 21030102, 21030202, 21030302, 21030403, 21030502, 21030602],
|
||||||
|
"1": [21020101, 21020201, 21020202, 21020301, 21020601, 21020701, 21020703, 21030101, 21030103, 21030201, 21030203, 21030301, 21030303, 21030304, 21030401, 21030402, 21030501, 21030601, 21030603, 25010301, 25010302, 25010401, 25010501, 25010601, 26010101, 26010102, 26010201, 26010301, 21020102, 21020203, 21020702, 21020302, 21020602],
|
||||||
|
"2": [21020401, 21020501, 21020801, 20020101, 20070101, 22010101, 22010102, 22010103, 22010104, 22010201, 22010202, 22010203, 22010204, 22010301, 22010302, 22010303, 22010304, 22010401, 22010403, 22010404, 24010101, 24010201, 23010101, 23010201, 23010301, 23010401, 23010501, 23010601, 23020101, 23020102, 23030101, 23030102, 23040101, 23040102, 23050101, 20060101, 20060201, 20060301, 20060401, 20060501, 20060601, 21020402, 21020502, 21020802, 22010105, 22010205, 22010305, 22010402]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user