mirror of
https://github.com/Melledy/LunarCore.git
synced 2025-12-12 21:34:35 +01:00
Rework battle system
This commit is contained in:
@@ -73,10 +73,10 @@ public class SpawnCommand implements CommandHandler {
|
||||
EntityMonster monster = new EntityMonster(target.getScene(), monsterExcel, groupInfo, monsterInfo);
|
||||
monster.getPos().set(pos);
|
||||
monster.setEventId(monsterInfo.getEventID());
|
||||
monster.setOverrideStageId(stage);
|
||||
monster.setCustomStageId(stage);
|
||||
|
||||
if (args.getLevel() > 0) {
|
||||
monster.setOverrideLevel(Math.min(args.getLevel(), 100));
|
||||
monster.setCustomLevel(Math.min(args.getLevel(), 100));
|
||||
}
|
||||
|
||||
target.getScene().addEntity(monster, true);
|
||||
|
||||
@@ -34,8 +34,13 @@ public class StageExcel extends GameResource {
|
||||
public void onLoad() {
|
||||
// Cache monster list
|
||||
this.monsterWaves = new ArrayList<>();
|
||||
|
||||
for (StageMonsterWave wave : MonsterList) {
|
||||
this.monsterWaves.add(wave.toList());
|
||||
var monsterIds = wave.toList();
|
||||
|
||||
if (!monsterIds.isEmpty()) {
|
||||
this.monsterWaves.add(monsterIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,19 +4,17 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import emu.lunarcore.GameConstants;
|
||||
import emu.lunarcore.data.GameData;
|
||||
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.lineup.PlayerLineup;
|
||||
import emu.lunarcore.game.scene.entity.EntityMonster;
|
||||
import emu.lunarcore.proto.ClientTurnSnapshotOuterClass.ClientTurnSnapshot;
|
||||
import emu.lunarcore.proto.SceneBattleInfoOuterClass.SceneBattleInfo;
|
||||
import emu.lunarcore.proto.SceneMonsterOuterClass.SceneMonster;
|
||||
import emu.lunarcore.proto.SceneMonsterWaveOuterClass.SceneMonsterWave;
|
||||
import emu.lunarcore.util.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
@@ -30,14 +28,14 @@ public class Battle {
|
||||
private final PlayerLineup lineup;
|
||||
private final List<EntityMonster> npcMonsters;
|
||||
private final List<MazeBuff> buffs;
|
||||
private final List<StageExcel> stages;
|
||||
private final List<BattleMonsterWave> waves;
|
||||
private final List<GameItem> drops;
|
||||
private final long timestamp;
|
||||
|
||||
private StageExcel stage; // Main battle stage
|
||||
private IntList turnSnapshotList; // TODO maybe turn it into a map?
|
||||
|
||||
@Setter private int staminaCost;
|
||||
@Setter private int levelOverride;
|
||||
@Setter private int roundsLimit;
|
||||
|
||||
// Used for calculating cocoon/farm element drops
|
||||
@@ -51,19 +49,78 @@ public class Battle {
|
||||
this.lineup = lineup;
|
||||
this.npcMonsters = new ArrayList<>();
|
||||
this.buffs = new ArrayList<>();
|
||||
this.stages = new ArrayList<>();
|
||||
this.waves = new ArrayList<>();
|
||||
this.drops = new ArrayList<>();
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public Battle(Player player, PlayerLineup lineup, StageExcel stage) {
|
||||
this(player, lineup);
|
||||
this.stages.add(stage);
|
||||
this.stage = stage;
|
||||
this.loadStage(stage);
|
||||
}
|
||||
|
||||
public Battle(Player player, PlayerLineup lineup, Collection<StageExcel> stages) {
|
||||
public Battle(Player player, PlayerLineup lineup, List<StageExcel> stages) {
|
||||
this(player, lineup);
|
||||
this.stages.addAll(stages);
|
||||
this.stage = stages.get(0);
|
||||
|
||||
for (StageExcel stage : stages) {
|
||||
this.loadStage(stage);
|
||||
}
|
||||
}
|
||||
|
||||
public Battle(Player player, PlayerLineup lineup, Collection<EntityMonster> npcMonsters) {
|
||||
this(player, lineup);
|
||||
|
||||
// Parse npc monster
|
||||
for (EntityMonster npcMonster : npcMonsters) {
|
||||
// Add monster
|
||||
this.npcMonsters.add(npcMonster);
|
||||
|
||||
// Check farm element
|
||||
if (npcMonster.getFarmElementId() != 0) {
|
||||
this.setMappingInfoId(npcMonster.getFarmElementId());
|
||||
this.setWorldLevel(npcMonster.getWorldLevel());
|
||||
this.setStaminaCost(GameConstants.FARM_ELEMENT_STAMINA_COST);
|
||||
}
|
||||
|
||||
// Get stage
|
||||
StageExcel stage = GameData.getStageExcelMap().get(npcMonster.getStageId());
|
||||
if (stage == null) continue;
|
||||
|
||||
// Set main battle stage if we havent already
|
||||
if (this.stage == null) {
|
||||
this.stage = stage;
|
||||
}
|
||||
|
||||
// Create monster waves from stage
|
||||
this.loadStage(stage, npcMonster);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadStage(StageExcel stage) {
|
||||
this.loadStage(stage, null);
|
||||
}
|
||||
|
||||
private void loadStage(StageExcel stage, EntityMonster npcMonster) {
|
||||
// Build monster waves
|
||||
for (IntList stageMonsterWave : stage.getMonsterWaves()) {
|
||||
// Create battle wave
|
||||
var wave = new BattleMonsterWave(stage);
|
||||
wave.getMonsters().addAll(stageMonsterWave);
|
||||
|
||||
// Handle npc monster
|
||||
if (npcMonster != null) {
|
||||
// Set wave custom level
|
||||
wave.setCustomLevel(npcMonster.getCustomLevel());
|
||||
|
||||
// Handle monster buffs
|
||||
npcMonster.applyBuffs(this, this.getWaves().size());
|
||||
}
|
||||
|
||||
// Finally add wave to battle
|
||||
this.getWaves().add(wave);
|
||||
}
|
||||
}
|
||||
|
||||
public IntList getTurnSnapshotList() {
|
||||
@@ -73,38 +130,14 @@ public class Battle {
|
||||
return this.turnSnapshotList;
|
||||
}
|
||||
|
||||
public StageType getStageType() {
|
||||
StageExcel stage = this.getFirstStage();
|
||||
if (stage != null) {
|
||||
return stage.getStageType();
|
||||
}
|
||||
return StageType.Unknown;
|
||||
}
|
||||
|
||||
public StageExcel getFirstStage() {
|
||||
if (this.getStages().size() > 0) {
|
||||
return this.getStages().get(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getStageId() {
|
||||
if (this.getStages().size() > 0) {
|
||||
return this.getStages().get(0).getId();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getMonsterWaveCount() {
|
||||
int count = 0;
|
||||
|
||||
for (StageExcel stage : stages) {
|
||||
count += stage.getMonsterWaves().size();
|
||||
return this.getWaves().size();
|
||||
}
|
||||
|
||||
public void setCustomLevel(int level) {
|
||||
for (var wave : this.getWaves()) {
|
||||
wave.setCustomLevel(level);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// Battle buffs
|
||||
@@ -140,34 +173,14 @@ public class Battle {
|
||||
// Build battle info
|
||||
var proto = SceneBattleInfo.newInstance()
|
||||
.setBattleId(this.getId())
|
||||
.setStageId(this.getStage().getId())
|
||||
.setRoundsLimit(this.getRoundsLimit())
|
||||
.setLogicRandomSeed(Utils.randomRange(1, Short.MAX_VALUE))
|
||||
.setWorldLevel(player.getWorldLevel());
|
||||
|
||||
// Add monster waves from stages
|
||||
for (StageExcel stage : stages) {
|
||||
// Build monster waves
|
||||
for (IntList sceneMonsterWave : stage.getMonsterWaves()) {
|
||||
var wave = SceneMonsterWave.newInstance()
|
||||
.setWaveId(1) // Probably not named correctly
|
||||
.setStageId(stage.getId());
|
||||
|
||||
if (this.levelOverride > 0) {
|
||||
wave.getMutableWaveParam().setLevel(this.levelOverride);
|
||||
}
|
||||
|
||||
for (int monsterId : sceneMonsterWave) {
|
||||
var monster = SceneMonster.newInstance().setMonsterId(monsterId);
|
||||
wave.addMonsterList(monster);
|
||||
}
|
||||
|
||||
proto.addMonsterWaveList(wave);
|
||||
}
|
||||
|
||||
// Set stage for the battle
|
||||
if (proto.getStageId() == 0) {
|
||||
proto.setStageId(stage.getId());
|
||||
}
|
||||
// Add monster waves
|
||||
for (var wave : this.getWaves()) {
|
||||
proto.addMonsterWaveList(wave.toProto());
|
||||
}
|
||||
|
||||
// Avatars
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package emu.lunarcore.game.battle;
|
||||
|
||||
import emu.lunarcore.data.excel.StageExcel;
|
||||
import emu.lunarcore.proto.SceneMonsterOuterClass.SceneMonster;
|
||||
import emu.lunarcore.proto.SceneMonsterWaveOuterClass.SceneMonsterWave;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
public class BattleMonsterWave {
|
||||
private final StageExcel stage;
|
||||
private IntList monsters;
|
||||
|
||||
@Setter
|
||||
private int customLevel;
|
||||
|
||||
public BattleMonsterWave(StageExcel stage) {
|
||||
this.stage = stage;
|
||||
this.monsters = new IntArrayList();
|
||||
}
|
||||
|
||||
public SceneMonsterWave toProto() {
|
||||
var proto = SceneMonsterWave.newInstance()
|
||||
.setWaveId(1) // Probably not named correctly
|
||||
.setStageId(stage.getId());
|
||||
|
||||
if (this.customLevel > 0) {
|
||||
proto.getMutableWaveParam().setLevel(this.customLevel);
|
||||
}
|
||||
|
||||
for (int monsterId : monsters) {
|
||||
var monster = SceneMonster.newInstance().setMonsterId(monsterId);
|
||||
proto.addMonsterList(monster);
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
}
|
||||
@@ -97,48 +97,15 @@ public class BattleService extends BaseGameService {
|
||||
|
||||
// Start battle
|
||||
if (monsters.size() > 0) {
|
||||
// Get stages from monsters
|
||||
List<StageExcel> stages = new ArrayList<>();
|
||||
// Create battle and add npc monsters to it
|
||||
Battle battle = new Battle(player, player.getLineupManager().getCurrentLineup(), monsters);
|
||||
|
||||
for (var monster : monsters) {
|
||||
StageExcel stage = GameData.getStageExcelMap().get(monster.getStageId());
|
||||
|
||||
if (stage != null) {
|
||||
stages.add(stage);
|
||||
}
|
||||
}
|
||||
|
||||
if (stages.size() == 0) {
|
||||
// An error has occurred while trying to get stage data
|
||||
// Make sure we have at least one stage for the battle
|
||||
if (battle.getStage() == null) {
|
||||
player.sendPacket(new PacketSceneCastSkillScRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
// Create battle and add npc monsters to it
|
||||
Battle battle = new Battle(player, player.getLineupManager().getCurrentLineup(), stages);
|
||||
|
||||
// Add npc monsters
|
||||
for (var monster : monsters) {
|
||||
// Add npc monster
|
||||
battle.getNpcMonsters().add(monster);
|
||||
|
||||
// Check farm element
|
||||
if (monster.getFarmElementId() != 0) {
|
||||
battle.setMappingInfoId(monster.getFarmElementId());
|
||||
battle.setWorldLevel(monster.getWorldLevel());
|
||||
battle.setStaminaCost(GameConstants.FARM_ELEMENT_STAMINA_COST);
|
||||
}
|
||||
|
||||
// Handle monster buffs
|
||||
// TODO handle multiple waves properly
|
||||
monster.applyBuffs(battle);
|
||||
|
||||
// Override level
|
||||
if (monster.getOverrideLevel() > 0) {
|
||||
battle.setLevelOverride(monster.getOverrideLevel());
|
||||
}
|
||||
}
|
||||
|
||||
// Add buffs to battle
|
||||
if (isPlayerCaster) {
|
||||
GameAvatar avatar = player.getCurrentLeaderAvatar();
|
||||
@@ -270,7 +237,7 @@ public class BattleService extends BaseGameService {
|
||||
case BATTLE_END_QUIT -> {
|
||||
updateStatus = false;
|
||||
// Only teleport back to anchor if stage is a random fight
|
||||
if (battle.getStageType().getVal() <= StageType.Maze.getVal()) {
|
||||
if (battle.getStage().getStageType().getVal() <= StageType.Maze.getVal()) {
|
||||
teleportToAnchor = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ChallengeEntityLoader extends SceneEntityLoader {
|
||||
// Create monster from group monster info
|
||||
EntityMonster monster = new EntityMonster(scene, npcMonsterExcel, group, monsterInfo);
|
||||
monster.setEventId(challengeMonsterInfo.getEventId());
|
||||
monster.setOverrideStageId(challengeMonsterInfo.getEventId());
|
||||
monster.setCustomStageId(challengeMonsterInfo.getEventId());
|
||||
|
||||
return monster;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class RogueEntityLoader extends SceneEntityLoader {
|
||||
// Actually create the monster now
|
||||
EntityMonster monster = new EntityMonster(scene, npcMonster, group, monsterInfo);
|
||||
monster.setEventId(rogueMonster.getEventID());
|
||||
monster.setOverrideStageId(rogueMonster.getEventID());
|
||||
monster.setCustomStageId(rogueMonster.getEventID());
|
||||
|
||||
return monster;
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ public class RogueInstance {
|
||||
// Set monster level for battle
|
||||
RogueMapExcel mapExcel = GameData.getRogueMapExcel(this.getExcel().getMapId(), this.getCurrentSiteId());
|
||||
if (mapExcel != null && mapExcel.getLevelList() != null && mapExcel.getLevelList().length >= 1) {
|
||||
battle.setLevelOverride(mapExcel.getLevelList()[0]);
|
||||
battle.setCustomLevel(mapExcel.getLevelList()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ public class EntityMonster implements GameEntity, Tickable {
|
||||
|
||||
private Int2ObjectMap<SceneBuff> buffs;
|
||||
private int farmElementId;
|
||||
@Setter private int overrideStageId;
|
||||
@Setter private int overrideLevel;
|
||||
@Setter private int customStageId;
|
||||
@Setter private int customLevel;
|
||||
|
||||
public EntityMonster(Scene scene, NpcMonsterExcel excel, GroupInfo group, MonsterInfo monsterInfo) {
|
||||
this.scene = scene;
|
||||
@@ -51,10 +51,10 @@ public class EntityMonster implements GameEntity, Tickable {
|
||||
}
|
||||
|
||||
public int getStageId() {
|
||||
if (this.overrideStageId == 0) {
|
||||
if (this.customStageId == 0) {
|
||||
return (this.getEventId() * 10) + worldLevel;
|
||||
} else {
|
||||
return this.overrideStageId;
|
||||
return this.customStageId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class EntityMonster implements GameEntity, Tickable {
|
||||
return buff;
|
||||
}
|
||||
|
||||
public synchronized void applyBuffs(Battle battle) {
|
||||
public synchronized void applyBuffs(Battle battle, int waveIndex) {
|
||||
if (this.buffs == null) return;
|
||||
|
||||
for (var entry : this.buffs.int2ObjectEntrySet()) {
|
||||
@@ -80,18 +80,12 @@ public class EntityMonster implements GameEntity, Tickable {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dont add duplicate buffs
|
||||
if (battle.hasBuff(entry.getIntKey())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get owner index
|
||||
int ownerIndex = battle.getLineup().indexOf(entry.getValue().getCasterAvatarId());
|
||||
|
||||
// Add buff to battle if owner exists
|
||||
if (ownerIndex != -1) {
|
||||
// TODO handle multiple waves properly
|
||||
battle.addBuff(entry.getIntKey(), ownerIndex, 1);
|
||||
battle.addBuff(entry.getIntKey(), ownerIndex, 1 << waveIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class PacketReEnterLastElementStageScRsp extends BasePacket {
|
||||
super(CmdId.ReEnterLastElementStageScRsp);
|
||||
|
||||
var data = ReEnterLastElementStageScRsp.newInstance()
|
||||
.setStageId(battle.getStageId())
|
||||
.setStageId(battle.getStage().getId())
|
||||
.setBattleInfo(battle.toProto());
|
||||
|
||||
this.setData(data);
|
||||
|
||||
Reference in New Issue
Block a user