-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathLevelSystem.kt
200 lines (182 loc) · 7.23 KB
/
LevelSystem.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
* This file is part of Mimic.
* Copyright (C) 2021 Osip Fatkullin
* Copyright (C) 2021 EndlessCode Group and contributors
*
* Mimic is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mimic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Mimic. If not, see <http://www.gnu.org/licenses/>.
*/
package ru.endlesscode.mimic.level
/**
* System that provides methods to work with player's level and experience points.
*
* Before implementing run an eye over all default method implementations
* and override all methods that works not properly for your case.
*/
@Suppress("DEPRECATION") // Allow to use setExp
public interface LevelSystem {
/** Assigned converter. */
public val converter: ExpLevelConverter
/**
* Current level of the player. Level can not be lesser than zero.
* @throws IllegalStateException If player-related object not exists
*/
public var level: Int
/**
* Player's total experience points.
* @throws IllegalStateException If player-related object not exists
*/
public var totalExp: Double
get() {
val levelExp = converter.levelToExp(level)
return levelExp + exp
}
set(value) {
val allowedTotalExperience = value.coerceAtLeast(0.0)
val fullLevels = converter.expToFullLevel(allowedTotalExperience)
val levelExp = converter.levelToExp(fullLevels)
level = fullLevels
exp = allowedTotalExperience - levelExp
}
/**
* Current fractional XP.
*
* This is a percentage value. 0 means "no progress" and 1 is "next level".
* @throws IllegalStateException If player-related object not exists
*/
public var fractionalExp: Double
get() {
val expToNextLevel = totalExpToNextLevel
val exp = exp.coerceAtMost(expToNextLevel - 1)
return if (exp <= 0.0) 0.0 else exp / expToNextLevel
}
set(value) {
val allowedExp = value.coerceAtLeast(0.0)
exp = if (value < 1.0) {
converter.getExpToReachNextLevel(level) * allowedExp
} else {
giveLevels(1)
0.0
}
}
/**
* Player's current level experience points.
*
* This field contains experience on current level, to get total player
* experience use [totalExp].
* Be careful with this field! To change experience value better to use
* [giveExp] and [takeExp]. To set total player experience use [totalExp].
* New experience value shouldn't be less than 0 and bigger than maximal
* possible XP on current level.
*
* For implementation:
* Better to add argument value validation to your implementation because
* new value can be bigger than maximal possible experience on current level,
* and you must trim it to the limit.
*
* @return Current level experience points or 0 if player has no exp
* @throws IllegalStateException If player-related object not exists
*/
@set:Deprecated("Better to use giveExp or takeExp to change experience value.")
public var exp: Double
/**
* Total amount of experience required for the player to reach next level.
*
* @return Experience required to level up or -1 if level-up is impossible
* @throws IllegalStateException If player-related object not exists
*/
public val totalExpToNextLevel: Double
get() = converter.getExpToReachNextLevel(level)
/**
* Remaining experience for the player to reach next level.
*
* @return Experience required to level up or -1 if level-up is impossible
* @throws IllegalStateException If player-related object not exists
*/
public val expToNextLevel: Double
get() = totalExpToNextLevel - exp
/**
* Decreases the player level by a specified amount.
*
* Never use negative amount to increase player level, use [giveLevels] instead.
*
* @param lvlAmount Amount of levels to take away
* @throws IllegalStateException If player-related object not exists
*/
public fun takeLevels(lvlAmount: Int) {
val currentLevel = level
level = currentLevel - lvlAmount.coerceAtMost(currentLevel)
}
/**
* Increases the player level by a specified amount.
*
* Never use negative amount to decrease player level, use [takeLevels] instead.
*
* @param lvlAmount Amount of additional levels
* @throws IllegalStateException If player-related object not exists
*/
public fun giveLevels(lvlAmount: Int) {
level += lvlAmount
}
/**
* Checks player reached required experience level.
*
* @param requiredLevel Required experience level. Negative value will be interpreted as 0.
* @return true if player player did reach required level
*/
public fun didReachLevel(requiredLevel: Int): Boolean = requiredLevel.coerceAtLeast(0) <= level
/**
* Takes away player the amount of experience specified.
*
* This method affects to total experience, which means that it can
* change both level and experience.
* Never use negative amount to increase exp, use [giveExp] instead.
*
* @param expAmount Exp amount to take away
* @throws IllegalStateException If player-related object not exists
* @see giveExp
*/
public fun takeExp(expAmount: Double) {
val currentTotalExp = totalExp
totalExp = currentTotalExp - expAmount.coerceAtMost(currentTotalExp)
}
/**
* Gives player the amount of experience specified.
*
* This method affects to total experience, which means that it can
* change both level and experience.
* Never use negative amount to decrease exp, use [takeExp] instead.
*
* @param expAmount Exp amount to give
* @throws IllegalStateException If player-related object not exists
* @see takeExp
*/
public fun giveExp(expAmount: Double) {
totalExp += expAmount
}
/**
* Checks player has required experience on current level.
*
* @param requiredExp Required experience amount. Negative value will be interpreted as 0
* @return true if player player has required experience
* @throws IllegalStateException If player-related object not exists
*/
public fun hasExp(requiredExp: Double): Boolean = requiredExp.coerceAtLeast(0.0) <= exp
/**
* Checks player has required total experience.
* @param requiredExp Required total experience amount. Negative value will be interpreted as 0.
* @return true if player player has required total experience
* @throws IllegalStateException If player-related object not exists
*/
public fun hasExpTotal(requiredExp: Double): Boolean = requiredExp.coerceAtLeast(0.0) <= totalExp
}