SotSManager.java 7.81 KB
Newer Older
1
package emu.grasscutter.game.managers;
2

gentlespoon's avatar
gentlespoon committed
3
import ch.qos.logback.classic.Logger;
4
import emu.grasscutter.Grasscutter;
5
import emu.grasscutter.game.entity.EntityAvatar;
6
7
8
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.PlayerProperty;
gentlespoon's avatar
gentlespoon committed
9
10
import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason;
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
11
12
13
14
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;

import java.util.List;
15
16
import java.util.Timer;
import java.util.TimerTask;
17
18
19
20

// Statue of the Seven Manager
public class SotSManager {

21
22
    // NOTE: Spring volume balance *1  = fight prop HP *100

23
    private final Player player;
gentlespoon's avatar
gentlespoon committed
24
    private final Logger logger = Grasscutter.getLogger();
25
    private Timer autoRecoverTimer;
gentlespoon's avatar
gentlespoon committed
26
    private final boolean enablePriorityHealing = false;
27

AnimeGitB's avatar
AnimeGitB committed
28
    public final static int GlobalMaximumSpringVolume = PlayerProperty.PROP_MAX_SPRING_VOLUME.getMax();
29

30
31
32
33
34
35
36
37
38
39
    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);
gentlespoon's avatar
gentlespoon committed
40
        player.save();
41
42
43
44
45
46
47
48
    }

    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);
gentlespoon's avatar
gentlespoon committed
49
        player.save();
50
51
    }

gentlespoon's avatar
gentlespoon committed
52
53
    public long getLastUsed() {
        return player.getSpringLastUsed();
54
55
    }

gentlespoon's avatar
gentlespoon committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    public void setLastUsed() {
        player.setSpringLastUsed(System.currentTimeMillis() / 1000);
        player.save();
    }

    public int getMaxVolume() {
        return player.getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
    }

    public void setMaxVolume(int volume) {
        player.setProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME, volume);
        player.save();
    }

    public int getCurrentVolume() {
        return player.getProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME);
    }

    public void setCurrentVolume(int volume) {
        player.setProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME, volume);
        setLastUsed();
        player.save();
    }

    public void handleEnterTransPointRegionNotify() {
        logger.trace("Player entered statue region");
        autoRevive();
83
84
        if (autoRecoverTimer == null) {
            autoRecoverTimer = new Timer();
gentlespoon's avatar
gentlespoon committed
85
            autoRecoverTimer.schedule(new AutoRecoverTimerTick(), 2500, 15000);
86
87
88
        }
    }

gentlespoon's avatar
gentlespoon committed
89
90
    public void handleExitTransPointRegionNotify() {
        logger.trace("Player left statue region");
91
92
93
94
95
96
        if (autoRecoverTimer != null) {
            autoRecoverTimer.cancel();
            autoRecoverTimer = null;
        }
    }

gentlespoon's avatar
gentlespoon committed
97
98
99
100
101
102
103
104
105
106
107
108
    // autoRevive automatically revives all team members.
    public void autoRevive() {
        player.getTeamManager().getActiveTeam().forEach(entity -> {
            boolean isAlive = entity.isAlive();
            if (isAlive) {
                return;
            }
            logger.trace("Reviving avatar " + entity.getAvatar().getAvatarData().getName());
            player.getTeamManager().reviveAvatar(entity.getAvatar());
            player.getTeamManager().healAvatar(entity.getAvatar(), 30, 0);
        });
    }
109

gentlespoon's avatar
gentlespoon committed
110
111
    private class AutoRecoverTimerTick extends TimerTask {
        // autoRecover checks player setting to see if auto recover is enabled, and refill HP to the predefined level.
112
        public void run() {
gentlespoon's avatar
gentlespoon committed
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
            refillSpringVolume();

            logger.trace("isAutoRecoveryEnabled: " + getIsAutoRecoveryEnabled() + "\tautoRecoverPercentage: " + getAutoRecoveryPercentage());

            if (getIsAutoRecoveryEnabled()) {
                List<EntityAvatar> activeTeam = player.getTeamManager().getActiveTeam();
                // When the statue does not have enough remaining volume:
                //      Enhanced experience: Enable priority healing
                //                              The current active character will get healed first, then sequential.
                //      Vanilla experience: Disable priority healing
                //                              Sequential healing based on character index.
                int priorityIndex = enablePriorityHealing ? player.getTeamManager().getCurrentCharacterIndex() : -1;
                if (priorityIndex >= 0) {
                    checkAndHealAvatar(activeTeam.get(priorityIndex));
                }
                for (int i = 0; i < activeTeam.size(); i++) {
                    if (i != priorityIndex) {
                        checkAndHealAvatar(activeTeam.get(i));
                    }
                }
            }
        }
    }

    public void checkAndHealAvatar(EntityAvatar entity) {
        int maxHP = (int) (entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * 100);
        int currentHP = (int) (entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) * 100);
        if (currentHP == maxHP) {
            return;
        }
        int targetHP = maxHP * getAutoRecoveryPercentage() / 100;

        if (targetHP > currentHP) {
            int needHP = targetHP - currentHP;
            int currentVolume = getCurrentVolume();
            if (currentVolume >= needHP) {
                // sufficient
                setCurrentVolume(currentVolume - needHP);
            } else {
                // insufficient balance
                needHP = currentVolume;
                setCurrentVolume(0);
            }
            if (needHP > 0) {
                logger.trace("Healing avatar " + entity.getAvatar().getAvatarData().getName() + " +" + needHP);
                player.getTeamManager().healAvatar(entity.getAvatar(), 0, needHP);
                player.getSession().send(new PacketEntityFightPropChangeReasonNotify(entity, FightProperty.FIGHT_PROP_CUR_HP,
160
161
                        ((float) needHP / 100), List.of(3), PropChangeReason.PROP_CHANGE_REASON_STATUE_RECOVER,
                        ChangeHpReason.CHANGE_HP_REASON_CHANGE_HP_ADD_STATUE));
gentlespoon's avatar
gentlespoon committed
162
163
164
                player.getSession().send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));

            }
165
        }
166
167
    }

168
    public void refillSpringVolume() {
169
170
        // Temporary: Max spring volume depends on level of the statues in Mondstadt and Liyue. Override until we have statue level.
        // TODO: remove
171
        // https://genshin-impact.fandom.com/wiki/Statue_of_The_Seven#:~:text=region%20of%20Inazuma.-,Statue%20Levels,-Upon%20first%20unlocking
gentlespoon's avatar
gentlespoon committed
172
        setMaxVolume(8500000);
173
174
        // Temporary: Auto enable 100% statue recovery until we can adjust statue settings in game
        // TODO: remove
gentlespoon's avatar
gentlespoon committed
175
176
        setAutoRecoveryPercentage(100);
        setIsAutoRecoveryEnabled(true);
177

gentlespoon's avatar
gentlespoon committed
178
179
180
181
182
183
184
185
186
187
188
        int maxVolume = getMaxVolume();
        int currentVolume = getCurrentVolume();
        if (currentVolume < maxVolume) {
            long now = System.currentTimeMillis() / 1000;
            int secondsSinceLastUsed = (int) (now - getLastUsed());
            // 15s = 1% max volume
            int volumeRefilled = secondsSinceLastUsed * maxVolume / 15 / 100;
            logger.trace("Statue has refilled HP volume: " + volumeRefilled);
            currentVolume = Math.min(currentVolume + volumeRefilled, maxVolume);
            logger.trace("Statue remaining HP volume: " + currentVolume);
            setCurrentVolume(currentVolume);
189
190
191
        }
    }
}