Skip to content

Commit

Permalink
Fix mirror tower stages; fix tower time challenge and star scoring (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
longfruit authored Oct 19, 2023
1 parent bc8e7c2 commit f5703e5
Show file tree
Hide file tree
Showing 13 changed files with 264 additions and 53 deletions.
69 changes: 59 additions & 10 deletions src/main/java/emu/grasscutter/data/excels/tower/TowerLevelData.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,82 @@
package emu.grasscutter.data.excels.tower;

import emu.grasscutter.data.*;
import java.util.List;
import lombok.*;

@ResourceType(name = "TowerLevelExcelConfigData.json")
@Getter
public class TowerLevelData extends GameResource {

private int levelId;
private int levelIndex;
private int levelGroupId;
private int dungeonId;
private List<TowerLevelCond> conds;

public static class TowerLevelCond {
private TowerCondType towerCondType;
private List<Integer> argumentList;
}

public enum TowerCondType {
TOWER_COND_NONE,
TOWER_COND_CHALLENGE_LEFT_TIME_MORE_THAN,
TOWER_COND_LEFT_HP_GREATER_THAN
}

// Not actual data in TowerLevelExcelConfigData.
// Just packaging condition parameters for convenience.
@Getter
public class TowerCondTimeParams {
private int param1;
private int minimumTimeInSeconds;

public TowerCondTimeParams(int param1, int minimumTimeInSeconds) {
this.param1 = param1;
this.minimumTimeInSeconds = minimumTimeInSeconds;
}
}

@Getter
public class TowerCondHpParams {
private int sceneId;
private int configId;
private int minimumHpPercentage;

public TowerCondHpParams(int sceneId, int configId, int minimumHpPercentage) {
this.sceneId = sceneId;
this.configId = configId;
this.minimumHpPercentage = minimumHpPercentage;
}
}

@Override
public int getId() {
return this.getLevelId();
}

public int getLevelId() {
return levelId;
}

public int getLevelGroupId() {
return levelGroupId;
public TowerCondType getCondType(int star) {
if (star < 0 || conds == null || star >= conds.size()) {
return TowerCondType.TOWER_COND_NONE;
}
var condType = conds.get(star).towerCondType;
return condType == null ? TowerCondType.TOWER_COND_NONE : condType;
}

public int getLevelIndex() {
return levelIndex;
public TowerCondTimeParams getTimeCond(int star) {
if (star < 0 || conds == null || star >= conds.size()) {
return null;
}
var params = conds.get(star).argumentList;
return new TowerCondTimeParams(params.get(0), params.get(1));
}

public int getDungeonId() {
return dungeonId;
public TowerCondHpParams getHpCond(int star) {
if (star < 0 || conds == null || star >= conds.size()) {
return null;
}
var params = conds.get(star).argumentList;
return new TowerCondHpParams(params.get(0), params.get(1), params.get(2));
}
}
22 changes: 19 additions & 3 deletions src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public final class DungeonManager {
private boolean ended = false;
private int newestWayPoint = 0;
@Getter private int startSceneTime = 0;
@Setter @Getter private boolean towerDungeon = false;

DungeonTrialTeam trialTeam = null;

Expand Down Expand Up @@ -323,15 +324,30 @@ public void notifyEndDungeon(boolean successfully) {
p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON);
}
});
scene
.getScriptManager()
.callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
var future = scene
.getScriptManager()
.callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
// Note: There is a possible race condition with calling
// EVENT_DUNGEON_SETTLE here asynchronously:
// 1. EVENT_DUNGEON_SETTLE triggers some Lua-side logic,
// which may happen after 2 (below) finishes.
// 2. Some DungeonSettleListener could be comparing some
// Lua variable before its setting in 1 (above) finishes.
// For safety, ensure all events have finished before returning.
try {
future.get();
} catch (Exception e) {
e.printStackTrace();
}
}

public void endDungeon(BaseDungeonResult.DungeonEndReason endReason) {
if (scene.getDungeonSettleListeners() != null) {
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(this, endReason));
}
if (isTowerDungeon()) {
scene.getPlayers().get(0).getTowerManager().onEnd();
}
ended = true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ public boolean handoffDungeon(

if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
var scene = player.getScene();
scene.setDungeonManager(new DungeonManager(scene, data));
var dungeonManager = new DungeonManager(scene, data);
dungeonManager.setTowerDungeon(true);
scene.setDungeonManager(dungeonManager);
dungeonSettleListeners.forEach(scene::addDungeonSettleObserver);
}
return true;
Expand Down Expand Up @@ -168,6 +170,7 @@ public void exitDungeon(Player player) {
// clean temp team if it has
player.getTeamManager().cleanTemporaryTeam();
player.getTowerManager().clearEntry();
dungeonManager.setTowerDungeon(false);

// Transfer player back to world
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class TowerDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(DungeonManager dungeonManager, DungeonEndReason endReason) {
var scene = dungeonManager.getScene();

var dungeonData = dungeonManager.getDungeonData();
if (scene.getLoadedGroups().stream()
.anyMatch(
Expand All @@ -22,17 +23,18 @@ public void onDungeonSettle(DungeonManager dungeonManager, DungeonEndReason endR
}

var towerManager = scene.getPlayers().get(0).getTowerManager();
var stars = towerManager.getCurLevelStars();

towerManager.notifyCurLevelRecordChangeWhenDone(3);
towerManager.notifyCurLevelRecordChangeWhenDone(stars);
scene.broadcastPacket(
new PacketTowerFloorRecordChangeNotify(
towerManager.getCurrentFloorId(), 3, towerManager.canEnterScheduleFloor()));
towerManager.getCurrentFloorId(), stars, towerManager.canEnterScheduleFloor()));

var challenge = scene.getChallenge();
var dungeonStats =
new DungeonEndStats(
scene.getKilledMonsterCount(), challenge.getFinishedTime(), 0, endReason);
var result = new TowerResult(dungeonData, dungeonStats, towerManager, challenge);
var result = new TowerResult(dungeonData, dungeonStats, towerManager, challenge, stars);

scene.broadcastPacket(new PacketDungeonSettleNotify(result));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,16 @@ public void start() {
return;
}
this.progress = true;
this.startedAt = System.currentTimeMillis();
this.startedAt = getScene().getSceneTimeSeconds();
getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this));
challengeTriggers.forEach(t -> t.onBegin(this));

var player = scene.getPlayers().get(0);
var dungeonManager = scene.getDungeonManager();
var towerManager = player.getTowerManager();
if (dungeonManager != null && dungeonManager.isTowerDungeon() && towerManager != null) {
towerManager.onBegin();
}
}

public void done() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
package emu.grasscutter.game.dungeons.challenge.trigger;

import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;

public class InTimeTrigger extends ChallengeTrigger {
@Override
public void onBegin(WorldChallenge challenge) {
// Show time remaining UI
var scene = challenge.getScene();
scene.broadcastPacket(
new PacketChallengeDataNotify(
challenge,
2,
// Compensate for time passed so far in scene.
challenge.getTimeLimit() + scene.getSceneTimeSeconds()));
}

@Override
public void onCheckTimeout(WorldChallenge challenge) {
// In Tower challenges, time can run out without
// causing the challenge to fail. (Player just
// gets 0 stars when they ultimately finish.)
var dungeonManager = challenge.getScene().getDungeonManager();
if (dungeonManager != null && dungeonManager.isTowerDungeon()) return;

var current = challenge.getScene().getSceneTimeSeconds();
if (current - challenge.getStartedAt() > challenge.getTimeLimit()) {
challenge.fail();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ public class TowerResult extends BaseDungeonResult {
boolean canJump;
boolean hasNextLevel;
int nextFloorId;
int currentStars;

public TowerResult(
DungeonData dungeonData,
DungeonEndStats dungeonStats,
TowerManager towerManager,
WorldChallenge challenge) {
WorldChallenge challenge,
int currentStars) {
super(dungeonData, dungeonStats);
this.challenge = challenge;
this.canJump = towerManager.hasNextFloor();
this.hasNextLevel = towerManager.hasNextLevel();
this.nextFloorId = hasNextLevel ? 0 : towerManager.getNextFloorId();
this.currentStars = currentStars;
}

@Override
Expand All @@ -40,14 +43,16 @@ protected void onProto(DungeonSettleNotifyOuterClass.DungeonSettleNotify.Builder
TowerLevelEndNotify.newBuilder()
.setIsSuccess(challenge.isSuccess())
.setContinueState(continueStatus)
.addFinishedStarCondList(1)
.addFinishedStarCondList(2)
.addFinishedStarCondList(3)
.addRewardItemList(
ItemParamOuterClass.ItemParam.newBuilder().setItemId(201).setCount(1000).build());
ItemParamOuterClass.ItemParam.newBuilder().setItemId(201).setCount(1000));

for (int i = 1; i <= currentStars; i++) {
towerLevelEndNotify.addFinishedStarCondList(i);
}

if (nextFloorId > 0 && canJump) {
towerLevelEndNotify.setNextFloorId(nextFloorId);
}
builder.setTowerLevelEndNotify(towerLevelEndNotify);
builder.setTowerLevelEndNotify(towerLevelEndNotify.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ public TowerLevelRecord setLevelStars(int levelId, int stars) {
return this;
}

public int getLevelStars(int levelId) {
return passedLevelMap.get(levelId);
}

public int getStarCount() {
return passedLevelMap.values().stream().mapToInt(Integer::intValue).sum();
}
Expand Down
Loading

0 comments on commit f5703e5

Please sign in to comment.