Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
This commit is contained in:
474
src/main/java/com/tiedup/remake/labor/LaborTask.java
Normal file
474
src/main/java/com/tiedup/remake/labor/LaborTask.java
Normal file
@@ -0,0 +1,474 @@
|
||||
package com.tiedup.remake.labor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
/**
|
||||
* Unified "Bring X Items" labor task.
|
||||
*
|
||||
* DESIGN CHANGE (v2.0):
|
||||
* All tasks are now simplified to "bring X items" instead of:
|
||||
* - "Mine X blocks" (event-based tracking)
|
||||
* - "Kill X mobs" (event-based tracking)
|
||||
* - "Chop X logs" (event-based tracking)
|
||||
* - "Collect X items" (inventory-based tracking)
|
||||
*
|
||||
* Benefits:
|
||||
* - Single task class (was 4)
|
||||
* - Periodic inventory checks (no event dependencies)
|
||||
* - Works with ANY item source (/give, crafting, trading, mining, looting)
|
||||
* - Maid collects items and deposits in cell chest
|
||||
* - Tools are provided and automatically retrieved
|
||||
*/
|
||||
public class LaborTask {
|
||||
|
||||
private final UUID id;
|
||||
private final Item targetItem; // What to bring
|
||||
private final int quota; // How many
|
||||
private final int value; // Emerald reward
|
||||
private final ItemStack toolGiven; // Tool provided (can be null)
|
||||
private int progress; // Current count (based on inventory)
|
||||
private UUID campId;
|
||||
|
||||
// ==================== CONSTRUCTORS ====================
|
||||
|
||||
public LaborTask(
|
||||
Item targetItem,
|
||||
int quota,
|
||||
int value,
|
||||
@Nullable ItemStack tool
|
||||
) {
|
||||
this.id = UUID.randomUUID();
|
||||
this.targetItem = targetItem;
|
||||
this.quota = quota;
|
||||
this.value = value;
|
||||
this.toolGiven = tool != null ? tagAsLaborTool(tool.copy()) : null;
|
||||
this.progress = 0;
|
||||
}
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Item getTargetItem() {
|
||||
return targetItem;
|
||||
}
|
||||
|
||||
public int getQuota() {
|
||||
return quota;
|
||||
}
|
||||
|
||||
public int getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public UUID getCampId() {
|
||||
return campId;
|
||||
}
|
||||
|
||||
public void setCampId(UUID campId) {
|
||||
this.campId = campId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ItemStack getToolGiven() {
|
||||
return toolGiven;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool type (e.g., Items.IRON_AXE).
|
||||
* Used for retrieving stored tools from cell chest.
|
||||
*/
|
||||
@Nullable
|
||||
public Item getToolType() {
|
||||
return toolGiven != null ? toolGiven.getItem() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a combat task (requires killing mobs).
|
||||
* Combat tasks use a sword and depend on mob spawns (time-of-day dependent).
|
||||
*/
|
||||
public boolean isCombatTask() {
|
||||
return toolGiven != null && toolGiven.getItem() == Items.IRON_SWORD;
|
||||
}
|
||||
|
||||
// ==================== PROGRESS ====================
|
||||
|
||||
/**
|
||||
* Check if the task is complete.
|
||||
*/
|
||||
public boolean isComplete() {
|
||||
return progress >= quota;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get completion percentage (0-100).
|
||||
*/
|
||||
public int getProgressPercent() {
|
||||
if (quota <= 0) return 100;
|
||||
return Math.min(100, (progress * 100) / quota);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check progress by counting matching items in worker's inventory.
|
||||
* Called periodically (every ~5 seconds) by MaidManagePrisonersGoal.
|
||||
*
|
||||
* @param worker The player doing the task
|
||||
* @param level The server level (unused but kept for API compatibility)
|
||||
* @return true if progress was made since last check
|
||||
*/
|
||||
public boolean checkProgress(ServerPlayer worker, ServerLevel level) {
|
||||
int count = 0;
|
||||
var inventory = worker.getInventory();
|
||||
for (int i = 0; i < inventory.getContainerSize(); i++) {
|
||||
ItemStack stack = inventory.getItem(i);
|
||||
if (!stack.isEmpty() && isAcceptableItem(stack.getItem())) {
|
||||
count += stack.getCount();
|
||||
}
|
||||
}
|
||||
|
||||
int oldProgress = progress;
|
||||
progress = Math.min(count, quota);
|
||||
return progress > oldProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an item is acceptable for this task.
|
||||
* For logs, accept any type of log (oak, birch, spruce, etc.)
|
||||
*/
|
||||
private boolean isAcceptableItem(Item item) {
|
||||
// Direct match
|
||||
if (item == targetItem) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If target is any type of log, accept all logs
|
||||
if (isLogItem(targetItem) && isLogItem(item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If target is any type of planks, accept all planks
|
||||
if (isPlankItem(targetItem) && isPlankItem(item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an item is a log.
|
||||
*/
|
||||
private boolean isLogItem(Item item) {
|
||||
return (
|
||||
item == Items.OAK_LOG ||
|
||||
item == Items.BIRCH_LOG ||
|
||||
item == Items.SPRUCE_LOG ||
|
||||
item == Items.DARK_OAK_LOG ||
|
||||
item == Items.JUNGLE_LOG ||
|
||||
item == Items.ACACIA_LOG ||
|
||||
item == Items.MANGROVE_LOG ||
|
||||
item == Items.CHERRY_LOG ||
|
||||
item == Items.CRIMSON_STEM ||
|
||||
item == Items.WARPED_STEM
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an item is a plank.
|
||||
*/
|
||||
private boolean isPlankItem(Item item) {
|
||||
return (
|
||||
item == Items.OAK_PLANKS ||
|
||||
item == Items.BIRCH_PLANKS ||
|
||||
item == Items.SPRUCE_PLANKS ||
|
||||
item == Items.DARK_OAK_PLANKS ||
|
||||
item == Items.JUNGLE_PLANKS ||
|
||||
item == Items.ACACIA_PLANKS ||
|
||||
item == Items.MANGROVE_PLANKS ||
|
||||
item == Items.CHERRY_PLANKS ||
|
||||
item == Items.CRIMSON_PLANKS ||
|
||||
item == Items.WARPED_PLANKS ||
|
||||
item == Items.BAMBOO_PLANKS
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== EQUIPMENT ====================
|
||||
|
||||
/**
|
||||
* Give equipment to the worker for this task.
|
||||
* Equipment is tagged as LaborTool to prevent dropping.
|
||||
*
|
||||
* @param worker The player to give equipment to
|
||||
*/
|
||||
public void giveEquipment(ServerPlayer worker) {
|
||||
// Give tool if one is specified
|
||||
if (toolGiven != null) {
|
||||
ItemStack tool = toolGiven.copy();
|
||||
worker.getInventory().add(tool);
|
||||
}
|
||||
|
||||
// Always give food for sustenance
|
||||
ItemStack bread = new ItemStack(Items.BREAD, 8);
|
||||
tagAsLaborTool(bread);
|
||||
worker.getInventory().add(bread);
|
||||
|
||||
// Give torches if tool is a pickaxe (for mining)
|
||||
if (
|
||||
toolGiven != null &&
|
||||
(toolGiven.getItem() == Items.IRON_PICKAXE ||
|
||||
toolGiven.getItem() == Items.STONE_PICKAXE)
|
||||
) {
|
||||
ItemStack torches = new ItemStack(Items.TORCH, 32);
|
||||
tagAsLaborTool(torches);
|
||||
worker.getInventory().add(torches);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Give equipment using a retrieved tool from cell chest.
|
||||
* Used to reuse tools instead of creating new ones.
|
||||
*
|
||||
* @param worker The player to give equipment to
|
||||
* @param retrievedTool The tool retrieved from cell chest
|
||||
*/
|
||||
public void giveRetrievedEquipment(
|
||||
ServerPlayer worker,
|
||||
ItemStack retrievedTool
|
||||
) {
|
||||
// Ensure the retrieved tool has LaborTool tag
|
||||
tagAsLaborTool(retrievedTool);
|
||||
worker.getInventory().add(retrievedTool);
|
||||
|
||||
// Give consumables (food, torches)
|
||||
ItemStack bread = new ItemStack(Items.BREAD, 8);
|
||||
tagAsLaborTool(bread);
|
||||
worker.getInventory().add(bread);
|
||||
|
||||
if (
|
||||
retrievedTool.getItem() == Items.IRON_PICKAXE ||
|
||||
retrievedTool.getItem() == Items.STONE_PICKAXE
|
||||
) {
|
||||
ItemStack torches = new ItemStack(Items.TORCH, 32);
|
||||
tagAsLaborTool(torches);
|
||||
worker.getInventory().add(torches);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaim equipment from the worker after task completion.
|
||||
* Removes any items tagged as LaborTool belonging to this camp.
|
||||
*
|
||||
* @param worker The player to reclaim equipment from
|
||||
* @return List of reclaimed tool items (for storage in cell chest)
|
||||
*/
|
||||
public List<ItemStack> reclaimEquipment(ServerPlayer worker) {
|
||||
List<ItemStack> reclaimedTools = new ArrayList<>();
|
||||
var inventory = worker.getInventory();
|
||||
|
||||
for (int i = 0; i < inventory.getContainerSize(); i++) {
|
||||
ItemStack stack = inventory.getItem(i);
|
||||
if (!stack.isEmpty() && isLaborTool(stack)) {
|
||||
// Only store tools (not consumables like bread/torches)
|
||||
if (isReusableTool(stack)) {
|
||||
reclaimedTools.add(stack.copy());
|
||||
}
|
||||
inventory.setItem(i, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
return reclaimedTools;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect task items from worker's inventory.
|
||||
* Called by maid when task is complete.
|
||||
*
|
||||
* @param worker The player to collect items from
|
||||
* @return List of collected item stacks
|
||||
*/
|
||||
public List<ItemStack> collectItems(ServerPlayer worker) {
|
||||
List<ItemStack> collected = new ArrayList<>();
|
||||
var inventory = worker.getInventory();
|
||||
|
||||
int remaining = quota;
|
||||
for (
|
||||
int i = 0;
|
||||
i < inventory.getContainerSize() && remaining > 0;
|
||||
i++
|
||||
) {
|
||||
ItemStack stack = inventory.getItem(i);
|
||||
if (!stack.isEmpty() && isAcceptableItem(stack.getItem())) {
|
||||
int toTake = Math.min(stack.getCount(), remaining);
|
||||
ItemStack taken = stack.split(toTake);
|
||||
collected.add(taken);
|
||||
remaining -= toTake;
|
||||
}
|
||||
}
|
||||
|
||||
return collected;
|
||||
}
|
||||
|
||||
// ==================== HELPER METHODS ====================
|
||||
|
||||
/**
|
||||
* Check if an item is a labor tool from this camp.
|
||||
*/
|
||||
private boolean isLaborTool(ItemStack stack) {
|
||||
if (!stack.hasTag()) return false;
|
||||
CompoundTag tag = stack.getTag();
|
||||
if (tag == null) return false;
|
||||
if (!tag.getBoolean("LaborTool")) return false;
|
||||
|
||||
// Check camp ID if we have one
|
||||
if (campId != null && tag.hasUUID("CampId")) {
|
||||
return campId.equals(tag.getUUID("CampId"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a tool is reusable (should be stored, not discarded).
|
||||
*/
|
||||
private boolean isReusableTool(ItemStack stack) {
|
||||
Item item = stack.getItem();
|
||||
return (
|
||||
item == Items.IRON_PICKAXE ||
|
||||
item == Items.STONE_PICKAXE ||
|
||||
item == Items.IRON_AXE ||
|
||||
item == Items.IRON_SWORD ||
|
||||
item == Items.IRON_SHOVEL ||
|
||||
item == Items.IRON_HOE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag an item as a labor tool belonging to this camp.
|
||||
* BUG FIX: Made tools unbreakable to prevent soft-lock when tools break.
|
||||
* Problem: Tools breaking left prisoners stuck and punished in loop with no recourse.
|
||||
*/
|
||||
private ItemStack tagAsLaborTool(ItemStack stack) {
|
||||
CompoundTag tag = stack.getOrCreateTag();
|
||||
tag.putBoolean("LaborTool", true);
|
||||
tag.putBoolean("Unbreakable", true); // Prevent tool breakage soft-lock
|
||||
if (campId != null) {
|
||||
tag.putUUID("CampId", campId);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
// ==================== DESCRIPTION ====================
|
||||
|
||||
/**
|
||||
* Get a human-readable description of this task.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return String.format("Bring %d %s", quota, getTargetName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the target item name (formatted).
|
||||
* For logs, return generic "Logs" instead of specific type.
|
||||
*/
|
||||
public String getTargetName() {
|
||||
if (isLogItem(targetItem)) {
|
||||
return "Logs";
|
||||
}
|
||||
if (isPlankItem(targetItem)) {
|
||||
return "Planks";
|
||||
}
|
||||
return new ItemStack(targetItem).getHoverName().getString();
|
||||
}
|
||||
|
||||
// ==================== SERIALIZATION ====================
|
||||
|
||||
/**
|
||||
* Save task data to NBT.
|
||||
*/
|
||||
public CompoundTag save() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putUUID("id", id);
|
||||
|
||||
// Save target item
|
||||
ResourceLocation itemKey = ForgeRegistries.ITEMS.getKey(targetItem);
|
||||
if (itemKey != null) {
|
||||
tag.putString("targetItem", itemKey.toString());
|
||||
}
|
||||
|
||||
tag.putInt("quota", quota);
|
||||
tag.putInt("progress", progress);
|
||||
tag.putInt("value", value);
|
||||
|
||||
// Save tool if one was given
|
||||
if (toolGiven != null) {
|
||||
CompoundTag toolTag = new CompoundTag();
|
||||
toolGiven.save(toolTag);
|
||||
tag.put("toolGiven", toolTag);
|
||||
}
|
||||
|
||||
if (campId != null) {
|
||||
tag.putUUID("campId", campId);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load task from NBT. Returns null if invalid.
|
||||
*/
|
||||
@Nullable
|
||||
public static LaborTask load(CompoundTag tag) {
|
||||
if (
|
||||
!tag.contains("targetItem") ||
|
||||
!tag.contains("quota") ||
|
||||
!tag.contains("value")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Load target item
|
||||
String itemKeyStr = tag.getString("targetItem");
|
||||
ResourceLocation itemKey = ResourceLocation.tryParse(itemKeyStr);
|
||||
if (itemKey == null) return null;
|
||||
|
||||
Item item = ForgeRegistries.ITEMS.getValue(itemKey);
|
||||
if (item == null || item == Items.AIR) return null;
|
||||
|
||||
// Load tool (if present)
|
||||
ItemStack tool = null;
|
||||
if (tag.contains("toolGiven")) {
|
||||
tool = ItemStack.of(tag.getCompound("toolGiven"));
|
||||
}
|
||||
|
||||
// Create task
|
||||
int quota = tag.getInt("quota");
|
||||
int value = tag.getInt("value");
|
||||
LaborTask task = new LaborTask(item, quota, value, tool);
|
||||
|
||||
// Load progress and camp ID
|
||||
if (tag.contains("progress")) {
|
||||
task.progress = tag.getInt("progress");
|
||||
}
|
||||
if (tag.contains("campId")) {
|
||||
task.campId = tag.getUUID("campId");
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
}
|
||||
255
src/main/java/com/tiedup/remake/labor/LaborTaskGenerator.java
Normal file
255
src/main/java/com/tiedup/remake/labor/LaborTaskGenerator.java
Normal file
@@ -0,0 +1,255 @@
|
||||
package com.tiedup.remake.labor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
/**
|
||||
* Generator for random labor tasks.
|
||||
*
|
||||
* DESIGN CHANGE (v2.0):
|
||||
* All tasks simplified to "Bring X Items" with automatic tool assignment.
|
||||
*
|
||||
* Value Guidelines:
|
||||
* - Standard ransom: 100-200 emeralds
|
||||
* - Target: ~6 tasks average to pay off
|
||||
* - Per task value: 18-35 emeralds depending on difficulty
|
||||
*/
|
||||
public class LaborTaskGenerator {
|
||||
|
||||
private static final RandomSource RANDOM = RandomSource.create();
|
||||
|
||||
// ==================== TOOL MAPPING ====================
|
||||
|
||||
/**
|
||||
* Maps items to the tools needed to collect them.
|
||||
* If an item is not in this map, no tool is given.
|
||||
*/
|
||||
private static final Map<Item, ItemStack> TOOL_MAP = Map.ofEntries(
|
||||
// Logs → Axe
|
||||
Map.entry(Items.OAK_LOG, new ItemStack(Items.IRON_AXE)),
|
||||
Map.entry(Items.BIRCH_LOG, new ItemStack(Items.IRON_AXE)),
|
||||
Map.entry(Items.SPRUCE_LOG, new ItemStack(Items.IRON_AXE)),
|
||||
Map.entry(Items.DARK_OAK_LOG, new ItemStack(Items.IRON_AXE)),
|
||||
Map.entry(Items.JUNGLE_LOG, new ItemStack(Items.IRON_AXE)),
|
||||
Map.entry(Items.ACACIA_LOG, new ItemStack(Items.IRON_AXE)),
|
||||
Map.entry(Items.MANGROVE_LOG, new ItemStack(Items.IRON_AXE)),
|
||||
Map.entry(Items.CHERRY_LOG, new ItemStack(Items.IRON_AXE)),
|
||||
// Gathering → Shovel
|
||||
Map.entry(Items.SAND, new ItemStack(Items.IRON_SHOVEL)),
|
||||
Map.entry(Items.GRAVEL, new ItemStack(Items.IRON_SHOVEL)),
|
||||
Map.entry(Items.DIRT, new ItemStack(Items.IRON_SHOVEL)),
|
||||
Map.entry(Items.CLAY_BALL, new ItemStack(Items.IRON_SHOVEL)),
|
||||
// Basic mining → Pickaxe
|
||||
Map.entry(Items.COBBLESTONE, new ItemStack(Items.STONE_PICKAXE)),
|
||||
// Ores → Pickaxe
|
||||
Map.entry(Items.IRON_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.DEEPSLATE_IRON_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.RAW_IRON, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.COAL_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.DEEPSLATE_COAL_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.COAL, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.DIAMOND_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(
|
||||
Items.DEEPSLATE_DIAMOND_ORE,
|
||||
new ItemStack(Items.IRON_PICKAXE)
|
||||
),
|
||||
Map.entry(Items.DIAMOND, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.GOLD_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.DEEPSLATE_GOLD_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.RAW_GOLD, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.COPPER_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(
|
||||
Items.DEEPSLATE_COPPER_ORE,
|
||||
new ItemStack(Items.IRON_PICKAXE)
|
||||
),
|
||||
Map.entry(Items.RAW_COPPER, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.LAPIS_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.DEEPSLATE_LAPIS_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.LAPIS_LAZULI, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.REDSTONE_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(
|
||||
Items.DEEPSLATE_REDSTONE_ORE,
|
||||
new ItemStack(Items.IRON_PICKAXE)
|
||||
),
|
||||
Map.entry(Items.REDSTONE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(Items.EMERALD_ORE, new ItemStack(Items.IRON_PICKAXE)),
|
||||
Map.entry(
|
||||
Items.DEEPSLATE_EMERALD_ORE,
|
||||
new ItemStack(Items.IRON_PICKAXE)
|
||||
),
|
||||
Map.entry(Items.EMERALD, new ItemStack(Items.IRON_PICKAXE)),
|
||||
// Combat drops → Sword
|
||||
Map.entry(Items.ROTTEN_FLESH, new ItemStack(Items.IRON_SWORD)),
|
||||
Map.entry(Items.BONE, new ItemStack(Items.IRON_SWORD)),
|
||||
Map.entry(Items.STRING, new ItemStack(Items.IRON_SWORD)),
|
||||
Map.entry(Items.GUNPOWDER, new ItemStack(Items.IRON_SWORD)),
|
||||
Map.entry(Items.SPIDER_EYE, new ItemStack(Items.IRON_SWORD)),
|
||||
Map.entry(Items.ARROW, new ItemStack(Items.IRON_SWORD))
|
||||
|
||||
// Items not in this map (e.g., SWEET_BERRIES, KELP, STICK, TORCH, planks) get no tool
|
||||
);
|
||||
|
||||
// ==================== TASK POOL ====================
|
||||
|
||||
/**
|
||||
* Pool of all available labor tasks.
|
||||
* Each entry specifies: item to bring, quota, emerald value.
|
||||
*/
|
||||
private static final List<TaskSpec> TASK_POOL = List.of(
|
||||
// Logs (axe provided) — generic "Logs", accepts any type
|
||||
new TaskSpec(Items.OAK_LOG, 32, 18),
|
||||
new TaskSpec(Items.OAK_LOG, 48, 25),
|
||||
new TaskSpec(Items.OAK_LOG, 64, 32),
|
||||
// Gathering (shovel provided)
|
||||
new TaskSpec(Items.SAND, 32, 10),
|
||||
new TaskSpec(Items.GRAVEL, 32, 10),
|
||||
new TaskSpec(Items.DIRT, 64, 8),
|
||||
new TaskSpec(Items.CLAY_BALL, 16, 14),
|
||||
// Basic mining (stone pickaxe provided)
|
||||
new TaskSpec(Items.COBBLESTONE, 64, 10),
|
||||
new TaskSpec(Items.COBBLESTONE, 32, 8),
|
||||
// Easy picks (no tool needed)
|
||||
new TaskSpec(Items.SWEET_BERRIES, 16, 12),
|
||||
new TaskSpec(Items.KELP, 32, 10),
|
||||
// Crafted (no tool needed)
|
||||
new TaskSpec(Items.OAK_PLANKS, 64, 12),
|
||||
new TaskSpec(Items.STICK, 64, 10),
|
||||
new TaskSpec(Items.TORCH, 32, 15),
|
||||
// Mining - Coal (common, pickaxe provided)
|
||||
new TaskSpec(Items.COAL, 24, 18),
|
||||
new TaskSpec(Items.COAL, 32, 22),
|
||||
// Mining - Iron (pickaxe provided)
|
||||
new TaskSpec(Items.RAW_IRON, 16, 25),
|
||||
new TaskSpec(Items.RAW_IRON, 24, 32),
|
||||
// Mining - Copper (pickaxe provided)
|
||||
new TaskSpec(Items.RAW_COPPER, 20, 20),
|
||||
// Mining - Gold (pickaxe provided)
|
||||
new TaskSpec(Items.RAW_GOLD, 8, 30),
|
||||
// Mining - Lapis (pickaxe provided)
|
||||
new TaskSpec(Items.LAPIS_LAZULI, 10, 28),
|
||||
// Mining - Redstone (pickaxe provided)
|
||||
new TaskSpec(Items.REDSTONE, 12, 22),
|
||||
// Mining - Diamond (pickaxe provided, rare, high value)
|
||||
new TaskSpec(Items.DIAMOND, 5, 35),
|
||||
// Mining - Emerald (pickaxe provided, very rare)
|
||||
new TaskSpec(Items.EMERALD, 3, 35),
|
||||
// Combat drops (sword provided)
|
||||
new TaskSpec(Items.ROTTEN_FLESH, 24, 18),
|
||||
new TaskSpec(Items.BONE, 16, 20),
|
||||
new TaskSpec(Items.STRING, 32, 20),
|
||||
new TaskSpec(Items.GUNPOWDER, 12, 25),
|
||||
new TaskSpec(Items.SPIDER_EYE, 8, 20),
|
||||
new TaskSpec(Items.ARROW, 16, 18)
|
||||
);
|
||||
|
||||
// ==================== GENERATION ====================
|
||||
|
||||
/** Combat task items (require mob kills, only assigned at night). */
|
||||
private static final List<Item> COMBAT_ITEMS = List.of(
|
||||
Items.ROTTEN_FLESH,
|
||||
Items.BONE,
|
||||
Items.STRING,
|
||||
Items.GUNPOWDER,
|
||||
Items.SPIDER_EYE,
|
||||
Items.ARROW
|
||||
);
|
||||
|
||||
/**
|
||||
* Generate a random labor task, filtering combat tasks to nighttime only.
|
||||
*
|
||||
* @param level The server level (used to check time of day), or null to skip filtering
|
||||
*/
|
||||
public static LaborTask generateRandom(@Nullable ServerLevel level) {
|
||||
List<TaskSpec> pool;
|
||||
if (level != null && isDay(level)) {
|
||||
// Daytime: exclude combat tasks (mobs don't spawn)
|
||||
pool = TASK_POOL.stream()
|
||||
.filter(spec -> !COMBAT_ITEMS.contains(spec.item()))
|
||||
.toList();
|
||||
} else {
|
||||
pool = TASK_POOL;
|
||||
}
|
||||
TaskSpec spec = pickRandom(pool);
|
||||
ItemStack tool = TOOL_MAP.get(spec.item());
|
||||
return new LaborTask(spec.item(), spec.quota(), spec.value(), tool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if it's daytime in the level.
|
||||
* Minecraft day cycle: 0-12541 = day, 12542-23999 = night/dusk/dawn.
|
||||
* We use 13000-23000 as "night enough for mob spawns".
|
||||
*/
|
||||
private static boolean isDay(ServerLevel level) {
|
||||
long timeOfDay = level.getDayTime() % 24000;
|
||||
return timeOfDay < 13000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a task requiring a specific item type.
|
||||
* Used for testing or custom scenarios.
|
||||
*/
|
||||
public static LaborTask generateFor(Item item, int quota, int value) {
|
||||
ItemStack tool = TOOL_MAP.get(item);
|
||||
return new LaborTask(item, quota, value, tool);
|
||||
}
|
||||
|
||||
// ==================== UTILITY ====================
|
||||
|
||||
private static <T> T pickRandom(List<T> list) {
|
||||
return list.get(RANDOM.nextInt(list.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Task specification record.
|
||||
*/
|
||||
private record TaskSpec(Item item, int quota, int value) {}
|
||||
|
||||
// ==================== RANSOM CALCULATION ====================
|
||||
|
||||
/**
|
||||
* Calculate ransom amount based on player equipment/level.
|
||||
*
|
||||
* @param hasIronArmor Player has iron armor equipped
|
||||
* @param hasDiamondArmor Player has diamond/netherite armor equipped
|
||||
* @param hasValuables Player has emeralds/diamonds in inventory
|
||||
* @return Ransom amount in emeralds
|
||||
*/
|
||||
public static int calculateRansomAmount(
|
||||
boolean hasIronArmor,
|
||||
boolean hasDiamondArmor,
|
||||
boolean hasValuables
|
||||
) {
|
||||
int base = 100;
|
||||
|
||||
if (hasDiamondArmor) {
|
||||
base = 200;
|
||||
} else if (hasIronArmor) {
|
||||
base = 150;
|
||||
}
|
||||
|
||||
if (hasValuables) {
|
||||
base += 25;
|
||||
}
|
||||
|
||||
// Add some randomness
|
||||
int variance = RANDOM.nextInt(21) - 10; // -10 to +10
|
||||
return base + variance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate number of tasks to pay off a ransom.
|
||||
*
|
||||
* @param ransomAmount The ransom amount
|
||||
* @return Estimated number of tasks
|
||||
*/
|
||||
public static int estimateTasksToPayoff(int ransomAmount) {
|
||||
// Average task value is about 25 emeralds
|
||||
return (int) Math.ceil(ransomAmount / 25.0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user