From 58d26505058ce741f20d1143e502a052dd599b56 Mon Sep 17 00:00:00 2001 From: Thoronium <107363768+NotThorny@users.noreply.github.com> Date: Sun, 6 Aug 2023 22:25:59 -0600 Subject: [PATCH 1/7] Fix swim stamina cost (#2287) --- .../grasscutter/game/managers/stamina/StaminaManager.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java b/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java index b05567638..8a0a86b10 100644 --- a/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java +++ b/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java @@ -389,6 +389,9 @@ public class StaminaManager extends BasePlayerManager { return; } + // Update previous motion state + this.previousState = currentState; + // Update the current state. this.currentState = motionState; // logger.trace(currentState + "\t" + (notifyEntityId == currentAvatarEntityId ? "character" : "vehicle")); @@ -417,6 +420,11 @@ public class StaminaManager extends BasePlayerManager { // Internal handler private void handleImmediateStamina(GameSession session, @NotNull MotionState motionState) { + // Don't double dip on sustained stamina start costs + if (previousState == currentState) { + return; + } + switch (motionState) { case MOTION_STATE_CLIMB -> updateStaminaRelative(session, new Consumption(ConsumptionType.CLIMB_START), true); From 0b0dcf9b8e30d7d726eda7d11273de0a79a102a2 Mon Sep 17 00:00:00 2001 From: Nazrin Date: Sun, 6 Aug 2023 21:27:13 -0700 Subject: [PATCH 2/7] Implement QUEST_EXEC_RANDOM_QUEST_VAR (#2284) --- .../grasscutter/game/quest/GameMainQuest.java | 11 +++++++++++ .../grasscutter/game/quest/enums/QuestExec.java | 2 +- .../game/quest/exec/ExecRandomQuestVar.java | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/main/java/emu/grasscutter/game/quest/exec/ExecRandomQuestVar.java diff --git a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java index 38cf6f154..4688c0dae 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java @@ -16,6 +16,7 @@ import emu.grasscutter.net.proto.ChildQuestOuterClass.ChildQuest; import emu.grasscutter.net.proto.ParentQuestOuterClass.ParentQuest; import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.ConversionUtils; +import emu.grasscutter.utils.Utils; import java.util.*; import java.util.stream.Collectors; import lombok.*; @@ -120,6 +121,16 @@ public class GameMainQuest { this.triggerQuestVarAction(i, this.questVars[i]); } + public void randomQuestVar(int i, int low, int high) { + int previousValue = this.questVars[i]; + this.questVars[i] = Utils.random.nextInt(low, high); + Grasscutter.getLogger() + .debug( + "questVar {} value randomized from {} to {}", i, previousValue, this.questVars[i]); + + this.triggerQuestVarAction(i, this.questVars[i]); + } + public void triggerQuestVarAction(int index, int value) { var questManager = this.getQuestManager(); questManager.queueEvent(QuestCond.QUEST_COND_QUEST_VAR_EQUAL, index, value); diff --git a/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java b/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java index faba81e32..07c01a8b4 100644 --- a/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java +++ b/src/main/java/emu/grasscutter/game/quest/enums/QuestExec.java @@ -59,7 +59,7 @@ public enum QuestExec implements QuestTrigger { QUEST_EXEC_SET_QUEST_VAR(48), QUEST_EXEC_INC_QUEST_VAR(49), QUEST_EXEC_DEC_QUEST_VAR(50), - QUEST_EXEC_RANDOM_QUEST_VAR(51), // missing + QUEST_EXEC_RANDOM_QUEST_VAR(51), QUEST_EXEC_ACTIVATE_SCANNING_PIC(52), // missing, currently unused QUEST_EXEC_RELOAD_SCENE_TAG(53), // missing QUEST_EXEC_REGISTER_DYNAMIC_GROUP_ONLY(54), // missing diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecRandomQuestVar.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecRandomQuestVar.java new file mode 100644 index 000000000..0fa3ced33 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecRandomQuestVar.java @@ -0,0 +1,16 @@ +package emu.grasscutter.game.quest.exec; + +import emu.grasscutter.data.excels.quest.QuestData; +import emu.grasscutter.game.quest.GameQuest; +import emu.grasscutter.game.quest.QuestValueExec; +import emu.grasscutter.game.quest.enums.QuestExec; +import emu.grasscutter.game.quest.handlers.QuestExecHandler; + +@QuestValueExec(QuestExec.QUEST_EXEC_RANDOM_QUEST_VAR) +public class ExecRandomQuestVar extends QuestExecHandler { + @Override + public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { + quest.getMainQuest().randomQuestVar(Integer.parseInt(paramStr[0]), Integer.parseInt(paramStr[1]), Integer.parseInt(paramStr[2])); + return true; + } +} From 8200607a15481a8dce8354900b796e48fa11f880 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 04:28:56 +0000 Subject: [PATCH 3/7] Format code [skip actions] --- .../java/emu/grasscutter/game/quest/GameMainQuest.java | 3 +-- .../grasscutter/game/quest/exec/ExecRandomQuestVar.java | 7 ++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java index 4688c0dae..a03cbc6ea 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java @@ -125,8 +125,7 @@ public class GameMainQuest { int previousValue = this.questVars[i]; this.questVars[i] = Utils.random.nextInt(low, high); Grasscutter.getLogger() - .debug( - "questVar {} value randomized from {} to {}", i, previousValue, this.questVars[i]); + .debug("questVar {} value randomized from {} to {}", i, previousValue, this.questVars[i]); this.triggerQuestVarAction(i, this.questVars[i]); } diff --git a/src/main/java/emu/grasscutter/game/quest/exec/ExecRandomQuestVar.java b/src/main/java/emu/grasscutter/game/quest/exec/ExecRandomQuestVar.java index 0fa3ced33..d61a72772 100644 --- a/src/main/java/emu/grasscutter/game/quest/exec/ExecRandomQuestVar.java +++ b/src/main/java/emu/grasscutter/game/quest/exec/ExecRandomQuestVar.java @@ -10,7 +10,12 @@ import emu.grasscutter.game.quest.handlers.QuestExecHandler; public class ExecRandomQuestVar extends QuestExecHandler { @Override public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) { - quest.getMainQuest().randomQuestVar(Integer.parseInt(paramStr[0]), Integer.parseInt(paramStr[1]), Integer.parseInt(paramStr[2])); + quest + .getMainQuest() + .randomQuestVar( + Integer.parseInt(paramStr[0]), + Integer.parseInt(paramStr[1]), + Integer.parseInt(paramStr[2])); return true; } } From b9a493d424043824d9703915d9274a58d51b99e1 Mon Sep 17 00:00:00 2001 From: Nazrin Date: Mon, 7 Aug 2023 15:03:13 -0700 Subject: [PATCH 4/7] 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> --- .../game/dungeons/DungeonManager.java | 35 +++++++++---------- .../grasscutter/game/entity/EntityGadget.java | 3 +- .../game/inventory/EquipInventoryTab.java | 5 +++ .../grasscutter/game/inventory/GameItem.java | 2 +- .../grasscutter/game/inventory/Inventory.java | 25 ++++++++++++- .../game/inventory/InventoryTab.java | 2 ++ .../game/inventory/MaterialInventoryTab.java | 7 ++++ .../emu/grasscutter/game/quest/GameQuest.java | 2 ++ .../grasscutter/game/quest/QuestManager.java | 2 +- .../conditions/ConditionCompleteTalk.java | 14 +++----- .../conditions/ConditionItemNumLessThan.java | 6 ++-- .../conditions/ConditionPackHaveItem.java | 9 +++-- .../content/ContentAddQuestProgress.java | 6 +++- .../quest/content/ContentCompleteAnyTalk.java | 27 +++++++++----- .../quest/content/ContentCompleteTalk.java | 3 +- .../quest/content/ContentItemLessThan.java | 6 +++- .../game/quest/content/ContentLuaNotify.java | 8 +++-- .../game/quest/content/ContentObtainItem.java | 11 +++--- .../quest/content/ContentTriggerFire.java | 13 +++---- 19 files changed, 119 insertions(+), 67 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java b/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java index c856ac242..4b8fa0131 100644 --- a/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java +++ b/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java @@ -286,14 +286,18 @@ public final class DungeonManager { } 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)); + this.notifyEndDungeon(true); + this.endDungeon(BaseDungeonResult.DungeonEndReason.COMPLETED); + } - notifyEndDungeon(true); - endDungeon(BaseDungeonResult.DungeonEndReason.COMPLETED); + public void quitDungeon() { + this.notifyEndDungeon(false); + this.endDungeon(BaseDungeonResult.DungeonEndReason.QUIT); + } + + public void failDungeon() { + this.notifyEndDungeon(false); + this.endDungeon(BaseDungeonResult.DungeonEndReason.FAILED); } public void notifyEndDungeon(boolean successfully) { @@ -301,8 +305,11 @@ public final class DungeonManager { .getPlayers() .forEach( p -> { - // Trigger the fail event if needed. - if (!successfully) { + // Trigger the fail and success event. + if (successfully) { + var dungeonId = this.getDungeonData().getId(); + p.getPlayerProgress().markDungeonAsComplete(dungeonId); + } else { p.getQuestManager() .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)); } - 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)); diff --git a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java index 2cab739fc..a04d6e67d 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java @@ -150,6 +150,7 @@ public class EntityGadget extends EntityBaseGadget { public void updateState(int state) { if (state == this.getState()) return; // Don't triggers events + var oldState = this.getState(); this.setState(state); ticksSinceChange = getScene().getSceneTimeSeconds(); this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state)); @@ -157,7 +158,7 @@ public class EntityGadget extends EntityBaseGadget { .getScriptManager() .callEvent( 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! diff --git a/src/main/java/emu/grasscutter/game/inventory/EquipInventoryTab.java b/src/main/java/emu/grasscutter/game/inventory/EquipInventoryTab.java index 5082f978e..3d2f8fd5d 100644 --- a/src/main/java/emu/grasscutter/game/inventory/EquipInventoryTab.java +++ b/src/main/java/emu/grasscutter/game/inventory/EquipInventoryTab.java @@ -36,4 +36,9 @@ public class EquipInventoryTab implements InventoryTab { public int getMaxCapacity() { return this.maxCapacity; } + + @Override + public int getItemCountById(int itemId) { + return (int) items.stream().filter(item -> item.getItemId() == itemId).count(); + } } diff --git a/src/main/java/emu/grasscutter/game/inventory/GameItem.java b/src/main/java/emu/grasscutter/game/inventory/GameItem.java index 64029c752..4dbfbbb45 100644 --- a/src/main/java/emu/grasscutter/game/inventory/GameItem.java +++ b/src/main/java/emu/grasscutter/game/inventory/GameItem.java @@ -129,7 +129,7 @@ public class GameItem { public void checkIsNew(Inventory inventory) { // display notification when player obtain new item - if (inventory.getItemByGuid(this.itemId) == null) { + if (inventory.getItemById(this.itemId) == null) { this.newItem = true; } } diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index a06d55ed1..ecb12c35d 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -17,6 +17,9 @@ import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Utils; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.longs.*; +import lombok.val; +import javax.annotation.Nullable; + import java.util.*; public class Inventory extends BasePlayerManager implements Iterable { @@ -62,6 +65,26 @@ public class Inventory extends BasePlayerManager implements Iterable { 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) { return addItem(itemId, 1); } @@ -562,7 +585,7 @@ public class Inventory extends BasePlayerManager implements Iterable { tab = getInventoryTab(item.getItemData().getItemType()); } - putItem(item, tab); + this.putItem(item, tab); // Equip to a character if possible if (item.isEquipped()) { diff --git a/src/main/java/emu/grasscutter/game/inventory/InventoryTab.java b/src/main/java/emu/grasscutter/game/inventory/InventoryTab.java index e50f884bf..374a43c31 100644 --- a/src/main/java/emu/grasscutter/game/inventory/InventoryTab.java +++ b/src/main/java/emu/grasscutter/game/inventory/InventoryTab.java @@ -10,4 +10,6 @@ public interface InventoryTab { int getSize(); int getMaxCapacity(); + + int getItemCountById(int itemId); } diff --git a/src/main/java/emu/grasscutter/game/inventory/MaterialInventoryTab.java b/src/main/java/emu/grasscutter/game/inventory/MaterialInventoryTab.java index 9ebf0d7f1..5f71839c4 100644 --- a/src/main/java/emu/grasscutter/game/inventory/MaterialInventoryTab.java +++ b/src/main/java/emu/grasscutter/game/inventory/MaterialInventoryTab.java @@ -2,6 +2,7 @@ package emu.grasscutter.game.inventory; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import lombok.val; public class MaterialInventoryTab implements InventoryTab { private final Int2ObjectMap items; @@ -36,4 +37,10 @@ public class MaterialInventoryTab implements InventoryTab { public int getMaxCapacity() { return this.maxCapacity; } + + @Override + public int getItemCountById(int itemId) { + val item = getItemById(itemId); + return item != null ? item.getCount() : 0; + } } diff --git a/src/main/java/emu/grasscutter/game/quest/GameQuest.java b/src/main/java/emu/grasscutter/game/quest/GameQuest.java index 904a7b404..b69367c3d 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameQuest.java @@ -172,6 +172,8 @@ public class GameQuest { 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)); setState(QuestState.QUEST_STATE_UNSTARTED); diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index 572731edb..968e06fcb 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -279,7 +279,7 @@ public class QuestManager extends BasePlayerManager { } public GameMainQuest getMainQuestByTalkId(int talkId) { - int mainQuestId = GameData.getQuestTalkMap().getOrDefault(talkId, talkId / 100); + var mainQuestId = GameData.getQuestTalkMap().getOrDefault(talkId, 0); return getMainQuestById(mainQuestId); } diff --git a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionCompleteTalk.java b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionCompleteTalk.java index 1a4f5df6f..c9c03ad31 100644 --- a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionCompleteTalk.java +++ b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionCompleteTalk.java @@ -2,8 +2,6 @@ package emu.grasscutter.game.quest.conditions; 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.game.player.Player; import emu.grasscutter.game.quest.QuestValueCond; @@ -20,16 +18,12 @@ public class ConditionCompleteTalk extends BaseCondition { String paramStr, int... params) { val talkId = condition.getParam()[0]; - val unknownParam = condition.getParam()[1]; // e.g. 3 for 7081601 val checkMainQuest = owner.getQuestManager().getMainQuestByTalkId(talkId); - if (checkMainQuest == null - || GameData.getMainQuestDataMap().get(checkMainQuest.getParentQuestId()).getTalks() - == null) { - Grasscutter.getLogger() - .debug("Warning: mainQuest {} hasn't been started yet, or has no talks", talkId / 100); - return false; + if (checkMainQuest == null) { + return talkId == params[0]; } + val talkData = checkMainQuest.getTalks().get(talkId); - return talkData != null || checkMainQuest.getChildQuestById(talkId) != null; + return talkData != null; } } diff --git a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionItemNumLessThan.java b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionItemNumLessThan.java index 57eb1e8a6..8ea52cf76 100644 --- a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionItemNumLessThan.java +++ b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionItemNumLessThan.java @@ -18,8 +18,8 @@ public class ConditionItemNumLessThan extends BaseCondition { String paramStr, int... params) { val itemId = condition.getParam()[0]; - val amount = condition.getParam()[1]; - val checkItem = owner.getInventory().getItemByGuid(itemId); - return checkItem == null || checkItem.getCount() < amount; + val targetAmount = condition.getParam()[1]; + val amount = owner.getInventory().getItemCountById(itemId); + return amount < targetAmount; } } diff --git a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionPackHaveItem.java b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionPackHaveItem.java index 3719577b8..14bf7c662 100644 --- a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionPackHaveItem.java +++ b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionPackHaveItem.java @@ -18,8 +18,11 @@ public class ConditionPackHaveItem extends BaseCondition { String paramStr, int... params) { val itemId = condition.getParam()[0]; - val targetAmount = condition.getParam()[1]; - val checkItem = owner.getInventory().getItemByGuid(itemId); - return checkItem != null && checkItem.getCount() >= targetAmount; + var targetAmount = condition.getParam()[1]; + if (targetAmount == 0) { + targetAmount = 1; + } + val amount = owner.getInventory().getItemCountById(itemId); + return amount >= targetAmount; } } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentAddQuestProgress.java b/src/main/java/emu/grasscutter/game/quest/content/ContentAddQuestProgress.java index cdf1ff0f5..3dc6ff573 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentAddQuestProgress.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentAddQuestProgress.java @@ -17,8 +17,12 @@ public class ContentAddQuestProgress extends BaseContent { val currentCount = 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 // condition count from EXEC only needs to be 1 - return currentCount >= condition.getCount(); + return currentCount >= targetAmount; } } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteAnyTalk.java b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteAnyTalk.java index b76c144e7..19a2a3f0d 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteAnyTalk.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteAnyTalk.java @@ -2,11 +2,10 @@ package emu.grasscutter.game.quest.content; 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.game.quest.GameQuest; -import emu.grasscutter.game.quest.QuestValueContent; -import java.util.stream.Stream; +import emu.grasscutter.game.quest.*; +import lombok.val; +import java.util.Arrays; @QuestValueContent(QUEST_CONTENT_COMPLETE_ANY_TALK) public class ContentCompleteAnyTalk extends BaseContent { @@ -14,10 +13,22 @@ public class ContentCompleteAnyTalk extends BaseContent { @Override public boolean execute( 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) - .anyMatch( - talkId -> - GameData.getTalkConfigDataMap().get(params[0]) != null && talkId == params[0]); + .toArray(); + + 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; } } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java index 5378d4ba3..b93dffc81 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java @@ -12,10 +12,9 @@ public class ContentCompleteTalk extends BaseContent { public boolean execute( GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { val talkId = condition.getParam()[0]; - if (talkId != params[0]) return false; val checkMainQuest = quest.getOwner().getQuestManager().getMainQuestByTalkId(talkId); if (checkMainQuest == null) { - return false; + return talkId == params[0]; } val talkData = checkMainQuest.getTalks().get(talkId); diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentItemLessThan.java b/src/main/java/emu/grasscutter/game/quest/content/ContentItemLessThan.java index 0bf79f4e8..43fb1d89c 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentItemLessThan.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentItemLessThan.java @@ -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.game.quest.GameQuest; import emu.grasscutter.game.quest.QuestValueContent; +import lombok.val; @QuestValueContent(QUEST_CONTENT_ITEM_LESS_THAN) public class ContentItemLessThan extends BaseContent { @Override public boolean execute( 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; } } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java b/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java index 47d65bcd8..bb3f1b14c 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java @@ -12,8 +12,10 @@ public class ContentLuaNotify extends BaseContent { @Override public boolean execute( GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { - return condition.getParamStr().equals(paramStr) - && condition.getCount() - <= quest.getOwner().getPlayerProgress().getCurrentProgress(paramStr); + var targetAmount = condition.getCount(); + if (targetAmount == 0) { + targetAmount = 1; + } + return targetAmount <= quest.getOwner().getPlayerProgress().getCurrentProgress(condition.getParamStr()); } } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentObtainItem.java b/src/main/java/emu/grasscutter/game/quest/content/ContentObtainItem.java index ecf5bf858..f2e3bef1d 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentObtainItem.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentObtainItem.java @@ -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.game.quest.GameQuest; import emu.grasscutter.game.quest.QuestValueContent; +import lombok.val; @QuestValueContent(QUEST_CONTENT_OBTAIN_ITEM) public class ContentObtainItem extends BaseContent { @Override public boolean execute( GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { - var targetCount = condition.getCount(); - if (targetCount == 0) { - targetCount = 1; + val itemId = condition.getParam()[0]; + var targetAmount = condition.getCount(); + if (targetAmount == 0) { + targetAmount = 1; } - return condition.getParam()[0] == params[0] && targetCount <= params[1]; + val amount = quest.getOwner().getInventory().getItemCountById(itemId); + return amount >= targetAmount; } } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentTriggerFire.java b/src/main/java/emu/grasscutter/game/quest/content/ContentTriggerFire.java index be3992001..2a1256161 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentTriggerFire.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentTriggerFire.java @@ -2,23 +2,18 @@ package emu.grasscutter.game.quest.content; 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.game.quest.GameQuest; import emu.grasscutter.game.quest.QuestValueContent; +import lombok.val; @QuestValueContent(QUEST_CONTENT_TRIGGER_FIRE) public class ContentTriggerFire extends BaseContent { @Override public boolean execute( GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { - if (quest.getTriggers().containsKey(quest.getTriggerNameById(params[0]))) { - // We don't want to put a new key here - return quest.getTriggers().get(quest.getTriggerNameById(params[0])); - } else { - Grasscutter.getLogger() - .debug("Quest {} doesn't have trigger {} registered.", quest.getSubQuestId(), params[0]); - return false; - } + val triggerId = condition.getParam()[0]; + val triggerName = quest.getTriggerNameById(triggerId); + return quest.getTriggers().getOrDefault(triggerName, false); } } From bbf0d4dda1385fe5b739c79046ed0454967dbcfc Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 22:04:40 +0000 Subject: [PATCH 5/7] Format code [skip actions] --- .../emu/grasscutter/game/entity/EntityGadget.java | 6 +++++- .../emu/grasscutter/game/inventory/Inventory.java | 11 ++++------- .../game/quest/content/ContentCompleteAnyTalk.java | 7 +++---- .../game/quest/content/ContentLuaNotify.java | 3 ++- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java index a04d6e67d..55d0fd3ff 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java @@ -158,7 +158,11 @@ public class EntityGadget extends EntityBaseGadget { .getScriptManager() .callEvent( new ScriptArgs( - this.getGroupId(), EventType.EVENT_GADGET_STATE_CHANGE, state, this.getConfigId()).setParam3(oldState)); + this.getGroupId(), + EventType.EVENT_GADGET_STATE_CHANGE, + state, + this.getConfigId()) + .setParam3(oldState)); } @Deprecated(forRemoval = true) // Dont use! diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index ecb12c35d..eabda9c82 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -17,10 +17,9 @@ import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Utils; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.longs.*; -import lombok.val; -import javax.annotation.Nullable; - import java.util.*; +import javax.annotation.Nullable; +import lombok.val; public class Inventory extends BasePlayerManager implements Iterable { private final Long2ObjectMap store; @@ -65,8 +64,7 @@ public class Inventory extends BasePlayerManager implements Iterable { return this.getItems().get(id); } - @Nullable - public InventoryTab getInventoryTabByItemId(int itemId) { + @Nullable public InventoryTab getInventoryTabByItemId(int itemId) { val itemData = GameData.getItemDataMap().get(itemId); if (itemData == null || itemData.getItemType() == null) { return null; @@ -74,8 +72,7 @@ public class Inventory extends BasePlayerManager implements Iterable { return getInventoryTab(itemData.getItemType()); } - @Nullable - public GameItem getItemById(int itemId) { + @Nullable public GameItem getItemById(int itemId) { val inventoryTab = this.getInventoryTabByItemId(itemId); return inventoryTab != null ? inventoryTab.getItemById(itemId) : null; } diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteAnyTalk.java b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteAnyTalk.java index 19a2a3f0d..6a2b4c23c 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteAnyTalk.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentCompleteAnyTalk.java @@ -4,8 +4,8 @@ import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLE import emu.grasscutter.data.excels.quest.QuestData; import emu.grasscutter.game.quest.*; -import lombok.val; import java.util.Arrays; +import lombok.val; @QuestValueContent(QUEST_CONTENT_COMPLETE_ANY_TALK) public class ContentCompleteAnyTalk extends BaseContent { @@ -13,9 +13,8 @@ public class ContentCompleteAnyTalk extends BaseContent { @Override public boolean execute( GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { - var conditionTalk = Arrays.stream(condition.getParamStr().split(",")) - .mapToInt(Integer::parseInt) - .toArray(); + var conditionTalk = + Arrays.stream(condition.getParamStr().split(",")).mapToInt(Integer::parseInt).toArray(); for (var talkId : conditionTalk) { val checkMainQuest = quest.getOwner().getQuestManager().getMainQuestByTalkId(talkId); diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java b/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java index bb3f1b14c..3864a6d06 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentLuaNotify.java @@ -16,6 +16,7 @@ public class ContentLuaNotify extends BaseContent { if (targetAmount == 0) { targetAmount = 1; } - return targetAmount <= quest.getOwner().getPlayerProgress().getCurrentProgress(condition.getParamStr()); + return targetAmount + <= quest.getOwner().getPlayerProgress().getCurrentProgress(condition.getParamStr()); } } From d0dde1c9e204a62c87c7d397be5382cae008e064 Mon Sep 17 00:00:00 2001 From: Nazrin Date: Thu, 10 Aug 2023 17:06:55 -0700 Subject: [PATCH 6/7] Fix dungeons with no finish logic in DungeonManager.java (#2288) --- src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java b/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java index 4b8fa0131..ba184a56b 100644 --- a/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java +++ b/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java @@ -81,7 +81,7 @@ public final class DungeonManager { } public boolean isFinishedSuccessfully() { - if (passConfigData.getLogicType() == null) return false; + if (passConfigData.getConds() == null) return false; return LogicType.calculate(passConfigData.getLogicType(), finishedConditions); } From bdc4b5af89357acd540c16a83af423388f3d1cad Mon Sep 17 00:00:00 2001 From: Phong Date: Sat, 12 Aug 2023 10:54:19 +0700 Subject: [PATCH 7/7] Levelup City Implementation (#2281) * add statue promo data * implement levelup city feature * fix get level city when enter game * format code * fix typo, remove some property in the player, add the field cityInfoData to player class --- .../java/emu/grasscutter/data/GameData.java | 8 ++ .../data/excels/StatuePromoteData.java | 21 ++++ .../grasscutter/game/city/CityInfoData.java | 28 ++++++ .../game/managers/SotSManager.java | 96 +++++++++++++++++++ .../emu/grasscutter/game/player/Player.java | 8 +- .../packet/recv/HandlerLevelupCityReq.java | 22 +++++ .../packet/send/PacketGetSceneAreaRsp.java | 7 +- .../packet/send/PacketLevelupCityRsp.java | 29 ++++++ 8 files changed, 214 insertions(+), 5 deletions(-) create mode 100644 src/main/java/emu/grasscutter/data/excels/StatuePromoteData.java create mode 100644 src/main/java/emu/grasscutter/game/city/CityInfoData.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerLevelupCityReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketLevelupCityRsp.java diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 3b99f1f26..c47d0541c 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -404,6 +404,10 @@ public final class GameData { private static final Int2ObjectMap weaponPromoteDataMap = new Int2ObjectOpenHashMap<>(); + @Getter + private static final Int2ObjectMap statuePromoteDataMap = + new Int2ObjectOpenHashMap<>(); + @Getter private static final Int2ObjectMap weatherDataMap = new Int2ObjectOpenHashMap<>(); @@ -567,6 +571,10 @@ public final class GameData { return weaponPromoteDataMap.get((promoteId << 8) + promoteLevel); } + public static StatuePromoteData getStatuePromoteData(int cityId, int promoteLevel) { + return statuePromoteDataMap.get((cityId << 8) + promoteLevel); + } + public static ReliquaryLevelData getRelicLevelData(int rankLevel, int level) { return reliquaryLevelDataMap.get((rankLevel << 8) + level); } diff --git a/src/main/java/emu/grasscutter/data/excels/StatuePromoteData.java b/src/main/java/emu/grasscutter/data/excels/StatuePromoteData.java new file mode 100644 index 000000000..29e495a1c --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/StatuePromoteData.java @@ -0,0 +1,21 @@ +package emu.grasscutter.data.excels; + +import emu.grasscutter.data.GameResource; +import emu.grasscutter.data.ResourceType; +import emu.grasscutter.data.common.ItemParamData; +import lombok.Getter; +import lombok.Setter; + +@ResourceType(name = "StatuePromoteExcelConfigData.json") +public class StatuePromoteData extends GameResource { + @Getter @Setter private int level; + @Getter @Setter private int cityId; + @Getter @Setter private ItemParamData[] costItems; + @Getter @Setter private int[] rewardIdList; + @Getter @Setter private int stamina; + + @Override + public int getId() { + return (cityId << 8) + level; + } +} diff --git a/src/main/java/emu/grasscutter/game/city/CityInfoData.java b/src/main/java/emu/grasscutter/game/city/CityInfoData.java new file mode 100644 index 000000000..bc386bdec --- /dev/null +++ b/src/main/java/emu/grasscutter/game/city/CityInfoData.java @@ -0,0 +1,28 @@ +package emu.grasscutter.game.city; + +import dev.morphia.annotations.Entity; +import emu.grasscutter.net.proto.CityInfoOuterClass.CityInfo; +import lombok.Getter; +import lombok.Setter; + +@Entity +public class CityInfoData { + @Getter @Setter private int cityId; + + @Getter @Setter + private int level = 1; // level of the city (include level SotS, level Frostbearing Trees, etc.) + + @Getter @Setter private int numCrystal = 0; // number of crystals in the city + + public CityInfoData(int cityId) { + this.cityId = cityId; + } + + public CityInfo toProto() { + return CityInfo.newBuilder() + .setCityId(cityId) + .setLevel(level) + .setCrystalNum(numCrystal) + .build(); + } +} diff --git a/src/main/java/emu/grasscutter/game/managers/SotSManager.java b/src/main/java/emu/grasscutter/game/managers/SotSManager.java index 594e8cf5b..3e05351e3 100644 --- a/src/main/java/emu/grasscutter/game/managers/SotSManager.java +++ b/src/main/java/emu/grasscutter/game/managers/SotSManager.java @@ -2,15 +2,24 @@ package emu.grasscutter.game.managers; import ch.qos.logback.classic.Logger; import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.CityData; +import emu.grasscutter.data.excels.RewardData; +import emu.grasscutter.game.city.CityInfoData; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.quest.enums.QuestContent; import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason; import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; +import emu.grasscutter.server.packet.send.PacketLevelupCityRsp; +import emu.grasscutter.server.packet.send.PacketSceneForceUnlockNotify; +import java.util.HashMap; import java.util.List; import java.util.Timer; import java.util.TimerTask; @@ -208,4 +217,91 @@ public class SotSManager extends BasePlayerManager { } } } + + public CityData getCityByAreaId(int areaId) { + return GameData.getCityDataMap().values().stream() + .filter(city -> city.getAreaIdVec().contains(areaId)) + .findFirst() + .orElse(null); + } + + public CityInfoData getCityInfo(int cityId) { + if (player.getCityInfoData() == null) player.setCityInfoData(new HashMap<>()); + var cityInfo = player.getCityInfoData().get(cityId); + if (cityInfo == null) { + cityInfo = new CityInfoData(cityId); + player.getCityInfoData().put(cityId, cityInfo); + } + return cityInfo; + } + + public void addCityInfo(CityInfoData cityInfoData) { + if (player.getCityInfoData() == null) player.setCityInfoData(new HashMap<>()); + + player.getCityInfoData().put(cityInfoData.getCityId(), cityInfoData); + } + + public void levelUpSotS(int areaId, int sceneId, int itemNum) { + if (itemNum <= 0) return; + + // search city by areaId + var city = this.getCityByAreaId(areaId); + if (city == null) return; + var cityId = city.getCityId(); + + // check data level up + var cityInfo = this.getCityInfo(cityId); + var nextStatuePromoteData = GameData.getStatuePromoteData(cityId, cityInfo.getLevel() + 1); + if (nextStatuePromoteData == null) return; + var nextLevelCrystal = nextStatuePromoteData.getCostItems()[0].getCount(); + + // delete item from inventory + var itemNumrequired = Math.min(itemNum, nextLevelCrystal - cityInfo.getNumCrystal()); + player + .getInventory() + .removeItemById(nextStatuePromoteData.getCostItems()[0].getId(), itemNumrequired); + + // update number oculi + cityInfo.setNumCrystal(cityInfo.getNumCrystal() + itemNumrequired); + + // hanble quest + if (itemNumrequired >= 1) + player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_CITY_LEVEL_UP, cityId, areaId); + + // handle oculi overflow + if (cityInfo.getNumCrystal() >= nextLevelCrystal) { + cityInfo.setNumCrystal(cityInfo.getNumCrystal() - nextLevelCrystal); + cityInfo.setLevel(cityInfo.getLevel() + 1); + + // update max stamina and notify client + player.setProperty( + PlayerProperty.PROP_MAX_STAMINA, + player.getProperty(PlayerProperty.PROP_MAX_STAMINA) + + nextStatuePromoteData.getStamina() * 100, + true); + + // Add items to inventory + if (nextStatuePromoteData.getRewardIdList() != null) { + for (var rewardId : nextStatuePromoteData.getRewardIdList()) { + RewardData rewardData = GameData.getRewardDataMap().get(rewardId); + if (rewardData == null) continue; + + player + .getInventory() + .addItemParamDatas(rewardData.getRewardItemList(), ActionReason.CityLevelupReward); + } + } + + // unlock forcescene + player.sendPacket(new PacketSceneForceUnlockNotify(1, true)); + } + + // update data + this.addCityInfo(cityInfo); + + // Packets + player.sendPacket( + new PacketLevelupCityRsp( + sceneId, cityInfo.getLevel(), cityId, cityInfo.getNumCrystal(), areaId, 0)); + } } diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 26e091bb2..6fce17436 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -15,6 +15,7 @@ import emu.grasscutter.game.activity.ActivityManager; import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.AvatarStorage; import emu.grasscutter.game.battlepass.BattlePassManager; +import emu.grasscutter.game.city.CityInfoData; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.expedition.ExpeditionInfo; import emu.grasscutter.game.friends.FriendsList; @@ -28,7 +29,6 @@ import emu.grasscutter.game.mail.MailHandler; import emu.grasscutter.game.managers.FurnitureManager; import emu.grasscutter.game.managers.ResinManager; import emu.grasscutter.game.managers.SatiationManager; -import emu.grasscutter.game.managers.SotSManager; import emu.grasscutter.game.managers.cooking.ActiveCookCompoundData; import emu.grasscutter.game.managers.cooking.CookingCompoundManager; import emu.grasscutter.game.managers.cooking.CookingManager; @@ -38,6 +38,7 @@ import emu.grasscutter.game.managers.forging.ActiveForgeData; import emu.grasscutter.game.managers.forging.ForgingManager; import emu.grasscutter.game.managers.mapmark.MapMark; import emu.grasscutter.game.managers.mapmark.MapMarksManager; +import emu.grasscutter.game.managers.SotSManager; import emu.grasscutter.game.managers.stamina.StaminaManager; import emu.grasscutter.game.props.*; import emu.grasscutter.game.quest.QuestManager; @@ -221,6 +222,8 @@ public class Player implements PlayerHook, FieldFetch { @Getter @Setter private ElementType mainCharacterElement = ElementType.None; + @Getter @Setter private Map cityInfoData; // cityId -> CityData + @Deprecated @SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only! public Player() { @@ -267,6 +270,7 @@ public class Player implements PlayerHook, FieldFetch { this.chatEmojiIdList = new ArrayList<>(); this.playerProgress = new PlayerProgress(); this.activeQuestTimers = new HashSet<>(); + this.cityInfoData = new HashMap<>(); this.attackResults = new LinkedBlockingQueue<>(); this.coopRequests = new Int2ObjectOpenHashMap<>(); @@ -1520,6 +1524,8 @@ public class Player implements PlayerHook, FieldFetch { PropChangeReason.PROP_CHANGE_REASON_PLAYER_ADD_EXP)); case PROP_PLAYER_LEVEL -> this.sendPacket(new PacketPlayerPropChangeReasonNotify(this, prop, currentValue, value, PropChangeReason.PROP_CHANGE_REASON_LEVELUP)); + case PROP_MAX_STAMINA -> this.sendPacket(new PacketPlayerPropChangeReasonNotify(this, prop, currentValue, value, + PropChangeReason.PROP_CHANGE_REASON_CITY_LEVELUP)); // TODO: Handle world level changing. // case PROP_PLAYER_WORLD_LEVEL -> this.sendPacket(new PacketPlayerPropChangeReasonNotify(this, prop, currentValue, value, diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerLevelupCityReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerLevelupCityReq.java new file mode 100644 index 000000000..74e61911d --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerLevelupCityReq.java @@ -0,0 +1,22 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.LevelupCityReqOuterClass.LevelupCityReq; +import emu.grasscutter.server.game.GameSession; + +@Opcodes(PacketOpcodes.LevelupCityReq) +public class HandlerLevelupCityReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + LevelupCityReq req = LevelupCityReq.parseFrom(payload); + + // Level up city + session + .getPlayer() + .getSotsManager() + .levelUpSotS(req.getAreaId(), req.getSceneId(), req.getItemNum()); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java index d7e3b32f9..095337763 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java @@ -3,7 +3,6 @@ package emu.grasscutter.server.packet.send; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; -import emu.grasscutter.net.proto.CityInfoOuterClass.CityInfo; import emu.grasscutter.net.proto.GetSceneAreaRspOuterClass.GetSceneAreaRsp; public class PacketGetSceneAreaRsp extends BasePacket { @@ -17,9 +16,9 @@ public class PacketGetSceneAreaRsp extends BasePacket { GetSceneAreaRsp.newBuilder() .setSceneId(sceneId) .addAllAreaIdList(player.getUnlockedSceneAreas(sceneId)) - .addCityInfoList(CityInfo.newBuilder().setCityId(1).setLevel(1).build()) - .addCityInfoList(CityInfo.newBuilder().setCityId(2).setLevel(1).build()) - .addCityInfoList(CityInfo.newBuilder().setCityId(3).setLevel(1).build()) + .addCityInfoList(player.getSotsManager().getCityInfo(1).toProto()) + .addCityInfoList(player.getSotsManager().getCityInfo(2).toProto()) + .addCityInfoList(player.getSotsManager().getCityInfo(3).toProto()) .build(); this.setData(p); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketLevelupCityRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketLevelupCityRsp.java new file mode 100644 index 000000000..74cb7a988 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketLevelupCityRsp.java @@ -0,0 +1,29 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.CityInfoOuterClass.CityInfo; +import emu.grasscutter.net.proto.LevelupCityRspOuterClass.LevelupCityRsp; + +public class PacketLevelupCityRsp extends BasePacket { + + public PacketLevelupCityRsp( + int sceneId, int level, int cityId, int crystalNum, int areaId, int retcode) { + super(PacketOpcodes.LevelupCityRsp); + + LevelupCityRsp proto = + LevelupCityRsp.newBuilder() + .setSceneId(sceneId) + .setCityInfo( + CityInfo.newBuilder() + .setCityId(cityId) + .setLevel(level) + .setCrystalNum(crystalNum) + .build()) + .setAreaId(areaId) + .setRetcode(retcode) + .build(); + + this.setData(proto); + } +}