Skip to content

Commit f5703e5

Browse files
authored
Fix mirror tower stages; fix tower time challenge and star scoring (#2406)
1 parent bc8e7c2 commit f5703e5

File tree

13 files changed

+264
-53
lines changed

13 files changed

+264
-53
lines changed
Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,82 @@
11
package emu.grasscutter.data.excels.tower;
22

33
import emu.grasscutter.data.*;
4+
import java.util.List;
5+
import lombok.*;
46

57
@ResourceType(name = "TowerLevelExcelConfigData.json")
8+
@Getter
69
public class TowerLevelData extends GameResource {
710

811
private int levelId;
912
private int levelIndex;
1013
private int levelGroupId;
1114
private int dungeonId;
15+
private List<TowerLevelCond> conds;
16+
17+
public static class TowerLevelCond {
18+
private TowerCondType towerCondType;
19+
private List<Integer> argumentList;
20+
}
21+
22+
public enum TowerCondType {
23+
TOWER_COND_NONE,
24+
TOWER_COND_CHALLENGE_LEFT_TIME_MORE_THAN,
25+
TOWER_COND_LEFT_HP_GREATER_THAN
26+
}
27+
28+
// Not actual data in TowerLevelExcelConfigData.
29+
// Just packaging condition parameters for convenience.
30+
@Getter
31+
public class TowerCondTimeParams {
32+
private int param1;
33+
private int minimumTimeInSeconds;
34+
35+
public TowerCondTimeParams(int param1, int minimumTimeInSeconds) {
36+
this.param1 = param1;
37+
this.minimumTimeInSeconds = minimumTimeInSeconds;
38+
}
39+
}
40+
41+
@Getter
42+
public class TowerCondHpParams {
43+
private int sceneId;
44+
private int configId;
45+
private int minimumHpPercentage;
46+
47+
public TowerCondHpParams(int sceneId, int configId, int minimumHpPercentage) {
48+
this.sceneId = sceneId;
49+
this.configId = configId;
50+
this.minimumHpPercentage = minimumHpPercentage;
51+
}
52+
}
1253

1354
@Override
1455
public int getId() {
1556
return this.getLevelId();
1657
}
1758

18-
public int getLevelId() {
19-
return levelId;
20-
}
21-
22-
public int getLevelGroupId() {
23-
return levelGroupId;
59+
public TowerCondType getCondType(int star) {
60+
if (star < 0 || conds == null || star >= conds.size()) {
61+
return TowerCondType.TOWER_COND_NONE;
62+
}
63+
var condType = conds.get(star).towerCondType;
64+
return condType == null ? TowerCondType.TOWER_COND_NONE : condType;
2465
}
2566

26-
public int getLevelIndex() {
27-
return levelIndex;
67+
public TowerCondTimeParams getTimeCond(int star) {
68+
if (star < 0 || conds == null || star >= conds.size()) {
69+
return null;
70+
}
71+
var params = conds.get(star).argumentList;
72+
return new TowerCondTimeParams(params.get(0), params.get(1));
2873
}
2974

30-
public int getDungeonId() {
31-
return dungeonId;
75+
public TowerCondHpParams getHpCond(int star) {
76+
if (star < 0 || conds == null || star >= conds.size()) {
77+
return null;
78+
}
79+
var params = conds.get(star).argumentList;
80+
return new TowerCondHpParams(params.get(0), params.get(1), params.get(2));
3281
}
3382
}

src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public final class DungeonManager {
3838
private boolean ended = false;
3939
private int newestWayPoint = 0;
4040
@Getter private int startSceneTime = 0;
41+
@Setter @Getter private boolean towerDungeon = false;
4142

4243
DungeonTrialTeam trialTeam = null;
4344

@@ -323,15 +324,30 @@ public void notifyEndDungeon(boolean successfully) {
323324
p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON);
324325
}
325326
});
326-
scene
327-
.getScriptManager()
328-
.callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
327+
var future = scene
328+
.getScriptManager()
329+
.callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
330+
// Note: There is a possible race condition with calling
331+
// EVENT_DUNGEON_SETTLE here asynchronously:
332+
// 1. EVENT_DUNGEON_SETTLE triggers some Lua-side logic,
333+
// which may happen after 2 (below) finishes.
334+
// 2. Some DungeonSettleListener could be comparing some
335+
// Lua variable before its setting in 1 (above) finishes.
336+
// For safety, ensure all events have finished before returning.
337+
try {
338+
future.get();
339+
} catch (Exception e) {
340+
e.printStackTrace();
341+
}
329342
}
330343

331344
public void endDungeon(BaseDungeonResult.DungeonEndReason endReason) {
332345
if (scene.getDungeonSettleListeners() != null) {
333346
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(this, endReason));
334347
}
348+
if (isTowerDungeon()) {
349+
scene.getPlayers().get(0).getTowerManager().onEnd();
350+
}
335351
ended = true;
336352
}
337353

src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ public boolean handoffDungeon(
132132

133133
if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
134134
var scene = player.getScene();
135-
scene.setDungeonManager(new DungeonManager(scene, data));
135+
var dungeonManager = new DungeonManager(scene, data);
136+
dungeonManager.setTowerDungeon(true);
137+
scene.setDungeonManager(dungeonManager);
136138
dungeonSettleListeners.forEach(scene::addDungeonSettleObserver);
137139
}
138140
return true;
@@ -168,6 +170,7 @@ public void exitDungeon(Player player) {
168170
// clean temp team if it has
169171
player.getTeamManager().cleanTemporaryTeam();
170172
player.getTowerManager().clearEntry();
173+
dungeonManager.setTowerDungeon(false);
171174

172175
// Transfer player back to world
173176
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);

src/main/java/emu/grasscutter/game/dungeons/TowerDungeonSettleListener.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class TowerDungeonSettleListener implements DungeonSettleListener {
99
@Override
1010
public void onDungeonSettle(DungeonManager dungeonManager, DungeonEndReason endReason) {
1111
var scene = dungeonManager.getScene();
12+
1213
var dungeonData = dungeonManager.getDungeonData();
1314
if (scene.getLoadedGroups().stream()
1415
.anyMatch(
@@ -22,17 +23,18 @@ public void onDungeonSettle(DungeonManager dungeonManager, DungeonEndReason endR
2223
}
2324

2425
var towerManager = scene.getPlayers().get(0).getTowerManager();
26+
var stars = towerManager.getCurLevelStars();
2527

26-
towerManager.notifyCurLevelRecordChangeWhenDone(3);
28+
towerManager.notifyCurLevelRecordChangeWhenDone(stars);
2729
scene.broadcastPacket(
2830
new PacketTowerFloorRecordChangeNotify(
29-
towerManager.getCurrentFloorId(), 3, towerManager.canEnterScheduleFloor()));
31+
towerManager.getCurrentFloorId(), stars, towerManager.canEnterScheduleFloor()));
3032

3133
var challenge = scene.getChallenge();
3234
var dungeonStats =
3335
new DungeonEndStats(
3436
scene.getKilledMonsterCount(), challenge.getFinishedTime(), 0, endReason);
35-
var result = new TowerResult(dungeonData, dungeonStats, towerManager, challenge);
37+
var result = new TowerResult(dungeonData, dungeonStats, towerManager, challenge, stars);
3638

3739
scene.broadcastPacket(new PacketDungeonSettleNotify(result));
3840
}

src/main/java/emu/grasscutter/game/dungeons/challenge/WorldChallenge.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,16 @@ public void start() {
8080
return;
8181
}
8282
this.progress = true;
83-
this.startedAt = System.currentTimeMillis();
83+
this.startedAt = getScene().getSceneTimeSeconds();
8484
getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this));
8585
challengeTriggers.forEach(t -> t.onBegin(this));
86+
87+
var player = scene.getPlayers().get(0);
88+
var dungeonManager = scene.getDungeonManager();
89+
var towerManager = player.getTowerManager();
90+
if (dungeonManager != null && dungeonManager.isTowerDungeon() && towerManager != null) {
91+
towerManager.onBegin();
92+
}
8693
}
8794

8895
public void done() {

src/main/java/emu/grasscutter/game/dungeons/challenge/trigger/InTimeTrigger.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
11
package emu.grasscutter.game.dungeons.challenge.trigger;
22

33
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
4+
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
45

56
public class InTimeTrigger extends ChallengeTrigger {
7+
@Override
8+
public void onBegin(WorldChallenge challenge) {
9+
// Show time remaining UI
10+
var scene = challenge.getScene();
11+
scene.broadcastPacket(
12+
new PacketChallengeDataNotify(
13+
challenge,
14+
2,
15+
// Compensate for time passed so far in scene.
16+
challenge.getTimeLimit() + scene.getSceneTimeSeconds()));
17+
}
18+
619
@Override
720
public void onCheckTimeout(WorldChallenge challenge) {
21+
// In Tower challenges, time can run out without
22+
// causing the challenge to fail. (Player just
23+
// gets 0 stars when they ultimately finish.)
24+
var dungeonManager = challenge.getScene().getDungeonManager();
25+
if (dungeonManager != null && dungeonManager.isTowerDungeon()) return;
26+
827
var current = challenge.getScene().getSceneTimeSeconds();
928
if (current - challenge.getStartedAt() > challenge.getTimeLimit()) {
1029
challenge.fail();

src/main/java/emu/grasscutter/game/dungeons/dungeon_results/TowerResult.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@ public class TowerResult extends BaseDungeonResult {
1313
boolean canJump;
1414
boolean hasNextLevel;
1515
int nextFloorId;
16+
int currentStars;
1617

1718
public TowerResult(
1819
DungeonData dungeonData,
1920
DungeonEndStats dungeonStats,
2021
TowerManager towerManager,
21-
WorldChallenge challenge) {
22+
WorldChallenge challenge,
23+
int currentStars) {
2224
super(dungeonData, dungeonStats);
2325
this.challenge = challenge;
2426
this.canJump = towerManager.hasNextFloor();
2527
this.hasNextLevel = towerManager.hasNextLevel();
2628
this.nextFloorId = hasNextLevel ? 0 : towerManager.getNextFloorId();
29+
this.currentStars = currentStars;
2730
}
2831

2932
@Override
@@ -40,14 +43,16 @@ protected void onProto(DungeonSettleNotifyOuterClass.DungeonSettleNotify.Builder
4043
TowerLevelEndNotify.newBuilder()
4144
.setIsSuccess(challenge.isSuccess())
4245
.setContinueState(continueStatus)
43-
.addFinishedStarCondList(1)
44-
.addFinishedStarCondList(2)
45-
.addFinishedStarCondList(3)
4646
.addRewardItemList(
47-
ItemParamOuterClass.ItemParam.newBuilder().setItemId(201).setCount(1000).build());
47+
ItemParamOuterClass.ItemParam.newBuilder().setItemId(201).setCount(1000));
48+
49+
for (int i = 1; i <= currentStars; i++) {
50+
towerLevelEndNotify.addFinishedStarCondList(i);
51+
}
52+
4853
if (nextFloorId > 0 && canJump) {
4954
towerLevelEndNotify.setNextFloorId(nextFloorId);
5055
}
51-
builder.setTowerLevelEndNotify(towerLevelEndNotify);
56+
builder.setTowerLevelEndNotify(towerLevelEndNotify.build());
5257
}
5358
}

src/main/java/emu/grasscutter/game/tower/TowerLevelRecord.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ public TowerLevelRecord setLevelStars(int levelId, int stars) {
2525
return this;
2626
}
2727

28+
public int getLevelStars(int levelId) {
29+
return passedLevelMap.get(levelId);
30+
}
31+
2832
public int getStarCount() {
2933
return passedLevelMap.values().stream().mapToInt(Integer::intValue).sum();
3034
}

0 commit comments

Comments
 (0)