-
-
Notifications
You must be signed in to change notification settings - Fork 56
/
Skill.java
422 lines (346 loc) · 11.5 KB
/
Skill.java
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
package cn.academy.ability;
import cn.academy.ability.context.*;
import cn.academy.ability.context.Context.Status;
import cn.academy.datapart.AbilityData;
import cn.academy.ability.develop.DeveloperType;
import cn.academy.ability.develop.condition.DevConditionDep;
import cn.academy.ability.develop.condition.DevConditionDeveloperType;
import cn.academy.ability.develop.condition.DevConditionLevel;
import cn.academy.ability.develop.condition.IDevCondition;
import cn.academy.Resources;
import cn.academy.ACConfig;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.typesafe.config.Config;
import net.minecraft.util.text.translation.I18n;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation;
import scala.Function1;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
/**
* Skill is the basic control unit of an ESPer. A skill is learned through Ability Developer
* and can be activated/controlled via the Preset system. <br/>
* A skill must be added into a Category, otherwise its presence is meaningless. <br/>
*
* A skill can be specified to not appear in Preset Edit screen. This kind of skills usually serve as 'passive' skills and provide
* pipeline functions inside to affect the skill damage or other values. <br/>
*
*
* method so that the skill control will take effect.
* @author WeAthFolD
*/
public abstract class Skill extends Controllable {
private Category category;
private final List<IDevCondition> learningConditions = new ArrayList<>();
private String fullName;
/**
* The parent skill of the skill. This is the upper level skill in the Skill Tree UI. If not specified, this skill is the root skill of the type.
*/
private Skill parent;
private int id;
private final String name;
private ResourceLocation icon;
private final int level;
/**
* The place this skill is at in the Skill Tree UI.
*/
public float guiX, guiY;
/**
* Whether this skill has customized experience definition.
* If this is set to true, getSkillExp() will be called whenever
* querying experience of skill.
*/
public boolean expCustomized = false;
/**
* Whether this skill can be controlled (i.e. appear in preset edit ui).
*/
protected boolean canControl = true;
/**
* Whether this skill is a generic skill (Skill used across many categories).
* If set to true, the logo lookup path and the name lookup path will be changed. (CategoryName="generic")
*/
protected boolean isGeneric = false;
/**
* @param _name Skill internal name
* @param atLevel The level at which this skill is in
*/
public Skill(String _name, int atLevel) {
name = _name;
level = atLevel;
fullName = "<unassigned>." + name;
addDevCondition(new DevConditionLevel());
}
final void addedSkill(Category _category, int id) {
category = _category;
this.id = id;
icon = initIcon();
fullName = initFullName();
this.addDevCondition(new DevConditionDeveloperType(getMinimumDeveloperType()));
initSkill();
}
public void setPosition(float x, float y) {
guiX = x;
guiY = y;
}
/**
* Callback that is called AFTER the skill is added into the category.
*/
protected void initSkill() {}
/**
* Get the id of the skill in the Category.
*/
public int getID() {
return id;
}
/**
* Get the level id that this skill is in.
*/
public int getLevel() {
return level;
}
/**
* Get the direct name of the skill.
*/
public String getName() {
return name;
}
/**
* Get the full name of the skill, in format [category].[name].
*/
public String getFullName() {
return fullName;
}
/**
* Get the display name of the skill.
*/
public String getDisplayName() {
return getLocalized("name");
}
/**
* Get the detailed description for the skill, shown in Ability Developer.
*/
public String getDescription() {
return getLocalized("desc");
}
/**
* @return The configuration object for this skill.
*/
public Config getConfig() {
Config config = ACConfig.instance()
.getConfig("ac.ability.category")
.getConfig(getCategoryLocation())
.getConfig("skills")
.getConfig(getName());
Preconditions.checkNotNull(config);
return config;
}
public float getDamageScale() {
return getOptionalFloat("damage_scale", 1.0f);
}
/**
* @return Whether the skill is enabled. Disabled skill will NOT appear in Skill Tree, and its learning dependency
* will be automatically ignored.
*/
public boolean isEnabled() {
return getOptionalBool("enabled", true);
}
/**
* @return Whether this skill is permitted to destroy blocks.
*/
public boolean shouldDestroyBlocks() {
return getOptionalBool("destroy_blocks", true);
}
public float getCPConsumeSpeed() {
return getOptionalFloat("cp_consume_speed", 1.0f);
}
public float getOverloadConsumeSpeed() {
return getOptionalFloat("overload_consume_speed", 1.0f);
}
public float getExpIncrSpeed() {
return getOptionalFloat("exp_incr_speed", 1.0f);
}
private float getOptionalFloat(String path, float fallback) {
Config cfg = getConfig();
return cfg.hasPath(path) ? (float) cfg.getDouble(path) : fallback;
}
private boolean getOptionalBool(String path, boolean fallback) {
Config cfg = getConfig();
return cfg.hasPath(path) ? cfg.getBoolean(path) : fallback;
}
public boolean canControl() {
return isEnabled() && canControl;
}
@Override
public ResourceLocation getHintIcon() {
return icon;
}
@Override
public String getHintText() {
return getDisplayName();
}
protected String getLocalized(String key) {
return I18n.translateToLocal("ac.ability." + getFullName() + "." + key);
}
//--- Path init
protected String getCategoryLocation() {
return (isGeneric ? "generic" : category.getName());
}
/**
* @return The init full name. Is guaranteed to be called AFTER the Category is assigned.
*/
protected String initFullName() {
return getCategoryLocation() + "." + name;
}
/**
* @return The icon of this skill. Is guaranteed to be called AFTER the Category is assigned.
*/
protected ResourceLocation initIcon() {
return icon = Resources.getTexture("abilities/" + getCategoryLocation() + "/skills/" + name);
}
//--- Hooks
/**
* Get called when set expCustomize=true, to query the experience of the skill.
* @param data
* @return exp value in [0, 1]
*/
public float getSkillExp(AbilityData data) {
return 0.0f;
}
/**
* Java version
*/
@SideOnly(Side.CLIENT)
protected void activateSingleKey2(ClientRuntime rt, int keyID, Function<EntityPlayer, Context> contextSupplier) {
rt.addKey(keyID, new SingleKeyDelegate(contextSupplier));
}
/**
* Scala version
*/
@SideOnly(Side.CLIENT)
protected void activateSingleKey(ClientRuntime rt, int keyID,
Function1<EntityPlayer, Context> contextSupplier) {
activateSingleKey2(rt, keyID, contextSupplier::apply);
}
//--- Learning
public void setParent(Skill skill) {
setParent(skill, 0.0f);
}
public void setParent(Skill skill, float requiredExp) {
if(parent != null)
throw new IllegalStateException("You can't set the parent twice!");
if (skill.isEnabled()) {
parent = skill;
this.addDevCondition(new DevConditionDep(parent, requiredExp));
}
}
public Skill getParent() {
return parent;
}
public boolean isRoot() {
return parent == null;
}
public void addDevCondition(IDevCondition cond) {
learningConditions.add(cond);
}
public void addSkillDep(Skill skill, float exp) {
if (skill.isEnabled()) {
addDevCondition(new DevConditionDep(skill, exp));
}
}
/**
* Returns an immutable list of learning conditions of this skill.
*/
public List<IDevCondition> getDevConditions() {
return ImmutableList.copyOf(learningConditions);
}
/**
* @return The stimulation in the developer required in order to learn this skill
*/
public int getLearningStims() {
return (int) (3 + level * level * 0.5f);
}
/**
* @return The minimum developer type that this skill will appear on
*/
public DeveloperType getMinimumDeveloperType() {
if(level <= 2) // Level 1 and 2
return DeveloperType.PORTABLE;
if(level <= 3) // Level 3
return DeveloperType.NORMAL;
else // Level 4 and 5
return DeveloperType.ADVANCED;
}
@Override
public String toString() {
return getFullName();
}
public class SingleKeyDelegate extends KeyDelegate {
private final Function<EntityPlayer, Context> contextSupplier;
Context context;
public SingleKeyDelegate(Function<EntityPlayer, Context> contextSupplier) {
this.contextSupplier = contextSupplier;
}
public SingleKeyDelegate(Function1<EntityPlayer, Context> supplier) {
this((Function<EntityPlayer, Context>) supplier::apply);
}
@Override
public void onKeyDown() {
context = contextSupplier.apply(getPlayer());
ContextManager.instance.activate(context);
context.sendToSelf(Context.MSG_KEYDOWN);
}
@Override
public void onKeyTick() {
checkContext();
if (context != null) {
context.sendToSelf(Context.MSG_KEYTICK);
}
}
@Override
public void onKeyUp() {
checkContext();
if (context != null) {
context.sendToSelf(Context.MSG_KEYUP);
}
context = null;
}
@Override
public void onKeyAbort() {
checkContext();
if (context != null) {
context.sendToSelf(Context.MSG_KEYABORT);
}
context = null;
}
private void checkContext() {
if (context != null && context.getStatus() == Status.TERMINATED) {
context = null;
}
}
@Override
public DelegateState getState() {
if (context == null) {
return DelegateState.IDLE;
} else if (context instanceof IStateProvider) {
return ((IStateProvider) context).getState();
} else {
return DelegateState.ACTIVE;
}
}
@Override
public ResourceLocation getIcon() {
return getHintIcon();
}
@Override
public int createID() {
return 0;
}
public Skill getSkill() {
return Skill.this;
}
}
}