Implementes auto HP recovery at the statues.

- Respects player setting.
- SP + MP.
- Statue has unlimited HP volume (to be updated)
This commit is contained in:
gentlespoon 2022-05-06 00:05:38 -07:00 committed by Melledy
parent 39a49ae964
commit 39c932b041
3 changed files with 132 additions and 21 deletions

View File

@ -0,0 +1,118 @@
package emu.grasscutter.game.managers.SotSManager;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.net.proto.ChangeHpReasonOuterClass;
import emu.grasscutter.net.proto.PropChangeReasonOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import java.util.List;
// Statue of the Seven Manager
public class SotSManager {
private final Player player;
public SotSManager(Player player) {
this.player = player;
}
public boolean getIsAutoRecoveryEnabled() {
return player.getProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE) == 1;
}
public void setIsAutoRecoveryEnabled(boolean enabled) {
player.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, enabled ? 1 : 0);
}
public int getAutoRecoveryPercentage() {
return player.getProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT);
}
public void setAutoRecoveryPercentage(int percentage) {
player.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, percentage);
}
// autoRevive automatically revives all team members.
public void autoRevive(GameSession session) {
player.getTeamManager().getActiveTeam().forEach(entity -> {
boolean isAlive = entity.isAlive();
if (!isAlive) {
float maxHP = entity.getAvatar().getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, Math.min(150, maxHP));
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
}
});
}
public void scheduleAutoRecover(GameSession session) {
// TODO: play audio effects? possibly client side? - client automatically plays.
// delay 2.5 seconds
new Thread(() -> {
try {
Thread.sleep(2500);
autoRecover(session);
} catch (Exception e) {
Grasscutter.getLogger().error(e.getMessage());
}
}).start();
}
// autoRecover checks player setting to see if auto recover is enabled, and refill HP to the predefined level.
public void autoRecover(GameSession session) {
// TODO: Implement SotS Spring volume refill over time.
// Placeholder:
player.setProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME, 8500000);
player.setProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME, 8500000);
// TODO: In MP, respect SotS settings from the host.
boolean isAutoRecoveryEnabled = getIsAutoRecoveryEnabled();
int autoRecoverPercentage = getAutoRecoveryPercentage();
Grasscutter.getLogger().warn("isAutoRecoveryEnabled: " + isAutoRecoveryEnabled + "\tautoRecoverPercentage: " + autoRecoverPercentage);
if (isAutoRecoveryEnabled) {
player.getTeamManager().getActiveTeam().forEach(entity -> {
float maxHP = entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
float currentHP = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
if (currentHP == maxHP) {
return;
}
float targetHP = maxHP * autoRecoverPercentage / 100;
if (targetHP > currentHP) {
float needHP = targetHP - currentHP;
int sotsHPBalance = player.getProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME);
if (sotsHPBalance >= needHP) {
sotsHPBalance -= needHP;
player.setProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME, sotsHPBalance);
float newHP = currentHP + needHP;
session.send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_MAX_HP));
session.send(new PacketEntityFightPropChangeReasonNotify(entity, FightProperty.FIGHT_PROP_CUR_HP,
newHP, List.of(3), PropChangeReasonOuterClass.PropChangeReason.PROP_CHANGE_STATUE_RECOVER,
ChangeHpReasonOuterClass.ChangeHpReason.ChangeHpAddStatue));
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
Avatar avatar = entity.getAvatar();
session.send(new PacketAvatarFightPropUpdateNotify(avatar, FightProperty.FIGHT_PROP_CUR_HP));
avatar.setCurrentHp(newHP);
player.save();
}
}
});
}
}
}

View File

@ -22,6 +22,7 @@ import emu.grasscutter.game.inventory.Inventory;
import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.game.mail.MailHandler;
import emu.grasscutter.game.managers.MovementManager.MovementManager;
import emu.grasscutter.game.managers.SotSManager.SotSManager;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.props.PlayerProperty;
@ -89,6 +90,8 @@ public class Player {
@Transient private MailHandler mailHandler;
@Transient private MessageHandler messageHandler;
@Transient private SotSManager sotsManager;
private TeamManager teamManager;
private TowerManager towerManager;
@ -168,6 +171,7 @@ public class Player {
this.messageHandler = null;
this.mapMarksManager = new MapMarksManager();
this.movementManager = new MovementManager(this);
this.sotsManager = new SotSManager(this);
}
// On player creation
@ -196,6 +200,7 @@ public class Player {
this.messageHandler = null;
this.mapMarksManager = new MapMarksManager();
this.movementManager = new MovementManager(this);
this.sotsManager = new SotSManager(this);
}
public int getUid() {
@ -984,6 +989,8 @@ public class Player {
public MovementManager getMovementManager() { return movementManager; }
public SotSManager getSotSManager() { return sotsManager; }
public synchronized void onTick() {
// Check ping
if (this.getLastPingTime() > System.currentTimeMillis() + 60000) {

View File

@ -1,5 +1,7 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.managers.SotSManager.SotSManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
@ -18,26 +20,10 @@ import java.util.List;
public class HandlerEnterTransPointRegionNotify extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception{
session.getPlayer().getTeamManager().getActiveTeam().forEach(entity -> {
boolean isAlive = entity.isAlive();
if(entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) != entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)){
Float hp = entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)-entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
session.send(new PacketEntityFightPropUpdateNotify(entity,FightProperty.FIGHT_PROP_MAX_HP));
session.send(new PacketEntityFightPropChangeReasonNotify(
entity, FightProperty.FIGHT_PROP_CUR_HP, hp, List.of(3),
PropChangeReason.PROP_CHANGE_STATUE_RECOVER, ChangeHpReason.ChangeHpAddStatue));
entity.setFightProperty(
FightProperty.FIGHT_PROP_CUR_HP,
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)
);
session.send(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
if (!isAlive) {
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
}
}
});
Player player = session.getPlayer();
SotSManager sotsManager = player.getSotSManager();
sotsManager.autoRevive(session);
sotsManager.scheduleAutoRecover(session);
// TODO: allow interaction with the SotS?
}
}