Copy some files from Grasscutter-Quests

NOT completely finished, nor is it completely done. Protocol issues remain! (including lack of packet IDs)
This commit is contained in:
KingRainbow44
2023-04-01 18:06:30 -04:00
parent 262ee38ded
commit daa51e53b7
381 changed files with 10285 additions and 9150 deletions

View File

@@ -1,14 +1,14 @@
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import emu.grasscutter.utils.Utils;
public class BasicDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(Scene scene) {
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
scene.broadcastPacket(new PacketDungeonSettleNotify(scene.getChallenge()));
}
}
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import emu.grasscutter.utils.Utils;
public class BasicDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(Scene scene) {
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
scene.broadcastPacket(new PacketDungeonSettleNotify(scene.getChallenge()));
}
}

View File

@@ -1,18 +1,22 @@
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
import lombok.Getter;
public class DungeonEndStats {
@Getter private int killedMonsters;
@Getter private int timeTaken;
@Getter private int openChestCount;
@Getter private BaseDungeonResult.DungeonEndReason dungeonResult;
public DungeonEndStats(int killedMonsters, int timeTaken, int openChestCount, BaseDungeonResult.DungeonEndReason dungeonResult){
this.killedMonsters = killedMonsters;
this.timeTaken = timeTaken;
this.dungeonResult = dungeonResult;
this.openChestCount = openChestCount;
}
}
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
import lombok.Getter;
public class DungeonEndStats {
@Getter private int killedMonsters;
@Getter private int timeTaken;
@Getter private int openChestCount;
@Getter private BaseDungeonResult.DungeonEndReason dungeonResult;
public DungeonEndStats(
int killedMonsters,
int timeTaken,
int openChestCount,
BaseDungeonResult.DungeonEndReason dungeonResult) {
this.killedMonsters = killedMonsters;
this.timeTaken = timeTaken;
this.dungeonResult = dungeonResult;
this.openChestCount = openChestCount;
}
}

View File

@@ -1,315 +1,332 @@
package emu.grasscutter.game.dungeons;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.activity.trialavatar.TrialAvatarActivityHandler;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.ActivityType;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketDungeonWayPointNotify;
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter;
import lombok.NonNull;
import lombok.val;
import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* TODO handle time limits
* TODO handle respawn points
* TODO handle team wipes and respawns
* TODO check monster level and levelConfigMap
*/
public class DungeonManager {
@Getter private final Scene scene;
@Getter private final DungeonData dungeonData;
@Getter private final DungeonPassConfigData passConfigData;
@Getter private final int[] finishedConditions;
private final IntSet rewardedPlayers = new IntOpenHashSet();
private final Set<Integer> activeDungeonWayPoints = new HashSet<>();
private boolean ended = false;
private int newestWayPoint = 0;
@Getter private int startSceneTime = 0;
DungeonTrialTeam trialTeam = null;
public DungeonManager(@NonNull Scene scene, @NonNull DungeonData dungeonData) {
this.scene = scene;
this.dungeonData = dungeonData;
this.passConfigData = GameData.getDungeonPassConfigDataMap().get(dungeonData.getPassCond());
this.finishedConditions = new int[passConfigData.getConds().size()];
this.scene.setDungeonManager(this);
}
public void triggerEvent(DungeonPassConditionType conditionType, int... params) {
if (ended) {
return;
}
for (int i = 0; i < passConfigData.getConds().size(); i++) {
var cond = passConfigData.getConds().get(i);
if (conditionType == cond.getCondType()) {
if (getScene().getWorld().getServer().getDungeonSystem().triggerCondition(cond, params)) {
finishedConditions[i] = 1;
}
}
}
if (isFinishedSuccessfully()) {
finishDungeon();
}
}
public boolean isFinishedSuccessfully() {
return LogicType.calculate(passConfigData.getLogicType(), finishedConditions);
}
public int getLevelForMonster(int id) {
//TODO should use levelConfigMap? and how?
return dungeonData.getShowLevel();
}
public boolean activateRespawnPoint(int pointId) {
val respawnPoint = GameData.getScenePointEntryById(scene.getId(), pointId);
if (respawnPoint == null) {
Grasscutter.getLogger().warn("trying to activate unknown respawn point {}", pointId);
return false;
}
scene.broadcastPacket(new PacketDungeonWayPointNotify(activeDungeonWayPoints.add(pointId), activeDungeonWayPoints));
newestWayPoint = pointId;
Grasscutter.getLogger().debug("[unimplemented respawn] activated respawn point {}", pointId);
return true;
}
@Nullable
public Position getRespawnLocation() {
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
return null;
}
val pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
return pointData.getTranPos() != null ? pointData.getTranPos() : pointData.getPos();
}
public Position getRespawnRotation() {
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
return null;
}
val pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
return pointData.getRot() != null ? pointData.getRot() : null;
}
public boolean getStatueDrops(Player player, boolean useCondensed, int groupId) {
if (!isFinishedSuccessfully() || dungeonData.getRewardPreviewData() == null || dungeonData.getRewardPreviewData().getPreviewItems().length == 0) {
return false;
}
// Already rewarded
if (rewardedPlayers.contains(player.getUid())) {
return false;
}
if (!handleCost(player, useCondensed)) {
return false;
}
// Get and roll rewards.
List<GameItem> rewards = new ArrayList<>(this.rollRewards(useCondensed));
// Add rewards to player and send notification.
player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop);
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
rewardedPlayers.add(player.getUid());
scene.getScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_DUNGEON_REWARD_GET));
return true;
}
public boolean handleCost(Player player, boolean useCondensed) {
int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20;
if (resinCost == 0) {
return true;
}
if (useCondensed) {
// Check if condensed resin is usable here.
// For this, we use the following logic for now:
// The normal resin cost of the dungeon has to be 20.
if (resinCost != 20) {
return false;
}
// Spend the condensed resin and only proceed if the transaction succeeds.
return player.getResinManager().useCondensedResin(1);
} else if (dungeonData.getStatueCostID() == 106) {
// Spend the resin and only proceed if the transaction succeeds.
return player.getResinManager().useResin(resinCost);
}
return true;
}
private List<GameItem> rollRewards(boolean useCondensed) {
List<GameItem> rewards = new ArrayList<>();
int dungeonId = this.dungeonData.getId();
// If we have specific drop data for this dungeon, we use it.
if (GameData.getDungeonDropDataMap().containsKey(dungeonId)) {
List<DungeonDropEntry> dropEntries = GameData.getDungeonDropDataMap().get(dungeonId);
// Roll for each drop group.
for (var entry : dropEntries) {
// Determine the number of drops we get for this entry.
int start = entry.getCounts().get(0);
int end = entry.getCounts().get(entry.getCounts().size() - 1);
var candidateAmounts = IntStream.range(start, end + 1).boxed().collect(Collectors.toList());
int amount = Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
if (useCondensed) {
amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
}
// Double rewards in multiplay mode, if specified.
if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) {
amount *= 2;
}
// Roll items for this group.
// Here, we have to handle stacking, or the client will not display results correctly.
// For now, we use the following logic: If the possible drop item are a list of multiple items,
// we roll them separately. If not, we stack them. This should work out in practice, at least
// for the currently existing set of dungeons.
if (entry.getItems().size() == 1) {
rewards.add(new GameItem(entry.getItems().get(0), amount));
} else {
for (int i = 0; i < amount; i++) {
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
// int itemId = entry.getItems().get(itemIndex);
int itemId = Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities());
rewards.add(new GameItem(itemId, 1));
}
}
}
}
// Otherwise, we fall back to the preview data.
else {
Grasscutter.getLogger().info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId);
for (ItemParamData param : dungeonData.getRewardPreviewData().getPreviewItems()) {
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
}
}
return rewards;
}
public void applyTrialTeam(Player player) {
if (getDungeonData() == null) return;
switch (getDungeonData().getType()) {
// case DUNGEON_PLOT is handled by quest execs
case DUNGEON_ACTIVITY -> {
switch (getDungeonData().getPlayType()) {
case DUNGEON_PLAY_TYPE_TRIAL_AVATAR -> {
val activityHandler = player.getActivityManager()
.getActivityHandlerAs(ActivityType.NEW_ACTIVITY_TRIAL_AVATAR, TrialAvatarActivityHandler.class);
activityHandler.ifPresent(trialAvatarActivityHandler ->
this.trialTeam = trialAvatarActivityHandler.getTrialAvatarDungeonTeam());
}
}
}
case DUNGEON_ELEMENT_CHALLENGE -> {} // TODO
}
if(this.trialTeam != null) {
player.addTrialAvatarsForActivity(trialTeam.trialAvatarIds);
}
}
public void unsetTrialTeam(Player player){
if(this.trialTeam==null){
return;
}
player.removeTrialAvatarForActivity();
this.trialTeam = null;
}
public void startDungeon() {
this.startSceneTime = scene.getSceneTimeSeconds();
scene.getPlayers().forEach(p -> {
p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, dungeonData.getId());
applyTrialTeam(p);
});
}
public void finishDungeon() {
notifyEndDungeon(true);
endDungeon(BaseDungeonResult.DungeonEndReason.COMPLETED);
}
public void notifyEndDungeon(boolean successfully) {
scene.getPlayers().forEach(p -> {
// Quest trigger
p.getQuestManager().queueEvent(successfully ?
QuestContent.QUEST_CONTENT_FINISH_DUNGEON : QuestContent.QUEST_CONTENT_FAIL_DUNGEON,
dungeonData.getId());
// Battle pass trigger
if (dungeonData.getType().isCountsToBattlepass() && successfully) {
p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON);
}
});
scene.getScriptManager().callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
}
public void quitDungeon() {
notifyEndDungeon(false);
endDungeon(BaseDungeonResult.DungeonEndReason.QUIT);
}
public void failDungeon() {
notifyEndDungeon(false);
endDungeon(BaseDungeonResult.DungeonEndReason.FAILED);
}
public void endDungeon(BaseDungeonResult.DungeonEndReason endReason) {
if (scene.getDungeonSettleListeners() != null) {
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(this, endReason));
}
ended = true;
}
public void restartDungeon() {
this.scene.setKilledMonsterCount(0);
this.rewardedPlayers.clear();
Arrays.fill(finishedConditions, 0);
this.ended = false;
this.activeDungeonWayPoints.clear();
}
public void cleanUpScene() {
this.scene.setDungeonManager(null);
this.scene.setKilledMonsterCount(0);
}
}
package emu.grasscutter.game.dungeons;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.excels.dungeon.DungeonData;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
import emu.grasscutter.game.activity.trialavatar.TrialAvatarActivityHandler;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.ActivityType;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketDungeonWayPointNotify;
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.annotation.Nullable;
import lombok.Getter;
import lombok.NonNull;
import lombok.val;
/**
* TODO handle time limits TODO handle respawn points TODO handle team wipes and respawns TODO check
* monster level and levelConfigMap
*/
public class DungeonManager {
@Getter private final Scene scene;
@Getter private final DungeonData dungeonData;
@Getter private final DungeonPassConfigData passConfigData;
@Getter private final int[] finishedConditions;
private final IntSet rewardedPlayers = new IntOpenHashSet();
private final Set<Integer> activeDungeonWayPoints = new HashSet<>();
private boolean ended = false;
private int newestWayPoint = 0;
@Getter private int startSceneTime = 0;
DungeonTrialTeam trialTeam = null;
public DungeonManager(@NonNull Scene scene, @NonNull DungeonData dungeonData) {
this.scene = scene;
this.dungeonData = dungeonData;
this.passConfigData = GameData.getDungeonPassConfigDataMap().get(dungeonData.getPassCond());
this.finishedConditions = new int[passConfigData.getConds().size()];
this.scene.setDungeonManager(this);
}
public void triggerEvent(DungeonPassConditionType conditionType, int... params) {
if (ended) {
return;
}
for (int i = 0; i < passConfigData.getConds().size(); i++) {
var cond = passConfigData.getConds().get(i);
if (conditionType == cond.getCondType()) {
if (getScene().getWorld().getServer().getDungeonSystem().triggerCondition(cond, params)) {
finishedConditions[i] = 1;
}
}
}
if (isFinishedSuccessfully()) {
finishDungeon();
}
}
public boolean isFinishedSuccessfully() {
return LogicType.calculate(passConfigData.getLogicType(), finishedConditions);
}
public int getLevelForMonster(int id) {
// TODO should use levelConfigMap? and how?
return dungeonData.getShowLevel();
}
public boolean activateRespawnPoint(int pointId) {
val respawnPoint = GameData.getScenePointEntryById(scene.getId(), pointId);
if (respawnPoint == null) {
Grasscutter.getLogger().warn("trying to activate unknown respawn point {}", pointId);
return false;
}
scene.broadcastPacket(
new PacketDungeonWayPointNotify(
activeDungeonWayPoints.add(pointId), activeDungeonWayPoints));
newestWayPoint = pointId;
Grasscutter.getLogger().debug("[unimplemented respawn] activated respawn point {}", pointId);
return true;
}
@Nullable public Position getRespawnLocation() {
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
return null;
}
val pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
return pointData.getTranPos() != null ? pointData.getTranPos() : pointData.getPos();
}
public Position getRespawnRotation() {
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
return null;
}
val pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
return pointData.getRot() != null ? pointData.getRot() : null;
}
public boolean getStatueDrops(Player player, boolean useCondensed, int groupId) {
if (!isFinishedSuccessfully()
|| dungeonData.getRewardPreviewData() == null
|| dungeonData.getRewardPreviewData().getPreviewItems().length == 0) {
return false;
}
// Already rewarded
if (rewardedPlayers.contains(player.getUid())) {
return false;
}
if (!handleCost(player, useCondensed)) {
return false;
}
// Get and roll rewards.
List<GameItem> rewards = new ArrayList<>(this.rollRewards(useCondensed));
// Add rewards to player and send notification.
player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop);
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
rewardedPlayers.add(player.getUid());
scene.getScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_DUNGEON_REWARD_GET));
return true;
}
public boolean handleCost(Player player, boolean useCondensed) {
int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20;
if (resinCost == 0) {
return true;
}
if (useCondensed) {
// Check if condensed resin is usable here.
// For this, we use the following logic for now:
// The normal resin cost of the dungeon has to be 20.
if (resinCost != 20) {
return false;
}
// Spend the condensed resin and only proceed if the transaction succeeds.
return player.getResinManager().useCondensedResin(1);
} else if (dungeonData.getStatueCostID() == 106) {
// Spend the resin and only proceed if the transaction succeeds.
return player.getResinManager().useResin(resinCost);
}
return true;
}
private List<GameItem> rollRewards(boolean useCondensed) {
List<GameItem> rewards = new ArrayList<>();
int dungeonId = this.dungeonData.getId();
// If we have specific drop data for this dungeon, we use it.
if (GameData.getDungeonDropDataMap().containsKey(dungeonId)) {
List<DungeonDropEntry> dropEntries = GameData.getDungeonDropDataMap().get(dungeonId);
// Roll for each drop group.
for (var entry : dropEntries) {
// Determine the number of drops we get for this entry.
int start = entry.getCounts().get(0);
int end = entry.getCounts().get(entry.getCounts().size() - 1);
var candidateAmounts = IntStream.range(start, end + 1).boxed().collect(Collectors.toList());
int amount = Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
if (useCondensed) {
amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
}
// Double rewards in multiplay mode, if specified.
if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) {
amount *= 2;
}
// Roll items for this group.
// Here, we have to handle stacking, or the client will not display results correctly.
// For now, we use the following logic: If the possible drop item are a list of multiple
// items,
// we roll them separately. If not, we stack them. This should work out in practice, at
// least
// for the currently existing set of dungeons.
if (entry.getItems().size() == 1) {
rewards.add(new GameItem(entry.getItems().get(0), amount));
} else {
for (int i = 0; i < amount; i++) {
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
// int itemId = entry.getItems().get(itemIndex);
int itemId =
Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities());
rewards.add(new GameItem(itemId, 1));
}
}
}
}
// Otherwise, we fall back to the preview data.
else {
Grasscutter.getLogger()
.info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId);
for (ItemParamData param : dungeonData.getRewardPreviewData().getPreviewItems()) {
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
}
}
return rewards;
}
public void applyTrialTeam(Player player) {
if (getDungeonData() == null) return;
switch (getDungeonData().getType()) {
// case DUNGEON_PLOT is handled by quest execs
case DUNGEON_ACTIVITY -> {
switch (getDungeonData().getPlayType()) {
case DUNGEON_PLAY_TYPE_TRIAL_AVATAR -> {
val activityHandler =
player
.getActivityManager()
.getActivityHandlerAs(
ActivityType.NEW_ACTIVITY_TRIAL_AVATAR, TrialAvatarActivityHandler.class);
activityHandler.ifPresent(
trialAvatarActivityHandler ->
this.trialTeam = trialAvatarActivityHandler.getTrialAvatarDungeonTeam());
}
}
}
case DUNGEON_ELEMENT_CHALLENGE -> {} // TODO
}
if (this.trialTeam != null) {
player.getTeamManager().addTrialAvatars(trialTeam.trialAvatarIds);
}
}
public void unsetTrialTeam(Player player) {
if (this.trialTeam == null) {
return;
}
player.getTeamManager().removeTrialAvatar();
this.trialTeam = null;
}
public void startDungeon() {
this.startSceneTime = scene.getSceneTimeSeconds();
scene
.getPlayers()
.forEach(
p -> {
p.getQuestManager()
.queueEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, dungeonData.getId());
applyTrialTeam(p);
});
}
public void finishDungeon() {
notifyEndDungeon(true);
endDungeon(BaseDungeonResult.DungeonEndReason.COMPLETED);
}
public void notifyEndDungeon(boolean successfully) {
scene
.getPlayers()
.forEach(
p -> {
// Quest trigger
p.getQuestManager()
.queueEvent(
successfully
? QuestContent.QUEST_CONTENT_FINISH_DUNGEON
: QuestContent.QUEST_CONTENT_FAIL_DUNGEON,
dungeonData.getId());
// Battle pass trigger
if (dungeonData.getType().isCountsToBattlepass() && successfully) {
p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON);
}
});
scene
.getScriptManager()
.callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
}
public void quitDungeon() {
notifyEndDungeon(false);
endDungeon(BaseDungeonResult.DungeonEndReason.QUIT);
}
public void failDungeon() {
notifyEndDungeon(false);
endDungeon(BaseDungeonResult.DungeonEndReason.FAILED);
}
public void endDungeon(BaseDungeonResult.DungeonEndReason endReason) {
if (scene.getDungeonSettleListeners() != null) {
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(this, endReason));
}
ended = true;
}
public void restartDungeon() {
this.scene.setKilledMonsterCount(0);
this.rewardedPlayers.clear();
Arrays.fill(finishedConditions, 0);
this.ended = false;
this.activeDungeonWayPoints.clear();
}
public void cleanUpScene() {
this.scene.setDungeonManager(null);
this.scene.setKilledMonsterCount(0);
}
}

View File

@@ -1,7 +1,7 @@
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
public interface DungeonSettleListener {
void onDungeonSettle(Scene scene);
}
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
public interface DungeonSettleListener {
void onDungeonSettle(Scene scene);
}

View File

@@ -3,12 +3,8 @@ package emu.grasscutter.game.dungeons;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.ScenePointEntry;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.quest.enums.QuestTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.server.game.BaseGameSystem;
@@ -18,7 +14,7 @@ import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp;
import emu.grasscutter.utils.Position;
import java.util.List;
public class DungeonSystem extends BaseGameSystem {
public final class DungeonSystem extends BaseGameSystem {
private static final BasicDungeonSettleListener basicDungeonSettleObserver =
new BasicDungeonSettleListener();
@@ -27,7 +23,7 @@ public class DungeonSystem extends BaseGameSystem {
}
public void getEntryInfo(Player player, int pointId) {
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
var entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
if (entry == null) {
// Error
@@ -39,24 +35,24 @@ public class DungeonSystem extends BaseGameSystem {
}
public boolean enterDungeon(Player player, int pointId, int dungeonId) {
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
var data = GameData.getDungeonDataMap().get(dungeonId);
if (data == null) {
return false;
}
Grasscutter.getLogger()
.info(
.debug(
"{}({}) is trying to enter dungeon {}",
player.getNickname(),
player.getUid(),
dungeonId);
int sceneId = data.getSceneId();
var sceneId = data.getSceneId();
player.getScene().setPrevScene(sceneId);
if (player.getWorld().transferPlayerToScene(player, sceneId, data)) {
player.getScene().addDungeonSettleObserver(basicDungeonSettleObserver);
player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_ENTER_DUNGEON, data.getId());
player.getQuestManager().triggerEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, data.getId());
}
player.getScene().setPrevScenePoint(pointId);
@@ -67,13 +63,13 @@ public class DungeonSystem extends BaseGameSystem {
/** used in tower dungeons handoff */
public boolean handoffDungeon(
Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
var data = GameData.getDungeonDataMap().get(dungeonId);
if (data == null) {
return false;
}
Grasscutter.getLogger()
.info(
.debug(
"{}({}) is trying to enter tower dungeon {}",
player.getNickname(),
player.getUid(),
@@ -82,30 +78,32 @@ public class DungeonSystem extends BaseGameSystem {
if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
}
return true;
}
public void exitDungeon(Player player) {
Scene scene = player.getScene();
var scene = player.getScene();
if (scene == null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
return;
}
// Get previous scene
int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3;
var prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3;
// Get previous position
DungeonData dungeonData = scene.getDungeonData();
Position prevPos = new Position(GameConstants.START_POSITION);
var dungeonData = scene.getDungeonData();
var prevPos = new Position(GameConstants.START_POSITION);
if (dungeonData != null) {
ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint());
var entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint());
if (entry != null) {
prevPos.set(entry.getPointData().getTranPos());
}
}
// clean temp team if it has
player.getTeamManager().cleanTemporaryTeam();
player.getTowerManager().clearEntry();
@@ -114,9 +112,4 @@ public class DungeonSystem extends BaseGameSystem {
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
}
public void updateDailyDungeons() {
GameData.getScenePointEntries()
.forEach((id, entry) -> entry.getPointData().updateDailyDungeon());
}
}

View File

@@ -1,14 +1,13 @@
package emu.grasscutter.game.dungeons;
import emu.grasscutter.net.proto.TrialAvatarGrantRecordOuterClass.TrialAvatarGrantRecord;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
@Data
@AllArgsConstructor
public class DungeonTrialTeam {
List<Integer> trialAvatarIds;
TrialAvatarGrantRecord.GrantReason grantReason;
}
package emu.grasscutter.game.dungeons;
import emu.grasscutter.net.proto.TrialAvatarGrantRecordOuterClass.TrialAvatarGrantRecord;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class DungeonTrialTeam {
List<Integer> trialAvatarIds;
TrialAvatarGrantRecord.GrantReason grantReason;
}

View File

@@ -1,11 +1,10 @@
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface DungeonValue {
DungeonPassConditionType value();
}
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface DungeonValue {
DungeonPassConditionType value();
}

View File

@@ -1,213 +1,55 @@
package emu.grasscutter.game.dungeons.challenge;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.DataLoader;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.game.dungeons.DungeonDrop;
import emu.grasscutter.game.dungeons.DungeonDropEntry;
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.props.WatcherTriggerType;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.net.proto.ResinCostTypeOuterClass;
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 emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class DungeonChallenge extends WorldChallenge {
private static final Int2ObjectMap<List<DungeonDropEntry>> dungeonDropData =
new Int2ObjectOpenHashMap<>();
/** has more challenge */
private boolean stage;
private IntSet rewardedPlayers;
public DungeonChallenge(
Scene scene,
SceneGroup group,
int challengeId,
int challengeIndex,
List<Integer> paramList,
int timeLimit,
int goal,
List<ChallengeTrigger> challengeTriggers) {
super(scene, group, challengeId, challengeIndex, paramList, timeLimit, goal, challengeTriggers);
this.setRewardedPlayers(new IntOpenHashSet());
}
public static void initialize() {
// Read the data we need for dungeon rewards drops.
try {
DataLoader.loadList("DungeonDrop.json", DungeonDrop.class)
.forEach(
entry -> {
dungeonDropData.put(entry.getDungeonId(), entry.getDrops());
});
Grasscutter.getLogger().debug("Loaded {} dungeon drop data entries.", dungeonDropData.size());
} catch (Exception ex) {
Grasscutter.getLogger().error("Unable to load dungeon drop data.", ex);
}
}
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) {
var scene = this.getScene();
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(getScene()));
scene
.getScriptManager()
.callEvent(EventType.EVENT_DUNGEON_SETTLE, new ScriptArgs(this.isSuccess() ? 1 : 0));
// Battle pass trigger
scene
.getPlayers()
.forEach(
p ->
p.getBattlePassManager()
.triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON));
}
}
private List<GameItem> rollRewards(boolean useCondensed) {
List<GameItem> rewards = new ArrayList<>();
int dungeonId = this.getScene().getDungeonData().getId();
// If we have specific drop data for this dungeon, we use it.
if (dungeonDropData.containsKey(dungeonId)) {
List<DungeonDropEntry> dropEntries = dungeonDropData.get(dungeonId);
// Roll for each drop group.
for (var entry : dropEntries) {
// Determine the number of drops we get for this entry.
int start = entry.getCounts().get(0);
int end = entry.getCounts().get(entry.getCounts().size() - 1);
var candidateAmounts = IntStream.range(start, end + 1).boxed().collect(Collectors.toList());
int amount = Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
if (useCondensed) {
amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
}
// Double rewards in multiplay mode, if specified.
if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) {
amount *= 2;
}
// Roll items for this group.
// Here, we have to handle stacking, or the client will not display results correctly.
// For now, we use the following logic: If the possible drop item are a list of multiple
// items,
// we roll them separately. If not, we stack them. This should work out in practice, at
// least
// for the currently existing set of dungeons.
if (entry.getItems().size() == 1) {
rewards.add(new GameItem(entry.getItems().get(0), amount));
} else {
for (int i = 0; i < amount; i++) {
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
// int itemId = entry.getItems().get(itemIndex);
int itemId =
Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities());
rewards.add(new GameItem(itemId, 1));
}
}
}
}
// Otherwise, we fall back to the preview data.
else {
Grasscutter.getLogger()
.info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId);
for (ItemParamData param : getScene().getDungeonData().getRewardPreview().getPreviewItems()) {
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
}
}
return rewards;
}
public void getStatueDrops(Player player, GadgetInteractReq request) {
DungeonData dungeonData = getScene().getDungeonData();
int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20;
if (!isSuccess()
|| dungeonData == null
|| dungeonData.getRewardPreview() == null
|| dungeonData.getRewardPreview().getPreviewItems().length == 0) {
return;
}
// Already rewarded
if (getRewardedPlayers().contains(player.getUid())) {
return;
}
// Get rewards.
List<GameItem> rewards = new ArrayList<>();
if (request.getResinCostType()
== ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE) {
// Check if condensed resin is usable here.
// For this, we use the following logic for now:
// The normal resin cost of the dungeon has to be 20.
if (resinCost != 20) {
return;
}
// Spend the condensed resin and only proceed if the transaction succeeds.
if (!player.getResinManager().useCondensedResin(1)) return;
// Roll rewards.
rewards.addAll(this.rollRewards(true));
} else {
// Spend the resin and only proceed if the transaction succeeds.
if (!player.getResinManager().useResin(resinCost)) return;
// Roll rewards.
rewards.addAll(this.rollRewards(false));
}
// Add rewards to player and send notification.
player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop);
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
getRewardedPlayers().add(player.getUid());
}
}
package emu.grasscutter.game.dungeons.challenge;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public final class DungeonChallenge extends WorldChallenge {
/**
* has more challenge
*/
private boolean stage;
public DungeonChallenge(Scene scene, SceneGroup group,
int challengeId, int challengeIndex,
List<Integer> paramList,
int timeLimit, int goal,
List<ChallengeTrigger> challengeTriggers) {
super(scene, group, challengeId, challengeIndex, paramList, timeLimit, goal, challengeTriggers);
}
public boolean isStage() {
return stage;
}
public void setStage(boolean stage) {
this.stage = stage;
}
@Override
public void done() {
super.done();
this.getScene().triggerDungeonEvent(
DungeonPassConditionType.DUNGEON_COND_FINISH_CHALLENGE,
this.getChallengeId(), this.getChallengeIndex());
if (this.isSuccess())
this.settle();
}
private void settle() {
if (!stage) {
var scene = this.getScene();
/*if(this.isSuccess()){
scene.getDungeonManager().finishDungeon();
} else {
scene.getDungeonManager().failDungeon();
}*/
}
}
}

View File

@@ -1,19 +1,19 @@
package emu.grasscutter.game.dungeons.challenge.enums;
public enum ChallengeCondType {
CHALLENGE_COND_NONE, //00
CHALLENGE_COND_IN_TIME, //01
CHALLENGE_COND_ALL_TIME, //02
CHALLENGE_COND_KILL_COUNT, //03
CHALLENGE_COND_SURVIVE, //04
CHALLENGE_COND_TIME_INC, //05
CHALLENGE_COND_KILL_FAST, //06
CHALLENGE_COND_DOWN_LESS, //07
CHALLENGE_COND_BEATEN_LESS , //08
CHALLENGE_COND_UNNATURAL_COUNT , //09
CHALLENGE_COND_FROZEN_LESS , //10
CHALLENGE_COND_KILL_MONSTER , //11
CHALLENGE_COND_TRIGGER , //12
CHALLENGE_COND_GUARD_HP , //13
CHALLENGE_COND_TIME_DEC , //14
}
package emu.grasscutter.game.dungeons.challenge.enums;
public enum ChallengeCondType {
CHALLENGE_COND_NONE, // 00
CHALLENGE_COND_IN_TIME, // 01
CHALLENGE_COND_ALL_TIME, // 02
CHALLENGE_COND_KILL_COUNT, // 03
CHALLENGE_COND_SURVIVE, // 04
CHALLENGE_COND_TIME_INC, // 05
CHALLENGE_COND_KILL_FAST, // 06
CHALLENGE_COND_DOWN_LESS, // 07
CHALLENGE_COND_BEATEN_LESS, // 08
CHALLENGE_COND_UNNATURAL_COUNT, // 09
CHALLENGE_COND_FROZEN_LESS, // 10
CHALLENGE_COND_KILL_MONSTER, // 11
CHALLENGE_COND_TRIGGER, // 12
CHALLENGE_COND_GUARD_HP, // 13
CHALLENGE_COND_TIME_DEC, // 14
}

View File

@@ -1,9 +1,9 @@
package emu.grasscutter.game.dungeons.challenge.enums;
public enum ChallengeEventMarkType {
CHALLENGE_EVENT_NONE,
FLIGHT_TIME,
FLIGHT_GATHER_POINT,
SUMMER_TIME_SPRINT_BOAT_TIME,
SUMMER_TIME_SPRINT_BOAT_GATHER_POINT,
}
package emu.grasscutter.game.dungeons.challenge.enums;
public enum ChallengeEventMarkType {
CHALLENGE_EVENT_NONE,
FLIGHT_TIME,
FLIGHT_GATHER_POINT,
SUMMER_TIME_SPRINT_BOAT_TIME,
SUMMER_TIME_SPRINT_BOAT_GATHER_POINT,
}

View File

@@ -1,6 +1,6 @@
package emu.grasscutter.game.dungeons.challenge.enums;
public enum ChallengeRecordType {
CHALLENGE_RECORD_TYPE_NONE,
CHALLENGE_RECORD_TYPE_IN_TIME
}
package emu.grasscutter.game.dungeons.challenge.enums;
public enum ChallengeRecordType {
CHALLENGE_RECORD_TYPE_NONE,
CHALLENGE_RECORD_TYPE_IN_TIME
}

View File

@@ -1,27 +1,27 @@
package emu.grasscutter.game.dungeons.challenge.enums;
public enum ChallengeType {
CHALLENGE_NONE, //00
CHALLENGE_KILL_COUNT, //01
CHALLENGE_KILL_COUNT_IN_TIME, //02
CHALLENGE_SURVIVE, //03
CHALLENGE_TIME_FLY, //04
CHALLENGE_KILL_COUNT_FAST, //05
CHALLENGE_KILL_COUNT_FROZEN_LESS, //06
CHALLENGE_KILL_MONSTER_IN_TIME, //07
CHALLENGE_TRIGGER_IN_TIME, //08
CHALLENGE_GUARD_HP, //09
CHALLENGE_KILL_COUNT_GUARD_HP, //10
CHALLENGE_TRIGGER_IN_TIME_FLY , //11
//unknown if position and time match from here on
CHALLENGE_TRIGGER2_AVOID_TRIGGER1,
CHALLENGE_FATHER_SUCC_IN_TIME,
CHALLENGE_MONSTER_DAMAGE_COUNT,
CHALLENGE_ELEMENT_REACTION_COUNT,
CHALLENGE_FREEZE_ENEMY_IN_TIME,
CHALLENGE_CRYSTAL_ELEMENT_REACTION_COUNT,
CHALLENGE_SHEILD_ABSORB_DAMAGE_COUNT,
CHALLENGE_SWIRL_ELEMENT_REACTION_COUNT,
CHALLENGE_DIE_LESS_IN_TIME,
CHALLENGE_TRIGGER_COUNT,
}
package emu.grasscutter.game.dungeons.challenge.enums;
public enum ChallengeType {
CHALLENGE_NONE, // 00
CHALLENGE_KILL_COUNT, // 01
CHALLENGE_KILL_COUNT_IN_TIME, // 02
CHALLENGE_SURVIVE, // 03
CHALLENGE_TIME_FLY, // 04
CHALLENGE_KILL_COUNT_FAST, // 05
CHALLENGE_KILL_COUNT_FROZEN_LESS, // 06
CHALLENGE_KILL_MONSTER_IN_TIME, // 07
CHALLENGE_TRIGGER_IN_TIME, // 08
CHALLENGE_GUARD_HP, // 09
CHALLENGE_KILL_COUNT_GUARD_HP, // 10
CHALLENGE_TRIGGER_IN_TIME_FLY, // 11
// unknown if position and time match from here on
CHALLENGE_TRIGGER2_AVOID_TRIGGER1,
CHALLENGE_FATHER_SUCC_IN_TIME,
CHALLENGE_MONSTER_DAMAGE_COUNT,
CHALLENGE_ELEMENT_REACTION_COUNT,
CHALLENGE_FREEZE_ENEMY_IN_TIME,
CHALLENGE_CRYSTAL_ELEMENT_REACTION_COUNT,
CHALLENGE_SHEILD_ABSORB_DAMAGE_COUNT,
CHALLENGE_SWIRL_ELEMENT_REACTION_COUNT,
CHALLENGE_DIE_LESS_IN_TIME,
CHALLENGE_TRIGGER_COUNT,
}

View File

@@ -1,9 +1,9 @@
package emu.grasscutter.game.dungeons.challenge.enums;
public enum FatherChallengeProperty {
DURATION,
CUR_SUCC,
CUR_FAIL,
SUM_SUCC,
SUM_FAIL
}
package emu.grasscutter.game.dungeons.challenge.enums;
public enum FatherChallengeProperty {
DURATION,
CUR_SUCC,
CUR_FAIL,
SUM_SUCC,
SUM_FAIL
}

View File

@@ -1,34 +1,42 @@
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import lombok.val;
import java.util.List;
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_KILL_COUNT_GUARD_HP;
public class KillAndGuardChallengeFactoryHandler implements ChallengeFactoryHandler{
@Override
public boolean isThisType(ChallengeType challengeType) {
// ActiveChallenge with 1,188,234101003,12,3030,0
return challengeType == CHALLENGE_KILL_COUNT_GUARD_HP;
}
@Override /*TODO check param4 == monstesToKill*/
public WorldChallenge build(int challengeIndex, int challengeId, int groupId, int monstersToKill, int gadgetCFGId, int unused, Scene scene, SceneGroup group) {
val realGroup = scene.getScriptManager().getGroupById(groupId);
return new WorldChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(monstersToKill, 0),
0, // Limit
monstersToKill, // Goal
List.of(new KillMonsterCountTrigger(), new GuardTrigger(gadgetCFGId)));
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_KILL_COUNT_GUARD_HP;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
import lombok.val;
public class KillAndGuardChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(ChallengeType challengeType) {
// ActiveChallenge with 1,188,234101003,12,3030,0
return challengeType == CHALLENGE_KILL_COUNT_GUARD_HP;
}
@Override /*TODO check param4 == monstesToKill*/
public WorldChallenge build(
int challengeIndex,
int challengeId,
int groupId,
int monstersToKill,
int gadgetCFGId,
int unused,
Scene scene,
SceneGroup group) {
val realGroup = scene.getScriptManager().getGroupById(groupId);
return new WorldChallenge(
scene,
realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(monstersToKill, 0),
0, // Limit
monstersToKill, // Goal
List.of(new KillMonsterCountTrigger(), new GuardTrigger(gadgetCFGId)));
}
}

View File

@@ -1,32 +1,39 @@
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import lombok.val;
import java.util.List;
public class KillMonsterCountChallengeFactoryHandler implements ChallengeFactoryHandler{
@Override
public boolean isThisType(ChallengeType challengeType) {
// ActiveChallenge with 1, 1, 241033003, 15, 0, 0
return challengeType == ChallengeType.CHALLENGE_KILL_COUNT;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int groupId, int goal, int param5, int param6, Scene scene, SceneGroup group) {
val realGroup = scene.getScriptManager().getGroupById(groupId);
return new WorldChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(goal, groupId),
0, // Limit
goal, // Goal
List.of(new KillMonsterCountTrigger())
);
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
import lombok.val;
public class KillMonsterCountChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(ChallengeType challengeType) {
// ActiveChallenge with 1, 1, 241033003, 15, 0, 0
return challengeType == ChallengeType.CHALLENGE_KILL_COUNT;
}
@Override
public WorldChallenge build(
int challengeIndex,
int challengeId,
int groupId,
int goal,
int param5,
int param6,
Scene scene,
SceneGroup group) {
val realGroup = scene.getScriptManager().getGroupById(groupId);
return new WorldChallenge(
scene,
realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(goal, groupId),
0, // Limit
goal, // Goal
List.of(new KillMonsterCountTrigger()));
}
}

View File

@@ -1,33 +1,40 @@
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
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 lombok.val;
import java.util.List;
public class KillMonsterInTimeChallengeFactoryHandler implements ChallengeFactoryHandler{
@Override
public boolean isThisType(ChallengeType challengeType) {
// ActiveChallenge with 180, 72, 240, 133220161, 133220161, 0
return challengeType == ChallengeType.CHALLENGE_KILL_MONSTER_IN_TIME;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int timeLimit, int groupId, int targetCfgId, int param6, Scene scene, SceneGroup group) {
val realGroup = scene.getScriptManager().getGroupById(groupId);
return new WorldChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(timeLimit),
timeLimit, // Limit
0, // Goal
List.of(new KillMonsterTrigger(targetCfgId), new InTimeTrigger())
);
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
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;
import lombok.val;
public class KillMonsterInTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(ChallengeType challengeType) {
// ActiveChallenge with 180, 72, 240, 133220161, 133220161, 0
return challengeType == ChallengeType.CHALLENGE_KILL_MONSTER_IN_TIME;
}
@Override
public WorldChallenge build(
int challengeIndex,
int challengeId,
int timeLimit,
int groupId,
int targetCfgId,
int param6,
Scene scene,
SceneGroup group) {
val realGroup = scene.getScriptManager().getGroupById(groupId);
return new WorldChallenge(
scene,
realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(timeLimit),
timeLimit, // Limit
0, // Goal
List.of(new KillMonsterTrigger(targetCfgId), new InTimeTrigger()));
}
}

View File

@@ -1,35 +1,42 @@
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import lombok.val;
import java.util.List;
public class KillMonsterTimeChallengeFactoryHandler implements ChallengeFactoryHandler{
@Override
public boolean isThisType(ChallengeType challengeType) {
// ActiveChallenge with 180,180,45,133108061,1,0
// ActiveChallenge Fast with 1001, 5, 15, 240004005, 10, 0
return challengeType == ChallengeType.CHALLENGE_KILL_COUNT_IN_TIME ||
challengeType == ChallengeType.CHALLENGE_KILL_COUNT_FAST;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int timeLimit, int groupId, int targetCount, int param6, Scene scene, SceneGroup group) {
val realGroup = scene.getScriptManager().getGroupById(groupId);
return new WorldChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(targetCount, timeLimit),
timeLimit, // Limit
targetCount, // Goal
List.of(new KillMonsterCountTrigger(), new InTimeTrigger())
);
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
import lombok.val;
public class KillMonsterTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(ChallengeType challengeType) {
// ActiveChallenge with 180,180,45,133108061,1,0
// ActiveChallenge Fast with 1001, 5, 15, 240004005, 10, 0
return challengeType == ChallengeType.CHALLENGE_KILL_COUNT_IN_TIME
|| challengeType == ChallengeType.CHALLENGE_KILL_COUNT_FAST;
}
@Override
public WorldChallenge build(
int challengeIndex,
int challengeId,
int timeLimit,
int groupId,
int targetCount,
int param6,
Scene scene,
SceneGroup group) {
val realGroup = scene.getScriptManager().getGroupById(groupId);
return new WorldChallenge(
scene,
realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(targetCount, timeLimit),
timeLimit, // Limit
targetCount, // Goal
List.of(new KillMonsterCountTrigger(), new InTimeTrigger()));
}
}

View File

@@ -1,33 +1,40 @@
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.ForTimeTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_SURVIVE;
public class SurviveChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(ChallengeType challengeType) {
// grp 201055005
// ActiveChallenge with 100, 56, 60, 0, 0, 0
return challengeType == CHALLENGE_SURVIVE;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int timeToSurvive, int unused4, int unused5, int unused6, Scene scene, SceneGroup group) {
return new WorldChallenge(
scene, group,
challengeId, // Id
challengeIndex, // Index
List.of(timeToSurvive),
timeToSurvive, // Limit
0, // Goal
List.of(new ForTimeTrigger())
);
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_SURVIVE;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.ForTimeTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public class SurviveChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(ChallengeType challengeType) {
// grp 201055005
// ActiveChallenge with 100, 56, 60, 0, 0, 0
return challengeType == CHALLENGE_SURVIVE;
}
@Override
public WorldChallenge build(
int challengeIndex,
int challengeId,
int timeToSurvive,
int unused4,
int unused5,
int unused6,
Scene scene,
SceneGroup group) {
return new WorldChallenge(
scene,
group,
challengeId, // Id
challengeIndex, // Index
List.of(timeToSurvive),
timeToSurvive, // Limit
0, // Goal
List.of(new ForTimeTrigger()));
}
}

View File

@@ -1,36 +1,43 @@
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.TriggerGroupTriggerTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_TRIGGER_IN_TIME;
public class TriggerInTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(ChallengeType challengeType) {
// 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 challengeType == CHALLENGE_TRIGGER_IN_TIME;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int timeLimit, int param4, int triggerTag, int triggerCount, Scene scene, SceneGroup group) {
return new WorldChallenge(
scene, group,
challengeId, // Id
challengeIndex, // Index
List.of(timeLimit, triggerCount),
timeLimit, // Limit
triggerCount, // Goal
List.of(new InTimeTrigger(), new TriggerGroupTriggerTrigger(Integer.toString(triggerTag)))
);
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_TRIGGER_IN_TIME;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.TriggerGroupTriggerTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public class TriggerInTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(ChallengeType challengeType) {
// 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 challengeType == CHALLENGE_TRIGGER_IN_TIME;
}
@Override
public WorldChallenge build(
int challengeIndex,
int challengeId,
int timeLimit,
int param4,
int triggerTag,
int triggerCount,
Scene scene,
SceneGroup group) {
return new WorldChallenge(
scene,
group,
challengeId, // Id
challengeIndex, // Index
List.of(timeLimit, triggerCount),
timeLimit, // Limit
triggerCount, // Goal
List.of(new InTimeTrigger(), new TriggerGroupTriggerTrigger(Integer.toString(triggerTag))));
}
}

View File

@@ -1,13 +1,13 @@
package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
public class ForTimeTrigger extends ChallengeTrigger{
@Override
public void onCheckTimeout(WorldChallenge challenge) {
var current = challenge.getScene().getSceneTimeSeconds();
if(current - challenge.getStartedAt() > challenge.getTimeLimit()){
challenge.done();
}
}
}
package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
public class ForTimeTrigger extends ChallengeTrigger {
@Override
public void onCheckTimeout(WorldChallenge challenge) {
var current = challenge.getScene().getSceneTimeSeconds();
if (current - challenge.getStartedAt() > challenge.getTimeLimit()) {
challenge.done();
}
}
}

View File

@@ -1,23 +1,24 @@
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 KillMonsterCountTrigger 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();
}
}
}
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 KillMonsterCountTrigger 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();
}
}
}

View File

@@ -1,30 +1,31 @@
package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.scripts.data.SceneTrigger;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class TriggerGroupTriggerTrigger extends ChallengeTrigger{
String triggerTag;
@Override
public void onBegin(WorldChallenge challenge) {
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, challenge.getScore().get()));
}
@Override
public void onGroupTrigger(WorldChallenge challenge, SceneTrigger trigger) {
if(!triggerTag.equals(trigger.getTag())) {
return;
}
var newScore = challenge.increaseScore();
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, newScore));
if(newScore >= challenge.getGoal()){
challenge.done();
}
}
}
package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.scripts.data.SceneTrigger;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class TriggerGroupTriggerTrigger extends ChallengeTrigger {
String triggerTag;
@Override
public void onBegin(WorldChallenge challenge) {
challenge
.getScene()
.broadcastPacket(new PacketChallengeDataNotify(challenge, 2, challenge.getScore().get()));
}
@Override
public void onGroupTrigger(WorldChallenge challenge, SceneTrigger trigger) {
if (!triggerTag.equals(trigger.getTag())) {
return;
}
var newScore = challenge.increaseScore();
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, newScore));
if (newScore >= challenge.getGoal()) {
challenge.done();
}
}
}

View File

@@ -1,74 +1,77 @@
package emu.grasscutter.game.dungeons.dungeon_results;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass.DungeonSettleNotify;
import emu.grasscutter.net.proto.ParamListOuterClass;
import emu.grasscutter.utils.Utils;
import lombok.Getter;
public class BaseDungeonResult {
@Getter DungeonData dungeonData;
@Getter
DungeonEndStats dungeonStats;
public BaseDungeonResult(DungeonData dungeonData, DungeonEndStats dungeonStats){
this.dungeonData = dungeonData;
this.dungeonStats = dungeonStats;
}
protected void onProto(DungeonSettleNotify.Builder builder){ }
public final DungeonSettleNotify.Builder getProto(){
var success = dungeonStats.getDungeonResult().isSuccess();
var builder = DungeonSettleNotify.newBuilder()
.setDungeonId(dungeonData.getId())
.setIsSuccess(success)
.setCloseTime(getCloseTime())
.setResult(success ? 1 : 0);
// TODO check
if(dungeonData.getSettleShows()!=null) {
for (int i = 0; i < dungeonData.getSettleShows().size(); i++) {
var settle = dungeonData.getSettleShows().get(i);
builder.putSettleShow(i + 1,switch (settle) {
case SETTLE_SHOW_TIME_COST -> ParamListOuterClass.ParamList.newBuilder()
.addParamList(settle.getId())
.addParamList(dungeonStats.getTimeTaken())
.build();
case SETTLE_SHOW_KILL_MONSTER_COUNT -> ParamListOuterClass.ParamList.newBuilder()
.addParamList(settle.getId())
.addParamList(dungeonStats.getKilledMonsters())
.build();
default -> ParamListOuterClass.ParamList.newBuilder()
.addParamList(settle.getId())
.build();
});
}
}
//TODO handle settle show
onProto(builder);
return builder;
}
public int getCloseTime(){
return Utils.getCurrentSeconds() + switch (dungeonStats.getDungeonResult()){
case COMPLETED -> dungeonData.getSettleCountdownTime();
case FAILED -> dungeonData.getFailSettleCountdownTime();
case QUIT -> dungeonData.getQuitSettleCountdownTime();
};
}
public enum DungeonEndReason{
COMPLETED,
FAILED,
QUIT;
public boolean isSuccess(){
return this == COMPLETED;
}
}
}
package emu.grasscutter.game.dungeons.dungeon_results;
import emu.grasscutter.data.excels.dungeon.DungeonData;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass.DungeonSettleNotify;
import emu.grasscutter.net.proto.ParamListOuterClass;
import emu.grasscutter.utils.Utils;
import lombok.Getter;
public class BaseDungeonResult {
@Getter DungeonData dungeonData;
@Getter DungeonEndStats dungeonStats;
public BaseDungeonResult(DungeonData dungeonData, DungeonEndStats dungeonStats) {
this.dungeonData = dungeonData;
this.dungeonStats = dungeonStats;
}
protected void onProto(DungeonSettleNotify.Builder builder) {}
public final DungeonSettleNotify.Builder getProto() {
var success = dungeonStats.getDungeonResult().isSuccess();
var builder =
DungeonSettleNotify.newBuilder()
.setDungeonId(dungeonData.getId())
.setIsSuccess(success)
.setCloseTime(getCloseTime())
.setResult(success ? 1 : 0);
// TODO check
if (dungeonData.getSettleShows() != null) {
for (int i = 0; i < dungeonData.getSettleShows().size(); i++) {
var settle = dungeonData.getSettleShows().get(i);
builder.putSettleShow(
i + 1,
switch (settle) {
case SETTLE_SHOW_TIME_COST -> ParamListOuterClass.ParamList.newBuilder()
.addParamList(settle.getId())
.addParamList(dungeonStats.getTimeTaken())
.build();
case SETTLE_SHOW_KILL_MONSTER_COUNT -> ParamListOuterClass.ParamList.newBuilder()
.addParamList(settle.getId())
.addParamList(dungeonStats.getKilledMonsters())
.build();
default -> ParamListOuterClass.ParamList.newBuilder()
.addParamList(settle.getId())
.build();
});
}
}
// TODO handle settle show
onProto(builder);
return builder;
}
public int getCloseTime() {
return Utils.getCurrentSeconds()
+ switch (dungeonStats.getDungeonResult()) {
case COMPLETED -> dungeonData.getSettleCountdownTime();
case FAILED -> dungeonData.getFailSettleCountdownTime();
case QUIT -> dungeonData.getQuitSettleCountdownTime();
};
}
public enum DungeonEndReason {
COMPLETED,
FAILED,
QUIT;
public boolean isSuccess() {
return this == COMPLETED;
}
}
}

View File

@@ -1,50 +1,54 @@
package emu.grasscutter.game.dungeons.dungeon_results;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.tower.TowerManager;
import emu.grasscutter.net.proto.DungeonSettleExhibitionInfoOuterClass;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.TowerLevelEndNotifyOuterClass.TowerLevelEndNotify.ContinueStateType;
import emu.grasscutter.net.proto.TowerLevelEndNotifyOuterClass.TowerLevelEndNotify;
public class TowerResult extends BaseDungeonResult{
WorldChallenge challenge;
boolean canJump;
boolean hasNextLevel;
int nextFloorId;
public TowerResult(DungeonData dungeonData, DungeonEndStats dungeonStats, TowerManager towerManager, WorldChallenge challenge) {
super(dungeonData, dungeonStats);
this.challenge = challenge;
this.canJump = towerManager.hasNextFloor();
this.hasNextLevel = towerManager.hasNextLevel();
this.nextFloorId = hasNextLevel ? 0 : towerManager.getNextFloorId();
}
@Override
protected void onProto(DungeonSettleNotifyOuterClass.DungeonSettleNotify.Builder builder) {
var continueStatus = ContinueStateType.CONTINUE_STATE_TYPE_CAN_NOT_CONTINUE_VALUE;
if(challenge.isSuccess() && canJump){
continueStatus = hasNextLevel ? ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_LEVEL_VALUE
: ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_FLOOR_VALUE;
}
var towerLevelEndNotify = TowerLevelEndNotify.newBuilder()
.setIsSuccess(challenge.isSuccess())
.setContinueState(continueStatus)
.addFinishedStarCondList(1)
.addFinishedStarCondList(2)
.addFinishedStarCondList(3)
.addRewardItemList(ItemParamOuterClass.ItemParam.newBuilder()
.setItemId(201)
.setCount(1000)
.build())
;
if(nextFloorId > 0 && canJump){
towerLevelEndNotify.setNextFloorId(nextFloorId);
}
builder.setTowerLevelEndNotify(towerLevelEndNotify);
}
}
package emu.grasscutter.game.dungeons.dungeon_results;
import emu.grasscutter.data.excels.dungeon.DungeonData;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.tower.TowerManager;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.TowerLevelEndNotifyOuterClass.TowerLevelEndNotify;
import emu.grasscutter.net.proto.TowerLevelEndNotifyOuterClass.TowerLevelEndNotify.ContinueStateType;
public class TowerResult extends BaseDungeonResult {
WorldChallenge challenge;
boolean canJump;
boolean hasNextLevel;
int nextFloorId;
public TowerResult(
DungeonData dungeonData,
DungeonEndStats dungeonStats,
TowerManager towerManager,
WorldChallenge challenge) {
super(dungeonData, dungeonStats);
this.challenge = challenge;
this.canJump = towerManager.hasNextFloor();
this.hasNextLevel = towerManager.hasNextLevel();
this.nextFloorId = hasNextLevel ? 0 : towerManager.getNextFloorId();
}
@Override
protected void onProto(DungeonSettleNotifyOuterClass.DungeonSettleNotify.Builder builder) {
var continueStatus = ContinueStateType.CONTINUE_STATE_TYPE_CAN_NOT_CONTINUE_VALUE;
if (challenge.isSuccess() && canJump) {
continueStatus =
hasNextLevel
? ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_LEVEL_VALUE
: ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_FLOOR_VALUE;
}
var towerLevelEndNotify =
TowerLevelEndNotify.newBuilder()
.setIsSuccess(challenge.isSuccess())
.setContinueState(continueStatus)
.addFinishedStarCondList(1)
.addFinishedStarCondList(2)
.addFinishedStarCondList(3)
.addRewardItemList(
ItemParamOuterClass.ItemParam.newBuilder().setItemId(201).setCount(1000).build());
if (nextFloorId > 0 && canJump) {
towerLevelEndNotify.setNextFloorId(nextFloorId);
}
builder.setTowerLevelEndNotify(towerLevelEndNotify);
}
}

View File

@@ -1,23 +1,26 @@
package emu.grasscutter.game.dungeons.dungeon_results;
import emu.grasscutter.data.excels.DungeonData;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass;
import emu.grasscutter.net.proto.TrialAvatarFirstPassDungeonNotifyOuterClass.TrialAvatarFirstPassDungeonNotify;
public class TrialAvatarDungeonResult extends BaseDungeonResult {
int trialCharacterIndexId;
public TrialAvatarDungeonResult(DungeonData dungeonData, DungeonEndStats dungeonStats, int trialCharacterIndexId) {
super(dungeonData, dungeonStats);
this.trialCharacterIndexId = trialCharacterIndexId;
}
@Override
protected void onProto(DungeonSettleNotifyOuterClass.DungeonSettleNotify.Builder builder) {
if (dungeonStats.getDungeonResult() == DungeonEndReason.COMPLETED) { //TODO check if its the first pass(?)
builder.setTrialAvatarFirstPassDungeonNotify(TrialAvatarFirstPassDungeonNotify.newBuilder()
.setTrialAvatarIndexId(trialCharacterIndexId));
}
}
}
package emu.grasscutter.game.dungeons.dungeon_results;
import emu.grasscutter.data.excels.dungeon.DungeonData;
import emu.grasscutter.game.dungeons.DungeonEndStats;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass;
import emu.grasscutter.net.proto.TrialAvatarFirstPassDungeonNotifyOuterClass.TrialAvatarFirstPassDungeonNotify;
public class TrialAvatarDungeonResult extends BaseDungeonResult {
int trialCharacterIndexId;
public TrialAvatarDungeonResult(
DungeonData dungeonData, DungeonEndStats dungeonStats, int trialCharacterIndexId) {
super(dungeonData, dungeonStats);
this.trialCharacterIndexId = trialCharacterIndexId;
}
@Override
protected void onProto(DungeonSettleNotifyOuterClass.DungeonSettleNotify.Builder builder) {
if (dungeonStats.getDungeonResult()
== DungeonEndReason.COMPLETED) { // TODO check if its the first pass(?)
builder.setTrialAvatarFirstPassDungeonNotify(
TrialAvatarFirstPassDungeonNotify.newBuilder()
.setTrialAvatarIndexId(trialCharacterIndexId));
}
}
}

View File

@@ -1,7 +1,7 @@
package emu.grasscutter.game.dungeons.enums;
public enum DungeonEntrySatisfiedConditionType {
DUNGEON_ENTRY_CONDITION_NONE,
DUNGEON_ENTRY_CONDITION_LEVEL,
DUNGEON_ENTRY_CONDITION_QUEST
}
package emu.grasscutter.game.dungeons.enums;
public enum DungeonEntrySatisfiedConditionType {
DUNGEON_ENTRY_CONDITION_NONE,
DUNGEON_ENTRY_CONDITION_LEVEL,
DUNGEON_ENTRY_CONDITION_QUEST
}

View File

@@ -1,7 +1,7 @@
package emu.grasscutter.game.dungeons.enums;
public enum DungeonInvolveType {
INVOLVE_NONE,
INVOLVE_ONLY_SINGLE,
INVOLVE_SINGLE_MULTIPLE
}
package emu.grasscutter.game.dungeons.enums;
public enum DungeonInvolveType {
INVOLVE_NONE,
INVOLVE_ONLY_SINGLE,
INVOLVE_SINGLE_MULTIPLE
}

View File

@@ -1,27 +1,28 @@
package emu.grasscutter.game.dungeons.enums;
import emu.grasscutter.scripts.constants.IntValueEnum;
import lombok.Getter;
public enum DungeonPassConditionType implements IntValueEnum {
DUNGEON_COND_NONE(0),
DUNGEON_COND_KILL_MONSTER(3),
DUNGEON_COND_KILL_GROUP_MONSTER(5),
DUNGEON_COND_KILL_TYPE_MONSTER(7),
DUNGEON_COND_FINISH_QUEST(9),
DUNGEON_COND_KILL_MONSTER_COUNT(11), // TODO handle count
DUNGEON_COND_IN_TIME(13), // Missing triggers and tracking
DUNGEON_COND_FINISH_CHALLENGE(14),
DUNGEON_COND_END_MULTISTAGE_PLAY(15) // Missing
;
@Getter private final int id;
DungeonPassConditionType(int id){
this.id = id;
}
@Override
public int getValue() {
return id;
}
}
package emu.grasscutter.game.dungeons.enums;
import emu.grasscutter.scripts.constants.IntValueEnum;
import lombok.Getter;
public enum DungeonPassConditionType implements IntValueEnum {
DUNGEON_COND_NONE(0),
DUNGEON_COND_KILL_MONSTER(3),
DUNGEON_COND_KILL_GROUP_MONSTER(5),
DUNGEON_COND_KILL_TYPE_MONSTER(7),
DUNGEON_COND_FINISH_QUEST(9),
DUNGEON_COND_KILL_MONSTER_COUNT(11), // TODO handle count
DUNGEON_COND_IN_TIME(13), // Missing triggers and tracking
DUNGEON_COND_FINISH_CHALLENGE(14),
DUNGEON_COND_END_MULTISTAGE_PLAY(15) // Missing
;
@Getter private final int id;
DungeonPassConditionType(int id) {
this.id = id;
}
@Override
public int getValue() {
return id;
}
}

View File

@@ -1,7 +1,8 @@
package emu.grasscutter.game.dungeons.enums;
public enum DungeonPlayType {
DUNGEON_PLAY_TYPE_NONE,
DUNGEON_PLAY_TYPE_FOGGY_MAZE,
DUNGEON_PLAY_TYPE_MIST_TRIAL,
DUNGEON_PLAY_TYPE_TRIAL_AVATAR
}
package emu.grasscutter.game.dungeons.enums;
public enum DungeonPlayType {
DUNGEON_PLAY_TYPE_NONE,
DUNGEON_PLAY_TYPE_FOGGY_MAZE,
DUNGEON_PLAY_TYPE_MIST_TRIAL,
DUNGEON_PLAY_TYPE_TRIAL_AVATAR
}

View File

@@ -1,9 +1,9 @@
package emu.grasscutter.game.dungeons.enums;
public enum DungeonSubType {
DUNGEON_SUB_NONE,
DUNGEON_SUB_BOSS,
DUNGEON_SUB_TALENT,
DUNGEON_SUB_WEAPON,
DUNGEON_SUB_RELIQUARY
}
package emu.grasscutter.game.dungeons.enums;
public enum DungeonSubType {
DUNGEON_SUB_NONE,
DUNGEON_SUB_BOSS,
DUNGEON_SUB_TALENT,
DUNGEON_SUB_WEAPON,
DUNGEON_SUB_RELIQUARY
}

View File

@@ -1,49 +1,49 @@
package emu.grasscutter.game.dungeons.enums;
import lombok.Getter;
public enum DungeonType {
DUNGEON_NONE(false),
DUNGEON_PLOT(true),
DUNGEON_FIGHT(true),
DUNGEON_DAILY_FIGHT(false),
DUNGEON_WEEKLY_FIGHT(true),
DUNGEON_DISCARDED(false),
DUNGEON_TOWER(false),
DUNGEON_BOSS(true),
DUNGEON_ACTIVITY(false),
DUNGEON_EFFIGY(false),
DUNGEON_ELEMENT_CHALLENGE(true),
DUNGEON_THEATRE_MECHANICUS(false),
DUNGEON_FLEUR_FAIR(false),
DUNGEON_CHANNELLER_SLAB_LOOP(false),
DUNGEON_CHANNELLER_SLAB_ONE_OFF(false),
DUNGEON_BLITZ_RUSH(true),
DUNGEON_CHESS(false),
DUNGEON_SUMO_COMBAT(false),
DUNGEON_ROGUELIKE(false),
DUNGEON_HACHI(false),
DUNGEON_POTION(false),
DUNGEON_MINI_ELDRITCH(false),
DUNGEON_UGC(false),
DUNGEON_GCG(false),
DUNGEON_CRYSTAL_LINK(false),
DUNGEON_IRODORI_CHESS(false),
DUNGEON_ROGUE_DIARY(false),
DUNGEON_DREAMLAND(false),
DUNGEON_SUMMER_V2(true),
DUNGEON_MUQADAS_POTION(false),
DUNGEON_INSTABLE_SPRAY(false),
DUNGEON_WIND_FIELD(false),
DUNGEON_BIGWORLD_MIRROR(false),
DUNGEON_FUNGUS_FIGHTER_TRAINING(false),
DUNGEON_FUNGUS_FIGHTER_PLOT(false),
DUNGEON_EFFIGY_CHALLENGE_V2(false),
DUNGEON_CHAR_AMUSEMENT(false);
@Getter private final boolean countsToBattlepass;
DungeonType(boolean countsToBattlepass){
this.countsToBattlepass = countsToBattlepass;
}
}
package emu.grasscutter.game.dungeons.enums;
import lombok.Getter;
public enum DungeonType {
DUNGEON_NONE(false),
DUNGEON_PLOT(true),
DUNGEON_FIGHT(true),
DUNGEON_DAILY_FIGHT(false),
DUNGEON_WEEKLY_FIGHT(true),
DUNGEON_DISCARDED(false),
DUNGEON_TOWER(false),
DUNGEON_BOSS(true),
DUNGEON_ACTIVITY(false),
DUNGEON_EFFIGY(false),
DUNGEON_ELEMENT_CHALLENGE(true),
DUNGEON_THEATRE_MECHANICUS(false),
DUNGEON_FLEUR_FAIR(false),
DUNGEON_CHANNELLER_SLAB_LOOP(false),
DUNGEON_CHANNELLER_SLAB_ONE_OFF(false),
DUNGEON_BLITZ_RUSH(true),
DUNGEON_CHESS(false),
DUNGEON_SUMO_COMBAT(false),
DUNGEON_ROGUELIKE(false),
DUNGEON_HACHI(false),
DUNGEON_POTION(false),
DUNGEON_MINI_ELDRITCH(false),
DUNGEON_UGC(false),
DUNGEON_GCG(false),
DUNGEON_CRYSTAL_LINK(false),
DUNGEON_IRODORI_CHESS(false),
DUNGEON_ROGUE_DIARY(false),
DUNGEON_DREAMLAND(false),
DUNGEON_SUMMER_V2(true),
DUNGEON_MUQADAS_POTION(false),
DUNGEON_INSTABLE_SPRAY(false),
DUNGEON_WIND_FIELD(false),
DUNGEON_BIGWORLD_MIRROR(false),
DUNGEON_FUNGUS_FIGHTER_TRAINING(false),
DUNGEON_FUNGUS_FIGHTER_PLOT(false),
DUNGEON_EFFIGY_CHALLENGE_V2(false),
DUNGEON_CHAR_AMUSEMENT(false);
@Getter private final boolean countsToBattlepass;
DungeonType(boolean countsToBattlepass) {
this.countsToBattlepass = countsToBattlepass;
}
}

View File

@@ -1,12 +1,12 @@
package emu.grasscutter.game.dungeons.enums;
public enum DungunEntryType {
DUNGEN_ENTRY_TYPE_NONE ,
DUNGEN_ENTRY_TYPE_AVATAR_EXP ,
DUNGEN_ENTRY_TYPE_WEAPON_PROMOTE,
DUNGEN_ENTRY_TYPE_AVATAR_TALENT ,
DUNGEN_ENTRY_TYPE_RELIQUARY ,
DUNGEN_ENTRY_TYPE_SCOIN ,
DUNGEON_ENTRY_TYPE_OBSCURAE ,
DUNGEON_ENTRY_TYPE_NORMAL
}
package emu.grasscutter.game.dungeons.enums;
public enum DungunEntryType {
DUNGEN_ENTRY_TYPE_NONE,
DUNGEN_ENTRY_TYPE_AVATAR_EXP,
DUNGEN_ENTRY_TYPE_WEAPON_PROMOTE,
DUNGEN_ENTRY_TYPE_AVATAR_TALENT,
DUNGEN_ENTRY_TYPE_RELIQUARY,
DUNGEN_ENTRY_TYPE_SCOIN,
DUNGEON_ENTRY_TYPE_OBSCURAE,
DUNGEON_ENTRY_TYPE_NORMAL
}

View File

@@ -1,17 +1,17 @@
package emu.grasscutter.game.dungeons.enums;
import lombok.Getter;
public enum SettleShowType {
SETTLE_SHOW_NONE(0),
SETTLE_SHOW_TIME_COST(1),
SETTLE_SHOW_OPEN_CHEST_COUNT(2),
SETTLE_SHOW_KILL_MONSTER_COUNT(3),
SETTLE_SHOW_BLACKSCREEN(4);
@Getter private final int id;
SettleShowType(int id){
this.id = id;
}
}
package emu.grasscutter.game.dungeons.enums;
import lombok.Getter;
public enum SettleShowType {
SETTLE_SHOW_NONE(0),
SETTLE_SHOW_TIME_COST(1),
SETTLE_SHOW_OPEN_CHEST_COUNT(2),
SETTLE_SHOW_KILL_MONSTER_COUNT(3),
SETTLE_SHOW_BLACKSCREEN(4);
@Getter private final int id;
SettleShowType(int id) {
this.id = id;
}
}

View File

@@ -1,9 +1,9 @@
package emu.grasscutter.game.dungeons.handlers;
import emu.grasscutter.data.excels.DungeonPassConfigData;
public abstract class DungeonBaseHandler {
public abstract boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params);
}
package emu.grasscutter.game.dungeons.handlers;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
public abstract class DungeonBaseHandler {
public abstract boolean execute(
DungeonPassConfigData.DungeonPassCondition condition, int... params);
}

View File

@@ -1,17 +1,16 @@
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_NONE)
public class BaseCondition extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
// TODO Auto-generated method stub
return false;
}
}
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_NONE)
public class BaseCondition extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
// TODO Auto-generated method stub
return false;
}
}

View File

@@ -1,15 +1,15 @@
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_FINISH_CHALLENGE)
public class ConditionFinishChallenge extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0] || params[1] == condition.getParam()[0];
}
}
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_FINISH_CHALLENGE)
public class ConditionFinishChallenge extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0] || params[1] == condition.getParam()[0];
}
}

View File

@@ -1,15 +1,15 @@
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_FINISH_QUEST)
public class ConditionFinishQuest extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0];
}
}
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_FINISH_QUEST)
public class ConditionFinishQuest extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0];
}
}

View File

@@ -1,15 +1,15 @@
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_IN_TIME)
public class ConditionInTime extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] <= condition.getParam()[0];
}
}
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_IN_TIME)
public class ConditionInTime extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] <= condition.getParam()[0];
}
}

View File

@@ -1,15 +1,15 @@
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_KILL_GROUP_MONSTER)
public class ConditionKillGroupMonster extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0];
}
}
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_KILL_GROUP_MONSTER)
public class ConditionKillGroupMonster extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0];
}
}

View File

@@ -1,15 +1,15 @@
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_KILL_MONSTER)
public class ConditionKillMonster extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0];
}
}
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_KILL_MONSTER)
public class ConditionKillMonster extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0];
}
}

View File

@@ -1,15 +1,15 @@
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_KILL_MONSTER_COUNT)
public class ConditionKillMonsterCount extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] >= condition.getParam()[0];
}
}
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_KILL_MONSTER_COUNT)
public class ConditionKillMonsterCount extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] >= condition.getParam()[0];
}
}

View File

@@ -1,15 +1,15 @@
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_KILL_TYPE_MONSTER)
public class ConditionKillTypeMonster extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0];
}
}
package emu.grasscutter.game.dungeons.pass_condition;
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
import emu.grasscutter.game.dungeons.DungeonValue;
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
@DungeonValue(DungeonPassConditionType.DUNGEON_COND_KILL_TYPE_MONSTER)
public class ConditionKillTypeMonster extends DungeonBaseHandler {
@Override
public boolean execute(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
return params[0] == condition.getParam()[0];
}
}