/
HungerTrait.java
231 lines (206 loc) · 6.94 KB
/
HungerTrait.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
package com.denizenscript.denizen.npc.traits;
import com.denizenscript.denizen.events.bukkit.ExhaustedNPCEvent;
import com.denizenscript.denizen.objects.NPCTag;
import com.denizenscript.denizen.utilities.DenizenAPI;
import net.citizensnpcs.api.ai.event.NavigationBeginEvent;
import net.citizensnpcs.api.ai.event.NavigationCancelEvent;
import net.citizensnpcs.api.ai.event.NavigationCompleteEvent;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class HungerTrait extends Trait implements Listener {
// Saved to the C2 saves.yml
@Persist("maxhunger")
private double maxhunger = 20.0;
@Persist("currenthunger")
private double currenthunger = 0.0;
@Persist("multiplier")
private int multiplier = 1;
@Persist("allowexhaustion")
private boolean allowexhaustion = false;
// Used internally
private boolean listening = false;
private Location location = null;
private int count = 0;
/**
* Watches the NPCs movement to calculate hunger loss. Loses 0.01 hunger points
* per block moved, unless a modifier is used.
*/
@Override
public void run() {
if (!listening) {
return;
}
// We'll only actually calculate hunger-loss once per second
count++;
if (count >= 20) {
// Reset counter
count = 0;
double td = getDistance(npc.getEntity().getLocation());
if (td > 0) {
location = npc.getEntity().getLocation().clone();
currenthunger = currenthunger - (td * 0.01 * multiplier);
}
}
}
// <--[action]
// @Actions
// exhausted
//
// @Triggers when the NPC is exhausted (Requires the Hunger trait)
//
// @Context
// None
//
// -->
/**
* Listens for the NPC to move so hunger-loss can be calculated.
* Cuts down on processing since loss is only calculated when moving.
* Also checks for exhaustion, if enabled. If a NPC is exhausted, that is,
* if currenthunger >= maxhunger, the NPC cannot move and a
* NPCExhaustedEvent and 'On Exhausted:' action will fire.
*/
@EventHandler
public void onMove(NavigationBeginEvent event) {
// TODO: Check if NPC == this NPC?
if (allowexhaustion) {
if (isStarving()) {
// Create NPCExhaustedEvent, give chance for outside plugins to cancel.
ExhaustedNPCEvent e = new ExhaustedNPCEvent(npc);
Bukkit.getServer().getPluginManager().callEvent(e);
// If still exhausted, cancel navigation and fire 'On Exhausted:' action
if (!e.isCancelled()) {
npc.getNavigator().cancelNavigation();
new NPCTag(npc).action("exhausted", null);
// No need to progress any further.
return;
}
}
}
location = npc.getEntity().getLocation();
listening = true;
}
/**
* Stops the listening process for hunger-loss since the NPC is no longer moving.
*/
@EventHandler
public void onCancel(NavigationCancelEvent event) {
listening = false;
}
/**
* Stops the listening process for hunger-loss since the NPC is no longer moving.
*/
@EventHandler
public void onCancel(NavigationCompleteEvent event) {
listening = false;
}
public HungerTrait() {
super("hunger");
}
/**
* Gets the NPCs current hunger level. 0.00 = no hunger, NPC is satiated.
*
* @return current hunger level
*/
public double getHunger() {
return currenthunger;
}
/**
* Gets the upper bounds of the hunger level. Default is 20.0. Can be set higher
* or lower to require more or less 'feeding'.
*
* @return max hunger level
*/
public double getMaxHunger() {
return maxhunger;
}
/**
* Gets the percentage of hunger based on currenthunger and maxhunger. 100 = npc
* is starving. 0 = npc is satiated.
*
* @return hunger percentage
*/
public int getHungerPercentage() {
return (int) ((int) currenthunger / maxhunger);
}
/**
* Gets the multiplier used to calculate hunger loss. Default is 1. Setting a higher value
* reduces hunger quicker.
*
* @return current hunger multiplier
*/
public int getHungerMultiplier() {
return multiplier;
}
/**
* Sets the multiplier used to calculate hunger loss. Default is 1. Setting a higher value
* reduces hunger quicker. Lower value, in turn, makes hunger loss slower.
*
* @param multiplier new multiplier
*/
public void setHungerMultiplier(int multiplier) {
this.multiplier = multiplier;
}
/**
* Sets the current hunger level.
*
* @param hunger new hunger level
*/
public void setHunger(double hunger) {
if (currenthunger > maxhunger) {
currenthunger = maxhunger;
}
else {
currenthunger = hunger;
}
}
/**
* "Feeds" the NPC. The value used will reduce the total currenthunger value.
*
* @param hunger amount of hunger-points to reduce currenthunger by
*/
public void feed(double hunger) {
currenthunger = currenthunger - hunger;
if (currenthunger < 0) {
currenthunger = 0;
}
}
/**
* Sets the max hunger value. Once hunger reaches this level the NPC is starving and
* may not be able to move. This method does not change the NPC's currenthunger.
*
* @param hunger new max hunger value
*/
public void setMaxhunger(double hunger) {
maxhunger = hunger;
}
/**
* Checks to see if the NPC is starving. If currenthunger >= maxhunger, the NPC is starving.
*
* @return true if NPC is starving
*/
public boolean isStarving() {
return currenthunger >= maxhunger;
}
/**
* Checks to see if the NPC is hungry. If currenthunger is 10% or more of maxhunger,
* the NPC is hungry. A NPC that is starving is also hungry.
*
* @return true if the NPC is hungry
*/
public boolean isHungry() {
return currenthunger > (maxhunger / 10);
}
// Used internally
private double getDistance(Location location) {
if (!npc.getEntity().getWorld().equals(location.getWorld())) {
// World change, update location
this.location = npc.getEntity().getLocation();
return 0;
}
return location.distance(this.location);
}
}