-
-
Notifications
You must be signed in to change notification settings - Fork 103
/
ZapCommand.java
195 lines (167 loc) · 8.56 KB
/
ZapCommand.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
package com.denizenscript.denizen.scripts.commands.core;
import com.denizenscript.denizen.scripts.containers.core.InteractScriptHelper;
import com.denizenscript.denizen.utilities.DenizenAPI;
import com.denizenscript.denizen.utilities.Utilities;
import com.denizenscript.denizen.utilities.debugging.Debug;
import com.denizenscript.denizencore.exceptions.InvalidArgumentsException;
import com.denizenscript.denizencore.objects.*;
import com.denizenscript.denizencore.objects.core.DurationTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.ScriptTag;
import com.denizenscript.denizencore.scripts.ScriptEntry;
import com.denizenscript.denizencore.scripts.commands.AbstractCommand;
import org.bukkit.event.Listener;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ZapCommand extends AbstractCommand implements Listener {
// <--[command]
// @Name Zap
// @Syntax zap (<script>) [<step>] (<duration>)
// @Required 0
// @Short Changes the current interact script step.
// @Group core
// @Guide https://guide.denizenscript.com/guides/npcs/interact-scripts.html
//
// @Description
// Changes the current interact script step for the linked player.
//
// The step name input should match the name of a step in the interact script.
//
// If used inside an interact script, will default to the current interact script.
// For anywhere else, you must specify the script by name.
//
// Optionally specify a duration. When the duration is up, the script will zap back to the step it was previously on.
// If any zap commands are used during the duration, that duration will be discarded.
//
// The command's name was inspired by a command in the language "ZZT-OOP", from a 1991 DOS game enjoyed by the original developer of Denizen.
//
// @Tags
// <ScriptTag.step[<player>]>
//
// @Usage
// Use to change the step to 2
// - zap 2
//
// @Usage
// Use to change the step to 3 in a script called Interact_Example.
// - zap 3 Interact_Example
//
// @Usage
// Use to change the step to 1 for player bob in a script called InteractScript.
// - zap 1 InteractScript player:p@bob
// -->
@Override
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException {
for (Argument arg : scriptEntry.getProcessedArgs()) {
// If the scripter uses the 'script:step' format, handle it.
if (!scriptEntry.hasObject("script")
&& !scriptEntry.hasObject("step")
&& arg.hasPrefix()
&& arg.getPrefix().matchesArgumentType(ScriptTag.class)) {
scriptEntry.addObject("script", arg.getPrefix().asType(ScriptTag.class));
scriptEntry.addObject("step", arg.asElement());
}
// If a script is found, use that to ZAP
else if (!scriptEntry.hasObject("script")
&& arg.matchesArgumentType(ScriptTag.class)
&& !arg.matchesPrefix("step")) {
scriptEntry.addObject("script", arg.asType(ScriptTag.class));
}
// Add argument as step
else if (!scriptEntry.hasObject("step")) {
scriptEntry.addObject("step", arg.asElement());
}
// Lastly duration
else if (!scriptEntry.hasObject("duration")
&& arg.matchesArgumentType(DurationTag.class)) {
scriptEntry.addObject("duration", arg.asType(DurationTag.class));
}
else {
arg.reportUnhandled();
}
}
// Add default script if none was specified.
scriptEntry.defaultObject("script", scriptEntry.getScript());
// Check if player is valid
if (!Utilities.entryHasPlayer(scriptEntry) || !Utilities.getEntryPlayer(scriptEntry).isValid()) {
throw new InvalidArgumentsException("Must have player context!");
}
}
//"PlayerName,ScriptName", TaskID
private static Map<String, Integer> durations = new ConcurrentHashMap<>(8, 0.9f, 1);
@Override
public void execute(final ScriptEntry scriptEntry) {
final ScriptTag script = (ScriptTag) scriptEntry.getObject("script");
DurationTag duration = (DurationTag) scriptEntry.getObject("duration");
if (scriptEntry.dbCallShouldDebug()) {
Debug.report(scriptEntry, getName(), Utilities.getEntryPlayer(scriptEntry).debug() + script.debug()
+ (scriptEntry.hasObject("step")
? scriptEntry.getElement("step").debug() : ArgumentHelper.debugObj("step", "++ (inc)"))
+ (duration != null ? duration.debug() : ""));
}
String step = scriptEntry.hasObject("step") ? scriptEntry.getElement("step").asString() : null;
// Let's get the current step for reference.
String currentStep = InteractScriptHelper.getCurrentStep(Utilities.getEntryPlayer(scriptEntry), script.getName());
// Special-case for backwards compatibility: ability to use ZAP to count up steps.
if (step == null) {
// Okay, no step was identified.. that means we should count up,
// ie. if currentStep = 1, new step should = 2
// If the currentStep is a number, increment it. If not, set it
// to '1' so it can be incremented next time.
if (ArgumentHelper.matchesInteger(currentStep)) {
step = String.valueOf(Integer.parseInt(currentStep) + 1);
}
else {
step = "1";
}
}
if (step.equalsIgnoreCase(currentStep)) {
Debug.echoError(scriptEntry.getResidingQueue(), "Zapping to own current step!");
return;
}
// If the durationsMap already contains an entry for this player/script combination,
// cancel the task since it's probably not desired to change back anymore if another
// ZAP for this script is taking place.
String durationKey = Utilities.getEntryPlayer(scriptEntry).getSaveName() + "," + script.getName();
Integer durationObj = durations.get(durationKey);
if (durationObj != null) {
try {
DenizenAPI.getCurrentInstance().getServer().getScheduler().cancelTask(durationObj);
}
catch (Exception ex) {
Debug.echoError(ex);
}
}
// One last thing... check for duration.
if (duration != null && duration.getSeconds() > 0) {
// If a DURATION is specified, the currentStep should be remembered and
// restored after the duration.
scriptEntry.addObject("step", new ElementTag(currentStep));
// And let's take away the duration that was set to avoid a re-duration
// inception-ion-ion-ion-ion... ;)
scriptEntry.addObject("duration", DurationTag.ZERO);
// Now let's add a delayed task to set it back after the duration
// Delays are in ticks, so let's multiply our duration (which is in seconds) by 20.
// 20 ticks per second.
long delay = (long) (duration.getSeconds() * 20);
// Set delayed task and put id in a map
Debug.log("Setting delayed task 'RESET ZAP' for '" + script.identify() + "'");
durations.put(durationKey,
DenizenAPI.getCurrentInstance().getServer().getScheduler().scheduleSyncDelayedTask(DenizenAPI.getCurrentInstance(),
new Runnable() {
@Override
public void run() {
Debug.log("Running delayed task 'RESET ZAP' for '" + script.identify() + "'");
durations.remove(durationKey);
execute(scriptEntry);
}
}, delay));
}
//
// FINALLY! ZAP! Change the step in Saves... your step is now ZAPPED!
// Fun fact: ZAP is named in homage of ZZT-OOPs ZAP command. Google it.
//
DenizenAPI.getCurrentInstance().getSaves().set("Players." + Utilities.getEntryPlayer(scriptEntry).getSaveName()
+ ".Scripts." + script.getName().toUpperCase() + "." + "Current Step", step);
}
}