RuneHive-Game
Loading...
Searching...
No Matches
FarmingPatch.java
Go to the documentation of this file.
1package com.runehive.content.skill.impl.farming.patches;
2
3import com.google.gson.JsonObject;
4import com.runehive.Config;
5import com.runehive.content.skill.impl.farming.CompostType;
6import com.runehive.content.skill.impl.farming.FarmingConstants;
7import com.runehive.content.skill.impl.farming.FarmingStage;
8import com.runehive.content.skill.impl.farming.FarmingState;
9import com.runehive.content.skill.impl.farming.plants.Plant;
10import com.runehive.content.skill.impl.farming.zones.FarmingZone;
11import com.runehive.game.action.Action;
12import com.runehive.game.action.policy.WalkablePolicy;
13import com.runehive.game.task.Task;
14import com.runehive.game.world.Interactable;
15import com.runehive.game.world.World;
16import com.runehive.game.world.entity.mob.player.Player;
17import com.runehive.game.world.entity.skill.Skill;
18import com.runehive.game.world.items.Item;
19import com.runehive.game.world.position.Position;
20import com.runehive.util.Stopwatch;
21import com.runehive.util.Utility;
22
23import java.util.concurrent.TimeUnit;
24
25public abstract class FarmingPatch {
26 private static final double CLEARING_EXPERIENCE = 4;
27
28 protected Plant plant;
29
32
33 protected int growth;
34
35 protected boolean fullyGrown;
37
38 protected final Player player;
39 protected final FarmingZone zone;
40 private final Interactable[] boundaries;
41 protected final Stopwatch timer = Stopwatch.start();
42
44 this.player = player;
45 this.zone = zone;
46 this.boundaries = boundaries;
47 resetPatch();
48 }
49
50 public void tick() {
51
52 /* if the patch is empty, grow back the weeds */
53 if (!stage.equals(FarmingStage.FULL_WEEDS) && plant == null && timer.elapsed(5, TimeUnit.MINUTES)) {
54 stage = stage.getPreviousStage();
55 zone.sendPatchConfigs(player);
56 timer.reset();
57 }
58
59 /* nothing is growing on this patch */
60 if (plant == null) {
61 return;
62 }
63
64 int elapsed = (int) timer.elapsedTime(TimeUnit.SECONDS) / 12;
65 int growthStates = plant.getEndingState() - plant.getStartingState();
66 int growthTime = plant.getGrowthTime();
67
68 if (elapsed > growthTime) {
69 elapsed = growthTime;
70 }
71
72 int completed = growthStates * elapsed / growthTime;
73
74 if (growth != completed) {
75 fullyGrown = completed == growthStates;
76 onGrowth();
77 if (!isDead()) {
78 growth = completed;
79 }
80 zone.sendPatchConfigs(player);
81 }
82 }
83
84 private void simulate(long elapsed) {
85
86 /* nothing is growing on this patch */
87 if (plant == null || isDead()) {
88 return;
89 }
90
91 int growthStates = plant.getEndingState() - plant.getStartingState();
92 int growthTime = plant.getGrowthTime();
93
94 if (elapsed > growthTime) {
95 elapsed = growthTime;
96 }
97
98 int completed = (int) (growthStates * elapsed / growthTime);
99
100 for (int i = growth; i <= completed; i++) {
101 fullyGrown = i == growthStates;
102 onGrowth();
103
104 if (isDead()) {
105 return;
106 }
107
108 growth = i;
109 }
110 }
111
112 protected void onGrowth() {}
113
114 public boolean clickObject(int opcode) {
115 if (opcode == 1 && (needsWeeding() || isDead())) {
116 clearPatch();
117 return true;
118 }
119 if (opcode == 2) {
120 inspect();
121 return true;
122 }
123 return false;
124 }
125
126 public boolean itemOnObject(Item item, int index) {
128 clearPatch();
129 return true;
130 }
131 return putCompost(item.getId(), index) || plantSeed(item.getId(), index);
132 }
133
134 private void clearPatch() {
135 int animation, delay;
136
137 if (isEmpty()) {
138 player.dialogueFactory.sendStatement("This patch is already empty.").execute();
139 return;
140 }
141
142 if (isGrowing()) {
143 if (!player.inventory.contains(FarmingConstants.SPADE)) {
144 player.dialogueFactory.sendStatement("You need a spade to clear this patch.").execute();
145 return;
146 }
147
148 delay = 3;
149 animation = FarmingConstants.SPADE_ANIM;
150 } else {
151 if (!player.inventory.contains(FarmingConstants.RAKE)) {
152 player.dialogueFactory.sendStatement("You need a rake to clear this patch.").execute();
153 return;
154 }
155
156 delay = 5;
157 animation = FarmingConstants.RAKING_ANIM;
158 }
159
160 player.action.execute(createClearingAction(player, animation, delay));
161 }
162
163 private boolean plantSeed(int seedId, int slot) {
164 if (player.locking.locked()) {
165 return false;
166 }
167
168 Plant toPlant = plantForSeed(seedId);
169
170 if (toPlant == null) {
171 return false;
172 }
173
174 if (!isEmpty()) {
175 player.message("You can't plant a seed here.");
176 return false;
177 }
178
179 if (toPlant.getLevelRequired() > player.skills.getLevel(Skill.FARMING)) {
180 player.dialogueFactory.sendStatement("You need a farming level of " + toPlant.getLevelRequired() + " to plant this seed.").execute();
181 return true;
182 }
183
184 if (!player.inventory.contains(FarmingConstants.SEED_DIBBER)) {
185 player.dialogueFactory.sendStatement("You need a seed dibber to plant seeds here.").execute();
186 return true;
187 }
188
189 if (!player.inventory.contains(toPlant.getSeedId(), toPlant.getSeedAmount())) {
190 player.dialogueFactory.sendStatement("You need at least " + toPlant.getSeedAmount() + " seeds to plant here.").execute();
191 return true;
192 }
193
194 plant = toPlant;
195 setNormal();
196 timer.reset();
197
198 player.locking.lock(3 * 3 / 5);
200 player.inventory.remove(new Item(seedId, toPlant.getSeedAmount()), slot, true);
201
202 World.schedule(3, () -> {
203 player.resetAnimation();
204 player.skills.addExperience(Skill.FARMING, plant.getPlantingXp() * Config.FARMING_MODIFICATION);
205 zone.sendPatchConfigs(player);
206 });
207 return true;
208 }
209
210 private boolean putCompost(int itemId, int slot) {
211 if (player.locking.locked()) {
212 return false;
213 }
214
215 CompostType type = CompostType.forItem(itemId);
216
217 if (type == CompostType.NONE) {
218 return false;
219 }
220
221 if (needsWeeding() || isComposted()) {
222 player.message("This patch doesn't need compost.");
223 return true;
224 }
225
226 player.locking.lock(7 * 3 / 5);
228 player.inventory.replace(itemId, FarmingConstants.BUCKET, slot, true);
229
230 player.message("You pour some " + type.name().toLowerCase() + " on the patch.");
231 player.skills.addExperience(Skill.FARMING, type.getExp() * Config.FARMING_MODIFICATION);
232 compost = type;
233 return true;
234 }
235
236 private void inspect() {
237 if (isDiseased()) {
238 player.dialogueFactory.sendStatement("This plant is diseased. Use a plant cure on it to cure it, ", "or clear the patch with a spade.").execute();
239 return;
240 } else if (isDead()) {
241 player.dialogueFactory.sendStatement("This plant is dead. You did not cure it while it was diseased.", "Clear the patch with a spade.").execute();
242 return;
243 }
244
245 String patch = getClass().getSimpleName().replace("Patch", "").toLowerCase();
246 patch = Utility.getAOrAn(patch) + " " + patch;
247
248 if (needsWeeding()) {
249 player.dialogueFactory.sendStatement("This is " + patch + " patch. The soil has not been treated.", "The patches needs weeding.").execute();
250 } else if (isWatered() && isEmpty()) {
251 if (compost == CompostType.COMPOST) {
252 player.dialogueFactory.sendStatement("This is " + patch + " patch. The soil has been treated with water", "and compost. The patches is empty and weeded.").execute();
253 } else if (compost == CompostType.SUPERCOMPOST) {
254 player.dialogueFactory.sendStatement("This is " + patch + " patch. The soil has been treated with water", "and supercompost. The patches is empty and weeded.").execute();
255 } else if (compost == CompostType.ULTRACOMPOST) {
256 player.dialogueFactory.sendStatement("This is " + patch + " patch. The soil has been treated with water", "and ultracompost. The patches is empty and weeded.").execute();
257 } else {
258 player.dialogueFactory.sendStatement("This is " + patch + " patch. The soil has been treated with water.", "The patches is empty and weeded.").execute();
259 }
260 } else if (isComposted() && isEmpty()) {
261 if (compost == CompostType.COMPOST) {
262 player.dialogueFactory.sendStatement("This is " + patch + " patch. The soil has been treated with compost.", "The patches is empty and weeded.").execute();
263 } else if (compost == CompostType.SUPERCOMPOST) {
264 player.dialogueFactory.sendStatement("This is " + patch + " patch. The soil has been treated with supercompost.", "The patches is empty and weeded.").execute();
265 } else if (compost == CompostType.ULTRACOMPOST) {
266 player.dialogueFactory.sendStatement("This is " + patch + " patch. The soil has been treated with ultracompost.", "The patches is empty and weeded.").execute();
267 }
268 } else if (isEmpty()) {
269 player.dialogueFactory.sendStatement("This is " + patch + " patch. The soil has not been treated.", "The patches is empty and weeded.").execute();
270 } else {
271 player.locking.lock(5);
272 player.message("You bend down and start to inspect the patch...");
273 player.animate(1331);
274
275 World.schedule(new Task(5) {
276 @Override
277 public void execute() {
278 int index = growth % plant.getInspectMessages().length;
279 if (growth > index) index = growth - index - 1;
280 player.dialogueFactory.sendStatement(plant.getInspectMessages()[index]).execute();
281 cancel();
282 }
283
284 @Override
285 public void onCancel(boolean logout) {
286 player.animate(1332);
287 }
288 });
289 }
290 }
291
292 public int getConfig() {
293 if (isEmpty() || needsWeeding()) {
294 return stage.ordinal();
295 }
296 return (state.ordinal() << 6) | (plant.getStartingState() + growth);
297 }
298
299 protected void resetPatch() {
300 plant = null;
304 growth = 0;
305 fullyGrown = false;
306 timer.reset();
307 }
308
309 public abstract Plant plantForSeed(int seedId);
310
311 public void setNormal() {
313 }
314
315 public void setWatered() {
317 }
318
319 public void setDiseased() {
321 }
322
323 public void setDead() {
325 }
326
327 public void setEmpty() {
328 plant = null;
330 }
331
332 public boolean isNormal() {
333 return state.equals(FarmingState.NORMAL);
334 }
335
336 public boolean isWatered() {
337 return state.equals(FarmingState.WATERED);
338 }
339
340 public boolean isDiseased() {
341 return state.equals(FarmingState.DISEASED);
342 }
343
344 public boolean isDead() {
345 return state.equals(FarmingState.DEAD);
346 }
347
348 public boolean isEmpty() {
349 return stage.equals(FarmingStage.EMPTY) && plant == null;
350 }
351
352 public boolean isGrowing() {
353 return !isEmpty() && !needsWeeding();
354 }
355
356 public boolean isComposted() {
357 return compost != CompostType.NONE;
358 }
359
360 public boolean needsWeeding() {
362 }
363
364 public boolean within(Position position) {
365 for (Interactable boundary : boundaries) {
366 if (Utility.inside(boundary, position))
367 return true;
368 }
369 return false;
370 }
371
372 private Action<Player> createClearingAction(Player player, int animation, int delay) {
373 return new Action<Player>(player, delay) {
374 @Override
375 protected void onSchedule() {
376 player.animate(animation);
377 }
378
379 @Override
380 public void execute() {
381 if (needsWeeding()) {
382 stage = stage.getNextStage();
383 player.inventory.add(6055, 1);
384 } else {
385 setEmpty();
386 }
387
388 timer.reset();
389 player.animate(animation);
391 zone.sendPatchConfigs(player);
392
393 if (isEmpty()) {
394 player.message("You clear the patch.");
395 resetPatch();
396 setEmpty();
397 cancel();
398 }
399 }
400
401 @Override
402 public void onCancel(boolean logut) {
403 player.resetAnimation();
404 }
405
406 @Override
407 public WalkablePolicy getWalkablePolicy() {
409 }
410
411 @Override
412 public String getName() {
413 return "Farming Clear";
414 }
415 };
416 }
417
418 public JsonObject toJson() {
419 JsonObject object = new JsonObject();
420 object.addProperty("stage", stage.name());
421 object.addProperty("state", state.name());
422 object.addProperty("compost", compost.name());
423 object.addProperty("timer", timer.getCachedTime());
424 object.addProperty("fully-grown", fullyGrown);
425 object.addProperty("growth", growth);
426 if (plant != null) {
427 object.addProperty("plant", plant.getSeedId());
428 }
429 return object;
430 }
431
432 public void fromJson(JsonObject object) {
433 stage = FarmingStage.valueOf(object.get("stage").getAsString());
434 state = FarmingState.valueOf(object.get("state").getAsString());
435 compost = CompostType.valueOf(object.get("compost").getAsString());
436 fullyGrown = object.get("fully-grown").getAsBoolean();
437 growth = object.get("growth").getAsInt();
438
439 if (object.has("plant")) {
440 plant = plantForSeed(object.get("plant").getAsInt());
441 }
442
443 long cached = object.get("timer").getAsLong();
444 simulate(TimeUnit.SECONDS.convert(System.nanoTime() - cached, TimeUnit.NANOSECONDS) / 12);
445 timer.setCachedTime(cached);
446 }
447
448}
The class that contains setting-related constants for the server.
Definition Config.java:24
static final double FARMING_MODIFICATION
The experience modification for farming.
Definition Config.java:295
Action< Player > createClearingAction(Player player, int animation, int delay)
FarmingPatch(Player player, FarmingZone zone, Interactable[] boundaries)
Represents an action an entity can execute.
Definition Action.java:12
A game representing a cyclic unit of work.
Definition Task.java:11
Represents the game world.
Definition World.java:46
static void schedule(Task task)
Submits a new event.
Definition World.java:247
This class represents a character controlled by a player.
Definition Player.java:125
Represents a trainable and usable skill.
Definition Skill.java:18
static final int FARMING
The farming skill id.
Definition Skill.java:78
The container class that represents an item that can be interacted with.
Definition Item.java:21
final int getId()
Gets the identification of this item.
Definition Item.java:324
Represents a single tile on the game world.
Definition Position.java:14
static Stopwatch start()
Handles miscellaneous methods.
Definition Utility.java:27
static boolean inside(Interactable source, Interactable target)
Definition Utility.java:783
static String getAOrAn(String nextWord)
A or an.
Definition Utility.java:116
TWO_THIRDS_WEEDS
The patch needs to be weeded two more times.
ONE_THIRD_WEEDS
The patch needs to be weeded one more time.
NORMAL
The patch is empty and ready to be used.
A queue policy determines whether the action can occur while walking.
NON_WALKABLE
This indicates actions cannot occur while walking.
An object implementing Interactable has uses.