2022-05-08 07:29:40 +08:00
|
|
|
package emu.grasscutter.game.managers;
|
2022-05-06 15:05:38 +08:00
|
|
|
|
|
|
|
import emu.grasscutter.Grasscutter;
|
|
|
|
import emu.grasscutter.game.avatar.Avatar;
|
2022-05-07 05:38:14 +08:00
|
|
|
import emu.grasscutter.game.entity.EntityAvatar;
|
2022-05-06 15:05:38 +08:00
|
|
|
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;
|
2022-05-07 05:38:14 +08:00
|
|
|
import java.util.Timer;
|
|
|
|
import java.util.TimerTask;
|
2022-05-06 15:05:38 +08:00
|
|
|
|
|
|
|
// Statue of the Seven Manager
|
|
|
|
public class SotSManager {
|
|
|
|
|
2022-05-06 17:23:10 +08:00
|
|
|
// NOTE: Spring volume balance *1 = fight prop HP *100
|
|
|
|
|
2022-05-06 15:05:38 +08:00
|
|
|
private final Player player;
|
2022-05-07 05:38:14 +08:00
|
|
|
private Timer autoRecoverTimer;
|
2022-05-06 15:05:38 +08:00
|
|
|
|
2022-05-08 07:29:40 +08:00
|
|
|
public final static int GlobalMaximumSpringVolume = 8500000;
|
|
|
|
|
2022-05-06 15:05:38 +08:00
|
|
|
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();
|
2022-05-07 05:38:14 +08:00
|
|
|
float currentHP = entity.getAvatar().getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
|
|
|
float maxHP = entity.getAvatar().getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
|
|
|
// Grasscutter.getLogger().debug("" + entity.getAvatar().getAvatarData().getName() + "\t" + currentHP + "/" + maxHP + "\t" + (isAlive ? "ALIVE":"DEAD"));
|
|
|
|
float newHP = (float)(maxHP * 0.3);
|
|
|
|
if (currentHP < newHP) {
|
|
|
|
updateAvatarCurHP(session, entity, newHP);
|
|
|
|
}
|
2022-05-06 15:05:38 +08:00
|
|
|
if (!isAlive) {
|
|
|
|
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public void scheduleAutoRecover(GameSession session) {
|
2022-05-07 05:38:14 +08:00
|
|
|
if (autoRecoverTimer == null) {
|
|
|
|
autoRecoverTimer = new Timer();
|
|
|
|
autoRecoverTimer.schedule(new AutoRecoverTimerTick(session), 2500);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void cancelAutoRecover() {
|
|
|
|
if (autoRecoverTimer != null) {
|
|
|
|
autoRecoverTimer.cancel();
|
|
|
|
autoRecoverTimer = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class AutoRecoverTimerTick extends TimerTask
|
|
|
|
{
|
|
|
|
private GameSession session;
|
|
|
|
|
|
|
|
public AutoRecoverTimerTick(GameSession session) {
|
|
|
|
this.session = session;
|
|
|
|
}
|
|
|
|
public void run() {
|
|
|
|
autoRecover(session);
|
|
|
|
cancelAutoRecover();
|
|
|
|
}
|
2022-05-06 15:05:38 +08:00
|
|
|
}
|
|
|
|
|
2022-05-06 17:23:10 +08:00
|
|
|
public void refillSpringVolume() {
|
2022-05-10 17:03:18 +08:00
|
|
|
// Temporary: Max spring volume depends on level of the statues in Mondstadt and Liyue. Override until we have statue level.
|
|
|
|
// TODO: remove
|
2022-05-06 17:23:10 +08:00
|
|
|
// https://genshin-impact.fandom.com/wiki/Statue_of_The_Seven#:~:text=region%20of%20Inazuma.-,Statue%20Levels,-Upon%20first%20unlocking
|
2022-05-06 15:05:38 +08:00
|
|
|
player.setProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME, 8500000);
|
2022-05-10 17:03:18 +08:00
|
|
|
// Temporary: Auto enable 100% statue recovery until we can adjust statue settings in game
|
|
|
|
// TODO: remove
|
|
|
|
player.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, 100);
|
|
|
|
player.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, 1);
|
2022-05-06 15:05:38 +08:00
|
|
|
|
2022-05-06 17:23:10 +08:00
|
|
|
long now = System.currentTimeMillis() / 1000;
|
|
|
|
long secondsSinceLastUsed = now - player.getSpringLastUsed();
|
|
|
|
float percentageRefilled = (float)secondsSinceLastUsed / 15 / 100; // 15s = 1% max volume
|
|
|
|
int maxVolume = player.getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
|
|
|
|
int currentVolume = player.getProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME);
|
|
|
|
if (currentVolume < maxVolume) {
|
|
|
|
int volumeRefilled = (int)(percentageRefilled * maxVolume);
|
|
|
|
int newVolume = currentVolume + volumeRefilled;
|
|
|
|
if (currentVolume + volumeRefilled > maxVolume) {
|
|
|
|
newVolume = maxVolume;
|
|
|
|
}
|
|
|
|
player.setProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME, newVolume);
|
|
|
|
}
|
|
|
|
player.setSpringLastUsed(now);
|
|
|
|
player.save();
|
|
|
|
}
|
|
|
|
|
|
|
|
// autoRecover checks player setting to see if auto recover is enabled, and refill HP to the predefined level.
|
|
|
|
public void autoRecover(GameSession session) {
|
|
|
|
// TODO: In MP, respect SotS settings from the HOST.
|
2022-05-06 15:05:38 +08:00
|
|
|
boolean isAutoRecoveryEnabled = getIsAutoRecoveryEnabled();
|
|
|
|
int autoRecoverPercentage = getAutoRecoveryPercentage();
|
2022-05-06 15:28:35 +08:00
|
|
|
Grasscutter.getLogger().debug("isAutoRecoveryEnabled: " + isAutoRecoveryEnabled + "\tautoRecoverPercentage: " + autoRecoverPercentage);
|
2022-05-06 15:05:38 +08:00
|
|
|
|
|
|
|
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;
|
2022-05-06 17:23:10 +08:00
|
|
|
float needSV = needHP * 100; // convert HP needed to Spring Volume needed
|
|
|
|
|
|
|
|
int sotsSVBalance = player.getProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME);
|
|
|
|
if (sotsSVBalance >= needSV) {
|
|
|
|
// sufficient
|
|
|
|
sotsSVBalance -= needSV;
|
|
|
|
} else {
|
|
|
|
// insufficient balance
|
|
|
|
needSV = sotsSVBalance;
|
|
|
|
sotsSVBalance = 0;
|
|
|
|
}
|
|
|
|
player.setProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME, sotsSVBalance);
|
|
|
|
player.setSpringLastUsed(System.currentTimeMillis() / 1000);
|
2022-05-06 15:05:38 +08:00
|
|
|
|
2022-05-06 17:23:10 +08:00
|
|
|
float newHP = currentHP + needSV / 100; // convert SV to HP
|
2022-05-06 15:05:38 +08:00
|
|
|
|
2022-05-07 05:38:14 +08:00
|
|
|
updateAvatarCurHP(session, entity, newHP);
|
2022-05-06 15:05:38 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-07 05:38:14 +08:00
|
|
|
private void updateAvatarCurHP(GameSession session, EntityAvatar entity, float newHP) {
|
|
|
|
// TODO: Figure out why client shows current HP instead of added HP.
|
|
|
|
// Say an avatar had 12000 and now has 14000, it should show "2000".
|
|
|
|
// The client always show "+14000" which is incorrect.
|
|
|
|
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
|
|
|
|
session.send(new PacketEntityFightPropChangeReasonNotify(entity, FightProperty.FIGHT_PROP_CUR_HP,
|
|
|
|
newHP, List.of(3), PropChangeReasonOuterClass.PropChangeReason.PROP_CHANGE_STATUE_RECOVER,
|
|
|
|
ChangeHpReasonOuterClass.ChangeHpReason.ChangeHpAddStatue));
|
|
|
|
session.send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
|
|
|
|
|
|
|
|
Avatar avatar = entity.getAvatar();
|
|
|
|
avatar.setCurrentHp(newHP);
|
|
|
|
session.send(new PacketAvatarFightPropUpdateNotify(avatar, FightProperty.FIGHT_PROP_CUR_HP));
|
|
|
|
player.save();
|
|
|
|
}
|
|
|
|
|
2022-05-06 15:05:38 +08:00
|
|
|
|
|
|
|
}
|