From 1b3a62f8546f5514ab451c658de8fa49276bac93 Mon Sep 17 00:00:00 2001 From: Quackster Date: Wed, 8 May 2024 18:38:33 +1000 Subject: [PATCH] Add pet eating, drinking, playing and commands --- .../commands/registered/PickAllCommand.java | 2 +- .../alexdev/havana/game/item/ItemManager.java | 2 +- .../havana/game/item/base/ItemBehaviour.java | 5 +- .../item/interactors/InteractionType.java | 4 + .../item/interactors/types/BedInteractor.java | 11 - .../interactors/types/ChairInteractor.java | 8 - .../interactors/types/PetFoodInteractor.java | 65 +++ .../interactors/types/PetNestInteractor.java | 2 + .../interactors/types/PetToyInteractor.java | 62 +++ .../types/PetWaterBowlInteractor.java | 70 +++ .../org/alexdev/havana/game/pets/Pet.java | 61 +-- .../alexdev/havana/game/pets/PetAction.java | 10 +- .../alexdev/havana/game/pets/PetManager.java | 227 ++++------ .../havana/game/room/entities/RoomEntity.java | 18 +- .../havana/game/room/entities/RoomPet.java | 133 +----- .../havana/game/room/enums/StatusType.java | 8 +- .../havana/game/room/mapping/RoomMapping.java | 8 +- .../havana/game/room/tasks/EntityTask.java | 164 ------- .../havana/game/room/tasks/PetTask.java | 420 ++++++++++++++++++ .../havana/game/room/tasks/StatusTask.java | 8 + .../havana/game/room/tasks/TickTask.java | 17 + .../incoming/rooms/items/ADDSTRIPITEM.java | 2 +- .../rooms/items/CONVERT_FURNI_TO_CREDITS.java | 2 +- .../incoming/rooms/items/PRESENTOPEN.java | 10 +- .../incoming/rooms/items/REMOVEITEM.java | 2 +- .../server/rcon/RconConnectionHandler.java | 2 +- tools/migrations/update.1.1.sql | 7 + 27 files changed, 806 insertions(+), 524 deletions(-) create mode 100644 Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetFoodInteractor.java create mode 100644 Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetToyInteractor.java create mode 100644 Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetWaterBowlInteractor.java create mode 100644 Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/PetTask.java create mode 100644 Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/TickTask.java create mode 100644 tools/migrations/update.1.1.sql diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/commands/registered/PickAllCommand.java b/Havana-Server/src/main/java/org/alexdev/havana/game/commands/registered/PickAllCommand.java index 1e2b9df..1afceb2 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/commands/registered/PickAllCommand.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/commands/registered/PickAllCommand.java @@ -52,7 +52,7 @@ public class PickAllCommand extends Command { for (Item item : itemsToPickup) { item.setOwnerId(player.getDetails().getId()); - player.getRoomUser().getRoom().getMapping().removeItem(player, item); + player.getRoomUser().getRoom().getMapping().pickupItem(player, item); player.getInventory().addItem(item); } diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/item/ItemManager.java b/Havana-Server/src/main/java/org/alexdev/havana/game/item/ItemManager.java index 07c7ce0..0c130b4 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/item/ItemManager.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/item/ItemManager.java @@ -114,7 +114,7 @@ public class ItemManager { if (item != null) { // Item is currently loaded in room, remove it! if (item.getRoom() != null) { - item.getRoom().getMapping().removeItem(PlayerManager.getInstance().getPlayerById(item.getOwnerId()), item); + item.getRoom().getMapping().pickupItem(PlayerManager.getInstance().getPlayerById(item.getOwnerId()), item); } else { // Item is in players' hands, remove it! Player itemOwner = PlayerManager.getInstance().getPlayerById(item.getOwnerId()); diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/item/base/ItemBehaviour.java b/Havana-Server/src/main/java/org/alexdev/havana/game/item/base/ItemBehaviour.java index 3bb9c8f..b9ecac0 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/item/base/ItemBehaviour.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/item/base/ItemBehaviour.java @@ -45,8 +45,11 @@ public enum ItemBehaviour { NO_HEAD_TURN, ECO_BOX, PET_WATER_BOWL, + PET_FOOD, PET_CAT_FOOD, PET_DOG_FOOD, - PET_CROC_FOOD; + PET_CROC_FOOD, + + PET_TOY, } diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/InteractionType.java b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/InteractionType.java index 2e71cc5..4b5f5cd 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/InteractionType.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/InteractionType.java @@ -25,6 +25,10 @@ public enum InteractionType { FORTUNE(new FortuneInteractor()), PET_NEST(new PetNestInteractor()), + PET_FOOD(new PetFoodInteractor()), + PET_WATER_BOWL(new PetWaterBowlInteractor()), + PET_TOY(new PetToyInteractor()), + POOL_BOOTH(new PoolBoothInteractor()), POOL_LADDER(new PoolLadderInteractor()), POOL_EXIT(new PoolExitInteractor()), diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/BedInteractor.java b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/BedInteractor.java index 83668ed..e5cde0c 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/BedInteractor.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/BedInteractor.java @@ -45,18 +45,7 @@ public class BedInteractor extends GenericTrigger { roomEntity.stopCarrying(); roomEntity.stopDancing(); - roomEntity.getPosition().setRotation(item.getPosition().getRotation()); - double topHeight = item.getDefinition().getTopHeight(); - - if (entity.getType() == EntityType.PET) { - topHeight = 0.5 + item.getTile().getWalkingHeight(); - - Pet pet = (Pet) entity; - pet.setAction(PetAction.LAY); - pet.setActionDuration(ThreadLocalRandom.current().nextInt(10, 30)); - } - roomEntity.getPosition().setRotation(item.getPosition().getRotation()); roomEntity.setStatus(StatusType.LAY, StringUtil.format(topHeight)); } diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/ChairInteractor.java b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/ChairInteractor.java index ffea5b0..bdd9bc2 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/ChairInteractor.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/ChairInteractor.java @@ -29,14 +29,6 @@ public class ChairInteractor extends GenericTrigger { int headRotation = roomEntity.getPosition().getHeadRotation(); double topHeight = item.getDefinition().getTopHeight(); - if (entity.getType() == EntityType.PET) { - topHeight = 0.5 + item.getTile().getWalkingHeight(); - - Pet pet = (Pet) entity; - pet.setAction(PetAction.SIT); - pet.setActionDuration(ThreadLocalRandom.current().nextInt(10, 30)); - } - roomEntity.getPosition().setRotation(item.getPosition().getRotation()); roomEntity.stopDancing(); roomEntity.setStatus(StatusType.SIT, StringUtil.format(topHeight)); diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetFoodInteractor.java b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetFoodInteractor.java new file mode 100644 index 0000000..822a45f --- /dev/null +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetFoodInteractor.java @@ -0,0 +1,65 @@ +package org.alexdev.havana.game.item.interactors.types; + +import org.alexdev.havana.game.entity.Entity; +import org.alexdev.havana.game.entity.EntityType; +import org.alexdev.havana.game.item.Item; +import org.alexdev.havana.game.item.interactors.InteractionType; +import org.alexdev.havana.game.pathfinder.Position; +import org.alexdev.havana.game.pets.Pet; +import org.alexdev.havana.game.player.Player; +import org.alexdev.havana.game.room.Room; +import org.alexdev.havana.game.room.entities.RoomEntity; +import org.alexdev.havana.game.triggers.GenericTrigger; + +public class PetFoodInteractor extends GenericTrigger { + @Override + public void onItemPlaced(Player player, Room room, Item item) { + if (item.getCustomData().isBlank()) { + item.setCustomData("0"); + item.updateStatus(); + item.save(); + } + } + + @Override + public void onEntityStop(Entity entity, RoomEntity roomEntity, Item item, boolean isRotation) { + if (entity.getType() != EntityType.PET) { + return; + } + + var pet = (Pet) entity; + var front = item.getPosition().getSquareInFront(); + + pet.getRoomUser().look(front, true); + pet.getRoomUser().getTask().startEating(); + } + + public void onItemPickup(Player player, Room room, Item item) { + cancelPetsEating(room, item.getPosition()); + } + + public void onItemMoved(Player player, Room room, Item item, boolean isRotation, Position oldPosition, Item itemBelow, Item itemAbove) { + cancelPetsEating(room, oldPosition); + } + + private void cancelPetsEating(Room room, Position position) { + room.getMapping().getTile(position).getEntities().forEach(x -> { + if (x.getType() == EntityType.PET) { + ((Pet)x).getRoomUser().getTask().eatingComplete(false); + } + }); + } + + /* + @Override + public void onEntityLeave(Entity entity, RoomEntity roomEntity, Item item) { + if (entity.getType() != EntityType.PET) { + return; + } + + var pet = (Pet) entity; + pet.getRoomUser().getTask().eatingComplete(); + } + + */ +} diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetNestInteractor.java b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetNestInteractor.java index 834e111..3497ae6 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetNestInteractor.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetNestInteractor.java @@ -82,6 +82,8 @@ public class PetNestInteractor extends GenericTrigger { room.getEntityManager().enterRoom(pet, position); room.getMapping().getTile(position).addEntity(pet); + pet.getRoomUser().createTask(room); + /*GameScheduler.getInstance().getService().scheduleAtFixedRate(()-> { pet.getRoomUser().walkTo(room.getModel().getRandomBound(0), room.getModel().getRandomBound(0)); }, 0, 5, TimeUnit.SECONDS);*/ diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetToyInteractor.java b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetToyInteractor.java new file mode 100644 index 0000000..15eb8f2 --- /dev/null +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetToyInteractor.java @@ -0,0 +1,62 @@ +package org.alexdev.havana.game.item.interactors.types; + +import org.alexdev.havana.game.entity.Entity; +import org.alexdev.havana.game.entity.EntityType; +import org.alexdev.havana.game.fuserights.Fuseright; +import org.alexdev.havana.game.item.Item; +import org.alexdev.havana.game.item.interactors.InteractionType; +import org.alexdev.havana.game.pathfinder.Position; +import org.alexdev.havana.game.pets.Pet; +import org.alexdev.havana.game.player.Player; +import org.alexdev.havana.game.room.Room; +import org.alexdev.havana.game.room.entities.RoomEntity; +import org.alexdev.havana.game.triggers.GenericTrigger; +import org.apache.commons.lang3.StringUtils; + +public class PetToyInteractor extends GenericTrigger { + public void onInteract(Player player, Room room, Item item, int status) { + InteractionType.DEFAULT.getTrigger().onInteract(player, room, item, status); + } + + @Override + public void onEntityStop(Entity entity, RoomEntity roomEntity, Item item, boolean isRotation) { + if (entity.getType() != EntityType.PET) { + return; + } + + var pet = (Pet) entity; + var front = item.getPosition().getSquareInFront(); + + pet.getRoomUser().look(front, true); + pet.getRoomUser().getTask().startPlay(); + } + + public void onItemPickup(Player player, Room room, Item item) { + cancelPetsPlaying(room, item.getPosition()); + } + + public void onItemMoved(Player player, Room room, Item item, boolean isRotation, Position oldPosition, Item itemBelow, Item itemAbove) { + cancelPetsPlaying(room, oldPosition); + } + + private void cancelPetsPlaying(Room room, Position position) { + room.getMapping().getTile(position).getEntities().forEach(x -> { + if (x.getType() == EntityType.PET) { + ((Pet) x).getRoomUser().getTask().playingComplete(false); + } + }); + } + + /* + @Override + public void onEntityLeave(Entity entity, RoomEntity roomEntity, Item item) { + if (entity.getType() != EntityType.PET) { + return; + } + + var pet = (Pet) entity; + pet.getRoomUser().getTask().eatingComplete(); + } + + */ +} diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetWaterBowlInteractor.java b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetWaterBowlInteractor.java new file mode 100644 index 0000000..12d835f --- /dev/null +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/item/interactors/types/PetWaterBowlInteractor.java @@ -0,0 +1,70 @@ +package org.alexdev.havana.game.item.interactors.types; + +import org.alexdev.havana.game.entity.Entity; +import org.alexdev.havana.game.entity.EntityType; +import org.alexdev.havana.game.item.Item; +import org.alexdev.havana.game.item.interactors.InteractionType; +import org.alexdev.havana.game.pathfinder.Position; +import org.alexdev.havana.game.pets.Pet; +import org.alexdev.havana.game.player.Player; +import org.alexdev.havana.game.room.Room; +import org.alexdev.havana.game.room.entities.RoomEntity; +import org.alexdev.havana.game.triggers.GenericTrigger; +import org.apache.commons.lang.StringUtils; + +public class PetWaterBowlInteractor extends GenericTrigger { + public void onInteract(Player player, Room room, Item item, int status) { + InteractionType.DEFAULT.getTrigger().onInteract(player, room, item, status); + } + + @Override + public void onItemPlaced(Player player, Room room, Item item) { + if (item.getCustomData().isBlank()) { + item.setCustomData("5"); + item.updateStatus(); + item.save(); + } + } + + @Override + public void onEntityStop(Entity entity, RoomEntity roomEntity, Item item, boolean isRotation) { + if (entity.getType() != EntityType.PET) { + return; + } + + var pet = (Pet) entity; + var front = item.getPosition().getSquareInFront(); + + pet.getRoomUser().look(front, true); + pet.getRoomUser().getTask().startDrinking(); + } + + public void onItemPickup(Player player, Room room, Item item) { + cancelPetsDrinking(room, item.getPosition()); + } + + public void onItemMoved(Player player, Room room, Item item, boolean isRotation, Position oldPosition, Item itemBelow, Item itemAbove) { + cancelPetsDrinking(room, oldPosition); + } + + private void cancelPetsDrinking(Room room, Position position) { + room.getMapping().getTile(position).getEntities().forEach(x -> { + if (x.getType() == EntityType.PET) { + ((Pet)x).getRoomUser().getTask().drinkingComplete(false); + } + }); + } + + /* + @Override + public void onEntityLeave(Entity entity, RoomEntity roomEntity, Item item) { + if (entity.getType() != EntityType.PET) { + return; + } + + var pet = (Pet) entity; + pet.getRoomUser().getTask().eatingComplete(); + } + + */ +} diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/pets/Pet.java b/Havana-Server/src/main/java/org/alexdev/havana/game/pets/Pet.java index f5d6ccd..8f9b0d9 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/pets/Pet.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/pets/Pet.java @@ -13,27 +13,11 @@ import java.util.concurrent.TimeUnit; public class Pet extends Entity { private PetDetails petDetails; - private PetAction petAction; - private long actionExpiry; private RoomPet roomUser; - private boolean walkBeforeSitLay; - private int lastActionTime; public Pet(PetDetails petDetails) { this.petDetails = petDetails; this.roomUser = new RoomPet(this); - this.petAction = PetAction.NONE; - } - - public void awake() { - this.roomUser.removeStatus(StatusType.SLEEP); - this.roomUser.setNeedsUpdate(true); - - this.petAction = PetAction.NONE; - this.actionExpiry = 0; - - this.petDetails.setLastKip(DateUtil.getCurrentTimeSeconds()); - PetDao.saveDetails(this.petDetails.getId(), this.petDetails); } public int getAge() { @@ -94,48 +78,7 @@ public class Pet extends Entity { } - public PetAction getAction() { - return petAction; - } - - public void setAction(PetAction petAction) { - this.petAction = petAction; - this.lastActionTime = DateUtil.getCurrentTimeSeconds(); - } - - public boolean isDoingAction() { - return !hasActionExpired() && (this.petAction == PetAction.SLEEP || this.petAction == PetAction.EAT || this.petAction == PetAction.DRINK || this.petAction == PetAction.LAY || this.petAction == PetAction.SIT); - } - - public boolean isActionAllowed() { - return (this.petAction == PetAction.NONE || this.petAction == PetAction.SIT || this.petAction == PetAction.LAY) && (this.roomUser.getCurrentItem() == null || ((!this.roomUser.getCurrentItem().getDefinition().hasBehaviour(ItemBehaviour.CAN_SIT_ON_TOP) && !this.roomUser.getCurrentItem().getDefinition().hasBehaviour(ItemBehaviour.CAN_LAY_ON_TOP)) && this.roomUser.getCurrentItem().getDatabaseId() != this.petDetails.getItemId())); - } - - public boolean hasActionExpired() { - return DateUtil.getCurrentTimeSeconds() > this.actionExpiry; - } - - public void setActionDuration(int seconds) { - this.actionExpiry = DateUtil.getCurrentTimeSeconds() + seconds; - } - - public boolean isWalkBeforeSitLay() { - return walkBeforeSitLay; - } - - public void setWalkBeforeSitLay(boolean walkBeforeSitLay) { - this.walkBeforeSitLay = walkBeforeSitLay; - } - - public boolean isTired() { - return getEnergy() <= 2; - } - - public int getLastActionTime() { - return lastActionTime; - } - - public void setLastActionTime(int lastActionTime) { - this.lastActionTime = lastActionTime; + public void saveDetails() { + PetDao.saveDetails(this.getDetails().getId(), this.getDetails()); } } diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/pets/PetAction.java b/Havana-Server/src/main/java/org/alexdev/havana/game/pets/PetAction.java index 2fd7cd3..93dd6a9 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/pets/PetAction.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/pets/PetAction.java @@ -1,17 +1,11 @@ package org.alexdev.havana.game.pets; public enum PetAction { - NONE(0), - SLEEP(0), - EAT(0), - DRINK(0), - WALKING(0), + TALK(0), SIT(0), LAY(0), - JUMP(0), - DEAD(0), PLAY(0), - BEG(0); + WALK(0); private final int actionLength; diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/pets/PetManager.java b/Havana-Server/src/main/java/org/alexdev/havana/game/pets/PetManager.java index bbed053..fcf51a7 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/pets/PetManager.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/pets/PetManager.java @@ -1,104 +1,21 @@ package org.alexdev.havana.game.pets; import org.alexdev.havana.game.fuserights.Fuseright; -import org.alexdev.havana.game.item.Item; import org.alexdev.havana.game.player.Player; import org.alexdev.havana.game.room.Room; -import org.alexdev.havana.game.room.enums.StatusType; import org.alexdev.havana.game.wordfilter.WordfilterManager; import org.alexdev.havana.util.DateUtil; import org.alexdev.havana.util.StringUtil; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; public class PetManager { private static PetManager instance; - public String[] petSpeeches = { - "pet.saying.play.croc.0=*Chases tail*", - "pet.saying.sleep.cat.4=Meow!", - "pet.saying.sniff.dog.2=*Grrruff! *Sniffs happily*", - "pet.saying.angry.croc.2=*licks foot*", - "pet.saying.sniff.dog.1=Grrruff! *Sniffs happily*", - "pet.saying.eat.dog.0=Woof! *wags tail excitedly*", - "pet.saying.sniff.dog.0=Grrruff! *Sniffs happily*", - "pet.saying.beg.cat.2=Meow!", - "pet.saying.play.dog.0=*Chases tail*", - "pet.saying.beg.croc.2=Snap!", - "pet.saying.play.croc.1=*Snaps happily*", - "pet.saying.generic.dog.2=*Runs happily up to Habbo*", - "pet.saying.generic.dog.3=*Jumps on Habbo happily*", - "pet.saying.sniff.croc.0=*sniffs inquisitively*", - "pet.saying.angry.dog.4=*Licks foot apologetically*", - "pet.saying.angry.dog.3=Woof! Woof!", - "pet.saying.play.dog.1=*Fetches ball*", - "pet.saying.eat.cat.2=Meow! *Licks food*", - "pet.saying.eat.cat.1=Meow! *Sniffs food*", - "pet.saying.angry.croc.3=Snap! *innocent smile*", - "pet.saying.beg.croc.1=Snap!", - "pet.saying.beg.cat.0=Purrrrrr *walks around legs*", - "pet.saying.generic.cat.4=Meow", - "pet.saying.sleep.dog.6=Woof! Zzzzzzz", - "pet.saying.angry.croc.4=Snap! *innocent smile*", - "pet.saying.play.cat.1=*Chases mouse*", - "pet.saying.sleep.dog.5=Ruff! Zzzzzzzz *wags tail*", - "pet.saying.eat.croc.4=*Smiles contently*", - "pet.saying.eat.cat.0=Meow! *Sniffs food*", - "pet.saying.sleep.dog.3=Ruff! Zzzzzzzz *wags tail*", - "pet.saying.sleep.dog.4=Ruff! Zzzzzzzz *wags tail*", - "pet.saying.generic.croc.0=Rrrr....Grrrrrg....", - "pet.saying.eat.croc.3=Snap! *Chomps on food*", - "pet.saying.eat.croc.1=Snap! *Swallows food whole*", - "pet.saying.angry.cat.2=Meow!", - "pet.saying.sleep.dog.2=Ruff! Zzzzzzzz *wags tail*", - "pet.saying.eat.croc.2=Snap! *Swallows food whole*", - "pet.saying.sleep.croc.0=Zzzzzz *dreams of wilderbeast*", - "pet.saying.sleep.croc.1=Zzzzzz *dreams of zebra*", - "pet.saying.sleep.croc.5=Zzzzzz *dreams of wilderbeast*", - "pet.saying.sleep.dog.0=Ruff! Zzzzzzzz *wags tail*", - "pet.saying.sleep.croc.3=Zzzzzz *dreams of springboekt*", - "pet.saying.angry.cat.3=Meow", - "pet.saying.sleep.cat.1=Purrr zzzzz", - "pet.saying.generic.croc.1=Snap!", - "pet.saying.sleep.dog.1=Zzzzzz", - "pet.saying.angry.cat.0=Mew *sad eyes*", - "pet.saying.sniff.croc.2=*Watches for hours until it moves*", - "pet.saying.sniff.croc.1=*Watches for hours until it moves*", - "pet.saying.sleep.croc.2=Zzzzzz *dreams of wilderbeast*", - "pet.saying.angry.cat.1=Purrrrrr ... *walks around legs*", - "pet.saying.sniff.cat.0=*sniffs inquisitively*", - "pet.saying.eat.dog.2=Woof! *chews*", - "pet.saying.eat.dog.1=Woof! *chews*", - "pet.saying.sleep.croc.6=Zzzzzz *dreams of wilderbeast*", - "pet.saying.eat.dog.3=Woof! *wags tail excitedly*", - "pet.saying.beg.croc.0=Snap!", - "pet.saying.play.cat.0=*Jumps at shadow puppet*", - "pet.saying.generic.croc.2=*Tail flip*", - "pet.saying.beg.dog.1=Woof! Woof!", - "pet.saying.generic.cat.1=Purrrr", - "pet.saying.generic.cat.0=Purrrr", - "pet.saying.eat.croc.0=Snap! *Swallows food whole*", - "pet.saying.beg.dog.2=Woof! *Sits patiently*", - "pet.saying.angry.dog.1=Ruff!", - "pet.saying.generic.cat.3=Meow", - "pet.saying.generic.dog.1=Woof! Woof!", - "pet.saying.eat.dog.4=Woof! *wags tail excitedly*", - "pet.saying.angry.croc.1=Snap! *innocent smile*", - "pet.saying.generic.croc.3=*Walks up to Habbo excitedly*", - "pet.saying.angry.croc.0=Snap!", - "pet.saying.angry.dog.0=*Puppy dog eyes*", - "pet.saying.beg.dog.0=*lifts paws onto Habbos knees*", - "pet.saying.beg.cat.1=Purrrrrr *walks around legs*", - "pet.saying.generic.cat.2=Purrrr", - "pet.saying.sleep.cat.3=Meow!", - "pet.saying.sleep.cat.0=Purrr zzzzz", - "pet.saying.generic.dog.0=Grrrrufff!", - "pet.saying.sleep.croc.4=Zzzzzz *dreams of elephant burgers*", - "pet.saying.sleep.cat.2=Purrr zzzzz", - "pet.saying.angry.dog.2=*Whines*" - }; + + private String[] dogSpeech = new String[] { "Woooff... wooofff...", "Woooooooooooooooffff... wooff", "Nomnomnomnom..", "Grrrr....", "Grrrr.. grrrrr.." }; + private String[] catSpeech = new String[] { "Prrrrrrr... prrrrrr", "Prrrrrrrrrrrrrrrr...... prrrr..", "Meowwwww... meowwww..", "Meowwww!" }; + private String[] crocSpeech = new String[] { "Gnawwwwwwww... gnaw..", "Gnawwwwwwwwwwwwwwwwwwwww.... gnawwwwwwww.....", "Gnaw! Gnaw!" }; /** * Handle speech for pets. @@ -118,11 +35,76 @@ public class PetManager { for (Pet pet : room.getEntityManager().getEntitiesByClass(Pet.class)) { if (pet.getDetails().getName().toLowerCase().equals(data[0].toLowerCase())) { - petCommand(player, room, pet, speech.replace(data[0] + " ", "")); + if (pet.getRoomUser().getTask().canMove()) { + petCommand(player, room, pet, speech.replace(data[0] + " ", "")); + } } } } + private void petCommand(Player player, Room room, Pet pet, String command) { + var item = pet.getRoomUser().getCurrentItem(); + boolean petCommanded = false; + + switch (command.toLowerCase()) { + case "speak": { + pet.getRoomUser().getTask().talk(); + pet.getRoomUser().getTask().setInteractionTimer(5); + break; + } + case "beg": { + // Beg for reward + break; + } + case "go": + case "go away": { + pet.getRoomUser().getTask().walk(); + pet.getRoomUser().getTask().setInteractionTimer(10); + break; + } + case "come over": + case "come here": + case "come": + case "heel": { + pet.getRoomUser().walkTo(player.getRoomUser().getPosition().getSquareInFront().getX(), player.getRoomUser().getPosition().getSquareInFront().getY()); + pet.getRoomUser().getTask().setInteractionTimer(10); + break; + } + case "play dead": + case "dead": { + int length = ThreadLocalRandom.current().nextInt(4, 11); + pet.getRoomUser().getTask().playDead(length); + break; + } + case "sit": { + int length = ThreadLocalRandom.current().nextInt(10, 30); + pet.getRoomUser().getTask().sit(length); + break; + } + case "lie down": + case "lay": { + if (pet.getRoomUser().isWalking()) { + pet.getRoomUser().stopWalking(); + } + + int length = ThreadLocalRandom.current().nextInt(10, 30); + pet.getRoomUser().getTask().lay(length); + break; + } + case "jump": { + if (pet.getRoomUser().isWalking()) { + pet.getRoomUser().stopWalking(); + } + + int length = ThreadLocalRandom.current().nextInt(2, 4); + pet.getRoomUser().getTask().jump(length); + break; + } + + } + } + + /* private void petCommand(Player player, Room room, Pet pet, String command) { var item = pet.getRoomUser().getCurrentItem(); boolean petCommanded = false; @@ -164,7 +146,7 @@ public class PetManager { pet.getRoomUser().setStatus(StatusType.DEAD, StatusType.DEAD.getStatusCode(), length, null, -1, -1); pet.getRoomUser().setNeedsUpdate(true); - pet.setAction(PetAction.DEAD); + pet}.setAction(PetAction.DEAD); pet.setActionDuration(length); petCommanded = true; break; @@ -217,14 +199,14 @@ public class PetManager { return; } - Item nest = room.getItemManager().getByDatabaseId(pet.getDetails().getItemId()); + Item nest = room.getItemManager().getById(pet.getDetails().getItemId()); pet.getRoomUser().walkTo(nest.getPosition().getX(), nest.getPosition().getY()); if (pet.getRoomUser().isWalking()) { pet.setAction(PetAction.SLEEP); } else { if (item != null) { - if (item.getDatabaseId() == pet.getDetails().getItemId()) { + if (item.getId() == pet.getDetails().getItemId()) { item.getDefinition().getInteractionType().getTrigger().onEntityStop(pet, pet.getRoomUser(), item, false); pet.setAction(PetAction.SLEEP); } @@ -254,6 +236,7 @@ public class PetManager { } } } + */ /** * Get the pet stats when given the last time and stat type. @@ -298,10 +281,10 @@ public class PetManager { return 2; } - if (name.isBlank() || name.contains(" ")) { + if (name.isBlank() || name.contains(" ")) { return 2; } - + if (name.length() > 15) { return 1; } @@ -315,6 +298,7 @@ public class PetManager { } return 0; + } public PetType getType(Pet pet) { @@ -336,55 +320,28 @@ public class PetManager { /** * Gets a random speech element by pet type. * - * @param pet the pet type given + * @param petType the pet type given * @return the speech selected */ - public String getRandomSpeech(Pet pet) { - List possibleChatValues = new ArrayList<>(); - + public String getRandomSpeech(String petType) { String speech = null; - if (pet.getAction() != null) { - switch (pet.getAction()) { - case SLEEP: - case DEAD: - possibleChatValues.addAll(getChatValue(this.getType(pet), "sleep")); - break; - case EAT: - possibleChatValues.addAll(getChatValue(this.getType(pet), "eat")); - break; - case BEG: - possibleChatValues.addAll(getChatValue(this.getType(pet), "beg")); - break; - case JUMP: - case PLAY: - possibleChatValues.addAll(getChatValue(this.getType(pet), "play")); - break; + switch (petType) { + case "0": { + speech = this.dogSpeech[ThreadLocalRandom.current().nextInt(0, this.dogSpeech.length)]; + break; + } + case "1": { + speech = this.catSpeech[ThreadLocalRandom.current().nextInt(0, this.catSpeech.length)]; + break; + } + case "2": { + speech = this.crocSpeech[ThreadLocalRandom.current().nextInt(0, this.crocSpeech.length)]; + break; } } - if (pet.getAction() == PetAction.NONE || pet.getAction() == PetAction.SIT || pet.getAction() == PetAction.LAY) { - possibleChatValues.addAll(getChatValue(this.getType(pet), "sniff")); - possibleChatValues.addAll(getChatValue(this.getType(pet), "generic")); - } - - if (possibleChatValues.size() > 0) { - return possibleChatValues.get(ThreadLocalRandom.current().nextInt(possibleChatValues.size())); - } - - return null; - } - - private List getChatValue(PetType type, String action) { - List speeches = new ArrayList<>(); - - for (var speech : this.petSpeeches) { - if (speech.startsWith("pet.saying." + action + "." + type.name().toLowerCase())) { - speeches.add(speech.split("=")[1]); - } - } - - return speeches; + return speech; } /** diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/room/entities/RoomEntity.java b/Havana-Server/src/main/java/org/alexdev/havana/game/room/entities/RoomEntity.java index 45a1086..e465446 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/room/entities/RoomEntity.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/room/entities/RoomEntity.java @@ -664,6 +664,10 @@ public abstract class RoomEntity { * @param towards the coordinate direction to look towards */ public void look(Position towards) { + this.look(towards, false); + } + + public void look(Position towards, boolean body) { if (this.isWalking) { return; } @@ -676,7 +680,19 @@ public abstract class RoomEntity { } } - this.position.setHeadRotation(Rotation.getHeadRotation(this.position.getRotation(), this.position, towards)); + if (body) { + int rotation = Rotation.calculateHumanDirection( + this.getPosition().getX(), + this.getPosition().getY(), + towards.getX(), + towards.getY()); + + this.position.setHeadRotation(rotation); + this.position.setBodyRotation(rotation); + } else { + this.timerManager.beginLookTimer(); + } + this.timerManager.beginLookTimer(); this.needsUpdate = true; } diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/room/entities/RoomPet.java b/Havana-Server/src/main/java/org/alexdev/havana/game/room/entities/RoomPet.java index b6dba2a..eb29fd8 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/room/entities/RoomPet.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/room/entities/RoomPet.java @@ -11,20 +11,20 @@ import org.alexdev.havana.game.pets.Pet; import org.alexdev.havana.game.pets.PetAction; import org.alexdev.havana.game.pets.PetManager; import org.alexdev.havana.game.pets.PetType; +import org.alexdev.havana.game.room.Room; import org.alexdev.havana.game.room.enums.StatusType; +import org.alexdev.havana.game.room.tasks.PetTask; import org.alexdev.havana.util.DateUtil; import org.alexdev.havana.util.StringUtil; import java.util.Collections; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; public class RoomPet extends RoomEntity { private Pet pet; private Item item; - private int lastActionLength; + private PetTask task; public RoomPet(Entity entity) { super(entity); @@ -38,7 +38,6 @@ public class RoomPet extends RoomEntity { @Override public void invokeItem(Position oldPosition, boolean instantUpdate) { super.invokeItem(oldPosition, instantUpdate); - this.pet.setWalkBeforeSitLay(false); } @@ -68,10 +67,6 @@ public class RoomPet extends RoomEntity { return; } - this.lastActionLength = ThreadLocalRandom.current().nextInt(30); - - this.pet.setAction(PetAction.DRINK); - this.pet.setActionDuration(this.lastActionLength); this.item = item; } @@ -114,43 +109,6 @@ public class RoomPet extends RoomEntity { return; } - this.lastActionLength = ThreadLocalRandom.current().nextInt(30); - - this.pet.setAction(PetAction.EAT); - this.pet.setActionDuration(this.lastActionLength); - this.item = item; - } - - public void trySleep() { - if (this.getRoom() == null) { - return; - } - - var room = this.getRoom(); - var bedsInRoom = room.getItemManager().getFloorItems().stream().filter(item -> item.getDefinition().getInteractionType() == InteractionType.PET_NEST && - item.getTile().getEntities().isEmpty()).collect(Collectors.toList()); - - if (bedsInRoom.size() < 1) { - return; - } - - Collections.shuffle(bedsInRoom); - Item item = bedsInRoom.get(0); - - if (item == null) { - return; - } - - this.pet.getRoomUser().walkTo(item.getPosition().getX(), item.getPosition().getY()); - - if (!this.pet.getRoomUser().isWalking()) { - return; - } - - this.lastActionLength = ThreadLocalRandom.current().nextInt(20, 60); - - this.pet.setAction(PetAction.SLEEP); - this.pet.setActionDuration(this.lastActionLength); this.item = item; } @@ -158,7 +116,7 @@ public class RoomPet extends RoomEntity { public void stopWalking() { super.stopWalking(); - if (this.pet.getAction() == PetAction.DRINK) { + /*if (this.pet.getAction() == PetAction.DRINK) { if (this.item.getRoom() != null) { this.getPosition().setRotation(this.item.getPosition().getRotation()); @@ -168,9 +126,10 @@ public class RoomPet extends RoomEntity { this.pet.getDetails().setLastDrink(DateUtil.getCurrentTimeSeconds()); PetDao.saveDetails(this.pet.getDetails().getId(), this.pet.getDetails()); - return; + } else { + this.pet.setAction(PetAction.NONE); + this.pet.setActionDuration(0); } - } if (this.pet.getAction() == PetAction.EAT) { @@ -183,86 +142,18 @@ public class RoomPet extends RoomEntity { this.pet.getDetails().setLastEat(DateUtil.getCurrentTimeSeconds()); PetDao.saveDetails(this.pet.getDetails().getId(), this.pet.getDetails()); - return; - } - } - - if (this.pet.getAction() == PetAction.SLEEP) { - if (this.item.getRoom() != null) { - this.getPosition().setRotation(this.item.getPosition().getRotation()); - - this.setStatus(StatusType.SLEEP, StringUtil.format(pet.getRoomUser().getPosition().getZ()) + " null"); - this.setNeedsUpdate(true); - removeAwake(this.pet); - - this.pet.getDetails().setLastKip(DateUtil.getCurrentTimeSeconds()); - PetDao.saveDetails(this.pet.getDetails().getId(), this.pet.getDetails()); - return; - } - } - - this.pet.setAction(PetAction.NONE); - this.pet.setActionDuration(0); - - // See PetNestInteractor -> "onEntityStop - /* - if (this.pet.getAction() == PetAction.SLEEP) { - if (this.item.getRoom() != null) { - this.getPosition().setRotation(this.item.getPosition().getRotation()); - - this.setStatus(StatusType.SLEEP, ""); - this.setNeedsUpdate(true); - removeAwake(this.pet); - - this.pet.getDetails().setLastKip(DateUtil.getCurrentTimeSeconds()); - PetDao.saveDetails(this.pet.getDetails().getId(), this.pet.getDetails()); } else { this.pet.setAction(PetAction.NONE); this.pet.setActionDuration(0); } - } - */ + }*/ } - private void emptyPetBowl(final Pet pet) { - GameScheduler.getInstance().getService().schedule(()-> { - if (item.getRoom() != null) { - item.setCustomData("0"); - item.updateStatus(); - item.save(); - } - - removeStatus(StatusType.EAT); - setNeedsUpdate(true); - }, this.lastActionLength, TimeUnit.SECONDS); + public PetTask getTask() { + return task; } - private void removeFoodItem(final Pet pet) { - GameScheduler.getInstance().getService().schedule(()-> { - if (item.getRoom() != null) { - getRoom().getMapping().removeItem(null, item); - item.delete(); - } - - pet.setAction(PetAction.NONE); - pet.setActionDuration(0); - - removeStatus(StatusType.EAT); - setNeedsUpdate(true); - }, this.lastActionLength, TimeUnit.SECONDS); - } - - private void removeAwake(Pet pet) { - GameScheduler.getInstance().getService().schedule(()-> { - pet.setAction(PetAction.NONE); - pet.setActionDuration(0); - - removeStatus(StatusType.SLEEP); - setNeedsUpdate(true); - }, this.lastActionLength, TimeUnit.SECONDS); - } - - public Item getItem() { - return item; + public void createTask(Room room) { + this.task = new PetTask(this.pet, room); } } diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/room/enums/StatusType.java b/Havana-Server/src/main/java/org/alexdev/havana/game/room/enums/StatusType.java index 7247a76..628c57c 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/room/enums/StatusType.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/room/enums/StatusType.java @@ -19,11 +19,13 @@ public enum StatusType { TRADE("trd"), DANCE("dance"), - SIGN("sign"), DEAD("ded"), JUMP("jmp"), - SLEEP("slp"), - EAT("eat"); + PET_SLEEP("slp"), + EAT("eat"), + SMILE("sml"), + PLAY("pla"), + SIGN("sign"); private String statusCode; diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/room/mapping/RoomMapping.java b/Havana-Server/src/main/java/org/alexdev/havana/game/room/mapping/RoomMapping.java index eec6248..322cb3c 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/room/mapping/RoomMapping.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/room/mapping/RoomMapping.java @@ -291,13 +291,17 @@ public class RoomMapping { refreshRoomItems(); } + public void pickupItem(Player player, Item item) { + item.getDefinition().getInteractionType().getTrigger().onItemPickup(player, this.room, item); + this.removeItem(item); + } + /** * Remove an item from the room. * * @param item the item that is being removed */ - public void removeItem(Player player, Item item) { - item.getDefinition().getInteractionType().getTrigger().onItemPickup(player, this.room, item); + public void removeItem(Item item) { this.room.getItems().remove(item); if (item.hasBehaviour(ItemBehaviour.WALL_ITEM)) { diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/EntityTask.java b/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/EntityTask.java index 691032c..0fc6378 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/EntityTask.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/EntityTask.java @@ -56,10 +56,6 @@ public class EntityTask implements Runnable { && entity.getRoomUser().getRoom() != null && entity.getRoomUser().getRoom() == this.room) { - if (entity.getType() == EntityType.PET) { - this.processPet((Pet) entity); - } - if (entity.getType() == EntityType.PLAYER) { ((Player) entity).getRoomUser().handleSpamTicks(); } @@ -248,167 +244,7 @@ public class EntityTask implements Runnable { } } - /** - * Process pet actions. - * - * @param pet the pet to process - */ - private void processPet(Pet pet) { - if (pet.hasActionExpired() && pet.getAction() != PetAction.NONE) { - if (pet.getAction() == PetAction.SLEEP) { - pet.awake(); - } - pet.getRoomUser().getStatuses().clear(); - pet.getRoomUser().setNeedsUpdate(true); - pet.setAction(PetAction.NONE); - } else { - switch (ThreadLocalRandom.current().nextInt(0, 6)) { - case 1: { - pet.getRoomUser().removeStatus(StatusType.SIT); - pet.getRoomUser().removeStatus(StatusType.LAY); - pet.getRoomUser().removeStatus(StatusType.SLEEP); - - if (pet.getRoomUser().containsStatus(StatusType.EAT) || - pet.getRoomUser().containsStatus(StatusType.DEAD) || - pet.getRoomUser().containsStatus(StatusType.JUMP)) { - return; - } - - if (pet.isDoingAction()) { - return; - } - - switch (ThreadLocalRandom.current().nextInt(0, 9)) { - case 0: { - if (pet.isThirsty()) { - pet.getRoomUser().tryDrinking(); - return; - } - break; - } - case 1: { - if (pet.isHungry()) { - pet.getRoomUser().tryEating(); - return; - } - break; - } - case 2: { - if (pet.isTired()) { - pet.getRoomUser().trySleep(); - return; - } - break; - } - } - - - Position availableTile = this.room.getMapping().getRandomWalkableBound(pet, false); - - if (availableTile != null) { - pet.getRoomUser().walkTo(availableTile.getX(), availableTile.getY()); - } - - break; - } - } - - if (!pet.isWalkBeforeSitLay() && pet.isActionAllowed()) { - switch (ThreadLocalRandom.current().nextInt(0, 15)) { - case 1: { - if (!pet.getRoomUser().isWalking() && pet.getAction() == PetAction.NONE) { - pet.getRoomUser().getPosition().setRotation(pet.getRoomUser().getPosition().getBodyRotation()); - pet.getRoomUser().setStatus(StatusType.SIT, StringUtil.format(pet.getRoomUser().getPosition().getZ())); - pet.setWalkBeforeSitLay(true); - - pet.setAction(PetAction.SIT); - pet.setActionDuration(ThreadLocalRandom.current().nextInt(15, 30)); - - if (ThreadLocalRandom.current().nextInt(0, 3) == 0) { - List playerList = this.room.getEntityManager().getEntitiesByClass(Player.class); - playerList.sort(Comparator.comparingInt(p -> p.getRoomUser().getPosition().getDistanceSquared(pet.getRoomUser().getPosition()))); - - if (playerList.size() > 0) { - pet.getRoomUser().getPosition().setRotation(Rotation.calculateWalkDirection( - pet.getRoomUser().getPosition(), - playerList.get(0).getRoomUser().getPosition())); - } - } - - pet.getRoomUser().setNeedsUpdate(true); - } - break; - } - case 2: { - if (!pet.getRoomUser().isWalking() && pet.getAction() == PetAction.NONE) { - pet.getRoomUser().getPosition().setRotation(pet.getRoomUser().getPosition().getBodyRotation()); - pet.getRoomUser().setStatus(StatusType.LAY, StringUtil.format(pet.getRoomUser().getPosition().getZ()) + " null"); - pet.setWalkBeforeSitLay(true); - - pet.setAction(PetAction.LAY); - pet.setActionDuration(ThreadLocalRandom.current().nextInt(15, 30)); - - if (ThreadLocalRandom.current().nextInt(0, 5) == 0) { - List playerList = this.room.getEntityManager().getEntitiesByClass(Player.class); - playerList.sort(Comparator.comparingInt(p -> p.getRoomUser().getPosition().getDistanceSquared(pet.getRoomUser().getPosition()))); - - if (playerList.size() > 0) { - pet.getRoomUser().getPosition().setRotation(Rotation.calculateWalkDirection( - pet.getRoomUser().getPosition(), - playerList.get(0).getRoomUser().getPosition())); - } - } - - pet.getRoomUser().setNeedsUpdate(true); - } - break; - } - } - } - - if (pet.getAction() == PetAction.SIT || pet.getAction() == PetAction.LAY || pet.getAction() == PetAction.NONE) { - if (ThreadLocalRandom.current().nextInt(0, 8) == 0) { - if (!pet.getRoomUser().isWalking()) { - List playerList = this.room.getEntityManager().getEntitiesByClass(Player.class); - playerList.sort(Comparator.comparingInt(p -> p.getRoomUser().getPosition().getDistanceSquared(pet.getRoomUser().getPosition()))); - - if (playerList.size() > 0) { - pet.getRoomUser().getPosition().setHeadRotation(Rotation.getHeadRotation( - pet.getRoomUser().getPosition().getRotation(), - pet.getRoomUser().getPosition(), - playerList.get(0).getRoomUser().getPosition())); - pet.getRoomUser().setNeedsUpdate(true); - } - } - } - } - } - - int maxRange = 25; - - if (pet.getAction() != PetAction.NONE && pet.getAction() != PetAction.SIT && pet.getAction() != PetAction.LAY) { - maxRange = 8; - } - - switch (ThreadLocalRandom.current().nextInt(0, maxRange)) { - case 2: { - var talkMessage = PetManager.getInstance().getRandomSpeech(pet); - - if (talkMessage != null) { - /*if (pet.getAction() != PetAction.NONE && pet.getAction() != PetAction.SIT && pet.getAction() != PetAction.LAY) { - pet.getRoomUser().talk(talkMessage, CHAT_MESSAGE.ChatMessageType.CHAT); - } else {*/ - if (ThreadLocalRandom.current().nextInt(0, 10/* 8 */) == 0) { - pet.getRoomUser().talk(talkMessage, CHAT_MESSAGE.ChatMessageType.CHAT); - } - //} - } - - break; - } - } - } /** diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/PetTask.java b/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/PetTask.java new file mode 100644 index 0000000..86c9355 --- /dev/null +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/PetTask.java @@ -0,0 +1,420 @@ +package org.alexdev.havana.game.room.tasks; + +import org.alexdev.havana.game.item.Item; +import org.alexdev.havana.game.item.base.ItemBehaviour; +import org.alexdev.havana.game.pathfinder.Position; +import org.alexdev.havana.game.pets.Pet; +import org.alexdev.havana.game.pets.PetAction; +import org.alexdev.havana.game.pets.PetManager; +import org.alexdev.havana.game.pets.PetType; +import org.alexdev.havana.game.room.Room; +import org.alexdev.havana.game.room.enums.StatusType; +import org.alexdev.havana.messages.outgoing.rooms.user.CHAT_MESSAGE; +import org.alexdev.havana.util.DateUtil; +import org.alexdev.havana.util.StringUtil; +import org.apache.commons.lang.StringUtils; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +public class PetTask extends TickTask { + private final Pet pet; + private final Room room; + + private int eatingTimer; + private int drinkTimer; + private int playTimer; + private int interactionTimer; + + private static final PetAction[] possibleActions = { + PetAction.WALK, PetAction.LAY, PetAction.SIT, PetAction.PLAY + }; + + + public PetTask(Pet pet, Room room) { + this.pet = pet; + this.room = room; + } + + public void tick() { + this.tickTimers(); + + if (!this.isTickRunnable()) + return; + + if (!this.canMove()) + return; + + if (this.pet.getHunger() <= 2) { + if (this.tryEat()) { + return; + } + } + + if (this.pet.getThirst() <= 1) { + if (this.tryDrink()) { + return; + } + } + + PetAction petAction = possibleActions[ThreadLocalRandom.current().nextInt(0, possibleActions.length - 1)]; + + switch (petAction) { + case WALK: + this.walk(); + break; + + case SIT: + this.sit(); + break; + + case PLAY: + this.tryPlay(); + break; + /* + case TALK: + this.sayRandomSpeech(); + break; + */ + case LAY: + this.lay(); + break; + } + + if (ThreadLocalRandom.current().nextInt(0, 25) == 0) { + this.talk(); + } + + + this.setTimeUntilNextTick(ThreadLocalRandom.current().nextInt(10, 26)); + } + + public void walk() { + Position availableTile = this.room.getMapping().getRandomWalkableBound(pet, false); + + if (availableTile != null) { + pet.getRoomUser().walkTo(availableTile.getX(), availableTile.getY()); + } + } + + public void sit() { + this.sit(0); + } + + public void sit(int time) { + if (this.pet.getRoomUser().isWalking()) { + this.pet.getRoomUser().stopWalking(); + } + + int rotation = this.pet.getRoomUser().getPosition().getRotation() / 2 * 2; + + this.pet.getRoomUser().getPosition().setRotation(rotation); + + if (time > 0) { + this.pet.getRoomUser().setStatus(StatusType.SIT, StringUtil.format(pet.getRoomUser().getPosition().getZ()), time, null, -1, -1); + this.interactionTimer = time; + } else { + this.pet.getRoomUser().setStatus(StatusType.SIT, StringUtil.format(pet.getRoomUser().getPosition().getZ())); + } + + this.pet.getRoomUser().removeStatus(StatusType.LAY); + this.pet.getRoomUser().setNeedsUpdate(true); + } + + public void lay() { + this.lay(0); + } + + public void lay(int time) { + if (this.pet.getRoomUser().isWalking()) { + this.pet.getRoomUser().stopWalking(); + } + + int rotation = this.pet.getRoomUser().getPosition().getRotation() / 2 * 2; + + this.pet.getRoomUser().getPosition().setRotation(rotation); + + if (time > 0) { + this.pet.getRoomUser().setStatus(StatusType.LAY, StringUtil.format(pet.getRoomUser().getPosition().getZ()), time, null, -1, -1); + this.interactionTimer = time; + } else { + this.pet.getRoomUser().setStatus(StatusType.LAY, StringUtil.format(pet.getRoomUser().getPosition().getZ())); + } + + this.pet.getRoomUser().removeStatus(StatusType.SIT); + this.pet.getRoomUser().setNeedsUpdate(true); + } + + private void tickTimers() { + if (this.eatingTimer != 0) { + this.eatingTimer--; + + if (this.eatingTimer == 1) { + this.eatingComplete(true); + } + } + + if (this.drinkTimer != 0) { + this.drinkTimer--; + + if (this.drinkTimer == 1) { + this.drinkingComplete(true); + } + } + + + if (this.playTimer != 0) { + this.playTimer--; + + if (this.playTimer == 1) { + this.playingComplete(true); + } + } + + if (this.interactionTimer != 0) { + this.interactionTimer--; + } + } + + private boolean tryEat() { + this.talk(); + + final PetType petType = PetManager.getInstance().getType(this.pet); + + List foodInRoom = + this.room.getItemManager().getFloorItems().stream() + .filter(item -> (item.hasBehaviour(ItemBehaviour.PET_FOOD) || + ( + (petType == PetType.CAT && item.hasBehaviour(ItemBehaviour.PET_CAT_FOOD)) || + (petType == PetType.DOG && item.hasBehaviour(ItemBehaviour.PET_DOG_FOOD)) || + (petType == PetType.CROC && item.hasBehaviour(ItemBehaviour.PET_CROC_FOOD)) + )) && + !item.getCustomData().equalsIgnoreCase("4") && + item.getTile().getOtherEntities(this.pet).isEmpty()).toList(); + + + + if (foodInRoom.isEmpty()) { + return false; + } + + Item item = foodInRoom.get(0); + + if (item == null) + return false; + + return this.pet.getRoomUser().walkTo(item.getPosition().getX(), item.getPosition().getY()); + } + + public void startEating() { + this.pet.getRoomUser().setStatus(StatusType.EAT, "1"); + this.pet.getRoomUser().setNeedsUpdate(true); + + this.eatingTimer = 30; + } + + + public void eatingComplete(boolean reapBenefits) { + this.pet.getRoomUser().removeStatus(StatusType.EAT); + this.pet.getRoomUser().setStatus(StatusType.SMILE, "1", 30, null, -1, -1); + this.pet.getRoomUser().setNeedsUpdate(true); + + if (reapBenefits) { + this.pet.getDetails().setLastEat(DateUtil.getCurrentTimeSeconds()); + this.pet.saveDetails(); + + var currentItem = this.pet.getRoomUser().getCurrentItem(); + + if (currentItem != null && + currentItem.hasBehaviour(ItemBehaviour.PET_FOOD)) { + + if (currentItem.hasBehaviour(ItemBehaviour.PET_CAT_FOOD) || + currentItem.hasBehaviour(ItemBehaviour.PET_DOG_FOOD)) { + + this.room.getMapping().removeItem(currentItem); + currentItem.delete(); + } else { + if (StringUtils.isNumeric(currentItem.getCustomData())) { + int state = Integer.parseInt(currentItem.getCustomData()) + 1; + + if (state <= 4) { + currentItem.setCustomData(String.valueOf(state)); + currentItem.updateStatus(); + currentItem.save(); + } + } + } + } + + /* + var currentItem = this.pet.getRoomUser().getCurrentItem(); + + + if (currentItem != null && + currentItem.hasBehaviour(ItemBehaviour.PET_FOOD) && + currentItem.getCustomData().equalsIgnoreCase("5")) { + this.room.getMapping().removeItem(currentItem); + currentItem.delete(); + }*/ + } + + this.talk(); + } + + private boolean tryDrink() { + this.talk(); + // var petType = PetManager.getInstance().getType(this.pet); + + List drinkInRoom = + this.room.getItemManager().getFloorItems().stream() + .filter(item -> item.hasBehaviour(ItemBehaviour.PET_WATER_BOWL) && + !item.getCustomData().equalsIgnoreCase("0") && + item.getTile().getOtherEntities(this.pet).isEmpty()).toList(); + + if (drinkInRoom.isEmpty()) { + return false; + } + + Item item = drinkInRoom.get(0); + + if (item == null) + return false; + + return this.pet.getRoomUser().walkTo(item.getPosition().getX(), item.getPosition().getY()); + } + + public void startDrinking() { + this.pet.getRoomUser().setStatus(StatusType.EAT, "1"); + this.pet.getRoomUser().setNeedsUpdate(true); + + this.drinkTimer = 30; + } + + + public void drinkingComplete(boolean reapBenefits) { + this.pet.getRoomUser().removeStatus(StatusType.EAT); + this.pet.getRoomUser().setStatus(StatusType.SMILE, "1", 30, null, -1, -1); + this.pet.getRoomUser().setNeedsUpdate(true); + + if (reapBenefits) { + this.pet.getDetails().setLastDrink(DateUtil.getCurrentTimeSeconds()); + this.pet.saveDetails(); + + var currentItem = this.pet.getRoomUser().getCurrentItem(); + + if (currentItem != null && + currentItem.hasBehaviour(ItemBehaviour.PET_WATER_BOWL)) { + + if (StringUtils.isNumeric(currentItem.getCustomData())) { + int state = Integer.parseInt(currentItem.getCustomData()) - 1; + + if (state >= 0) { + currentItem.setCustomData(String.valueOf(state)); + currentItem.updateStatus(); + currentItem.save(); + } + } + } + } + + this.talk(); + } + + private void tryPlay() { + this.talk(); + final PetType petType = PetManager.getInstance().getType(this.pet); + + List foodInRoom = + this.room.getItemManager().getFloorItems().stream() + .filter(item -> item.hasBehaviour(ItemBehaviour.PET_TOY) && + item.getTile().getOtherEntities(this.pet).isEmpty()).toList(); + + + + if (foodInRoom.isEmpty()) { + return; + } + + Item item = foodInRoom.get(0); + + if (item == null) + return; + + this.pet.getRoomUser().walkTo(item.getPosition().getX(), item.getPosition().getY()); + } + + public void startPlay() { + this.pet.getRoomUser().setStatus(StatusType.PLAY, "1"); + this.pet.getRoomUser().setNeedsUpdate(true); + + this.talk(); + + this.playTimer = 15; + } + + + public void playingComplete(boolean reapBenefits) { + this.pet.getRoomUser().removeStatus(StatusType.PLAY); + this.pet.getRoomUser().setStatus(StatusType.SMILE, "1", 30, null, -1, -1); + this.pet.getRoomUser().setNeedsUpdate(true); + + if (reapBenefits) { + this.pet.getDetails().setLastPlayToy(DateUtil.getCurrentTimeSeconds()); + this.pet.saveDetails(); + } + + this.talk(); + } + + public void talk() { + this.pet.getRoomUser().talk( + PetManager.getInstance().getRandomSpeech(pet.getDetails().getType()), + CHAT_MESSAGE.ChatMessageType.CHAT + ); + } + + public boolean canMove() { + return this.eatingTimer == 0 && this.drinkTimer == 0 && this.playTimer == 0 && this.interactionTimer == 0; + } + + public void jump(int length) { + if (this.pet.getRoomUser().isWalking()) { + this.pet.getRoomUser().stopWalking(); + } + + this.pet.getRoomUser().getStatuses().clear(); + this.pet.getRoomUser().getPosition().setRotation(pet.getRoomUser().getPosition().getBodyRotation()); + + if (length > 0) { + this.pet.getRoomUser().setStatus(StatusType.JUMP, StatusType.JUMP.getStatusCode().toLowerCase(), length, null, -1, -1); + this.interactionTimer = length; + } else { + this.pet.getRoomUser().setStatus(StatusType.JUMP, StatusType.JUMP.getStatusCode().toLowerCase()); + } + + this.pet.getRoomUser().setNeedsUpdate(true); + } + + public void playDead(int length) { + if (this.pet.getRoomUser().isWalking()) { + this.pet.getRoomUser().stopWalking(); + } + + this.pet.getRoomUser().getStatuses().clear(); + this.pet.getRoomUser().getPosition().setRotation(pet.getRoomUser().getPosition().getBodyRotation()); + + if (length > 0) { + this.pet.getRoomUser().setStatus(StatusType.DEAD, StatusType.DEAD.getStatusCode().toLowerCase(), length, null, -1, -1); + this.interactionTimer = length; + } else { + this.pet.getRoomUser().setStatus(StatusType.DEAD, StatusType.DEAD.getStatusCode().toLowerCase()); + } + + this.pet.getRoomUser().setNeedsUpdate(true); + + } + + public void setInteractionTimer(int i) { + this.interactionTimer = i; + } +} diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/StatusTask.java b/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/StatusTask.java index 33da329..189a9c5 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/StatusTask.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/StatusTask.java @@ -3,6 +3,7 @@ package org.alexdev.havana.game.room.tasks; import org.alexdev.havana.game.entity.Entity; import org.alexdev.havana.game.entity.EntityType; import org.alexdev.havana.game.pathfinder.Position; +import org.alexdev.havana.game.pets.Pet; import org.alexdev.havana.game.player.Player; import org.alexdev.havana.game.room.Room; import org.alexdev.havana.game.room.RoomUserStatus; @@ -54,6 +55,13 @@ public class StatusTask implements Runnable { processPoolQueue(entity); } + if (entity.getType() == EntityType.PET) { + Pet pet = (Pet) entity; + + if (pet.getRoomUser().getTask() != null) + pet.getRoomUser().getTask().tick(); + } + if (entity.getType() == EntityType.PLAYER) { processChatBubble((Player)entity); } diff --git a/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/TickTask.java b/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/TickTask.java new file mode 100644 index 0000000..2ba3953 --- /dev/null +++ b/Havana-Server/src/main/java/org/alexdev/havana/game/room/tasks/TickTask.java @@ -0,0 +1,17 @@ +package org.alexdev.havana.game.room.tasks; + +import org.alexdev.havana.util.DateUtil; + +public abstract class TickTask { + private long timeUntilNextTick; + + public abstract void tick(); + + public void setTimeUntilNextTick(int secs) { + this.timeUntilNextTick = DateUtil.getCurrentTimeSeconds() + secs; + } + + public boolean isTickRunnable() { + return DateUtil.getCurrentTimeSeconds() > timeUntilNextTick; + } +} diff --git a/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/ADDSTRIPITEM.java b/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/ADDSTRIPITEM.java index a1cec73..e7d8210 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/ADDSTRIPITEM.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/ADDSTRIPITEM.java @@ -44,7 +44,7 @@ public class ADDSTRIPITEM implements MessageEvent { ItemDao.updateItemOwnership(item); } - room.getMapping().removeItem(player, item); + room.getMapping().pickupItem(player, item); player.getInventory().addItem(item); player.getInventory().getView("update"); diff --git a/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/CONVERT_FURNI_TO_CREDITS.java b/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/CONVERT_FURNI_TO_CREDITS.java index 9e0495e..5e0370c 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/CONVERT_FURNI_TO_CREDITS.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/CONVERT_FURNI_TO_CREDITS.java @@ -68,7 +68,7 @@ public class CONVERT_FURNI_TO_CREDITS implements MessageEvent { amount, 0, false); // Notify room of item removal and set credits of player - room.getMapping().removeItem(player, item); + room.getMapping().pickupItem(player, item); player.getDetails().setCredits(currentAmount); // Send new credit amount diff --git a/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/PRESENTOPEN.java b/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/PRESENTOPEN.java index dd5f5b2..7da4bcd 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/PRESENTOPEN.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/PRESENTOPEN.java @@ -70,7 +70,7 @@ public class PRESENTOPEN implements MessageEvent { CatalogueItem catalogueItem = CatalogueManager.getInstance().getCatalogueItem(saleCode); if (catalogueItem != null) { - room.getMapping().removeItem(player, item); + room.getMapping().removeItem(item); item.setDefinitionId(catalogueItem.getDefinition().getId()); ItemDao.updateItem(item); @@ -104,7 +104,7 @@ public class PRESENTOPEN implements MessageEvent { CatalogueItem catalogueItem = CatalogueManager.getInstance().getCatalogueItem(saleCode); if (catalogueItem == null) { - room.getMapping().removeItem(player, item); + room.getMapping().pickupItem(player, item); item.delete(); return; } @@ -117,7 +117,7 @@ public class PRESENTOPEN implements MessageEvent { !catalogueItem.getDefinition().hasBehaviour(ItemBehaviour.DECORATION) && !catalogueItem.getDefinition().hasBehaviour(ItemBehaviour.POST_IT) && !catalogueItem.getDefinition().getSprite().equalsIgnoreCase("film")) { - room.getMapping().removeItem(player, item); + room.getMapping().pickupItem(player, item); item.setDefinitionId(catalogueItem.getDefinition().getId()); item.setCustomData(extraData); @@ -136,7 +136,7 @@ public class PRESENTOPEN implements MessageEvent { player.getInventory().getView("new"); } - room.getMapping().removeItem(player, item); + room.getMapping().pickupItem(player, item); item.delete(); } } @@ -178,7 +178,7 @@ public class PRESENTOPEN implements MessageEvent { return; } - room.getMapping().removeItem(player, item); + room.getMapping().pickupItem(player, item); item.setDefinitionId(catalogueItem.getDefinition().getId()); item.setCustomData(""); diff --git a/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/REMOVEITEM.java b/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/REMOVEITEM.java index b9e4717..4ce2d2b 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/REMOVEITEM.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/messages/incoming/rooms/items/REMOVEITEM.java @@ -41,7 +41,7 @@ public class REMOVEITEM implements MessageEvent { } } - room.getMapping().removeItem(player, item); + room.getMapping().pickupItem(player, item); item.delete(); player.getRoomUser().getTimerManager().resetRoomTimer(); diff --git a/Havana-Server/src/main/java/org/alexdev/havana/server/rcon/RconConnectionHandler.java b/Havana-Server/src/main/java/org/alexdev/havana/server/rcon/RconConnectionHandler.java index 89e9623..34dbc2a 100644 --- a/Havana-Server/src/main/java/org/alexdev/havana/server/rcon/RconConnectionHandler.java +++ b/Havana-Server/src/main/java/org/alexdev/havana/server/rcon/RconConnectionHandler.java @@ -293,7 +293,7 @@ public class RconConnectionHandler extends ChannelInboundHandlerAdapter { Room room = item.getRoom(); if (room != null) { - room.getMapping().removeItem(null, item); + room.getMapping().removeItem(item); } item.delete(); diff --git a/tools/migrations/update.1.1.sql b/tools/migrations/update.1.1.sql new file mode 100644 index 0000000..8e0fa6b --- /dev/null +++ b/tools/migrations/update.1.1.sql @@ -0,0 +1,7 @@ +UPDATE `items_definitions` SET `behaviour`='can_stand_on_top,requires_rights_for_interaction,pet_food', `interactor`='pet_food' WHERE `sprite` IN ('petfood1','petfood2','petfood3'); +UPDATE `items_definitions` SET `behaviour`='can_stand_on_top,requires_rights_for_interaction,pet_cat_food', `interactor`='pet_food' WHERE `sprite` IN ('goodie2'); +UPDATE `items_definitions` SET `behaviour`='can_stand_on_top,requires_rights_for_interaction,pet_dog_food', `interactor`='pet_food' WHERE `sprite` IN ('goodie1'); +UPDATE `items_definitions` SET `behaviour`='can_stand_on_top,requires_rights_for_interaction,pet_croc_food', `interactor`='pet_food' WHERE `sprite` IN ('petfood4'); + +UPDATE `items_definitions` SET `behaviour`='can_stand_on_top,requires_rights_for_interaction,pet_water_bowl', `interactor`='pet_water_bowl', `max_status`=6 WHERE `sprite` IN ('waterbowl*1','waterbowl*2','waterbowl*3','waterbowl*4', 'waterbowl*5'); +UPDATE `items_definitions` SET `behaviour`='can_stand_on_top,requires_rights_for_interaction,pet_toy', `interactor`='pet_toy' WHERE `sprite` IN ('toy1', 'toy1*1', 'toy1*2', 'toy1*3', 'toy1*4'); \ No newline at end of file