diff --git a/gameserver/src/main/java/brainwine/gameserver/item/ItemUseType.java b/gameserver/src/main/java/brainwine/gameserver/item/ItemUseType.java index 15282a7f..df4524d0 100644 --- a/gameserver/src/main/java/brainwine/gameserver/item/ItemUseType.java +++ b/gameserver/src/main/java/brainwine/gameserver/item/ItemUseType.java @@ -15,6 +15,7 @@ import brainwine.gameserver.item.interactions.TargetTeleportInteraction; import brainwine.gameserver.item.interactions.TeleportInteraction; import brainwine.gameserver.item.interactions.TransmitInteraction; +import brainwine.gameserver.item.interactions.WorldMachineActivationInteraction; /** * Much like with {@link Action}, block interactions depend on their use type. @@ -47,6 +48,7 @@ public enum ItemUseType { TRANSMIT(new TransmitInteraction()), TRANSMITTED, ZONE_TELEPORT, + WORLD_MACHINE_ACTIVATION(new WorldMachineActivationInteraction()), @JsonEnumDefaultValue UNKNOWN; diff --git a/gameserver/src/main/java/brainwine/gameserver/item/interactions/ContainerInteraction.java b/gameserver/src/main/java/brainwine/gameserver/item/interactions/ContainerInteraction.java index 14971f12..6237dbfd 100644 --- a/gameserver/src/main/java/brainwine/gameserver/item/interactions/ContainerInteraction.java +++ b/gameserver/src/main/java/brainwine/gameserver/item/interactions/ContainerInteraction.java @@ -2,6 +2,7 @@ import brainwine.gameserver.GameServer; import brainwine.gameserver.entity.Entity; +import brainwine.gameserver.entity.player.NotificationType; import brainwine.gameserver.entity.player.Player; import brainwine.gameserver.item.Item; import brainwine.gameserver.item.ItemUseType; @@ -69,8 +70,29 @@ public void interact(Zone zone, Entity entity, int x, int y, Layer layer, Item i metaBlock.removeProperty("$"); metaBlock.removeProperty("xp"); } + + var firstLoot = loot.getItems().entrySet().iterator().next(); - player.awardLoot(loot, item.getLootGraphic()); + if (firstLoot.getKey().getId().startsWith("accessories/eco")) { + // ecological machine. loot is for the world + loot.getItems().forEach((myLoot, quantity) -> { + zone.installEcologicalMachinePart(myLoot, quantity); + }); + + loot.getItems().forEach((myLoot, quantity) -> { + String itemTitle = myLoot.getTitle(); + player.notify(String.format( + "You discovered %d %s%s!", + quantity, + itemTitle, + quantity == 1 ? "" : (java.util.List.of("a", "e", "i", "o", "u").stream().anyMatch(itemTitle::endsWith) ? "s" : "es") + ), NotificationType.ACCOMPLISHMENT); + }); + } else { + // loot is for the player + player.awardLoot(loot, item.getLootGraphic()); + } + player.addExperience(experience); player.getStatistics().trackContainerLooted(item); } else { diff --git a/gameserver/src/main/java/brainwine/gameserver/item/interactions/WorldMachineActivationInteraction.java b/gameserver/src/main/java/brainwine/gameserver/item/interactions/WorldMachineActivationInteraction.java new file mode 100644 index 00000000..47c6ba13 --- /dev/null +++ b/gameserver/src/main/java/brainwine/gameserver/item/interactions/WorldMachineActivationInteraction.java @@ -0,0 +1,67 @@ +package brainwine.gameserver.item.interactions; + +import java.util.Map; + +import brainwine.gameserver.entity.Entity; +import brainwine.gameserver.entity.player.NotificationType; +import brainwine.gameserver.entity.player.Player; +import brainwine.gameserver.item.Item; +import brainwine.gameserver.item.ItemUseType; +import brainwine.gameserver.item.Layer; +import brainwine.gameserver.zone.MetaBlock; +import brainwine.gameserver.zone.Zone; + +public class WorldMachineActivationInteraction implements ItemInteraction { + + @Override + public void interact(Zone zone, Entity entity, int x, int y, Layer layer, Item item, int mod, MetaBlock metaBlock, + Object config, Object[] data) { + final Map ECOLOGICAL_MACHINE_PART_COUNTS = Map.of( + "purifier", 7, + "composter", 5, + "recycler", 5 + ); + + final Map MACHINE_ITEM_IDS = Map.of( + "purifier", "mechanical/purifier", + "composter", "mechanical/composter-chamber", + "recycler", "mechanical/recycler" + ); + + // Do nothing if entity is dead or not a player + if (!entity.isPlayer() || entity.isDead()) { + return; + } + + Player player = (Player)entity; + + if (!(item.getUse(ItemUseType.WORLD_MACHINE_ACTIVATION) instanceof String)) return; + + String machineType = (String) item.getUse(ItemUseType.WORLD_MACHINE_ACTIVATION); + + int properParts = zone.getEcologicalMachineParts().getOrDefault(machineType, 0); + int pooledParts = zone.getEcologicalMachineParts().getOrDefault("common_machine_part_pool", 0); + int requiredParts = ECOLOGICAL_MACHINE_PART_COUNTS.getOrDefault(machineType, Integer.MAX_VALUE); + + if (properParts + pooledParts >= requiredParts) { + String machineItemId = MACHINE_ITEM_IDS.get(machineType); + Item machine = Item.get(machineItemId); + + if (machine == null) player.notify(String.format( + "Activated state of the machine is not recognized. ID was %s. Please report to the server developers.", + machineItemId + )); + zone.updateBlock(x, y, Layer.FRONT, machine); + zone.getEcologicalMachineParts().put("common_machine_part_pool", properParts >= requiredParts ? pooledParts : pooledParts - (requiredParts - properParts)); + zone.getEcologicalMachineParts().put(machineType, properParts >= requiredParts ? properParts - requiredParts : 0); + player.notify(String.format("You have successfully activated the %s!", machine.getTitle()), NotificationType.ACCOMPLISHMENT); + } else { + player.notify(String.format( + "Not all parts to activate this machine have been collected yet. %d out of %d have been collected.", + properParts + pooledParts, + requiredParts + )); + } + } + +} diff --git a/gameserver/src/main/java/brainwine/gameserver/zone/Zone.java b/gameserver/src/main/java/brainwine/gameserver/zone/Zone.java index 7735c41d..71aabd65 100644 --- a/gameserver/src/main/java/brainwine/gameserver/zone/Zone.java +++ b/gameserver/src/main/java/brainwine/gameserver/zone/Zone.java @@ -63,6 +63,7 @@ public class Zone { private final Biome biome; private final int width; private final int height; + private Map ecologicalMachineParts = new HashMap<>(); private final int chunkWidth = DEFAULT_CHUNK_WIDTH; private final int chunkHeight = DEFAULT_CHUNK_HEIGHT; private final int numChunksWidth; @@ -91,6 +92,7 @@ public class Zone { protected Zone(String documentId, ZoneConfigFile config, ZoneDataFile data) { this(documentId, config.getName(), config.getBiome(), config.getWidth(), config.getHeight()); + this.ecologicalMachineParts.putAll(config.getEcologicalMachineParts()); int[] surface = data.getSurface(); int[] sunlight = data.getSunlight(); int[] depths = data.getDepths(); @@ -1578,4 +1580,22 @@ public Object getStatusConfig(Player player) { return player.hasClientVersion("2.1.0") ? MapHelper.map("w", status) : status; } + + public void installEcologicalMachinePart(Item item, Integer quantity) { + final Map PART_ID_TO_MACHINE_ID = Map.of( + "accessories/eco", "common_machine_part_pool", + "accessories/purifier", "purifier", + "accessories/composter", "composter", + "accessories/recycler", "recycler" + ); + + String machineId = PART_ID_TO_MACHINE_ID.get(item.getId()); + + int old = ecologicalMachineParts.computeIfAbsent(machineId, k -> 0); + ecologicalMachineParts.put(machineId, old + quantity); + } + + public Map getEcologicalMachineParts() { + return ecologicalMachineParts; + } } diff --git a/gameserver/src/main/java/brainwine/gameserver/zone/ZoneConfigFile.java b/gameserver/src/main/java/brainwine/gameserver/zone/ZoneConfigFile.java index 567bc9a4..b6812eec 100644 --- a/gameserver/src/main/java/brainwine/gameserver/zone/ZoneConfigFile.java +++ b/gameserver/src/main/java/brainwine/gameserver/zone/ZoneConfigFile.java @@ -1,6 +1,8 @@ package brainwine.gameserver.zone; import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.Map; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -28,18 +30,22 @@ public class ZoneConfigFile { @JsonSetter(nulls = Nulls.SKIP) private OffsetDateTime creationDate = OffsetDateTime.now(); + + @JsonSetter(nulls = Nulls.SKIP) + private Map ecologicalMachineParts = new HashMap<>(); public ZoneConfigFile(Zone zone) { - this(zone.getName(), zone.getBiome(), zone.getWidth(), zone.getHeight(), zone.getAcidity(), zone.getCreationDate()); + this(zone.getName(), zone.getBiome(), zone.getWidth(), zone.getHeight(), zone.getAcidity(), zone.getCreationDate(), zone.getEcologicalMachineParts()); } - public ZoneConfigFile(String name, Biome biome, int width, int height, float acidity, OffsetDateTime creationDate) { + public ZoneConfigFile(String name, Biome biome, int width, int height, float acidity, OffsetDateTime creationDate, Map ecologicalMachineParts) { this.name = name; this.biome = biome; this.width = width; this.height = height; this.acidity = acidity; this.creationDate = creationDate; + this.ecologicalMachineParts = ecologicalMachineParts; } @JsonCreator @@ -74,4 +80,8 @@ public float getAcidity() { public OffsetDateTime getCreationDate() { return creationDate; } + + public Map getEcologicalMachineParts() { + return ecologicalMachineParts; + } }