diff --git a/src/main/java/emu/grasscutter/game/dungeons/DungeonChallenge.java b/src/main/java/emu/grasscutter/game/dungeons/DungeonChallenge.java deleted file mode 100644 index 35e1407a8..000000000 --- a/src/main/java/emu/grasscutter/game/dungeons/DungeonChallenge.java +++ /dev/null @@ -1,180 +0,0 @@ -package emu.grasscutter.game.dungeons; - -import emu.grasscutter.data.common.ItemParamData; -import emu.grasscutter.data.def.DungeonData; -import emu.grasscutter.game.entity.EntityMonster; -import emu.grasscutter.game.inventory.GameItem; -import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.props.ActionReason; -import emu.grasscutter.game.world.Scene; -import emu.grasscutter.scripts.constants.EventType; -import emu.grasscutter.scripts.data.SceneGroup; -import emu.grasscutter.scripts.data.ScriptArgs; -import emu.grasscutter.server.packet.send.PacketChallengeDataNotify; -import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify; -import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify; -import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; - -import java.util.ArrayList; -import java.util.List; - -public class DungeonChallenge { - private final Scene scene; - private final SceneGroup group; - - private int challengeIndex; - private int challengeId; - private boolean success; - private boolean progress; - /** - * has more challenge - */ - private boolean stage; - private int score; - private int objective = 0; - private IntSet rewardedPlayers; - - public DungeonChallenge(Scene scene, SceneGroup group, int challengeId, int challengeIndex, int objective) { - this.scene = scene; - this.group = group; - this.challengeId = challengeId; - this.challengeIndex = challengeIndex; - this.objective = objective; - this.setRewardedPlayers(new IntOpenHashSet()); - } - - public Scene getScene() { - return scene; - } - - public SceneGroup getGroup() { - return group; - } - - public int getChallengeIndex() { - return challengeIndex; - } - - public void setChallengeIndex(int challengeIndex) { - this.challengeIndex = challengeIndex; - } - - public int getChallengeId() { - return challengeId; - } - - public void setChallengeId(int challengeId) { - this.challengeId = challengeId; - } - - public int getObjective() { - return objective; - } - - public void setObjective(int objective) { - this.objective = objective; - } - - public boolean isSuccess() { - return success; - } - - public void setSuccess(boolean isSuccess) { - this.success = isSuccess; - } - - public boolean inProgress() { - return progress; - } - - public int getScore() { - return score; - } - - public boolean isStage() { - return stage; - } - - public void setStage(boolean stage) { - this.stage = stage; - } - - public int getTimeLimit() { - return 600; - } - - public IntSet getRewardedPlayers() { - return rewardedPlayers; - } - - public void setRewardedPlayers(IntSet rewardedPlayers) { - this.rewardedPlayers = rewardedPlayers; - } - - public void start() { - this.progress = true; - getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this)); - } - - public void finish() { - this.progress = false; - - getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this)); - - if (this.isSuccess()) { - // Call success script event - this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_SUCCESS, - // TODO record the time in PARAM2 and used in action - new ScriptArgs().setParam2(100)); - - // Settle - settle(); - } else { - this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_FAIL, null); - } - } - - private void settle() { - getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene())); - - if(!stage){ - getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, - new ScriptArgs(this.isSuccess() ? 1 : 0)); - } - } - - public void onMonsterDie(EntityMonster entity) { - score = getScore() + 1; - - getScene().broadcastPacket(new PacketChallengeDataNotify(this, 1, getScore())); - - if (getScore() >= getObjective() && this.progress) { - this.setSuccess(true); - finish(); - } - } - - public void getStatueDrops(Player player) { - DungeonData dungeonData = getScene().getDungeonData(); - if (!isSuccess() || dungeonData == null || dungeonData.getRewardPreview() == null || dungeonData.getRewardPreview().getPreviewItems().length == 0) { - return; - } - - // Already rewarded - if (getRewardedPlayers().contains(player.getUid())) { - return; - } - - List rewards = new ArrayList<>(); - for (ItemParamData param : getScene().getDungeonData().getRewardPreview().getPreviewItems()) { - rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1))); - } - - player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop); - player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards)); - - getRewardedPlayers().add(player.getUid()); - } -} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java new file mode 100644 index 000000000..f2a485f1d --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java @@ -0,0 +1,91 @@ +package emu.grasscutter.game.dungeons.challenge; + +import emu.grasscutter.data.common.ItemParamData; +import emu.grasscutter.data.def.DungeonData; +import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger; +import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.world.Scene; +import emu.grasscutter.scripts.constants.EventType; +import emu.grasscutter.scripts.data.SceneGroup; +import emu.grasscutter.scripts.data.ScriptArgs; +import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; + +import java.util.ArrayList; +import java.util.List; + +public class DungeonChallenge extends WorldChallenge { + + /** + * has more challenge + */ + private boolean stage; + private IntSet rewardedPlayers; + + public DungeonChallenge(Scene scene, SceneGroup group, + int challengeId, int challengeIndex, + List paramList, + int timeLimit, int goal, + List challengeTriggers) { + super(scene, group, challengeId, challengeIndex, paramList, timeLimit, goal, challengeTriggers); + this.setRewardedPlayers(new IntOpenHashSet()); + } + + public boolean isStage() { + return stage; + } + + public void setStage(boolean stage) { + this.stage = stage; + } + + public IntSet getRewardedPlayers() { + return rewardedPlayers; + } + + public void setRewardedPlayers(IntSet rewardedPlayers) { + this.rewardedPlayers = rewardedPlayers; + } + + @Override + public void done() { + super.done(); + if (this.isSuccess()) { + // Settle + settle(); + } + } + + private void settle() { + if(!stage){ + getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene())); + getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, + new ScriptArgs(this.isSuccess() ? 1 : 0)); + } + } + + public void getStatueDrops(Player player) { + DungeonData dungeonData = getScene().getDungeonData(); + if (!isSuccess() || dungeonData == null || dungeonData.getRewardPreview() == null || dungeonData.getRewardPreview().getPreviewItems().length == 0) { + return; + } + + // Already rewarded + if (getRewardedPlayers().contains(player.getUid())) { + return; + } + + List rewards = new ArrayList<>(); + for (ItemParamData param : getScene().getDungeonData().getRewardPreview().getPreviewItems()) { + rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1))); + } + + player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop); + player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards)); + + getRewardedPlayers().add(player.getUid()); + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/WorldChallenge.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/WorldChallenge.java new file mode 100644 index 000000000..106bd13e8 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/WorldChallenge.java @@ -0,0 +1,132 @@ +package emu.grasscutter.game.dungeons.challenge; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger; +import emu.grasscutter.game.entity.EntityGadget; +import emu.grasscutter.game.entity.EntityMonster; +import emu.grasscutter.game.world.Scene; +import emu.grasscutter.scripts.constants.EventType; +import emu.grasscutter.scripts.data.SceneGroup; +import emu.grasscutter.scripts.data.ScriptArgs; +import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify; +import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +@Getter +@Setter +public class WorldChallenge { + private final Scene scene; + private final SceneGroup group; + private final int challengeId; + private final int challengeIndex; + private final List paramList; + private final int timeLimit; + private final List challengeTriggers; + private boolean progress; + private boolean success; + private long startedAt; + private int finishedTime; + private final int goal; + private final AtomicInteger score; + + public WorldChallenge(Scene scene, SceneGroup group, + int challengeId, int challengeIndex, List paramList, + int timeLimit, int goal, + List challengeTriggers){ + this.scene = scene; + this.group = group; + this.challengeId = challengeId; + this.challengeIndex = challengeIndex; + this.paramList = paramList; + this.timeLimit = timeLimit; + this.challengeTriggers = challengeTriggers; + this.goal = goal; + this.score = new AtomicInteger(0); + } + public boolean inProgress(){ + return this.progress; + } + public void onCheckTimeOut(){ + if(!inProgress()){ + return; + } + if(timeLimit <= 0){ + return; + } + challengeTriggers.forEach(t -> t.onCheckTimeout(this)); + } + public void start(){ + if(inProgress()){ + Grasscutter.getLogger().info("Could not start a in progress challenge."); + return; + } + this.progress = true; + this.startedAt = System.currentTimeMillis(); + getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this)); + challengeTriggers.forEach(t -> t.onBegin(this)); + } + + public void done(){ + if(!inProgress()){ + return; + } + finish(true); + this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_SUCCESS, + // TODO record the time in PARAM2 and used in action + new ScriptArgs().setParam2(finishedTime)); + + challengeTriggers.forEach(t -> t.onFinish(this)); + } + + public void fail(){ + if(!inProgress()){ + return; + } + finish(false); + this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_FAIL, null); + challengeTriggers.forEach(t -> t.onFinish(this)); + } + + private void finish(boolean success){ + this.progress = false; + this.success = success; + this.finishedTime = (int)((System.currentTimeMillis() - this.startedAt) / 1000L); + getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this)); + } + + public int increaseScore(){ + return score.incrementAndGet(); + } + public void onMonsterDeath(EntityMonster monster){ + if(!inProgress()){ + return; + } + if(monster.getGroupId() != getGroup().id){ + return; + } + this.challengeTriggers.forEach(t -> t.onMonsterDeath(this, monster)); + } + public void onGadgetDeath(EntityGadget gadget){ + if(!inProgress()){ + return; + } + if(gadget.getGroupId() != getGroup().id){ + return; + } + this.challengeTriggers.forEach(t -> t.onGadgetDeath(this, gadget)); + } + + public void onGadgetDamage(EntityGadget gadget){ + if(!inProgress()){ + return; + } + if(gadget.getGroupId() != getGroup().id){ + return; + } + this.challengeTriggers.forEach(t -> t.onGadgetDamage(this, gadget)); + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/ChallengeFactory.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/ChallengeFactory.java new file mode 100644 index 000000000..fd1662de6 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/ChallengeFactory.java @@ -0,0 +1,30 @@ +package emu.grasscutter.game.dungeons.challenge.factory; + +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.game.world.Scene; +import emu.grasscutter.scripts.data.SceneGroup; + +import java.util.ArrayList; +import java.util.List; + +public class ChallengeFactory { + + private static final List challengeFactoryHandlers = new ArrayList<>(); + + static { + challengeFactoryHandlers.add(new DungeonChallengeFactoryHandler()); + challengeFactoryHandlers.add(new DungeonGuardChallengeFactoryHandler()); + challengeFactoryHandlers.add(new KillGadgetChallengeFactoryHandler()); + challengeFactoryHandlers.add(new KillMonsterChallengeFactoryHandler()); + } + + public static WorldChallenge getChallenge(int param1, int param2, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group){ + for(var handler : challengeFactoryHandlers){ + if(!handler.isThisType(param1, param2, param3, param4, param5, param6, scene, group)){ + continue; + } + return handler.build(param1, param2, param3, param4, param5, param6, scene, group); + } + return null; + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/ChallengeFactoryHandler.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/ChallengeFactoryHandler.java new file mode 100644 index 000000000..a91d55a28 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/ChallengeFactoryHandler.java @@ -0,0 +1,10 @@ +package emu.grasscutter.game.dungeons.challenge.factory; + +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.game.world.Scene; +import emu.grasscutter.scripts.data.SceneGroup; + +public interface ChallengeFactoryHandler { + boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group); + WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group); +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/DungeonChallengeFactoryHandler.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/DungeonChallengeFactoryHandler.java new file mode 100644 index 000000000..8357c9642 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/DungeonChallengeFactoryHandler.java @@ -0,0 +1,33 @@ +package emu.grasscutter.game.dungeons.challenge.factory; + +import emu.grasscutter.game.dungeons.challenge.DungeonChallenge; +import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger; +import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger; +import emu.grasscutter.game.props.SceneType; +import emu.grasscutter.game.world.Scene; +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.scripts.data.SceneGroup; + +import java.util.List; + +public class DungeonChallengeFactoryHandler implements ChallengeFactoryHandler{ + @Override + public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) { + // ActiveChallenge with 1,1000,300,233101003,15,0 + return scene.getSceneType() == SceneType.SCENE_DUNGEON + && param4 == group.id; + } + + @Override + public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) { + var realGroup = scene.getScriptManager().getGroupById(param4); + return new DungeonChallenge( + scene, realGroup, + challengeId, // Id + challengeIndex, // Index + List.of(param5, param3), + param3, // Limit + param5, // Goal + List.of(new InTimeTrigger(), new KillMonsterTrigger())); + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/DungeonGuardChallengeFactoryHandler.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/DungeonGuardChallengeFactoryHandler.java new file mode 100644 index 000000000..3ea68f114 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/DungeonGuardChallengeFactoryHandler.java @@ -0,0 +1,34 @@ +package emu.grasscutter.game.dungeons.challenge.factory; + +import emu.grasscutter.game.dungeons.challenge.DungeonChallenge; +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger; +import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger; +import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger; +import emu.grasscutter.game.props.SceneType; +import emu.grasscutter.game.world.Scene; +import emu.grasscutter.scripts.data.SceneGroup; + +import java.util.List; + +public class DungeonGuardChallengeFactoryHandler implements ChallengeFactoryHandler{ + @Override + public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) { + // ActiveChallenge with 1,188,234101003,12,3030,0 + return scene.getSceneType() == SceneType.SCENE_DUNGEON + && param3 == group.id; + } + + @Override + public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) { + var realGroup = scene.getScriptManager().getGroupById(param3); + return new DungeonChallenge( + scene, realGroup, + challengeId, // Id + challengeIndex, // Index + List.of(param4, 0), + 0, // Limit + param5, // Goal + List.of(new GuardTrigger())); + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/KillGadgetChallengeFactoryHandler.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/KillGadgetChallengeFactoryHandler.java new file mode 100644 index 000000000..4e075f2d3 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/KillGadgetChallengeFactoryHandler.java @@ -0,0 +1,34 @@ +package emu.grasscutter.game.dungeons.challenge.factory; + +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.game.dungeons.challenge.factory.ChallengeFactoryHandler; +import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger; +import emu.grasscutter.game.dungeons.challenge.trigger.KillGadgetTrigger; +import emu.grasscutter.game.world.Scene; +import emu.grasscutter.scripts.data.SceneGroup; + +import java.util.List; + +public class KillGadgetChallengeFactoryHandler implements ChallengeFactoryHandler { + @Override + public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) { + // kill gadgets(explosive barrel) in time + // ActiveChallenge with 56,201,20,2,201,4 + // open chest in time + // ActiveChallenge with 666,202,30,7,202,1 + return challengeId == 201 || challengeId == 202; + } + + @Override + public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) { + return new WorldChallenge( + scene, group, + challengeId, // Id + challengeIndex, // Index + List.of(param3, param6, 0), + param3, // Limit + param6, // Goal + List.of(new InTimeTrigger(), new KillGadgetTrigger()) + ); + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/KillMonsterChallengeFactoryHandler.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/KillMonsterChallengeFactoryHandler.java new file mode 100644 index 000000000..b2285ee3e --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/factory/KillMonsterChallengeFactoryHandler.java @@ -0,0 +1,31 @@ +package emu.grasscutter.game.dungeons.challenge.factory; + +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger; +import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger; +import emu.grasscutter.game.world.Scene; +import emu.grasscutter.scripts.data.SceneGroup; + +import java.util.List; + +public class KillMonsterChallengeFactoryHandler implements ChallengeFactoryHandler{ + @Override + public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) { + // ActiveChallenge with 180,180,45,133108061,1,0 + return challengeId == 180; + } + + @Override + public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) { + var realGroup = scene.getScriptManager().getGroupById(param4); + return new WorldChallenge( + scene, realGroup, + challengeId, // Id + challengeIndex, // Index + List.of(param5, param3), + param3, // Limit + param5, // Goal + List.of(new KillMonsterTrigger(), new InTimeTrigger()) + ); + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/ChallengeTrigger.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/ChallengeTrigger.java new file mode 100644 index 000000000..b0b174f8d --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/ChallengeTrigger.java @@ -0,0 +1,14 @@ +package emu.grasscutter.game.dungeons.challenge.trigger; + +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.game.entity.EntityGadget; +import emu.grasscutter.game.entity.EntityMonster; + +public abstract class ChallengeTrigger { + public void onBegin(WorldChallenge challenge){} + public void onFinish(WorldChallenge challenge){} + public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster){} + public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget){} + public void onCheckTimeout(WorldChallenge challenge){} + public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget){} +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/GuardTrigger.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/GuardTrigger.java new file mode 100644 index 000000000..4b9bc9e43 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/GuardTrigger.java @@ -0,0 +1,27 @@ +package emu.grasscutter.game.dungeons.challenge.trigger; + +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.game.entity.EntityGadget; +import emu.grasscutter.game.entity.EntityMonster; +import emu.grasscutter.game.props.FightProperty; +import emu.grasscutter.server.packet.send.PacketChallengeDataNotify; + +public class GuardTrigger extends KillMonsterTrigger{ + @Override + public void onBegin(WorldChallenge challenge) { + super.onBegin(challenge); + challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, 100)); + } + + @Override + public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) { + var curHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_CUR_HP.getId()); + var maxHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_BASE_HP.getId()); + int percent = (int) (curHp / maxHp); + challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent)); + + if(percent <= 0){ + challenge.fail(); + } + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/InTimeTrigger.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/InTimeTrigger.java new file mode 100644 index 000000000..abb51c512 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/InTimeTrigger.java @@ -0,0 +1,13 @@ +package emu.grasscutter.game.dungeons.challenge.trigger; + +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; + +public class InTimeTrigger extends ChallengeTrigger{ + @Override + public void onCheckTimeout(WorldChallenge challenge) { + var current = System.currentTimeMillis(); + if(current - challenge.getStartedAt() > challenge.getTimeLimit() * 1000L){ + challenge.fail(); + } + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/KillGadgetTrigger.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/KillGadgetTrigger.java new file mode 100644 index 000000000..87a1997d4 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/KillGadgetTrigger.java @@ -0,0 +1,23 @@ +package emu.grasscutter.game.dungeons.challenge.trigger; + +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.game.entity.EntityGadget; +import emu.grasscutter.server.packet.send.PacketChallengeDataNotify; + +public class KillGadgetTrigger extends ChallengeTrigger{ + @Override + public void onBegin(WorldChallenge challenge) { + challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, challenge.getScore().get())); + } + + @Override + public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget) { + var newScore = challenge.increaseScore(); + challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, newScore)); + + if(newScore >= challenge.getGoal()){ + challenge.done(); + } + + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/KillMonsterTrigger.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/KillMonsterTrigger.java new file mode 100644 index 000000000..dcde43049 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/KillMonsterTrigger.java @@ -0,0 +1,23 @@ +package emu.grasscutter.game.dungeons.challenge.trigger; + +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; +import emu.grasscutter.game.entity.EntityMonster; +import emu.grasscutter.server.packet.send.PacketChallengeDataNotify; + +public class KillMonsterTrigger extends ChallengeTrigger{ + @Override + public void onBegin(WorldChallenge challenge) { + challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, challenge.getScore().get())); + } + + @Override + public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) { + var newScore = challenge.increaseScore(); + challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, newScore)); + + if(newScore >= challenge.getGoal()){ + challenge.done(); + } + + } +} diff --git a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java index efd3289ba..22d3759cc 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java @@ -1,18 +1,10 @@ package emu.grasscutter.game.entity; -import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.def.GadgetData; -import emu.grasscutter.game.entity.gadget.GadgetChest; -import emu.grasscutter.game.entity.gadget.GadgetContent; -import emu.grasscutter.game.entity.gadget.GadgetGatherPoint; -import emu.grasscutter.game.entity.gadget.GadgetRewardStatue; -import emu.grasscutter.game.entity.gadget.GadgetWorktop; -import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.props.EntityIdType; -import emu.grasscutter.game.props.EntityType; -import emu.grasscutter.game.props.FightProperty; -import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.data.def.GadgetPropData; +import emu.grasscutter.game.entity.gadget.*; +import emu.grasscutter.game.props.*; import emu.grasscutter.game.world.Scene; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; @@ -32,6 +24,7 @@ import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.data.SceneGadget; import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.server.packet.send.PacketGadgetStateNotify; +import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify; import emu.grasscutter.utils.Position; import emu.grasscutter.utils.ProtoHelper; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; @@ -160,7 +153,10 @@ public class EntityGadget extends EntityBaseGadget { @Override public void onDeath(int killerId) { - + if(getScene().getChallenge() != null){ + getScene().getChallenge().onGadgetDeath(this); + } + getScene().getScriptManager().callEvent(EventType.EVENT_ANY_GADGET_DIE, new ScriptArgs(this.getConfigId())); } @Override @@ -203,4 +199,8 @@ public class EntityGadget extends EntityBaseGadget { return entityInfo.build(); } + public void die() { + getScene().broadcastPacket(new PacketLifeStateChangeNotify(this, LifeState.LIFE_DEAD)); + this.onDeath(0); + } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java index 0ccdfef2e..851f0e2ad 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java @@ -122,8 +122,8 @@ public class EntityMonster extends GameEntity { this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); } // first set the challenge data - if (getScene().getChallenge() != null && getScene().getChallenge().getGroup().id == this.getGroupId()) { - getScene().getChallenge().onMonsterDie(this); + if (getScene().getChallenge() != null) { + getScene().getChallenge().onMonsterDeath(this); } if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) { if(getScene().getScriptManager().getScriptMonsterSpawnService() != null){ diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java index 038b7d6dd..6e2cdf72b 100644 --- a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java +++ b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java @@ -38,6 +38,8 @@ public class GadgetChest extends GadgetContent { getGadget().updateState(ScriptGadgetState.ChestOpened); player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_OPEN_CHEST)); + // let the chest disappear + getGadget().die(); return true; } } diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetRewardStatue.java b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetRewardStatue.java index 7e606d4ca..69a25b0a5 100644 --- a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetRewardStatue.java +++ b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetRewardStatue.java @@ -1,5 +1,6 @@ package emu.grasscutter.game.entity.gadget; +import emu.grasscutter.game.dungeons.challenge.DungeonChallenge; import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.InterOpTypeOuterClass; @@ -14,8 +15,8 @@ public class GadgetRewardStatue extends GadgetContent { } public boolean onInteract(Player player, InterOpTypeOuterClass.InterOpType opType) { - if (player.getScene().getChallenge() != null) { - player.getScene().getChallenge().getStatueDrops(player); + if (player.getScene().getChallenge() != null && player.getScene().getChallenge() instanceof DungeonChallenge dungeonChallenge) { + dungeonChallenge.getStatueDrops(player); } player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_OPEN_STATUE)); diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java b/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java index 39f0a88fd..491bfd9bd 100644 --- a/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java +++ b/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java @@ -1,5 +1,6 @@ package emu.grasscutter.game.entity.gadget.chest; +import emu.grasscutter.Grasscutter; import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.game.entity.gadget.GadgetChest; import emu.grasscutter.game.inventory.GameItem; @@ -22,6 +23,10 @@ public class BossChestInteractHandler implements ChestInteractHandler{ var monster = chest.getGadget().getMetaGadget().group.monsters.get(chest.getGadget().getMetaGadget().boss_chest.monster_config_id); var reward = worldDataManager.getRewardByBossId(monster.monster_id); + if(reward == null){ + Grasscutter.getLogger().warn("Could not found the reward of boss monster {}", monster.monster_id); + return false; + } List rewards = new ArrayList<>(); for (ItemParamData param : reward.getPreviewItems()) { rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1))); diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index c1b6a2208..3d5c85a00 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -4,7 +4,6 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameDepot; import emu.grasscutter.data.def.*; -import emu.grasscutter.game.dungeons.DungeonChallenge; import emu.grasscutter.game.dungeons.DungeonSettleListener; import emu.grasscutter.game.entity.*; import emu.grasscutter.game.player.Player; @@ -14,6 +13,7 @@ import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.LifeState; import emu.grasscutter.game.props.SceneType; import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry; +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; @@ -32,8 +32,6 @@ import org.danilopianini.util.SpatialIndex; import java.util.*; import java.util.stream.Collectors; -import static emu.grasscutter.utils.Language.translate; - public class Scene { private final World world; private final SceneData sceneData; @@ -51,7 +49,7 @@ public class Scene { private int weather; private SceneScriptManager scriptManager; - private DungeonChallenge challenge; + private WorldChallenge challenge; private List dungeonSettleListeners; private DungeonData dungeonData; private int prevScene; // Id of the previous scene @@ -199,11 +197,11 @@ public class Scene { this.dungeonData = dungeonData; } - public DungeonChallenge getChallenge() { + public WorldChallenge getChallenge() { return challenge; } - public void setChallenge(DungeonChallenge challenge) { + public void setChallenge(WorldChallenge challenge) { this.challenge = challenge; } @@ -353,7 +351,14 @@ public class Scene { this.broadcastPacket(new PacketSceneEntityDisappearNotify(removed, visionType)); } } - + public synchronized void removeEntities(List entity, VisionType visionType) { + var toRemove = entity.stream() + .map(this::removeEntityDirectly) + .toList(); + if (toRemove.size() > 0) { + this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, visionType)); + } + } public synchronized void replaceEntity(EntityAvatar oldEntity, EntityAvatar newEntity) { this.removeEntityDirectly(oldEntity); this.addEntityDirectly(newEntity); @@ -418,6 +423,10 @@ public class Scene { } // Triggers this.scriptManager.checkRegions(); + + if(challenge != null){ + challenge.onCheckTimeOut(); + } } // TODO - Test @@ -590,21 +599,21 @@ public class Scene { if (suite == 0 || group.suites == null || group.suites.size() == 0) { continue; } - - do { - var suiteData = group.getSuiteByIndex(suite); - suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger); - entities.addAll(suiteData.sceneGadgets.stream() - .map(g -> scriptManager.createGadget(group.id, group.block_id, g)).toList()); - entities.addAll(suiteData.sceneMonsters.stream() - .map(mob -> scriptManager.createMonster(group.id, group.block_id, mob)).toList()); - - suite++; - } while (suite < group.init_config.end_suite); + // just load the 'init' suite, avoid spawn the suite added by AddExtraGroupSuite etc. + var suiteData = group.getSuiteByIndex(suite); + suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger); + + entities.addAll(suiteData.sceneGadgets.stream() + .map(g -> scriptManager.createGadget(group.id, group.block_id, g)).toList()); + entities.addAll(suiteData.sceneMonsters.stream() + .map(mob -> scriptManager.createMonster(group.id, group.block_id, mob)).toList()); + } scriptManager.meetEntities(entities); + //scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null); + //groups.forEach(g -> scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null)); Grasscutter.getLogger().info("Scene {} loaded {} group(s)", this.getId(), groups.size()); } diff --git a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java index 055bffe33..ef802dde9 100644 --- a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java +++ b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java @@ -26,16 +26,13 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class SceneScriptManager { private final Scene scene; private final Map variables; private SceneMeta meta; private boolean isInit; - /** - * SceneTrigger Set - */ - private final Map triggers; /** * current triggers controlled by RefreshGroup */ @@ -51,12 +48,11 @@ public class SceneScriptManager { public static final ExecutorService eventExecutor; static { eventExecutor = new ThreadPoolExecutor(4, 4, - 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100), + 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000), FastThreadLocalThread::new, new ThreadPoolExecutor.AbortPolicy()); } public SceneScriptManager(Scene scene) { this.scene = scene; - this.triggers = new HashMap<>(); this.currentTriggers = new Int2ObjectOpenHashMap<>(); this.regions = new Int2ObjectOpenHashMap<>(); @@ -96,13 +92,16 @@ public class SceneScriptManager { public Set getTriggersByEvent(int eventId) { return currentTriggers.computeIfAbsent(eventId, e -> new HashSet<>()); } + public void registerTrigger(List triggers) { + triggers.forEach(this::registerTrigger); + } public void registerTrigger(SceneTrigger trigger) { - this.triggers.put(trigger.name, trigger); getTriggersByEvent(trigger.event).add(trigger); } - + public void deregisterTrigger(List triggers) { + triggers.forEach(this::deregisterTrigger); + } public void deregisterTrigger(SceneTrigger trigger) { - this.triggers.remove(trigger.name); getTriggersByEvent(trigger.event).remove(trigger); } public void resetTriggers(int eventId) { @@ -205,7 +204,17 @@ public class SceneScriptManager { } } } - + + public void addGroupSuite(SceneGroup group, SceneSuite suite){ + spawnMonstersInGroup(group, suite); + spawnGadgetsInGroup(group, suite); + registerTrigger(suite.sceneTriggers); + } + public void removeGroupSuite(SceneGroup group, SceneSuite suite){ + removeMonstersInGroup(group, suite); + removeGadgetsInGroup(group, suite); + deregisterTrigger(suite.sceneTriggers); + } public void spawnGadgetsInGroup(SceneGroup group, int suiteIndex) { spawnGadgetsInGroup(group, group.getSuiteByIndex(suiteIndex)); } @@ -241,7 +250,6 @@ public class SceneScriptManager { } this.addEntities(suite.sceneMonsters.stream() .map(mob -> createMonster(group.id, group.block_id, mob)).toList()); - } public void spawnMonstersInGroup(SceneGroup group) { @@ -326,7 +334,7 @@ public class SceneScriptManager { try{ return func.call(ScriptLoader.getScriptLibLua(), args); }catch (LuaError error){ - ScriptLib.logger.error("[LUA] call trigger failed {},{},{}",name,args,error.getMessage()); + ScriptLib.logger.error("[LUA] call trigger failed {},{}",name,args,error); return LuaValue.valueOf(-1); } } @@ -388,6 +396,7 @@ public class SceneScriptManager { entity.setGroupId(groupId); entity.setBlockId(blockId); entity.setConfigId(monster.config_id); + entity.setPoseId(monster.pose_id); this.getScriptMonsterSpawnService() .onMonsterCreatedListener.forEach(action -> action.onNotify(entity)); @@ -410,4 +419,28 @@ public class SceneScriptManager { public PhTree getBlocksIndex() { return meta.sceneBlockIndex; } + public void removeMonstersInGroup(SceneGroup group, SceneSuite suite) { + var configSet = suite.sceneMonsters.stream() + .map(m -> m.config_id) + .collect(Collectors.toSet()); + var toRemove = getScene().getEntities().values().stream() + .filter(e -> e instanceof EntityMonster) + .filter(e -> e.getGroupId() == group.id) + .filter(e -> configSet.contains(e.getConfigId())) + .toList(); + + getScene().removeEntities(toRemove, VisionTypeOuterClass.VisionType.VISION_MISS); + } + public void removeGadgetsInGroup(SceneGroup group, SceneSuite suite) { + var configSet = suite.sceneGadgets.stream() + .map(m -> m.config_id) + .collect(Collectors.toSet()); + var toRemove = getScene().getEntities().values().stream() + .filter(e -> e instanceof EntityGadget) + .filter(e -> e.getGroupId() == group.id) + .filter(e -> configSet.contains(e.getConfigId())) + .toList(); + + getScene().removeEntities(toRemove, VisionTypeOuterClass.VisionType.VISION_MISS); + } } diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLib.java b/src/main/java/emu/grasscutter/scripts/ScriptLib.java index 7e67d8862..631250c90 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLib.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLib.java @@ -1,10 +1,11 @@ package emu.grasscutter.scripts; -import emu.grasscutter.game.dungeons.DungeonChallenge; +import emu.grasscutter.game.dungeons.challenge.DungeonChallenge; import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.gadget.GadgetWorktop; +import emu.grasscutter.game.dungeons.challenge.factory.ChallengeFactory; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneRegion; import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify; @@ -159,48 +160,102 @@ public class ScriptLib { if (group == null || group.monsters == null) { return 1; } - + var suiteData = group.getSuiteByIndex(suite); + if(suiteData == null){ + return 1; + } // avoid spawn wrong monster if(getSceneScriptManager().getScene().getChallenge() != null) if(!getSceneScriptManager().getScene().getChallenge().inProgress() || getSceneScriptManager().getScene().getChallenge().getGroup().id != groupId){ return 0; } - this.getSceneScriptManager().spawnMonstersInGroup(group, suite); - + this.getSceneScriptManager().addGroupSuite(group, suiteData); + + return 0; + } + public int GoToGroupSuite(int groupId, int suite) { + logger.debug("[LUA] Call GoToGroupSuite with {},{}", + groupId,suite); + SceneGroup group = getSceneScriptManager().getGroupById(groupId); + if (group == null || group.monsters == null) { + return 1; + } + var suiteData = group.getSuiteByIndex(suite); + if(suiteData == null){ + return 1; + } + + for(var suiteItem : group.suites){ + if(suiteData == suiteItem){ + continue; + } + this.getSceneScriptManager().removeGroupSuite(group, suiteItem); + } + this.getSceneScriptManager().addGroupSuite(group, suiteData); + + return 0; + } + public int RemoveExtraGroupSuite(int groupId, int suite) { + logger.debug("[LUA] Call RemoveExtraGroupSuite with {},{}", + groupId,suite); + + SceneGroup group = getSceneScriptManager().getGroupById(groupId); + if (group == null || group.monsters == null) { + return 1; + } + var suiteData = group.getSuiteByIndex(suite); + if(suiteData == null){ + return 1; + } + + this.getSceneScriptManager().removeGroupSuite(group, suiteData); + + return 0; + } + public int KillExtraGroupSuite(int groupId, int suite) { + logger.debug("[LUA] Call KillExtraGroupSuite with {},{}", + groupId,suite); + + SceneGroup group = getSceneScriptManager().getGroupById(groupId); + if (group == null || group.monsters == null) { + return 1; + } + var suiteData = group.getSuiteByIndex(suite); + if(suiteData == null){ + return 1; + } + + this.getSceneScriptManager().removeGroupSuite(group, suiteData); + return 0; } - // param3 (probably time limit for timed dungeons) public int ActiveChallenge(int challengeId, int challengeIndex, int timeLimitOrGroupId, int groupId, int objectiveKills, int param5) { logger.debug("[LUA] Call ActiveChallenge with {},{},{},{},{},{}", challengeId,challengeIndex,timeLimitOrGroupId,groupId,objectiveKills,param5); - SceneGroup group = getSceneScriptManager().getGroupById(groupId); - var objective = objectiveKills; + var challenge = ChallengeFactory.getChallenge( + challengeId, + challengeIndex, + timeLimitOrGroupId, + groupId, + objectiveKills, + param5, + getSceneScriptManager().getScene(), + getCurrentGroup().get() + ); - if(group == null){ - group = getSceneScriptManager().getGroupById(timeLimitOrGroupId); - objective = groupId; - } - - if (group == null || group.monsters == null) { + if(challenge == null){ return 1; } - if(getSceneScriptManager().getScene().getChallenge() != null && - getSceneScriptManager().getScene().getChallenge().inProgress()) - { - return 0; + if(challenge instanceof DungeonChallenge dungeonChallenge){ + // set if tower first stage (6-1) + dungeonChallenge.setStage(getSceneScriptManager().getVariables().getOrDefault("stage", -1) == 0); } - DungeonChallenge challenge = new DungeonChallenge(getSceneScriptManager().getScene(), - group, challengeId, challengeIndex, objective); - // set if tower first stage (6-1) - challenge.setStage(getSceneScriptManager().getVariables().getOrDefault("stage", -1) == 0); - getSceneScriptManager().getScene().setChallenge(challenge); - challenge.start(); return 0; } @@ -257,7 +312,7 @@ public class ScriptLib { public int GetRegionEntityCount(LuaTable table) { logger.debug("[LUA] Call GetRegionEntityCount with {}", - table); + printTable(table)); int regionId = table.get("region_eid").toint(); int entityType = table.get("entity_type").toint(); @@ -280,9 +335,8 @@ public class ScriptLib { // TODO record time return 0; } - public int GetGroupMonsterCount(int var1){ - logger.debug("[LUA] Call GetGroupMonsterCount with {}", - var1); + public int GetGroupMonsterCount(){ + logger.debug("[LUA] Call GetGroupMonsterCount "); return (int) getSceneScriptManager().getScene().getEntities().values().stream() .filter(e -> e instanceof EntityMonster && @@ -328,7 +382,7 @@ public class ScriptLib { var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId.toint()); if(entity == null){ - return 1; + return 0; } getSceneScriptManager().getScene().killEntity(entity, 0); return 0; @@ -398,8 +452,13 @@ public class ScriptLib { public int GetGadgetStateByConfigId(int groupId, int configId){ logger.debug("[LUA] Call GetGadgetStateByConfigId with {},{}", groupId, configId); + + if(groupId == 0){ + groupId = getCurrentGroup().get().id; + } + final int realGroupId = groupId; var gadget = getSceneScriptManager().getScene().getEntities().values().stream() - .filter(g -> g instanceof EntityGadget entityGadget && entityGadget.getGroupId() == groupId) + .filter(g -> g instanceof EntityGadget entityGadget && entityGadget.getGroupId() == realGroupId) .filter(g -> g.getConfigId() == configId) .findFirst(); if(gadget.isEmpty()){ @@ -409,8 +468,8 @@ public class ScriptLib { } public int MarkPlayerAction(int var1, int var2, int var3, int var4){ - logger.debug("[LUA] Call MarkPlayerAction with {},{}", - var1, var2); + logger.debug("[LUA] Call MarkPlayerAction with {},{},{},{}", + var1, var2,var3,var4); return 0; } diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java b/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java index ca37ac953..3b9f2bf7c 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java @@ -10,4 +10,5 @@ public class SceneGadget extends SceneObject{ public int state; public int point_type; public SceneBossChest boss_chest; + public int interact_id; } diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java index 197b80848..9275706a4 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java @@ -73,7 +73,7 @@ public class SceneGroup { return bindings; } - public SceneGroup load(int sceneId){ + public synchronized SceneGroup load(int sceneId){ if(loaded){ return this; } @@ -118,6 +118,7 @@ public class SceneGroup { garbages = new SceneGarbage(); if (garbagesTable.checktable().get("gadgets") != LuaValue.NIL) { garbages.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, garbagesTable.checktable().get("gadgets").checktable()); + garbages.gadgets.forEach(m -> m.group = this); } } diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneMonster.java b/src/main/java/emu/grasscutter/scripts/data/SceneMonster.java index 02435d800..070a87fee 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneMonster.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneMonster.java @@ -7,4 +7,6 @@ import lombok.ToString; @Setter public class SceneMonster extends SceneObject{ public int monster_id; + public int pose_id; + public int drop_id; } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketChallengeDataNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketChallengeDataNotify.java index 452ca7118..2a133149d 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketChallengeDataNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketChallengeDataNotify.java @@ -1,13 +1,13 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.game.dungeons.DungeonChallenge; +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.ChallengeDataNotifyOuterClass.ChallengeDataNotify; public class PacketChallengeDataNotify extends BasePacket { - - public PacketChallengeDataNotify(DungeonChallenge challenge, int index, int value) { + + public PacketChallengeDataNotify(WorldChallenge challenge, int index, int value) { super(PacketOpcodes.ChallengeDataNotify); ChallengeDataNotify proto = ChallengeDataNotify.newBuilder() diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonChallengeBeginNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonChallengeBeginNotify.java index 0c52c9d04..c02f41119 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonChallengeBeginNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonChallengeBeginNotify.java @@ -1,23 +1,22 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.game.dungeons.DungeonChallenge; +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.DungeonChallengeBeginNotifyOuterClass.DungeonChallengeBeginNotify; public class PacketDungeonChallengeBeginNotify extends BasePacket { - public PacketDungeonChallengeBeginNotify(DungeonChallenge challenge) { + public PacketDungeonChallengeBeginNotify(WorldChallenge challenge) { super(PacketOpcodes.DungeonChallengeBeginNotify, true); DungeonChallengeBeginNotify proto = DungeonChallengeBeginNotify.newBuilder() .setChallengeId(challenge.getChallengeId()) .setChallengeIndex(challenge.getChallengeIndex()) .setGroupId(challenge.getGroup().id) - .addParamList(challenge.getObjective()) - .addParamList(challenge.getTimeLimit()) + .addAllParamList(challenge.getParamList()) .build(); - + this.setData(proto); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonChallengeFinishNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonChallengeFinishNotify.java index a44c16778..22cd862cf 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonChallengeFinishNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonChallengeFinishNotify.java @@ -1,13 +1,13 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.game.dungeons.DungeonChallenge; +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.DungeonChallengeFinishNotifyOuterClass.DungeonChallengeFinishNotify; public class PacketDungeonChallengeFinishNotify extends BasePacket { - - public PacketDungeonChallengeFinishNotify(DungeonChallenge challenge) { + + public PacketDungeonChallengeFinishNotify(WorldChallenge challenge) { super(PacketOpcodes.DungeonChallengeFinishNotify, true); DungeonChallengeFinishNotify proto = DungeonChallengeFinishNotify.newBuilder() @@ -15,7 +15,7 @@ public class PacketDungeonChallengeFinishNotify extends BasePacket { .setIsSuccess(challenge.isSuccess()) .setUnk1(2) .build(); - + this.setData(proto); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonSettleNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonSettleNotify.java index 56d844d8d..5e214b219 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonSettleNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonSettleNotify.java @@ -1,6 +1,6 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.game.dungeons.DungeonChallenge; +import emu.grasscutter.game.dungeons.challenge.WorldChallenge; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass.DungeonSettleNotify; @@ -9,7 +9,7 @@ import emu.grasscutter.net.proto.TowerLevelEndNotifyOuterClass.TowerLevelEndNoti public class PacketDungeonSettleNotify extends BasePacket { - public PacketDungeonSettleNotify(DungeonChallenge challenge) { + public PacketDungeonSettleNotify(WorldChallenge challenge) { super(PacketOpcodes.DungeonSettleNotify); DungeonSettleNotify proto = DungeonSettleNotify.newBuilder() @@ -22,10 +22,10 @@ public class PacketDungeonSettleNotify extends BasePacket { this.setData(proto); } - public PacketDungeonSettleNotify(DungeonChallenge challenge, - boolean canJump, - boolean hasNextLevel, - int nextFloorId + public PacketDungeonSettleNotify(WorldChallenge challenge, + boolean canJump, + boolean hasNextLevel, + int nextFloorId ) { super(PacketOpcodes.DungeonSettleNotify); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketLifeStateChangeNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketLifeStateChangeNotify.java index 75685a27e..37545d8ea 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketLifeStateChangeNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketLifeStateChangeNotify.java @@ -1,17 +1,23 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.props.LifeState; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.LifeStateChangeNotifyOuterClass.LifeStateChangeNotify; import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType; -import emu.grasscutter.net.proto.ServerBuffOuterClass.ServerBuff; - -import java.util.ArrayList; public class PacketLifeStateChangeNotify extends BasePacket { + public PacketLifeStateChangeNotify(GameEntity target, LifeState lifeState) { + super(PacketOpcodes.LifeStateChangeNotify); + + LifeStateChangeNotify proto = LifeStateChangeNotify.newBuilder() + .setEntityId(target.getId()) + .setLifeState(lifeState.getValue()) + .build(); + + this.setData(proto); + } public PacketLifeStateChangeNotify(GameEntity attacker, GameEntity target, LifeState lifeState) { super(PacketOpcodes.LifeStateChangeNotify);