fix quest content and condition triggers (#2283)

* Add param3 to EVENT_GADGET_STATE_CHANGE

* Slight cleanup for DungeonManager

* Fix ContentTriggerFire

* Rework and fix talk content and conditions.

* redo item content and conditions, swap out getItemByGuid with getItemById, and make count handling consistent.

* Don't need to check if checkItem is null

* add this. to DungeonManager.java

* add this to Inventory.java

* Update src/main/java/emu/grasscutter/game/quest/QuestManager.java

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* add spaces to ContentCompleteAnyTalk.java

* Update src/main/java/emu/grasscutter/game/quest/content/ContentCompleteAnyTalk.java

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

---------

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
This commit is contained in:
Nazrin 2023-08-07 15:03:13 -07:00 committed by GitHub
parent 8200607a15
commit b9a493d424
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 119 additions and 67 deletions

View File

@ -286,14 +286,18 @@ public final class DungeonManager {
} }
public void finishDungeon() { public void finishDungeon() {
// Mark the dungeon has completed for the players. this.notifyEndDungeon(true);
var dungeonId = this.getDungeonData().getId(); this.endDungeon(BaseDungeonResult.DungeonEndReason.COMPLETED);
this.getScene() }
.getPlayers()
.forEach(player -> player.getPlayerProgress().markDungeonAsComplete(dungeonId));
notifyEndDungeon(true); public void quitDungeon() {
endDungeon(BaseDungeonResult.DungeonEndReason.COMPLETED); this.notifyEndDungeon(false);
this.endDungeon(BaseDungeonResult.DungeonEndReason.QUIT);
}
public void failDungeon() {
this.notifyEndDungeon(false);
this.endDungeon(BaseDungeonResult.DungeonEndReason.FAILED);
} }
public void notifyEndDungeon(boolean successfully) { public void notifyEndDungeon(boolean successfully) {
@ -301,8 +305,11 @@ public final class DungeonManager {
.getPlayers() .getPlayers()
.forEach( .forEach(
p -> { p -> {
// Trigger the fail event if needed. // Trigger the fail and success event.
if (!successfully) { if (successfully) {
var dungeonId = this.getDungeonData().getId();
p.getPlayerProgress().markDungeonAsComplete(dungeonId);
} else {
p.getQuestManager() p.getQuestManager()
.queueEvent(QuestContent.QUEST_CONTENT_FAIL_DUNGEON, dungeonData.getId()); .queueEvent(QuestContent.QUEST_CONTENT_FAIL_DUNGEON, dungeonData.getId());
} }
@ -317,16 +324,6 @@ public final class DungeonManager {
.callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0)); .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) { public void endDungeon(BaseDungeonResult.DungeonEndReason endReason) {
if (scene.getDungeonSettleListeners() != null) { if (scene.getDungeonSettleListeners() != null) {
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(this, endReason)); scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(this, endReason));

View File

@ -150,6 +150,7 @@ public class EntityGadget extends EntityBaseGadget {
public void updateState(int state) { public void updateState(int state) {
if (state == this.getState()) return; // Don't triggers events if (state == this.getState()) return; // Don't triggers events
var oldState = this.getState();
this.setState(state); this.setState(state);
ticksSinceChange = getScene().getSceneTimeSeconds(); ticksSinceChange = getScene().getSceneTimeSeconds();
this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state)); this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state));
@ -157,7 +158,7 @@ public class EntityGadget extends EntityBaseGadget {
.getScriptManager() .getScriptManager()
.callEvent( .callEvent(
new ScriptArgs( new ScriptArgs(
this.getGroupId(), EventType.EVENT_GADGET_STATE_CHANGE, state, this.getConfigId())); this.getGroupId(), EventType.EVENT_GADGET_STATE_CHANGE, state, this.getConfigId()).setParam3(oldState));
} }
@Deprecated(forRemoval = true) // Dont use! @Deprecated(forRemoval = true) // Dont use!

View File

@ -36,4 +36,9 @@ public class EquipInventoryTab implements InventoryTab {
public int getMaxCapacity() { public int getMaxCapacity() {
return this.maxCapacity; return this.maxCapacity;
} }
@Override
public int getItemCountById(int itemId) {
return (int) items.stream().filter(item -> item.getItemId() == itemId).count();
}
} }

View File

@ -129,7 +129,7 @@ public class GameItem {
public void checkIsNew(Inventory inventory) { public void checkIsNew(Inventory inventory) {
// display notification when player obtain new item // display notification when player obtain new item
if (inventory.getItemByGuid(this.itemId) == null) { if (inventory.getItemById(this.itemId) == null) {
this.newItem = true; this.newItem = true;
} }
} }

View File

@ -17,6 +17,9 @@ import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.longs.*; import it.unimi.dsi.fastutil.longs.*;
import lombok.val;
import javax.annotation.Nullable;
import java.util.*; import java.util.*;
public class Inventory extends BasePlayerManager implements Iterable<GameItem> { public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
@ -62,6 +65,26 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
return this.getItems().get(id); return this.getItems().get(id);
} }
@Nullable
public InventoryTab getInventoryTabByItemId(int itemId) {
val itemData = GameData.getItemDataMap().get(itemId);
if (itemData == null || itemData.getItemType() == null) {
return null;
}
return getInventoryTab(itemData.getItemType());
}
@Nullable
public GameItem getItemById(int itemId) {
val inventoryTab = this.getInventoryTabByItemId(itemId);
return inventoryTab != null ? inventoryTab.getItemById(itemId) : null;
}
public int getItemCountById(int itemId) {
val inventoryTab = this.getInventoryTabByItemId(itemId);
return inventoryTab != null ? inventoryTab.getItemCountById(itemId) : 0;
}
public boolean addItem(int itemId) { public boolean addItem(int itemId) {
return addItem(itemId, 1); return addItem(itemId, 1);
} }
@ -562,7 +585,7 @@ public class Inventory extends BasePlayerManager implements Iterable<GameItem> {
tab = getInventoryTab(item.getItemData().getItemType()); tab = getInventoryTab(item.getItemData().getItemType());
} }
putItem(item, tab); this.putItem(item, tab);
// Equip to a character if possible // Equip to a character if possible
if (item.isEquipped()) { if (item.isEquipped()) {

View File

@ -10,4 +10,6 @@ public interface InventoryTab {
int getSize(); int getSize();
int getMaxCapacity(); int getMaxCapacity();
int getItemCountById(int itemId);
} }

View File

@ -2,6 +2,7 @@ package emu.grasscutter.game.inventory;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.val;
public class MaterialInventoryTab implements InventoryTab { public class MaterialInventoryTab implements InventoryTab {
private final Int2ObjectMap<GameItem> items; private final Int2ObjectMap<GameItem> items;
@ -36,4 +37,10 @@ public class MaterialInventoryTab implements InventoryTab {
public int getMaxCapacity() { public int getMaxCapacity() {
return this.maxCapacity; return this.maxCapacity;
} }
@Override
public int getItemCountById(int itemId) {
val item = getItemById(itemId);
return item != null ? item.getCount() : 0;
}
} }

View File

@ -172,6 +172,8 @@ public class GameQuest {
this.failProgressList = new int[questData.getFailCond().size()]; this.failProgressList = new int[questData.getFailCond().size()];
} }
this.getMainQuest().getTalks().values().removeIf(talk -> talk.getId() == this.getSubQuestId());
this.getOwner().getPlayerProgress().resetCurrentProgress(String.valueOf(this.subQuestId)); this.getOwner().getPlayerProgress().resetCurrentProgress(String.valueOf(this.subQuestId));
setState(QuestState.QUEST_STATE_UNSTARTED); setState(QuestState.QUEST_STATE_UNSTARTED);

View File

@ -279,7 +279,7 @@ public class QuestManager extends BasePlayerManager {
} }
public GameMainQuest getMainQuestByTalkId(int talkId) { public GameMainQuest getMainQuestByTalkId(int talkId) {
int mainQuestId = GameData.getQuestTalkMap().getOrDefault(talkId, talkId / 100); var mainQuestId = GameData.getQuestTalkMap().getOrDefault(talkId, 0);
return getMainQuestById(mainQuestId); return getMainQuestById(mainQuestId);
} }

View File

@ -2,8 +2,6 @@ package emu.grasscutter.game.quest.conditions;
import static emu.grasscutter.game.quest.enums.QuestCond.QUEST_COND_COMPLETE_TALK; import static emu.grasscutter.game.quest.enums.QuestCond.QUEST_COND_COMPLETE_TALK;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.QuestValueCond; import emu.grasscutter.game.quest.QuestValueCond;
@ -20,16 +18,12 @@ public class ConditionCompleteTalk extends BaseCondition {
String paramStr, String paramStr,
int... params) { int... params) {
val talkId = condition.getParam()[0]; val talkId = condition.getParam()[0];
val unknownParam = condition.getParam()[1]; // e.g. 3 for 7081601
val checkMainQuest = owner.getQuestManager().getMainQuestByTalkId(talkId); val checkMainQuest = owner.getQuestManager().getMainQuestByTalkId(talkId);
if (checkMainQuest == null if (checkMainQuest == null) {
|| GameData.getMainQuestDataMap().get(checkMainQuest.getParentQuestId()).getTalks() return talkId == params[0];
== null) {
Grasscutter.getLogger()
.debug("Warning: mainQuest {} hasn't been started yet, or has no talks", talkId / 100);
return false;
} }
val talkData = checkMainQuest.getTalks().get(talkId); val talkData = checkMainQuest.getTalks().get(talkId);
return talkData != null || checkMainQuest.getChildQuestById(talkId) != null; return talkData != null;
} }
} }

View File

@ -18,8 +18,8 @@ public class ConditionItemNumLessThan extends BaseCondition {
String paramStr, String paramStr,
int... params) { int... params) {
val itemId = condition.getParam()[0]; val itemId = condition.getParam()[0];
val amount = condition.getParam()[1]; val targetAmount = condition.getParam()[1];
val checkItem = owner.getInventory().getItemByGuid(itemId); val amount = owner.getInventory().getItemCountById(itemId);
return checkItem == null || checkItem.getCount() < amount; return amount < targetAmount;
} }
} }

View File

@ -18,8 +18,11 @@ public class ConditionPackHaveItem extends BaseCondition {
String paramStr, String paramStr,
int... params) { int... params) {
val itemId = condition.getParam()[0]; val itemId = condition.getParam()[0];
val targetAmount = condition.getParam()[1]; var targetAmount = condition.getParam()[1];
val checkItem = owner.getInventory().getItemByGuid(itemId); if (targetAmount == 0) {
return checkItem != null && checkItem.getCount() >= targetAmount; targetAmount = 1;
}
val amount = owner.getInventory().getItemCountById(itemId);
return amount >= targetAmount;
} }
} }

View File

@ -17,8 +17,12 @@ public class ContentAddQuestProgress extends BaseContent {
val currentCount = val currentCount =
quest.getOwner().getPlayerProgress().getCurrentProgress(String.valueOf(progressId)); quest.getOwner().getPlayerProgress().getCurrentProgress(String.valueOf(progressId));
var targetAmount = condition.getCount();
if (targetAmount == 0) {
targetAmount = 1;
}
// if the condition count is 0 I think it is safe to assume that the // if the condition count is 0 I think it is safe to assume that the
// condition count from EXEC only needs to be 1 // condition count from EXEC only needs to be 1
return currentCount >= condition.getCount(); return currentCount >= targetAmount;
} }
} }

View File

@ -2,11 +2,10 @@ package emu.grasscutter.game.quest.content;
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK; import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.*;
import emu.grasscutter.game.quest.QuestValueContent; import lombok.val;
import java.util.stream.Stream; import java.util.Arrays;
@QuestValueContent(QUEST_CONTENT_COMPLETE_ANY_TALK) @QuestValueContent(QUEST_CONTENT_COMPLETE_ANY_TALK)
public class ContentCompleteAnyTalk extends BaseContent { public class ContentCompleteAnyTalk extends BaseContent {
@ -14,10 +13,22 @@ public class ContentCompleteAnyTalk extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
return Stream.of(condition.getParamStr().split(",")) var conditionTalk = Arrays.stream(condition.getParamStr().split(","))
.mapToInt(Integer::parseInt) .mapToInt(Integer::parseInt)
.anyMatch( .toArray();
talkId ->
GameData.getTalkConfigDataMap().get(params[0]) != null && talkId == params[0]); for (var talkId : conditionTalk) {
val checkMainQuest = quest.getOwner().getQuestManager().getMainQuestByTalkId(talkId);
if (checkMainQuest == null) {
if (talkId == params[0]) return true;
continue;
}
val talkData = checkMainQuest.getTalks().get(talkId);
if (talkData != null) {
return true;
}
}
return false;
} }
} }

View File

@ -12,10 +12,9 @@ public class ContentCompleteTalk extends BaseContent {
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
val talkId = condition.getParam()[0]; val talkId = condition.getParam()[0];
if (talkId != params[0]) return false;
val checkMainQuest = quest.getOwner().getQuestManager().getMainQuestByTalkId(talkId); val checkMainQuest = quest.getOwner().getQuestManager().getMainQuestByTalkId(talkId);
if (checkMainQuest == null) { if (checkMainQuest == null) {
return false; return talkId == params[0];
} }
val talkData = checkMainQuest.getTalks().get(talkId); val talkData = checkMainQuest.getTalks().get(talkId);

View File

@ -5,12 +5,16 @@ import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_ITEM_L
import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValueContent; import emu.grasscutter.game.quest.QuestValueContent;
import lombok.val;
@QuestValueContent(QUEST_CONTENT_ITEM_LESS_THAN) @QuestValueContent(QUEST_CONTENT_ITEM_LESS_THAN)
public class ContentItemLessThan extends BaseContent { public class ContentItemLessThan extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
return condition.getParam()[0] == params[0] && condition.getCount() > params[1]; val itemId = condition.getParam()[0];
val targetAmount = condition.getParam()[1];
val amount = quest.getOwner().getInventory().getItemCountById(itemId);
return amount < targetAmount;
} }
} }

View File

@ -12,8 +12,10 @@ public class ContentLuaNotify extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
return condition.getParamStr().equals(paramStr) var targetAmount = condition.getCount();
&& condition.getCount() if (targetAmount == 0) {
<= quest.getOwner().getPlayerProgress().getCurrentProgress(paramStr); targetAmount = 1;
}
return targetAmount <= quest.getOwner().getPlayerProgress().getCurrentProgress(condition.getParamStr());
} }
} }

View File

@ -5,16 +5,19 @@ import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_OBTAIN
import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValueContent; import emu.grasscutter.game.quest.QuestValueContent;
import lombok.val;
@QuestValueContent(QUEST_CONTENT_OBTAIN_ITEM) @QuestValueContent(QUEST_CONTENT_OBTAIN_ITEM)
public class ContentObtainItem extends BaseContent { public class ContentObtainItem extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
var targetCount = condition.getCount(); val itemId = condition.getParam()[0];
if (targetCount == 0) { var targetAmount = condition.getCount();
targetCount = 1; if (targetAmount == 0) {
targetAmount = 1;
} }
return condition.getParam()[0] == params[0] && targetCount <= params[1]; val amount = quest.getOwner().getInventory().getItemCountById(itemId);
return amount >= targetAmount;
} }
} }

View File

@ -2,23 +2,18 @@ package emu.grasscutter.game.quest.content;
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_TRIGGER_FIRE; import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_TRIGGER_FIRE;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValueContent; import emu.grasscutter.game.quest.QuestValueContent;
import lombok.val;
@QuestValueContent(QUEST_CONTENT_TRIGGER_FIRE) @QuestValueContent(QUEST_CONTENT_TRIGGER_FIRE)
public class ContentTriggerFire extends BaseContent { public class ContentTriggerFire extends BaseContent {
@Override @Override
public boolean execute( public boolean execute(
GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) {
if (quest.getTriggers().containsKey(quest.getTriggerNameById(params[0]))) { val triggerId = condition.getParam()[0];
// We don't want to put a new key here val triggerName = quest.getTriggerNameById(triggerId);
return quest.getTriggers().get(quest.getTriggerNameById(params[0])); return quest.getTriggers().getOrDefault(triggerName, false);
} else {
Grasscutter.getLogger()
.debug("Quest {} doesn't have trigger {} registered.", quest.getSubQuestId(), params[0]);
return false;
}
} }
} }