SotSManager.java 7.82 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
15
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;

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

// Statue of the Seven Manager
public class SotSManager {

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

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

29
30
    public final static int GlobalMaximumSpringVolume = 8500000;

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

    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
50
        player.save();
51
52
    }

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

gentlespoon's avatar
gentlespoon committed
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
83
    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();
84
85
        if (autoRecoverTimer == null) {
            autoRecoverTimer = new Timer();
gentlespoon's avatar
gentlespoon committed
86
            autoRecoverTimer.schedule(new AutoRecoverTimerTick(), 2500, 15000);
87
88
89
        }
    }

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

gentlespoon's avatar
gentlespoon committed
98
99
100
101
102
103
104
105
106
107
108
109
    // 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);
        });
    }
110

gentlespoon's avatar
gentlespoon committed
111
112
    private class AutoRecoverTimerTick extends TimerTask {
        // autoRecover checks player setting to see if auto recover is enabled, and refill HP to the predefined level.
113
        public void run() {
gentlespoon's avatar
gentlespoon committed
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
160
            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,
161
162
                        ((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
163
164
165
                player.getSession().send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));

            }
166
        }
167
168
    }

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

gentlespoon's avatar
gentlespoon committed
179
180
181
182
183
184
185
186
187
188
189
        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);
190
191
192
        }
    }
}