From 8bb7672a6b148809a441eb1aaeecd006f3e15a91 Mon Sep 17 00:00:00 2001 From: Melledy <121644117+Melledy@users.noreply.github.com> Date: Wed, 4 Oct 2023 23:58:34 -0700 Subject: [PATCH] Battles with monsters in mazes now drop items --- .../java/emu/lunarcore/data/GameData.java | 5 ++ .../data/excel/MonsterDropExcel.java | 24 +++++++++ .../emu/lunarcore/game/battle/Battle.java | 52 +++++++++++++++++++ .../lunarcore/game/battle/BattleService.java | 7 ++- .../recv/HandlerPVEBattleResultCsReq.java | 9 +++- .../send/PacketPVEBattleResultScRsp.java | 25 +++++++-- 6 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 src/main/java/emu/lunarcore/data/excel/MonsterDropExcel.java diff --git a/src/main/java/emu/lunarcore/data/GameData.java b/src/main/java/emu/lunarcore/data/GameData.java index 9e32719..c1fb37a 100644 --- a/src/main/java/emu/lunarcore/data/GameData.java +++ b/src/main/java/emu/lunarcore/data/GameData.java @@ -36,6 +36,7 @@ public class GameData { private static Int2ObjectMap equipmentPromotionExcelMap = new Int2ObjectOpenHashMap<>(); private static Int2ObjectMap mazeBuffExcelMap = new Int2ObjectOpenHashMap<>(); private static Int2ObjectMap cocoonExcelMap = new Int2ObjectOpenHashMap<>(); + private static Int2ObjectMap monsterDropExcelMap = new Int2ObjectOpenHashMap<>(); private static Int2ObjectMap playerLevelExcelMap = new Int2ObjectOpenHashMap<>(); private static Int2ObjectMap expTypeExcelMap = new Int2ObjectOpenHashMap<>(); @@ -117,4 +118,8 @@ public class GameData { public static CocoonExcel getCocoonExcel(int cocoonId, int worldLevel) { return cocoonExcelMap.get((cocoonId << 8) + worldLevel); } + + public static MonsterDropExcel getMonsterDropExcel(int monsterNpcId, int worldLevel) { + return monsterDropExcelMap.get((monsterNpcId << 4) + worldLevel); + } } diff --git a/src/main/java/emu/lunarcore/data/excel/MonsterDropExcel.java b/src/main/java/emu/lunarcore/data/excel/MonsterDropExcel.java new file mode 100644 index 0000000..617d157 --- /dev/null +++ b/src/main/java/emu/lunarcore/data/excel/MonsterDropExcel.java @@ -0,0 +1,24 @@ +package emu.lunarcore.data.excel; + +import java.util.List; + +import emu.lunarcore.data.GameResource; +import emu.lunarcore.data.ResourceType; +import emu.lunarcore.data.common.ItemParam; +import lombok.Getter; + +@Getter +@ResourceType(name = {"MonsterDrop.json"}) +public class MonsterDropExcel extends GameResource { + private int MonsterTemplateID; + private int WorldLevel; + private int AvatarExpReward; + + private List DisplayItemList; + + @Override + public int getId() { + return (MonsterTemplateID << 4) + WorldLevel; + } + +} diff --git a/src/main/java/emu/lunarcore/game/battle/Battle.java b/src/main/java/emu/lunarcore/game/battle/Battle.java index ef48736..5d564bd 100644 --- a/src/main/java/emu/lunarcore/game/battle/Battle.java +++ b/src/main/java/emu/lunarcore/game/battle/Battle.java @@ -5,10 +5,12 @@ import java.util.Collection; import java.util.List; import emu.lunarcore.data.GameData; +import emu.lunarcore.data.common.ItemParam; import emu.lunarcore.data.excel.MazeBuffExcel; import emu.lunarcore.data.excel.StageExcel; import emu.lunarcore.game.avatar.GameAvatar; import emu.lunarcore.game.enums.StageType; +import emu.lunarcore.game.inventory.GameItem; import emu.lunarcore.game.player.Player; import emu.lunarcore.game.player.PlayerLineup; import emu.lunarcore.game.scene.entity.EntityMonster; @@ -17,6 +19,7 @@ import emu.lunarcore.proto.SceneMonsterOuterClass.SceneMonster; import emu.lunarcore.proto.SceneMonsterWaveOuterClass.SceneMonsterWave; import emu.lunarcore.util.Utils; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.IntList; import lombok.Getter; @@ -28,6 +31,7 @@ public class Battle { private final List npcMonsters; private final List buffs; private final List stages; + private final List drops; private final long timestamp; private Battle(Player player, PlayerLineup lineup) { @@ -37,6 +41,7 @@ public class Battle { this.npcMonsters = new ArrayList<>(); this.buffs = new ArrayList<>(); this.stages = new ArrayList<>(); + this.drops = new ArrayList<>(); this.timestamp = System.currentTimeMillis(); } @@ -84,6 +89,8 @@ public class Battle { return count; } + // Battle buffs + public MazeBuff addBuff(int buffId, int ownerIndex) { return addBuff(buffId, ownerIndex, 0xffffffff); } @@ -102,6 +109,51 @@ public class Battle { this.buffs.clear(); } + // Drops + + public void calculateDrops() { + // TODO this isnt the right way drops are calculated on the official server... but its good enough for now + if (this.getNpcMonsters().size() == 0) { + return; + } + + var dropMap = new Int2IntOpenHashMap(); + + // Get drops from monsters + for (EntityMonster monster : this.getNpcMonsters()) { + var dropExcel = GameData.getMonsterDropExcel(monster.getExcel().getId(), monster.getWorldLevel()); + if (dropExcel == null || dropExcel.getDisplayItemList() == null) { + continue; + } + + for (ItemParam param : dropExcel.getDisplayItemList()) { + int id = param.getId(); + int count = Utils.randomRange(0, 3); + + if (id == 2) { + count = dropExcel.getAvatarExpReward(); + } + + dropMap.put(id, count + dropMap.get(id)); + } + } + + for (var entry : dropMap.int2IntEntrySet()) { + if (entry.getIntValue() <= 0) { + continue; + } + + // Create item and add it to player + GameItem item = new GameItem(entry.getIntKey(), entry.getIntValue()); + + if (getPlayer().getInventory().addItem(item)) { + this.getDrops().add(item); + } + } + } + + // Serialization + public SceneBattleInfo toProto() { // Build battle info var proto = SceneBattleInfo.newInstance() diff --git a/src/main/java/emu/lunarcore/game/battle/BattleService.java b/src/main/java/emu/lunarcore/game/battle/BattleService.java index 60756fb..17c6c56 100644 --- a/src/main/java/emu/lunarcore/game/battle/BattleService.java +++ b/src/main/java/emu/lunarcore/game/battle/BattleService.java @@ -179,10 +179,10 @@ public class BattleService extends BaseGameService { player.sendPacket(new PacketStartCocoonStageScRsp(battle, cocoonId, wave)); } - public void finishBattle(Player player, BattleEndStatus result, RepeatedMessage battleAvatars) { + public Battle finishBattle(Player player, BattleEndStatus result, RepeatedMessage battleAvatars) { // Sanity check to make sure player is in a battle if (!player.isInBattle()) { - return; + return null; } // Get battle object and setup variables @@ -199,6 +199,8 @@ public class BattleService extends BaseGameService { for (var monster : battle.getNpcMonsters()) { player.getScene().removeEntity(monster); } + // Drops + battle.calculateDrops(); } case BATTLE_END_LOSE -> { // Set avatar hp to 20% if the player's party is downed @@ -247,6 +249,7 @@ public class BattleService extends BaseGameService { // Done - Clear battle object from player player.setBattle(null); + return battle; } public void reEnterBattle(Player player, int stageId) { diff --git a/src/main/java/emu/lunarcore/server/packet/recv/HandlerPVEBattleResultCsReq.java b/src/main/java/emu/lunarcore/server/packet/recv/HandlerPVEBattleResultCsReq.java index 1e5b2e4..6fba4fb 100644 --- a/src/main/java/emu/lunarcore/server/packet/recv/HandlerPVEBattleResultCsReq.java +++ b/src/main/java/emu/lunarcore/server/packet/recv/HandlerPVEBattleResultCsReq.java @@ -1,5 +1,6 @@ package emu.lunarcore.server.packet.recv; +import emu.lunarcore.game.battle.Battle; import emu.lunarcore.proto.PVEBattleResultCsReqOuterClass.PVEBattleResultCsReq; import emu.lunarcore.server.game.GameSession; import emu.lunarcore.server.packet.CmdId; @@ -14,13 +15,17 @@ public class HandlerPVEBattleResultCsReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] data) throws Exception { var req = PVEBattleResultCsReq.parseFrom(data); - session.getServer().getBattleService().finishBattle( + Battle battle = session.getServer().getBattleService().finishBattle( session.getPlayer(), req.getEndStatus(), req.getStt().getBattleAvatarList() ); - session.send(new PacketPVEBattleResultScRsp(req)); + if (battle != null) { + session.send(new PacketPVEBattleResultScRsp(req, battle)); + } else { + session.send(new PacketPVEBattleResultScRsp()); + } } } diff --git a/src/main/java/emu/lunarcore/server/packet/send/PacketPVEBattleResultScRsp.java b/src/main/java/emu/lunarcore/server/packet/send/PacketPVEBattleResultScRsp.java index b874515..119f719 100644 --- a/src/main/java/emu/lunarcore/server/packet/send/PacketPVEBattleResultScRsp.java +++ b/src/main/java/emu/lunarcore/server/packet/send/PacketPVEBattleResultScRsp.java @@ -1,5 +1,7 @@ package emu.lunarcore.server.packet.send; +import emu.lunarcore.game.battle.Battle; +import emu.lunarcore.game.inventory.GameItem; import emu.lunarcore.proto.ItemListOuterClass.ItemList; import emu.lunarcore.proto.PVEBattleResultCsReqOuterClass.PVEBattleResultCsReq; import emu.lunarcore.proto.PVEBattleResultScRspOuterClass.PVEBattleResultScRsp; @@ -7,14 +9,31 @@ import emu.lunarcore.server.packet.BasePacket; import emu.lunarcore.server.packet.CmdId; public class PacketPVEBattleResultScRsp extends BasePacket { - - public PacketPVEBattleResultScRsp(PVEBattleResultCsReq req) { + + public PacketPVEBattleResultScRsp() { super(CmdId.PVEBattleResultScRsp); + var data = PVEBattleResultScRsp.newInstance() + .setRetcode(1); + + this.setData(data); + } + + public PacketPVEBattleResultScRsp(PVEBattleResultCsReq req, Battle battle) { + super(CmdId.PVEBattleResultScRsp); + + // Item drop list data + ItemList dropData = ItemList.newInstance(); + + for (GameItem drop : battle.getDrops()) { + dropData.addItemList(drop.toProto()); + } + + // Battle result var data = PVEBattleResultScRsp.newInstance() .setUnk1(ItemList.newInstance()) - .setUnk2(ItemList.newInstance()) .setUnk3(ItemList.newInstance()) + .setDropData(dropData) .setResVersion(Integer.toString(req.getClientResVersion())) .setBinVersion("") .setBattleId(req.getBattleId())