mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-22 12:05:39 +00:00
Implement abyss defense objective (#2422)
This commit is contained in:
parent
205b79dc02
commit
24874e7fba
@ -68,6 +68,10 @@ public final class DungeonManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isFinishedSuccessfully()) {
|
if (isFinishedSuccessfully()) {
|
||||||
|
// Set ended now because calling EVENT_DUNGEON_SETTLE
|
||||||
|
// during finishDungeon() may cause reentrance into
|
||||||
|
// this function, leading to double settles.
|
||||||
|
ended = true;
|
||||||
finishDungeon();
|
finishDungeon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package emu.grasscutter.game.dungeons;
|
package emu.grasscutter.game.dungeons;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||||
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult.DungeonEndReason;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult.DungeonEndReason;
|
||||||
import emu.grasscutter.game.dungeons.dungeon_results.TowerResult;
|
import emu.grasscutter.game.dungeons.dungeon_results.TowerResult;
|
||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
@ -25,16 +26,22 @@ public class TowerDungeonSettleListener implements DungeonSettleListener {
|
|||||||
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
||||||
var stars = towerManager.getCurLevelStars();
|
var stars = towerManager.getCurLevelStars();
|
||||||
|
|
||||||
towerManager.notifyCurLevelRecordChangeWhenDone(stars);
|
if (endReason == DungeonEndReason.COMPLETED) {
|
||||||
scene.broadcastPacket(
|
// Update star record only when challenge completes successfully.
|
||||||
new PacketTowerFloorRecordChangeNotify(
|
towerManager.notifyCurLevelRecordChangeWhenDone(stars);
|
||||||
towerManager.getCurrentFloorId(), stars, towerManager.canEnterScheduleFloor()));
|
scene.broadcastPacket(
|
||||||
|
new PacketTowerFloorRecordChangeNotify(
|
||||||
|
towerManager.getCurrentFloorId(), stars, towerManager.canEnterScheduleFloor()));
|
||||||
|
}
|
||||||
|
|
||||||
var challenge = scene.getChallenge();
|
var challenge = scene.getChallenge();
|
||||||
|
var finishedTime = challenge == null ? challenge.getFinishedTime() : 0;
|
||||||
var dungeonStats =
|
var dungeonStats =
|
||||||
new DungeonEndStats(
|
new DungeonEndStats(
|
||||||
scene.getKilledMonsterCount(), challenge.getFinishedTime(), 0, endReason);
|
scene.getKilledMonsterCount(), finishedTime, 0, endReason);
|
||||||
var result = new TowerResult(dungeonData, dungeonStats, towerManager, challenge, stars);
|
var result = endReason == DungeonEndReason.COMPLETED ?
|
||||||
|
new TowerResult(dungeonData, dungeonStats, towerManager, challenge, stars) :
|
||||||
|
new BaseDungeonResult(dungeonData, dungeonStats);
|
||||||
|
|
||||||
scene.broadcastPacket(new PacketDungeonSettleNotify(result));
|
scene.broadcastPacket(new PacketDungeonSettleNotify(result));
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import emu.grasscutter.Grasscutter;
|
|||||||
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
||||||
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||||
import emu.grasscutter.game.entity.*;
|
import emu.grasscutter.game.entity.*;
|
||||||
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
@ -22,6 +23,7 @@ public class WorldChallenge {
|
|||||||
private final int challengeIndex;
|
private final int challengeIndex;
|
||||||
private final List<Integer> paramList;
|
private final List<Integer> paramList;
|
||||||
private int timeLimit;
|
private int timeLimit;
|
||||||
|
private GameEntity guardEntity;
|
||||||
private final List<ChallengeTrigger> challengeTriggers;
|
private final List<ChallengeTrigger> challengeTriggers;
|
||||||
private final int goal;
|
private final int goal;
|
||||||
private final AtomicInteger score;
|
private final AtomicInteger score;
|
||||||
@ -58,6 +60,7 @@ public class WorldChallenge {
|
|||||||
this.challengeTriggers = challengeTriggers;
|
this.challengeTriggers = challengeTriggers;
|
||||||
this.goal = goal;
|
this.goal = goal;
|
||||||
this.score = new AtomicInteger(0);
|
this.score = new AtomicInteger(0);
|
||||||
|
this.guardEntity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean inProgress() {
|
public boolean inProgress() {
|
||||||
@ -143,6 +146,10 @@ public class WorldChallenge {
|
|||||||
this.progress = false;
|
this.progress = false;
|
||||||
this.success = success;
|
this.success = success;
|
||||||
this.finishedTime = (int) ((this.scene.getSceneTimeSeconds() - this.startedAt));
|
this.finishedTime = (int) ((this.scene.getSceneTimeSeconds() - this.startedAt));
|
||||||
|
|
||||||
|
// Despawn all leftover mobs in this challenge's SceneGroup
|
||||||
|
getScene().getScriptManager().removeMonstersInGroup(group);
|
||||||
|
|
||||||
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
|
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +157,18 @@ public class WorldChallenge {
|
|||||||
return score.incrementAndGet();
|
return score.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getGuardEntityHpPercent() {
|
||||||
|
if (guardEntity == null) {
|
||||||
|
Grasscutter.getLogger().warn("getGuardEntityHpPercent: Could not find guardEntity for this challenge = {}", this);
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
var curHp = guardEntity.getFightProperties().get(FightProperty.FIGHT_PROP_CUR_HP.getId());
|
||||||
|
var maxHp = guardEntity.getFightProperties().get(FightProperty.FIGHT_PROP_BASE_HP.getId());
|
||||||
|
int percent = (int) (curHp * 100 / maxHp);
|
||||||
|
return percent;
|
||||||
|
}
|
||||||
|
|
||||||
public void onMonsterDeath(EntityMonster monster) {
|
public void onMonsterDeath(EntityMonster monster) {
|
||||||
if (!inProgress()) {
|
if (!inProgress()) {
|
||||||
return;
|
return;
|
||||||
|
@ -33,7 +33,7 @@ public class KillAndGuardChallengeFactoryHandler implements ChallengeFactoryHand
|
|||||||
realGroup,
|
realGroup,
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(monstersToKill, 0),
|
List.of(monstersToKill, gadgetCFGId),
|
||||||
0, // Limit
|
0, // Limit
|
||||||
monstersToKill, // Goal
|
monstersToKill, // Goal
|
||||||
List.of(new KillMonsterCountTrigger(), new GuardTrigger(gadgetCFGId)));
|
List.of(new KillMonsterCountTrigger(), new GuardTrigger(gadgetCFGId)));
|
||||||
|
@ -14,7 +14,9 @@ public class GuardTrigger extends ChallengeTrigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onBegin(WorldChallenge challenge) {
|
public void onBegin(WorldChallenge challenge) {
|
||||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, 100));
|
challenge.setGuardEntity(challenge.getScene().getEntityByConfigId(entityToProtectCFGId, challenge.getGroup().id));
|
||||||
|
lastSendPercent = challenge.getGuardEntityHpPercent();
|
||||||
|
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, lastSendPercent));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -22,9 +24,7 @@ public class GuardTrigger extends ChallengeTrigger {
|
|||||||
if (gadget.getConfigId() != entityToProtectCFGId) {
|
if (gadget.getConfigId() != entityToProtectCFGId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var curHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_CUR_HP.getId());
|
var percent = challenge.getGuardEntityHpPercent();
|
||||||
var maxHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_BASE_HP.getId());
|
|
||||||
int percent = (int) (curHp / maxHp);
|
|
||||||
|
|
||||||
if (percent != lastSendPercent) {
|
if (percent != lastSendPercent) {
|
||||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent));
|
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent));
|
||||||
|
@ -18,12 +18,6 @@ public class InTimeTrigger extends ChallengeTrigger {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCheckTimeout(WorldChallenge challenge) {
|
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();
|
var current = challenge.getScene().getSceneTimeSeconds();
|
||||||
if (current - challenge.getStartedAt() > challenge.getTimeLimit()) {
|
if (current - challenge.getStartedAt() > challenge.getTimeLimit()) {
|
||||||
challenge.fail();
|
challenge.fail();
|
||||||
|
@ -32,11 +32,12 @@ public class TowerResult extends BaseDungeonResult {
|
|||||||
@Override
|
@Override
|
||||||
protected void onProto(DungeonSettleNotifyOuterClass.DungeonSettleNotify.Builder builder) {
|
protected void onProto(DungeonSettleNotifyOuterClass.DungeonSettleNotify.Builder builder) {
|
||||||
var continueStatus = ContinueStateType.CONTINUE_STATE_TYPE_CAN_NOT_CONTINUE_VALUE;
|
var continueStatus = ContinueStateType.CONTINUE_STATE_TYPE_CAN_NOT_CONTINUE_VALUE;
|
||||||
if (challenge.isSuccess() && canJump) {
|
if (challenge.isSuccess()) {
|
||||||
continueStatus =
|
if (hasNextLevel) {
|
||||||
hasNextLevel
|
continueStatus = ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_LEVEL_VALUE;
|
||||||
? ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_LEVEL_VALUE
|
} else if (canJump) {
|
||||||
: ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_FLOOR_VALUE;
|
continueStatus = ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_FLOOR_VALUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var towerLevelEndNotify =
|
var towerLevelEndNotify =
|
||||||
|
@ -70,6 +70,11 @@ public abstract class EntityBaseGadget extends GameEntity {
|
|||||||
.setSourceEntityId(getId())
|
.setSourceEntityId(getId())
|
||||||
.setParam3((int) this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP))
|
.setParam3((int) this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP))
|
||||||
.setEventSource(getConfigId()));
|
.setEventSource(getConfigId()));
|
||||||
|
|
||||||
|
var challenge = getScene().getChallenge();
|
||||||
|
if (challenge != null && this instanceof EntityGadget gadget) {
|
||||||
|
challenge.onGadgetDamage(gadget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
||||||
|
@ -4,7 +4,9 @@ import emu.grasscutter.Grasscutter;
|
|||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
import emu.grasscutter.data.binout.config.fields.ConfigAbilityData;
|
import emu.grasscutter.data.binout.config.fields.ConfigAbilityData;
|
||||||
|
import emu.grasscutter.data.common.PropGrowCurve;
|
||||||
import emu.grasscutter.data.excels.GadgetData;
|
import emu.grasscutter.data.excels.GadgetData;
|
||||||
|
import emu.grasscutter.data.excels.monster.MonsterCurveData;
|
||||||
import emu.grasscutter.game.entity.gadget.*;
|
import emu.grasscutter.game.entity.gadget.*;
|
||||||
import emu.grasscutter.game.entity.gadget.platform.*;
|
import emu.grasscutter.game.entity.gadget.platform.*;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
@ -104,6 +106,20 @@ public class EntityGadget extends EntityBaseGadget {
|
|||||||
this.bornRot = this.getRotation().clone();
|
this.bornRot = this.getRotation().clone();
|
||||||
this.fillFightProps(configGadget);
|
this.fillFightProps(configGadget);
|
||||||
|
|
||||||
|
// Check if this gadget is the abyss defense objective's gadget.
|
||||||
|
// That doesn't have a level and defaults to having 5000 hp, so it dies in like 2 hits on 11-1.
|
||||||
|
// I'll forgive player skill issues and scale its hp up here.
|
||||||
|
// TODO: find out how its fight props are actually scaled
|
||||||
|
if (gadgetData.getJsonName().equals("SceneObj_Gear_Operator_Mamolu_Entity")) {
|
||||||
|
MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(11);
|
||||||
|
if (curve != null) {
|
||||||
|
FightProperty[] hpProps = {FightProperty.FIGHT_PROP_MAX_HP, FightProperty.FIGHT_PROP_BASE_HP, FightProperty.FIGHT_PROP_CUR_HP};
|
||||||
|
for (var prop : hpProps) {
|
||||||
|
setFightProperty(prop, this.getFightProperty(prop) * curve.getMultByProp("GROW_CURVE_HP_ENVIRONMENT"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (GameData.getGadgetMappingMap().containsKey(gadgetId)) {
|
if (GameData.getGadgetMappingMap().containsKey(gadgetId)) {
|
||||||
var controllerName = GameData.getGadgetMappingMap().get(gadgetId).getServerController();
|
var controllerName = GameData.getGadgetMappingMap().get(gadgetId).getServerController();
|
||||||
this.setEntityController(EntityControllerScriptManager.getGadgetController(controllerName));
|
this.setEntityController(EntityControllerScriptManager.getGadgetController(controllerName));
|
||||||
|
@ -100,7 +100,7 @@ public final class PlayerProgressManager extends BasePlayerDataManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setOpenState(int openState, int value, boolean sendNotify) {
|
private void setOpenState(int openState, int value, boolean sendNotify) {
|
||||||
int previousValue = this.player.getOpenStates().getOrDefault(openState, 0);
|
int previousValue = this.player.getOpenStates().getOrDefault(openState, -1 /* non-existent */);
|
||||||
|
|
||||||
if (value != previousValue) {
|
if (value != previousValue) {
|
||||||
this.player.getOpenStates().put(openState, value);
|
this.player.getOpenStates().put(openState, value);
|
||||||
|
@ -40,7 +40,7 @@ public class TowerManager extends BasePlayerManager {
|
|||||||
|
|
||||||
public void onTick() {
|
public void onTick() {
|
||||||
var challenge = player.getScene().getChallenge();
|
var challenge = player.getScene().getChallenge();
|
||||||
if (challenge == null || !challenge.inProgress()) return;
|
if (!inProgress || challenge == null || !challenge.inProgress()) return;
|
||||||
|
|
||||||
// Check star conditions and notify client if any failed.
|
// Check star conditions and notify client if any failed.
|
||||||
int stars = getCurLevelStars();
|
int stars = getCurLevelStars();
|
||||||
@ -153,8 +153,11 @@ public class TowerManager extends BasePlayerManager {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (cond == TowerLevelData.TowerCondType.TOWER_COND_LEFT_HP_GREATER_THAN) {
|
} else if (cond == TowerLevelData.TowerCondType.TOWER_COND_LEFT_HP_GREATER_THAN) {
|
||||||
// TODO: Check monolith health
|
var params = levelData.getHpCond(star);
|
||||||
break;
|
var hpPercent = challenge.getGuardEntityHpPercent();
|
||||||
|
if (hpPercent >= params.getMinimumHpPercentage()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Grasscutter.getLogger()
|
Grasscutter.getLogger()
|
||||||
.error(
|
.error(
|
||||||
|
@ -600,7 +600,7 @@ public class Scene {
|
|||||||
// Should be OK to check only player 0,
|
// Should be OK to check only player 0,
|
||||||
// as no other players could enter Tower
|
// as no other players could enter Tower
|
||||||
var towerManager = getPlayers().get(0).getTowerManager();
|
var towerManager = getPlayers().get(0).getTowerManager();
|
||||||
if (towerManager != null) {
|
if (towerManager != null && towerManager.isInProgress()) {
|
||||||
towerManager.onTick();
|
towerManager.onTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ public class SceneScriptManager {
|
|||||||
/** current triggers controlled by RefreshGroup */
|
/** current triggers controlled by RefreshGroup */
|
||||||
private final Map<Integer, Set<SceneTrigger>> currentTriggers;
|
private final Map<Integer, Set<SceneTrigger>> currentTriggers;
|
||||||
|
|
||||||
|
private final Set<SceneTrigger> ongoingTriggers;
|
||||||
private final Map<String, Set<SceneTrigger>> triggersByGroupScene;
|
private final Map<String, Set<SceneTrigger>> triggersByGroupScene;
|
||||||
private final Map<Integer, Set<Pair<String, Integer>>> activeGroupTimers;
|
private final Map<Integer, Set<Pair<String, Integer>>> activeGroupTimers;
|
||||||
private final Map<String, AtomicInteger> triggerInvocations;
|
private final Map<String, AtomicInteger> triggerInvocations;
|
||||||
@ -76,6 +77,7 @@ public class SceneScriptManager {
|
|||||||
public SceneScriptManager(Scene scene) {
|
public SceneScriptManager(Scene scene) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.currentTriggers = new ConcurrentHashMap<>();
|
this.currentTriggers = new ConcurrentHashMap<>();
|
||||||
|
this.ongoingTriggers = ConcurrentHashMap.newKeySet();
|
||||||
this.triggersByGroupScene = new ConcurrentHashMap<>();
|
this.triggersByGroupScene = new ConcurrentHashMap<>();
|
||||||
this.activeGroupTimers = new ConcurrentHashMap<>();
|
this.activeGroupTimers = new ConcurrentHashMap<>();
|
||||||
this.triggerInvocations = new ConcurrentHashMap<>();
|
this.triggerInvocations = new ConcurrentHashMap<>();
|
||||||
@ -264,6 +266,15 @@ public class SceneScriptManager {
|
|||||||
|
|
||||||
this.addGroupSuite(groupInstance, suiteData, entitiesAdded);
|
this.addGroupSuite(groupInstance, suiteData, entitiesAdded);
|
||||||
|
|
||||||
|
// refreshGroup may be called by a trigger.
|
||||||
|
// If that trigger has been refreshed, ensure it does not get
|
||||||
|
// deregistered anyway when the trigger completes its invocation.
|
||||||
|
for (var triggerSet : currentTriggers.values()) {
|
||||||
|
var toSave = new HashSet<SceneTrigger>(triggerSet);
|
||||||
|
toSave.retainAll(ongoingTriggers);
|
||||||
|
toSave.forEach(t -> t.setPreserved(true));
|
||||||
|
}
|
||||||
|
|
||||||
// Refesh variables here
|
// Refesh variables here
|
||||||
group.variables.forEach(
|
group.variables.forEach(
|
||||||
variable -> {
|
variable -> {
|
||||||
@ -925,6 +936,7 @@ public class SceneScriptManager {
|
|||||||
|
|
||||||
private void callTrigger(SceneTrigger trigger, ScriptArgs params) {
|
private void callTrigger(SceneTrigger trigger, ScriptArgs params) {
|
||||||
// the SetGroupVariableValueByGroup in tower need the param to record the first stage time
|
// the SetGroupVariableValueByGroup in tower need the param to record the first stage time
|
||||||
|
ongoingTriggers.add(trigger);
|
||||||
var ret = this.callScriptFunc(trigger.getAction(), trigger.currentGroup, params);
|
var ret = this.callScriptFunc(trigger.getAction(), trigger.currentGroup, params);
|
||||||
var invocationsCounter = triggerInvocations.get(trigger.getName());
|
var invocationsCounter = triggerInvocations.get(trigger.getName());
|
||||||
var invocations = invocationsCounter.incrementAndGet();
|
var invocations = invocationsCounter.incrementAndGet();
|
||||||
@ -956,11 +968,16 @@ public class SceneScriptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// always deregister on error, otherwise only if the count is reached
|
// always deregister on error, otherwise only if the count is reached
|
||||||
if (ret.isboolean() && !ret.checkboolean()
|
// or the trigger should be preserved after a RefreshGroup call
|
||||||
|
if (trigger.isPreserved()) {
|
||||||
|
trigger.setPreserved(false);
|
||||||
|
}
|
||||||
|
else if (ret.isboolean() && !ret.checkboolean()
|
||||||
|| ret.isint() && ret.checkint() != 0
|
|| ret.isint() && ret.checkint() != 0
|
||||||
|| trigger.getTrigger_count() > 0 && invocations >= trigger.getTrigger_count()) {
|
|| trigger.getTrigger_count() > 0 && invocations >= trigger.getTrigger_count()) {
|
||||||
deregisterTrigger(trigger);
|
deregisterTrigger(trigger);
|
||||||
}
|
}
|
||||||
|
ongoingTriggers.remove(trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LuaValue callScriptFunc(String funcName, SceneGroup group, ScriptArgs params) {
|
private LuaValue callScriptFunc(String funcName, SceneGroup group, ScriptArgs params) {
|
||||||
@ -1104,6 +1121,18 @@ public class SceneScriptManager {
|
|||||||
return meta.sceneBlockIndex;
|
return meta.sceneBlockIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeMonstersInGroup(SceneGroup group) {
|
||||||
|
var configSet = group.monsters.values().stream().map(m -> m.config_id).collect(Collectors.toSet());
|
||||||
|
var toRemove =
|
||||||
|
getScene().getEntities().values().stream()
|
||||||
|
.filter(e -> e instanceof EntityMonster)
|
||||||
|
.filter(e -> e.getGroupId() == group.id)
|
||||||
|
.filter(e -> configSet.contains(e.getConfigId()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
getScene().removeEntities(toRemove, VisionTypeOuterClass.VisionType.VISION_TYPE_MISS);
|
||||||
|
}
|
||||||
|
|
||||||
public void removeMonstersInGroup(SceneGroup group, SceneSuite suite) {
|
public void removeMonstersInGroup(SceneGroup group, SceneSuite suite) {
|
||||||
var configSet = suite.sceneMonsters.stream().map(m -> m.config_id).collect(Collectors.toSet());
|
var configSet = suite.sceneMonsters.stream().map(m -> m.config_id).collect(Collectors.toSet());
|
||||||
var toRemove =
|
var toRemove =
|
||||||
|
@ -201,7 +201,7 @@ public class ScriptLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
||||||
if (towerManager.isInProgress()) {
|
if (towerManager.isInProgress() && towerManager.getCurrentTimeLimit() > 0) {
|
||||||
// Tower scripts call ActiveChallenge twice in mirror stages.
|
// Tower scripts call ActiveChallenge twice in mirror stages.
|
||||||
// The second call provides the time _taken_ in the first stage,
|
// The second call provides the time _taken_ in the first stage,
|
||||||
// not the actual time limit for the challenge.
|
// not the actual time limit for the challenge.
|
||||||
|
@ -17,6 +17,7 @@ public final class SceneTrigger {
|
|||||||
private String tag;
|
private String tag;
|
||||||
|
|
||||||
public transient SceneGroup currentGroup;
|
public transient SceneGroup currentGroup;
|
||||||
|
private boolean preserved;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
|
@ -62,7 +62,11 @@ public final class ScriptMonsterTideService {
|
|||||||
|
|
||||||
public SceneMonster getNextMonster() {
|
public SceneMonster getNextMonster() {
|
||||||
var nextId = this.monsterConfigOrders.poll();
|
var nextId = this.monsterConfigOrders.poll();
|
||||||
if (currentGroup.monsters.containsKey(nextId)) {
|
if (nextId == null) {
|
||||||
|
// AutoMonsterTide has been called with fewer monster config IDs than the total tide count.
|
||||||
|
// Get last config ID from the list, then.
|
||||||
|
return currentGroup.monsters.get(monsterConfigIds.get(monsterConfigIds.size() - 1));
|
||||||
|
} else if (currentGroup.monsters.containsKey(nextId)) {
|
||||||
return currentGroup.monsters.get(nextId);
|
return currentGroup.monsters.get(nextId);
|
||||||
}
|
}
|
||||||
// TODO some monster config_id do not exist in groups, so temporarily set it to the first
|
// TODO some monster config_id do not exist in groups, so temporarily set it to the first
|
||||||
|
Loading…
Reference in New Issue
Block a user