mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2026-04-03 14:32:29 +02:00
Merge unstable into development (#2173)
* Remove more scene synchronized
* Fix worktop options not appearing
* Format code [skip actions]
* Fix delay with server tasks
* Format code [skip actions]
* Fully fix fairy clock (#2146)
* Fix scene transition
* fully fix fairy clock
* Re-add call to `Player#updatePlayerGameTime`
* Format code [skip actions]
* Initialize the script loader in `ResourceLoader#loadAll`
* Fix region removal checking
* Format code [skip actions]
* Use Lombok's `EqualsAndHashCode` for comparing scene regions
* Format code [skip actions]
* Move 'invalid gather object' to `trace`
* Add more information to the 'unknown condition handler' message
* Move invalid ability action to trace
* Make `KcpTunnel` public
* Validate the NPC being talked to
* Format code [skip actions]
* NPCs are not spawned server side; change logic to handle it
* Format code [skip actions]
* unload scene when there are no players (#2147)
* unload scene when there are no players
* Update src/main/java/emu/grasscutter/game/world/Scene.java
Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
---------
Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
* Check if a command should be copied or HTTP should be used
* Lint Code [skip actions]
* Fix character names rendering incorrectly
* Add basic troubleshooting command
* Implement handbook teleporting
also a few formatting changes and sort data by logical sense
* Fix listener `ConcurrentModificationException` issue
* Add color change to `Join the Community!`
* Lint Code [skip actions]
* Make clickable buttons appear clickable
* Remove 'Mechanicus' entities from the list of entities
* Format code [skip actions]
* Fix going back returning a blank screen
* Implement entity spawning
* Add setting level to entity card
* Add support for 'plain text' mode
* Make descriptions of objects scrollable
* Lint Code [skip actions]
* Format code [skip actions]
* Change the way existing hooks work
* Format code [skip actions]
* Upgrade Javalin to 5.5.0 & Fix project warnings
* Upgrade logging libraries
* Fix gacha mappings static file issue
* Add temporary backwards compatability for `ServerHelper`
* Format code [skip actions]
* Remove artifact signatures from VCS
* Fix forge queue data protocol definition
* Run `spotlessApply`
* Format code [skip actions]
* Download data required for building artifacts
* Add call for Facebook logins
* Add the wiki page as a submodule
* Format code [skip actions]
* Update translation (#2150)
* Update translation
* Update translation
* Separate the dispatch and game servers (pt. 1)
gacha is still broken, handbook still needs to be done
* Format code [skip actions]
* Separate the dispatch and game servers (pt. 2)
this commit fixes the gacha page
* Add description for '/troubleshoot'
* Set default avatar talent level to 10
* Separate the dispatch and game servers (pt. 3)
implement handbook across servers!
* Format code [skip actions]
* Update GitHub Actions to use 'download-file' over 'wget'
* Gm handbook lmao (#2149)
* Fix font issue
* Fix avatars
* Fix text overflow in commands
* Fix virtualized lists and items page 😭😭
* magix why 💀
* use hover style in all minicards
* button
* remove console.log
* lint
* Add icons
* magix asked
* Fix overflow padding issue
* Fix achievement text overflow
* remove icons from repo
* Change command icon
* Add the wiki page as a submodule
* total magix moment
* fix text overflow in commands
* Fix discord button
* Make text scale on Minicard
* import icons and font from another source
* Add hover effects to siebar buttons
* move font and readme to submodule repo
* Make data folder a submodule
* import icons and font from data submodule
* Update README.md
* total magix moment
* magix moment v2
* submodule change
* Import `.webp` files
* Resize `HomeButton`
* Fix 'Copy Command' reappearing after changing pages
---------
Co-authored-by: KingRainbow44 <kobedo11@gmail.com>
* Lint Code [skip actions]
* Download data for the build, not for the lint
* format imports
this is really just to see if build handbook works kek
* Implement proper handbook authentication (pt. 1)
* Implement proper handbook authentication (pt. 2)
* Format code [skip actions]
* Add quest data dumping for the handbook
* Change colors to fit _something suitable_
* Format code [skip actions]
* Fix force pushing to branches after linting
* Fix logic of `SetPlayerPropReq`
* Move more group loading to `trace`
* Add handbook IP authentication in hybrid mode
* Fix player level up not displaying on the client properly
* Format code [skip actions]
* Fix game time locking
* Format code [skip actions]
* Update player properties
* Format code [skip actions]
* Move `warn`s for groups to `debug`
* Fix player pausing
* Move more logs to `trace`
* Use `removeItemById` for deleting items via quests
* Clean up logger more
* Pause in-game time when the world is paused
* Format code [skip actions]
* More player property documentation
* Multi-threaded resource loading
* Format code [skip actions]
* Add quest widgets
* Add quests page (basic impl.)
* Add/fix colors
also fix tailwind
* Remove banned packets
client modifications already perform the job of blocking malicious packets from being executed, no point in having this if self-windy is wanted
* Re-add `BeginCameraSceneLookNotify`
* Fix being unable to attack (#2157)
* Add `PlayerOpenChestEvent`
* Add methods to get players from the server
* Add static methods to register an event handler
* Add `PlayerEnterDungeonEvent`
* Remove legacy documentation from `PlayerMoveEvent`
* Add `PlayerChatEvent`
* Add defaults to `Position`
* Clean up `.utils`
* Revert `Multi-threaded resource loading`
* Fix changing target UID when talking to the server
* Lint Code [skip actions]
* Format code [skip actions]
* fix NPC talk triggering main quest in 46101 (#2158)
Make it so that only talks where the param matches the talkId are checked.
* Format code [skip actions]
* Partially fix Chasing Shadows (#2159)
* Partially fix Chasing Shadows
* Go ahead and move it before the return before Magix tells me to.
* Format code [skip actions]
* Bring back period lol (#2160)
* Disable SNI for the HTTPS server
* Add `EntityCreationEvent`
* Add initial startup message
this is so the server appears like its preparing to start
* Format code [skip actions]
* Enable debug mode for plugin loggers if enabled for the primary logger
* Add documentation about `WorldAreaConfigData`
* Make more fields in excels accessible
* Remove deprecated fields from `GetShopRsp`
* Run `spotlessApply` on definitions
* Add `PlayerEnterAreaEvent`
* Optimize event calls
* Fix event invokes
* Format code [skip actions]
* Remove manual autofinish for main quests. (#2162)
* Add world areas to the textmap cache
* Format code [skip actions]
* Don't overdefine variables in extended classes (#2163)
* Add dumper for world areas
* Format code [skip actions]
* instantiate personalLineList (#2165)
* Fix protocol definitions
thank you Nazrin! (+ hiro for raw definitions)
* Fix the background color leaking from the character widget
* Change HTML spacing to 2 spaces
* Implement hiding widgets
* Change scrollbar to a vibrant color
* Add _some_ scaling to the home buttons and its text
* Build the handbook with Gradle
* Fix the 'finer details' with the handbook UI
* Lint Code [skip actions]
* Fix target destination for the Gradle-built handbook
* Implement fetching a player across servers & Add a chainable JsonObject
useful for plugins! might be used in grasscutter eventually
* Fix GitHub actions
* Fix event calling & canceling
* Run `spotlessApply`
* Rename fields (might be wrong)
* Add/update all/more protocol definitions
* Add/update all/more protocol definitions
* Remove outdated packet
* Fix protocol definitions
* Format code [skip actions]
* Implement some lua variables for less console spam (#2172)
* Implement some lua variables for less console spam
* Add GetHostQuestState
This fixes some chapter 3 stuff.
* Format code [skip actions]
* Fix merge import
* Format code [skip actions]
* Fully fix fairy clock for real this time (#2167)
* Fully fix fairy clock For real this time
* Make it so relogging keeps the time lock state.
* Refactor out questLockTime
* Per Hartie, the client packet needs to be changed too
* Update src/main/java/emu/grasscutter/game/world/World.java
Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
* Update src/main/java/emu/grasscutter/server/packet/recv/HandlerClientLockGameTimeNotify.java
* Remove all code not needed to get clock working
---------
Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
* Implement a proper ability system (#2166)
* Apply fix `21dec2fe`
* Apply fix `89d01d5f`
* Apply fix `d900f154`
this one was already implemented; updated to use call from previous commit
* Ability changing commit
TODO: change info to debug
* Remove use of deprecated methods/fields
* Temp commit v2
(Adding LoseHP and some fixes)
* Oopsie
* Probably fix monster battle
* Fix issue with reflecting into fields
* Fix some things
* Fix ability names for 3.6 resources
* Improve logging
---------
Co-authored-by: StartForKiller <jesussanz2003@gmail.com>
* Format code [skip actions]
* Add system for sending messages between servers
* Format some code
* Remove protocol definitions from Spotless
* Default debug to false; enable with `-debug`
* Implement completely useless global value copying
* HACK: Return the avatar which holds the weapon when the weapon is referred to by ID
* Add properties to `AbilityModifier`
* Change the way HTML is served after authentication
* Use thread executors to speed up the database loading process
* Format code [skip actions]
* Add system for setting handbook address and port
* Lint Code [skip actions]
* Format code [skip actions]
* Fix game-related data not saving
* Format code [skip actions]
* Fix handbook server details
* Lint Code [skip actions]
* Format code [skip actions]
* Use the headers provided by a context to get the IP address
should acknowledge #1975
* Format code [skip actions]
* Move more logs to `trace`
* Format code [skip actions]
* more trace
* Fix something and implement weapon entities
* Format code [skip actions]
* Fix `EntityWeapon`
* Remove deprecated API & Fix resource checking
* Fix unnecessary warning for first-time setup
* Implement handbook request limiting
* Format code [skip actions]
* Fix new avatar weapons being null
* Format code [skip actions]
* Fix issue with 35303 being un-completable & Try to fix fulfilled quest conditions being met
* Load activity config on server startup
* Require plugins to specify an API version and match with the server
* Add default open state ignore list
* Format code [skip actions]
* Quick fix for questing, needs more investigation
This would make the questing work again
* Remove existing hack for 35303
* Fix ignored open states from being set
* Format code [skip actions]
* fix the stupidest bug ive ever seen
* Optimize player kicking on server close
* Format code [skip actions]
* Re-add hack to fix 35303
* Update GitHub actions
* Format code [skip actions]
* Potentially fix issues with regions
* Download additional handbook data
* Revert "Potentially fix issues with regions"
This reverts commit 84e3823695.
---------
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: scooterboo <lewasite@yahoo.com>
Co-authored-by: Tesutarin <105267106+Tesutarin@users.noreply.github.com>
Co-authored-by: Scald <104459145+Arikatsu@users.noreply.github.com>
Co-authored-by: StartForKiller <jesussanz2003@gmail.com>
This commit is contained in:
@@ -1,14 +1,19 @@
|
||||
package emu.grasscutter.game.dungeons;
|
||||
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||
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()));
|
||||
public void onDungeonSettle(
|
||||
DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason) {
|
||||
var scene = dungeonManager.getScene();
|
||||
var dungeonData = dungeonManager.getDungeonData();
|
||||
var time = scene.getSceneTimeSeconds() - dungeonManager.getStartSceneTime();
|
||||
// TODO time taken and chests handling
|
||||
DungeonEndStats stats = new DungeonEndStats(scene.getKilledMonsterCount(), time, 0, endReason);
|
||||
|
||||
scene.broadcastPacket(new PacketDungeonSettleNotify(new BaseDungeonResult(dungeonData, stats)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,22 @@ package emu.grasscutter.game.dungeons;
|
||||
import java.util.List;
|
||||
|
||||
public class DungeonDrop {
|
||||
private int dungeonId;
|
||||
private List<DungeonDropEntry> drops;
|
||||
private int dungeonId;
|
||||
private List<DungeonDropEntry> drops;
|
||||
|
||||
public int getDungeonId() {
|
||||
return dungeonId;
|
||||
}
|
||||
public void setDungeonId(int dungeonId) {
|
||||
this.dungeonId = dungeonId;
|
||||
}
|
||||
|
||||
public List<DungeonDropEntry> getDrops() {
|
||||
return drops;
|
||||
}
|
||||
public void setDrops(List<DungeonDropEntry> drops) {
|
||||
this.drops = drops;
|
||||
}
|
||||
public int getDungeonId() {
|
||||
return dungeonId;
|
||||
}
|
||||
|
||||
public void setDungeonId(int dungeonId) {
|
||||
this.dungeonId = dungeonId;
|
||||
}
|
||||
|
||||
public List<DungeonDropEntry> getDrops() {
|
||||
return drops;
|
||||
}
|
||||
|
||||
public void setDrops(List<DungeonDropEntry> drops) {
|
||||
this.drops = drops;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,44 +3,49 @@ package emu.grasscutter.game.dungeons;
|
||||
import java.util.List;
|
||||
|
||||
public class DungeonDropEntry {
|
||||
private List<Integer> counts;
|
||||
private List<Integer> items;
|
||||
private List<Integer> probabilities;
|
||||
private List<Integer> itemProbabilities;
|
||||
private boolean mpDouble;
|
||||
private List<Integer> counts;
|
||||
private List<Integer> items;
|
||||
private List<Integer> probabilities;
|
||||
private List<Integer> itemProbabilities;
|
||||
private boolean mpDouble;
|
||||
|
||||
public List<Integer> getCounts() {
|
||||
return counts;
|
||||
}
|
||||
public void setCounts(List<Integer> counts) {
|
||||
this.counts = counts;
|
||||
}
|
||||
|
||||
public List<Integer> getItems() {
|
||||
return items;
|
||||
}
|
||||
public void setItems(List<Integer> items) {
|
||||
this.items = items;
|
||||
}
|
||||
public List<Integer> getCounts() {
|
||||
return counts;
|
||||
}
|
||||
|
||||
public List<Integer> getProbabilities() {
|
||||
return probabilities;
|
||||
}
|
||||
public void setProbabilities(List<Integer> probabilities) {
|
||||
this.probabilities = probabilities;
|
||||
}
|
||||
public void setCounts(List<Integer> counts) {
|
||||
this.counts = counts;
|
||||
}
|
||||
|
||||
public List<Integer> getItemProbabilities() {
|
||||
return itemProbabilities;
|
||||
}
|
||||
public void setItemProbabilities(List<Integer> itemProbabilities) {
|
||||
this.itemProbabilities = itemProbabilities;
|
||||
}
|
||||
public List<Integer> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public boolean isMpDouble() {
|
||||
return mpDouble;
|
||||
}
|
||||
public void setMpDouble(boolean mpDouble) {
|
||||
this.mpDouble = mpDouble;
|
||||
}
|
||||
public void setItems(List<Integer> items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public List<Integer> getProbabilities() {
|
||||
return probabilities;
|
||||
}
|
||||
|
||||
public void setProbabilities(List<Integer> probabilities) {
|
||||
this.probabilities = probabilities;
|
||||
}
|
||||
|
||||
public List<Integer> getItemProbabilities() {
|
||||
return itemProbabilities;
|
||||
}
|
||||
|
||||
public void setItemProbabilities(List<Integer> itemProbabilities) {
|
||||
this.itemProbabilities = itemProbabilities;
|
||||
}
|
||||
|
||||
public boolean isMpDouble() {
|
||||
return mpDouble;
|
||||
}
|
||||
|
||||
public void setMpDouble(boolean mpDouble) {
|
||||
this.mpDouble = mpDouble;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +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;
|
||||
}
|
||||
}
|
||||
334
src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java
Normal file
334
src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java
Normal file
@@ -0,0 +1,334 @@
|
||||
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.Position;
|
||||
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.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 final 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()];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
var 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() {
|
||||
// Mark the dungeon has completed for the players.
|
||||
var dungeonId = this.getDungeonData().getId();
|
||||
this.getScene()
|
||||
.getPlayers()
|
||||
.forEach(player -> player.getPlayerProgress().markDungeonAsComplete(dungeonId));
|
||||
|
||||
notifyEndDungeon(true);
|
||||
endDungeon(BaseDungeonResult.DungeonEndReason.COMPLETED);
|
||||
}
|
||||
|
||||
public void notifyEndDungeon(boolean successfully) {
|
||||
scene
|
||||
.getPlayers()
|
||||
.forEach(
|
||||
p -> {
|
||||
// Trigger the fail event if needed.
|
||||
if (!successfully) {
|
||||
p.getQuestManager()
|
||||
.queueEvent(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);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package emu.grasscutter.game.dungeons;
|
||||
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||
|
||||
public interface DungeonSettleListener {
|
||||
void onDungeonSettle(Scene scene);
|
||||
void onDungeonSettle(DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason);
|
||||
}
|
||||
|
||||
@@ -4,38 +4,99 @@ 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.data.excels.dungeon.DungeonData;
|
||||
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
|
||||
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import emu.grasscutter.game.quest.enums.QuestTrigger;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.server.game.BaseGameSystem;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.List;
|
||||
import lombok.val;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
public class DungeonSystem extends BaseGameSystem {
|
||||
private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener();
|
||||
private static final BasicDungeonSettleListener basicDungeonSettleObserver =
|
||||
new BasicDungeonSettleListener();
|
||||
private final Int2ObjectMap<DungeonBaseHandler> passCondHandlers;
|
||||
|
||||
public DungeonSystem(GameServer server) {
|
||||
super(server);
|
||||
this.passCondHandlers = new Int2ObjectOpenHashMap<>();
|
||||
registerHandlers();
|
||||
}
|
||||
|
||||
public void getEntryInfo(Player player, int pointId, int sceneId) {
|
||||
ScenePointEntry entry = GameData.getScenePointEntryById(sceneId, pointId);
|
||||
public void registerHandlers() {
|
||||
this.registerHandlers(
|
||||
this.passCondHandlers,
|
||||
"emu.grasscutter.game.dungeons.pass_condition",
|
||||
DungeonBaseHandler.class);
|
||||
}
|
||||
|
||||
public <T> void registerHandlers(Int2ObjectMap<T> map, String packageName, Class<T> clazz) {
|
||||
Reflections reflections = new Reflections(packageName);
|
||||
var handlerClasses = reflections.getSubTypesOf(clazz);
|
||||
|
||||
for (var obj : handlerClasses) {
|
||||
this.registerHandler(map, obj);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void registerHandler(Int2ObjectMap<T> map, Class<? extends T> handlerClass) {
|
||||
try {
|
||||
DungeonValue opcode = handlerClass.getAnnotation(DungeonValue.class);
|
||||
|
||||
if (opcode == null || opcode.value() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
map.put(opcode.value().ordinal(), handlerClass.getDeclaredConstructor().newInstance());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the entry info for the given dungeon point to the player.
|
||||
*
|
||||
* @param player The player to send the entry info to.
|
||||
* @param pointId The dungeon point ID.
|
||||
*/
|
||||
public void sendEntryInfoFor(Player player, int pointId, int sceneId) {
|
||||
var entry = GameData.getScenePointEntryById(sceneId, pointId);
|
||||
if (entry == null) {
|
||||
// Error
|
||||
// An invalid point ID was sent.
|
||||
player.sendPacket(new PacketDungeonEntryInfoRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
|
||||
// Check if the player has quests with dungeon IDs.
|
||||
var questDungeons = player.getQuestManager().questsForDungeon(entry);
|
||||
if (questDungeons.size() > 0) {
|
||||
player.sendPacket(new PacketDungeonEntryInfoRsp(entry.getPointData(), questDungeons));
|
||||
} else {
|
||||
player.sendPacket(new PacketDungeonEntryInfoRsp(entry.getPointData()));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean triggerCondition(
|
||||
DungeonPassConfigData.DungeonPassCondition condition, int... params) {
|
||||
var handler = passCondHandlers.get(condition.getCondType().ordinal());
|
||||
|
||||
if (handler == null) {
|
||||
Grasscutter.getLogger()
|
||||
.debug("Could not trigger condition {} at {}", condition.getCondType(), params);
|
||||
return false;
|
||||
}
|
||||
|
||||
return handler.execute(condition, params);
|
||||
}
|
||||
|
||||
public boolean enterDungeon(Player player, int pointId, int dungeonId) {
|
||||
@@ -44,31 +105,41 @@ public class DungeonSystem extends BaseGameSystem {
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
|
||||
Grasscutter.getLogger()
|
||||
.debug(
|
||||
"{} ({}) is trying to enter dungeon {}.",
|
||||
player.getNickname(),
|
||||
player.getUid(),
|
||||
dungeonId);
|
||||
|
||||
int sceneId = data.getSceneId();
|
||||
player.getScene().setPrevScene(sceneId);
|
||||
var sceneId = data.getSceneId();
|
||||
var scene = player.getScene();
|
||||
scene.setPrevScene(sceneId);
|
||||
|
||||
if (player.getWorld().transferPlayerToScene(player, sceneId, data)) {
|
||||
player.getScene().addDungeonSettleObserver(basicDungeonSettleObserver);
|
||||
player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_ENTER_DUNGEON, data.getId());
|
||||
scene = player.getScene();
|
||||
scene.setDungeonManager(new DungeonManager(scene, data));
|
||||
scene.addDungeonSettleObserver(basicDungeonSettleObserver);
|
||||
}
|
||||
|
||||
player.getScene().setPrevScenePoint(pointId);
|
||||
player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId));
|
||||
scene.setPrevScenePoint(pointId);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* used in tower dungeons handoff
|
||||
*/
|
||||
public boolean handoffDungeon(Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
|
||||
/** used in tower dungeons handoff */
|
||||
public boolean handoffDungeon(
|
||||
Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
|
||||
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
|
||||
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
|
||||
Grasscutter.getLogger()
|
||||
.info(
|
||||
"{}({}) is trying to enter tower dungeon {}",
|
||||
player.getNickname(),
|
||||
player.getUid(),
|
||||
dungeonId);
|
||||
|
||||
if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
|
||||
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
|
||||
@@ -79,7 +150,7 @@ public class DungeonSystem extends BaseGameSystem {
|
||||
public void exitDungeon(Player player) {
|
||||
Scene scene = player.getScene();
|
||||
|
||||
if (scene==null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
|
||||
if (scene == null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,7 +158,8 @@ public class DungeonSystem extends BaseGameSystem {
|
||||
int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3;
|
||||
|
||||
// Get previous position
|
||||
DungeonData dungeonData = scene.getDungeonData();
|
||||
val dungeonManager = scene.getDungeonManager();
|
||||
DungeonData dungeonData = dungeonManager != null ? dungeonManager.getDungeonData() : null;
|
||||
Position prevPos = new Position(GameConstants.START_POSITION);
|
||||
|
||||
if (dungeonData != null) {
|
||||
@@ -96,6 +168,11 @@ public class DungeonSystem extends BaseGameSystem {
|
||||
if (entry != null) {
|
||||
prevPos.set(entry.getPointData().getTranPos());
|
||||
}
|
||||
if (!dungeonManager.isFinishedSuccessfully()) {
|
||||
dungeonManager.quitDungeon();
|
||||
}
|
||||
|
||||
dungeonManager.unsetTrialTeam(player);
|
||||
}
|
||||
// clean temp team if it has
|
||||
player.getTeamManager().cleanTemporaryTeam();
|
||||
@@ -105,8 +182,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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +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();
|
||||
}
|
||||
@@ -1,34 +1,40 @@
|
||||
package emu.grasscutter.game.dungeons;
|
||||
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult.DungeonEndReason;
|
||||
import emu.grasscutter.game.dungeons.dungeon_results.TowerResult;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketTowerFloorRecordChangeNotify;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
|
||||
public class TowerDungeonSettleListener implements DungeonSettleListener {
|
||||
|
||||
@Override
|
||||
public void onDungeonSettle(Scene scene) {
|
||||
if(scene.getScriptManager().getVariables().containsKey("stage")
|
||||
&& scene.getScriptManager().getVariables().get("stage") == 1){
|
||||
public void onDungeonSettle(DungeonManager dungeonManager, DungeonEndReason endReason) {
|
||||
var scene = dungeonManager.getScene();
|
||||
var dungeonData = dungeonManager.getDungeonData();
|
||||
if (scene.getLoadedGroups().stream()
|
||||
.anyMatch(
|
||||
g -> {
|
||||
var variables = scene.getScriptManager().getVariables(g.id);
|
||||
return variables != null
|
||||
&& variables.containsKey("stage")
|
||||
&& variables.get("stage") == 1;
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
|
||||
|
||||
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
||||
|
||||
towerManager.notifyCurLevelRecordChangeWhenDone(3);
|
||||
scene.broadcastPacket(new PacketTowerFloorRecordChangeNotify(
|
||||
towerManager.getCurrentFloorId(),
|
||||
3,
|
||||
towerManager.canEnterScheduleFloor()
|
||||
));
|
||||
scene.broadcastPacket(
|
||||
new PacketTowerFloorRecordChangeNotify(
|
||||
towerManager.getCurrentFloorId(), 3, towerManager.canEnterScheduleFloor()));
|
||||
|
||||
scene.broadcastPacket(new PacketDungeonSettleNotify(
|
||||
scene.getChallenge(),
|
||||
towerManager.hasNextFloor(),
|
||||
towerManager.hasNextLevel(),
|
||||
towerManager.hasNextLevel() ? 0 : towerManager.getNextFloorId()
|
||||
));
|
||||
var challenge = scene.getChallenge();
|
||||
var dungeonStats =
|
||||
new DungeonEndStats(
|
||||
scene.getKilledMonsterCount(), challenge.getFinishedTime(), 0, endReason);
|
||||
var result = new TowerResult(dungeonData, dungeonStats, towerManager, challenge);
|
||||
|
||||
scene.broadcastPacket(new PacketDungeonSettleNotify(result));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +1,18 @@
|
||||
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.enums.DungeonPassConditionType;
|
||||
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 {
|
||||
public final class DungeonChallenge extends WorldChallenge {
|
||||
|
||||
/**
|
||||
* has more challenge
|
||||
*/
|
||||
private boolean stage;
|
||||
private IntSet rewardedPlayers;
|
||||
|
||||
private final static Int2ObjectMap<List<DungeonDropEntry>> dungeonDropData = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
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 DungeonChallenge(Scene scene, SceneGroup group,
|
||||
int challengeId, int challengeIndex,
|
||||
@@ -58,7 +20,6 @@ public class DungeonChallenge extends WorldChallenge {
|
||||
int timeLimit, int goal,
|
||||
List<ChallengeTrigger> challengeTriggers) {
|
||||
super(scene, group, challengeId, challengeIndex, paramList, timeLimit, goal, challengeTriggers);
|
||||
this.setRewardedPlayers(new IntOpenHashSet());
|
||||
}
|
||||
|
||||
public boolean isStage() {
|
||||
@@ -69,130 +30,26 @@ public class DungeonChallenge extends WorldChallenge {
|
||||
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();
|
||||
}
|
||||
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();
|
||||
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));
|
||||
/*if(this.isSuccess()){
|
||||
scene.getDungeonManager().finishDungeon();
|
||||
} else {
|
||||
scene.getDungeonManager().failDungeon();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,21 @@ package emu.grasscutter.game.dungeons.challenge;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
||||
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.entity.EntityMonster;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.SceneTrigger;
|
||||
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;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -24,19 +26,34 @@ public class WorldChallenge {
|
||||
private final int challengeId;
|
||||
private final int challengeIndex;
|
||||
private final List<Integer> paramList;
|
||||
private final int timeLimit;
|
||||
private int timeLimit;
|
||||
private final List<ChallengeTrigger> challengeTriggers;
|
||||
private final int goal;
|
||||
private final AtomicInteger score;
|
||||
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<Integer> paramList,
|
||||
int timeLimit, int goal,
|
||||
List<ChallengeTrigger> challengeTriggers){
|
||||
/**
|
||||
* @param scene The scene the challenge is in.
|
||||
* @param group The group the challenge is in.
|
||||
* @param challengeId The challenge's id.
|
||||
* @param challengeIndex The challenge's index.
|
||||
* @param paramList The challenge's parameters.
|
||||
* @param timeLimit The challenge's time limit.
|
||||
* @param goal The challenge's goal.
|
||||
* @param challengeTriggers The challenge's triggers.
|
||||
*/
|
||||
public WorldChallenge(
|
||||
Scene scene,
|
||||
SceneGroup group,
|
||||
int challengeId,
|
||||
int challengeIndex,
|
||||
List<Integer> paramList,
|
||||
int timeLimit,
|
||||
int goal,
|
||||
List<ChallengeTrigger> challengeTriggers) {
|
||||
this.scene = scene;
|
||||
this.group = group;
|
||||
this.challengeId = challengeId;
|
||||
@@ -47,20 +64,23 @@ public class WorldChallenge {
|
||||
this.goal = goal;
|
||||
this.score = new AtomicInteger(0);
|
||||
}
|
||||
public boolean inProgress(){
|
||||
|
||||
public boolean inProgress() {
|
||||
return this.progress;
|
||||
}
|
||||
public void onCheckTimeOut(){
|
||||
if(!inProgress()){
|
||||
|
||||
public void onCheckTimeOut() {
|
||||
if (!inProgress()) {
|
||||
return;
|
||||
}
|
||||
if(timeLimit <= 0){
|
||||
if (timeLimit <= 0) {
|
||||
return;
|
||||
}
|
||||
challengeTriggers.forEach(t -> t.onCheckTimeout(this));
|
||||
}
|
||||
public void start(){
|
||||
if(inProgress()){
|
||||
|
||||
public void start() {
|
||||
if (inProgress()) {
|
||||
Grasscutter.getLogger().info("Could not start a in progress challenge.");
|
||||
return;
|
||||
}
|
||||
@@ -70,61 +90,100 @@ public class WorldChallenge {
|
||||
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));
|
||||
public void done() {
|
||||
if (!this.inProgress()) return;
|
||||
this.finish(true);
|
||||
|
||||
var scene = this.getScene();
|
||||
var scriptManager = scene.getScriptManager();
|
||||
var dungeonManager = scene.getDungeonManager();
|
||||
if (dungeonManager != null && dungeonManager.getDungeonData() != null) {
|
||||
scene
|
||||
.getPlayers()
|
||||
.forEach(
|
||||
p ->
|
||||
p.getActivityManager()
|
||||
.triggerWatcher(
|
||||
WatcherTriggerType.TRIGGER_FINISH_CHALLENGE,
|
||||
String.valueOf(dungeonManager.getDungeonData().getId()),
|
||||
String.valueOf(this.getGroup().id),
|
||||
String.valueOf(this.getChallengeId())));
|
||||
}
|
||||
|
||||
// TODO: record the time in PARAM2 and used in action
|
||||
scriptManager.callEvent(
|
||||
new ScriptArgs(this.getGroup().id, EventType.EVENT_CHALLENGE_SUCCESS)
|
||||
.setParam2(finishedTime)
|
||||
.setEventSource(this.getChallengeIndex()));
|
||||
|
||||
this.getScene()
|
||||
.triggerDungeonEvent(
|
||||
DungeonPassConditionType.DUNGEON_COND_FINISH_CHALLENGE,
|
||||
getChallengeId(),
|
||||
getChallengeIndex());
|
||||
|
||||
this.challengeTriggers.forEach(t -> t.onFinish(this));
|
||||
}
|
||||
|
||||
public void fail() {
|
||||
if (!this.inProgress()) return;
|
||||
this.finish(false);
|
||||
|
||||
// TODO: Set 'eventSource' in script arguments.
|
||||
var scriptManager = this.getScene().getScriptManager();
|
||||
scriptManager.callEvent(
|
||||
new ScriptArgs(this.getGroup().id, EventType.EVENT_CHALLENGE_FAIL)
|
||||
.setEventSource(this.getChallengeIndex()));
|
||||
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){
|
||||
private void finish(boolean success) {
|
||||
this.progress = false;
|
||||
this.success = success;
|
||||
this.finishedTime = (int)((System.currentTimeMillis() - this.startedAt) / 1000L);
|
||||
this.finishedTime = (int) ((this.scene.getSceneTimeSeconds() - this.startedAt));
|
||||
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
|
||||
}
|
||||
|
||||
public int increaseScore(){
|
||||
public int increaseScore() {
|
||||
return score.incrementAndGet();
|
||||
}
|
||||
public void onMonsterDeath(EntityMonster monster){
|
||||
if(!inProgress()){
|
||||
|
||||
public void onMonsterDeath(EntityMonster monster) {
|
||||
if (!inProgress()) {
|
||||
return;
|
||||
}
|
||||
if(monster.getGroupId() != getGroup().id){
|
||||
if (monster.getGroupId() != getGroup().id) {
|
||||
return;
|
||||
}
|
||||
this.challengeTriggers.forEach(t -> t.onMonsterDeath(this, monster));
|
||||
}
|
||||
public void onGadgetDeath(EntityGadget gadget){
|
||||
if(!inProgress()){
|
||||
|
||||
public void onGadgetDeath(EntityGadget gadget) {
|
||||
if (!inProgress()) {
|
||||
return;
|
||||
}
|
||||
if(gadget.getGroupId() != getGroup().id){
|
||||
if (gadget.getGroupId() != getGroup().id) {
|
||||
return;
|
||||
}
|
||||
this.challengeTriggers.forEach(t -> t.onGadgetDeath(this, gadget));
|
||||
}
|
||||
|
||||
public void onGadgetDamage(EntityGadget gadget){
|
||||
if(!inProgress()){
|
||||
public void onGroupTriggerDeath(SceneTrigger trigger) {
|
||||
if (!this.inProgress()) return;
|
||||
|
||||
var triggerGroup = trigger.getCurrentGroup();
|
||||
if (triggerGroup == null || triggerGroup.id != getGroup().id) {
|
||||
return;
|
||||
}
|
||||
if(gadget.getGroupId() != getGroup().id){
|
||||
|
||||
this.challengeTriggers.forEach(t -> t.onGroupTrigger(this, trigger));
|
||||
}
|
||||
|
||||
public void onGadgetDamage(EntityGadget gadget) {
|
||||
if (!inProgress()) {
|
||||
return;
|
||||
}
|
||||
if (gadget.getGroupId() != getGroup().id) {
|
||||
return;
|
||||
}
|
||||
this.challengeTriggers.forEach(t -> t.onGadgetDamage(this, gadget));
|
||||
|
||||
@@ -0,0 +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
|
||||
}
|
||||
@@ -0,0 +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,
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package emu.grasscutter.game.dungeons.challenge.enums;
|
||||
|
||||
public enum ChallengeRecordType {
|
||||
CHALLENGE_RECORD_TYPE_NONE,
|
||||
CHALLENGE_RECORD_TYPE_IN_TIME
|
||||
}
|
||||
@@ -0,0 +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,
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package emu.grasscutter.game.dungeons.challenge.enums;
|
||||
|
||||
public enum FatherChallengeProperty {
|
||||
DURATION,
|
||||
CUR_SUCC,
|
||||
CUR_FAIL,
|
||||
SUM_SUCC,
|
||||
SUM_FAIL
|
||||
}
|
||||
@@ -1,29 +1,44 @@
|
||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
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;
|
||||
import lombok.val;
|
||||
|
||||
public class ChallengeFactory {
|
||||
|
||||
public abstract class ChallengeFactory {
|
||||
private static final List<ChallengeFactoryHandler> challengeFactoryHandlers = new ArrayList<>();
|
||||
|
||||
static {
|
||||
challengeFactoryHandlers.add(new DungeonChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new DungeonGuardChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new KillGadgetChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new KillMonsterChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new KillAndGuardChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new KillMonsterCountChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new KillMonsterInTimeChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new KillMonsterTimeChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new SurviveChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new TriggerInTimeChallengeFactoryHandler());
|
||||
challengeFactoryHandlers.add(new KillMonsterCountInTimeIncChallengeFactoryHandler());
|
||||
}
|
||||
|
||||
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)){
|
||||
public static WorldChallenge getChallenge(
|
||||
int localChallengeId,
|
||||
int challengeDataId,
|
||||
int param3,
|
||||
int param4,
|
||||
int param5,
|
||||
int param6,
|
||||
Scene scene,
|
||||
SceneGroup group) {
|
||||
val challengeData = GameData.getDungeonChallengeConfigDataMap().get(challengeDataId);
|
||||
val challengeType = challengeData.getChallengeType();
|
||||
|
||||
for (var handler : challengeFactoryHandlers) {
|
||||
if (!handler.isThisType(challengeType)) {
|
||||
continue;
|
||||
}
|
||||
return handler.build(param1, param2, param3, param4, param5, param6, scene, group);
|
||||
return handler.build(
|
||||
localChallengeId, challengeDataId, param3, param4, param5, param6, scene, group);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
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.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);
|
||||
boolean isThisType(ChallengeType challengeType);
|
||||
|
||||
WorldChallenge build(
|
||||
int challengeIndex,
|
||||
int challengeId,
|
||||
int param3,
|
||||
int param4,
|
||||
int param5,
|
||||
int param6,
|
||||
Scene scene,
|
||||
SceneGroup group);
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
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()));
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
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
|
||||
param4, // Goal
|
||||
List.of(new GuardTrigger()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
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)));
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
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())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
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())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +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 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()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +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.KillMonsterCountTrigger;
|
||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTimeIncTrigger;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import java.util.List;
|
||||
import lombok.val;
|
||||
|
||||
public class KillMonsterCountInTimeIncChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||
@Override
|
||||
public boolean isThisType(ChallengeType challengeType) {
|
||||
return challengeType == ChallengeType.CHALLENGE_TIME_FLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldChallenge build(
|
||||
int challengeIndex,
|
||||
int challengeId,
|
||||
int groupId,
|
||||
int monsterCount,
|
||||
int timeLimit,
|
||||
int timeInc,
|
||||
Scene scene,
|
||||
SceneGroup group) {
|
||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||
return new WorldChallenge(
|
||||
scene,
|
||||
realGroup,
|
||||
challengeId, // Id
|
||||
challengeIndex, // Index
|
||||
List.of(monsterCount, timeLimit, timeInc),
|
||||
timeLimit, // Limit
|
||||
monsterCount, // Goal
|
||||
List.of(
|
||||
new KillMonsterCountTrigger(),
|
||||
new InTimeTrigger(),
|
||||
new KillMonsterTimeIncTrigger(timeInc)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +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 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()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +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 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()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
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()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
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))));
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,20 @@ 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.scripts.data.SceneTrigger;
|
||||
|
||||
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){}
|
||||
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) {}
|
||||
|
||||
public void onGroupTrigger(WorldChallenge challenge, SceneTrigger trigger) {}
|
||||
}
|
||||
|
||||
@@ -0,0 +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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,25 +2,36 @@ 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 class GuardTrigger extends ChallengeTrigger {
|
||||
private final int entityToProtectCFGId;
|
||||
private int lastSendPercent = 100;
|
||||
|
||||
public GuardTrigger(int entityToProtectCFGId) {
|
||||
this.entityToProtectCFGId = entityToProtectCFGId;
|
||||
}
|
||||
|
||||
public void onBegin(WorldChallenge challenge) {
|
||||
super.onBegin(challenge);
|
||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, 100));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) {
|
||||
if (gadget.getConfigId() != entityToProtectCFGId) {
|
||||
return;
|
||||
}
|
||||
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){
|
||||
if (percent != lastSendPercent) {
|
||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent));
|
||||
lastSendPercent = percent;
|
||||
}
|
||||
|
||||
if (percent <= 0) {
|
||||
challenge.fail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package emu.grasscutter.game.dungeons.challenge.trigger;
|
||||
|
||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||
|
||||
public class InTimeTrigger extends ChallengeTrigger{
|
||||
public class InTimeTrigger extends ChallengeTrigger {
|
||||
@Override
|
||||
public void onCheckTimeout(WorldChallenge challenge) {
|
||||
var current = System.currentTimeMillis();
|
||||
if(current - challenge.getStartedAt() > challenge.getTimeLimit() * 1000L){
|
||||
var current = challenge.getScene().getSceneTimeSeconds();
|
||||
if (current - challenge.getStartedAt() > challenge.getTimeLimit()) {
|
||||
challenge.fail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ 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{
|
||||
public class KillGadgetTrigger extends ChallengeTrigger {
|
||||
@Override
|
||||
public void onBegin(WorldChallenge challenge) {
|
||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, challenge.getScore().get()));
|
||||
challenge
|
||||
.getScene()
|
||||
.broadcastPacket(new PacketChallengeDataNotify(challenge, 2, challenge.getScore().get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -15,9 +17,8 @@ public class KillGadgetTrigger extends ChallengeTrigger{
|
||||
var newScore = challenge.increaseScore();
|
||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, newScore));
|
||||
|
||||
if(newScore >= challenge.getGoal()){
|
||||
if (newScore >= challenge.getGoal()) {
|
||||
challenge.done();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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 KillMonsterTimeIncTrigger extends ChallengeTrigger {
|
||||
|
||||
private int increment;
|
||||
|
||||
public KillMonsterTimeIncTrigger(int increment) {
|
||||
this.increment = increment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBegin(WorldChallenge challenge) {
|
||||
// challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 0,
|
||||
// challenge.getScore().get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {
|
||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 0, increment));
|
||||
|
||||
challenge.setTimeLimit(challenge.getTimeLimit() + increment);
|
||||
}
|
||||
}
|
||||
@@ -3,21 +3,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;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class KillMonsterTrigger extends ChallengeTrigger {
|
||||
private int monsterCfgId;
|
||||
|
||||
public class KillMonsterTrigger extends ChallengeTrigger{
|
||||
@Override
|
||||
public void onBegin(WorldChallenge challenge) {
|
||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, challenge.getScore().get()));
|
||||
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()){
|
||||
if (monster.getConfigId() == monsterCfgId) {
|
||||
challenge.done();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package emu.grasscutter.game.dungeons.enums;
|
||||
|
||||
public enum DungeonEntrySatisfiedConditionType {
|
||||
DUNGEON_ENTRY_CONDITION_NONE,
|
||||
DUNGEON_ENTRY_CONDITION_LEVEL,
|
||||
DUNGEON_ENTRY_CONDITION_QUEST
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package emu.grasscutter.game.dungeons.enums;
|
||||
|
||||
public enum DungeonInvolveType {
|
||||
INVOLVE_NONE,
|
||||
INVOLVE_ONLY_SINGLE,
|
||||
INVOLVE_SINGLE_MULTIPLE
|
||||
}
|
||||
@@ -0,0 +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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +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
|
||||
}
|
||||
@@ -0,0 +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
|
||||
}
|
||||
@@ -0,0 +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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +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
|
||||
}
|
||||
@@ -0,0 +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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user