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