Implement techniques that debuff enemies

This commit is contained in:
Melledy
2023-12-04 02:10:11 -08:00
parent a2e10640c4
commit ca7b9fd8dd
13 changed files with 144 additions and 17 deletions

View File

@@ -121,6 +121,10 @@ public class Battle {
return buff;
}
public boolean hasBuff(int buffId) {
return this.buffs.stream().filter(buff -> buff.getId() == buffId).findFirst().isPresent();
}
public void clearBuffs() {
this.buffs.clear();
}

View File

@@ -64,13 +64,13 @@ public class BattleService extends BaseGameService {
}
}
// Give the client an error if no attacked entities detected
// Skip if no attacked entities detected
if (targetEntities.size() == 0) {
player.sendPacket(new PacketSceneCastSkillScRsp());
player.sendPacket(new PacketSceneCastSkillScRsp(attackedGroupId));
return;
}
// Monster list
// Separate entities into monster list
List<EntityMonster> monsters = new ArrayList<>();
// Destroy props
@@ -85,6 +85,15 @@ public class BattleService extends BaseGameService {
player.getScene().removeEntity(entity);
}
}
// Check if we are using a skill that doesnt trigger a battle
if (castedSkill != null && !castedSkill.isTriggerBattle()) {
// Apply buffs to monsters
castedSkill.onAttack(player.getCurrentLeaderAvatar(), monsters);
// Skip battle if our technique does not trigger a battle
player.sendPacket(new PacketSceneCastSkillScRsp(attackedGroupId));
return;
}
// Start battle
if (monsters.size() > 0) {
@@ -109,11 +118,16 @@ public class BattleService extends BaseGameService {
Battle battle = new Battle(player, player.getLineupManager().getCurrentLineup(), stages);
// Add npc monsters
for (var npcMonster : monsters) {
battle.getNpcMonsters().add(npcMonster);
for (var monster : monsters) {
battle.getNpcMonsters().add(monster);
if (npcMonster.getOverrideLevel() > 0) {
battle.setLevelOverride(npcMonster.getOverrideLevel());
// Handle monster buffs
// TODO handle multiple waves properly
monster.applyBuffs(battle);
// Override level
if (monster.getOverrideLevel() > 0) {
battle.setLevelOverride(monster.getOverrideLevel());
}
}

View File

@@ -1,6 +1,7 @@
package emu.lunarcore.game.battle;
import emu.lunarcore.data.excel.MazeBuffExcel;
import emu.lunarcore.game.scene.entity.GameEntity;
import emu.lunarcore.proto.BattleBuffOuterClass.BattleBuff;
import emu.lunarcore.proto.BattleBuffOuterClass.BattleBuff.DynamicValuesEntry;
import it.unimi.dsi.fastutil.ints.IntArrayList;
@@ -9,6 +10,7 @@ import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@Getter
public class MazeBuff {
@@ -19,7 +21,10 @@ public class MazeBuff {
private IntList targetIndex;
@Getter(AccessLevel.NONE)
private Object2DoubleMap<String> dynamicValues;
private Object2DoubleMap<String> dynamicValues;
@Setter
private transient GameEntity owner;
public MazeBuff(MazeBuffExcel excel, int ownerIndex, int waveFlag) {
this(excel.getBuffId(), excel.getLv(), ownerIndex, waveFlag);
@@ -52,9 +57,12 @@ public class MazeBuff {
var proto = BattleBuff.newInstance()
.setId(this.getId())
.setLevel(this.getLevel())
.setOwnerId(this.getOwnerIndex())
.setWaveFlag(this.getWaveFlag());
if (this.ownerIndex != 0) {
proto.setOwnerId(this.getOwnerIndex());
}
if (this.targetIndex != null) {
for (int index : this.targetIndex) {
proto.addTargetIndexList(index);

View File

@@ -6,6 +6,7 @@ import java.util.List;
import emu.lunarcore.data.excel.AvatarExcel;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.battle.Battle;
import emu.lunarcore.game.scene.entity.EntityMonster;
import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
import lombok.Getter;
import lombok.Setter;
@@ -44,4 +45,13 @@ public class MazeSkill {
action.onAttack(caster, battle);
}
}
// Triggered when player attacks an enemy
public void onAttack(GameAvatar caster, List<EntityMonster> monsters) {
if (this.getAttackActions().size() == 0) return;
for (var action : this.getAttackActions()) {
action.onAttack(caster, monsters);
}
}
}

View File

@@ -1,7 +1,10 @@
package emu.lunarcore.game.battle.skills;
import java.util.List;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.battle.Battle;
import emu.lunarcore.game.scene.entity.EntityMonster;
import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
public abstract class MazeSkillAction {
@@ -10,4 +13,6 @@ public abstract class MazeSkillAction {
public abstract void onAttack(GameAvatar caster, Battle battle);
public abstract void onAttack(GameAvatar caster, List<EntityMonster> monsters);
}

View File

@@ -1,7 +1,10 @@
package emu.lunarcore.game.battle.skills;
import java.util.List;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.battle.Battle;
import emu.lunarcore.game.scene.entity.EntityMonster;
import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
import lombok.Getter;
@@ -29,5 +32,12 @@ public class MazeSkillAddBuff extends MazeSkillAction {
battle.addBuff(buffId, battle.getLineup().getLeader(), 1 << i);
}
}
@Override
public void onAttack(GameAvatar caster, List<EntityMonster> monsters) {
for (EntityMonster monster : monsters) {
monster.addBuff(caster.getAvatarId(), buffId, duration);
}
}
}

View File

@@ -1,7 +1,10 @@
package emu.lunarcore.game.battle.skills;
import java.util.List;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.battle.Battle;
import emu.lunarcore.game.scene.entity.EntityMonster;
import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
public class MazeSkillModifyHP extends MazeSkillAction {
@@ -21,4 +24,9 @@ public class MazeSkillModifyHP extends MazeSkillAction {
}
@Override
public void onAttack(GameAvatar caster, List<EntityMonster> monsters) {
}
}

View File

@@ -1,7 +1,10 @@
package emu.lunarcore.game.battle.skills;
import java.util.List;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.battle.Battle;
import emu.lunarcore.game.scene.entity.EntityMonster;
import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
public class MazeSkillModifySP extends MazeSkillAction {
@@ -24,4 +27,9 @@ public class MazeSkillModifySP extends MazeSkillAction {
}
@Override
public void onAttack(GameAvatar caster, List<EntityMonster> monsters) {
}
}

View File

@@ -1,7 +1,10 @@
package emu.lunarcore.game.battle.skills;
import java.util.List;
import emu.lunarcore.game.avatar.GameAvatar;
import emu.lunarcore.game.battle.Battle;
import emu.lunarcore.game.scene.entity.EntityMonster;
import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
public class MazeSkillSummonUnit extends MazeSkillAction {
@@ -16,4 +19,9 @@ public class MazeSkillSummonUnit extends MazeSkillAction {
// TODO Auto-generated method stub
}
@Override
public void onAttack(GameAvatar caster, List<EntityMonster> monsters) {
// TODO Auto-generated method stub
}
}

View File

@@ -128,6 +128,10 @@ public class PlayerLineup {
}
}
public int indexOf(int ownerId) {
return this.getAvatars().indexOf(ownerId);
}
/**
* Checks if the slot contains an avatar
* @param slot The slot we are checking for

View File

@@ -0,0 +1,16 @@
package emu.lunarcore.game.scene;
import lombok.Getter;
@Getter
public class SceneEntityBuff {
private int owner; // Owner avatar id
private int id;
private long expiry;
public SceneEntityBuff(int owner, int id, long duration) {
this.owner = owner;
this.id = id;
this.expiry = System.currentTimeMillis() + (duration * 1000);
}
}

View File

@@ -3,12 +3,16 @@ package emu.lunarcore.game.scene.entity;
import emu.lunarcore.data.config.GroupInfo;
import emu.lunarcore.data.config.MonsterInfo;
import emu.lunarcore.data.excel.NpcMonsterExcel;
import emu.lunarcore.game.battle.Battle;
import emu.lunarcore.game.scene.Scene;
import emu.lunarcore.game.scene.SceneEntityBuff;
import emu.lunarcore.game.scene.triggers.PropTriggerType;
import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
import emu.lunarcore.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.lunarcore.proto.SceneNpcMonsterInfoOuterClass.SceneNpcMonsterInfo;
import emu.lunarcore.util.Position;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
import lombok.Setter;
@@ -25,6 +29,7 @@ public class EntityMonster implements GameEntity {
private final Position pos;
private final Position rot;
private Int2ObjectMap<SceneEntityBuff> buffs;
private int farmElementId;
@Setter private int overrideStageId;
@Setter private int overrideLevel;
@@ -51,6 +56,39 @@ public class EntityMonster implements GameEntity {
}
}
public void addBuff(int caster, int buffId, int duration) {
if (this.buffs == null) {
this.buffs = new Int2ObjectOpenHashMap<>();
}
this.buffs.put(buffId, new SceneEntityBuff(caster, buffId, duration));
}
public void applyBuffs(Battle battle) {
if (this.buffs == null) return;
for (var entry : this.buffs.int2ObjectEntrySet()) {
// Check expiry for buff
if (entry.getValue().getExpiry() < battle.getTimestamp()) {
continue;
}
// Dont add duplicate buffs
if (battle.hasBuff(entry.getIntKey())) {
continue;
}
// Get owner index
int ownerIndex = battle.getLineup().indexOf(entry.getValue().getOwner());
// Add buff to battle if owner exists
if (ownerIndex != -1) {
// TODO handle multiple waves properly
battle.addBuff(entry.getIntKey(), ownerIndex, 1);
}
}
}
@Override
public void onRemove() {
// Try to fire any triggers

View File

@@ -57,14 +57,8 @@ public class HandlerSceneCastSkillCsReq extends PacketHandler {
req.getHitTargetIdList().forEach(targets::add);
req.getAssistMonsterIdList().forEach(targets::add);
// Check if we can start a battle
if (skill != null && !skill.isTriggerBattle()) {
// Skip battle if our technique does not trigger a battle
session.send(new PacketSceneCastSkillScRsp(req.getAttackedGroupId()));
} else {
// Start battle normally
session.getServer().getBattleService().startBattle(player, req.getCasterId(), req.getAttackedGroupId(), skill, targets);
}
// Start battle
session.getServer().getBattleService().startBattle(player, req.getCasterId(), req.getAttackedGroupId(), skill, targets);
} else {
// We had no targets for some reason
session.send(new PacketSceneCastSkillScRsp(req.getAttackedGroupId()));