mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 18:57:32 +00:00
190 lines
7.4 KiB
Java
190 lines
7.4 KiB
Java
package noppes.npcs.containers;
|
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
|
import net.minecraft.inventory.Slot;
|
|
import net.minecraft.item.ItemStack;
|
|
import noppes.npcs.NoppesUtilPlayer;
|
|
import noppes.npcs.controllers.data.PlayerData;
|
|
import noppes.npcs.entity.EntityNPCInterface;
|
|
import noppes.npcs.roles.RoleTrader;
|
|
|
|
|
|
public class ContainerNPCTrader extends ContainerNpcInterface {
|
|
public RoleTrader role;
|
|
private final EntityNPCInterface npc;
|
|
|
|
// Layout constants for 256px wide GUI
|
|
public static final int COLUMN_WIDTH = 80;
|
|
public static final int COLUMN_START_X = 8;
|
|
public static final int ROW_HEIGHT = 22;
|
|
public static final int ROW_START_Y = 6;
|
|
|
|
// Slot offsets within each column (for 18x18 slots, items render centered)
|
|
public static final int CURRENCY1_OFFSET = 2; // Primary currency slot
|
|
public static final int CURRENCY2_OFFSET = 20; // Secondary currency slot
|
|
public static final int OUTPUT_OFFSET = 50; // Output slot
|
|
|
|
public ContainerNPCTrader(EntityNPCInterface npc, EntityPlayer player) {
|
|
super(player);
|
|
this.npc = npc;
|
|
role = (RoleTrader) npc.roleInterface;
|
|
|
|
// Register this player as viewing the trader (server-side only)
|
|
// Needed for shared stock (not per-player) to sync updates to other viewers
|
|
// Works for both linked markets (MarketRegistry) and normal traders (local viewers)
|
|
if (player instanceof EntityPlayerMP && !role.stock.perPlayer) {
|
|
role.registerViewer((EntityPlayerMP) player);
|
|
}
|
|
|
|
// Trade slots: 3 columns x 6 rows, 80px column width
|
|
// Layout per column: [Slot1][Slot2] = [Output]
|
|
for (int i = 0; i < 18; i++) {
|
|
int col = i % 3;
|
|
int row = i / 3;
|
|
int x = COLUMN_START_X + col * COLUMN_WIDTH;
|
|
int y = ROW_START_Y + row * ROW_HEIGHT;
|
|
// Output slot position (slot texture is 18x18, item renders centered at +1)
|
|
addSlotToContainer(new Slot(role.inventorySold, i, x + OUTPUT_OFFSET + 1, y + 1));
|
|
}
|
|
|
|
for (int i1 = 0; i1 < 3; i1++) {
|
|
for (int l1 = 0; l1 < 9; l1++) {
|
|
addSlotToContainer(new Slot(player.inventory, l1 + i1 * 9 + 9, 48 + l1 * 18, 137 + i1 * 18));
|
|
}
|
|
}
|
|
|
|
// Player hotbar
|
|
for (int j1 = 0; j1 < 9; j1++) {
|
|
addSlotToContainer(new Slot(player.inventory, j1, 48 + j1 * 18, 195));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onContainerClosed(EntityPlayer player) {
|
|
super.onContainerClosed(player);
|
|
// Unregister this player from viewer tracking (only if registered for shared stock)
|
|
if (player instanceof EntityPlayerMP && !role.stock.perPlayer) {
|
|
role.unregisterViewer((EntityPlayerMP) player);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int i) {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public ItemStack slotClick(int i, int j, int par3, EntityPlayer entityplayer) {
|
|
if (par3 == 6)
|
|
par3 = 0;
|
|
if (i < 0 || i >= 18)
|
|
return super.slotClick(i, j, par3, entityplayer);
|
|
if (j == 1)
|
|
return null;
|
|
Slot slot = (Slot) inventorySlots.get(i);
|
|
if (slot == null || slot.getStack() == null)
|
|
return null;
|
|
ItemStack item = slot.getStack();
|
|
if (!canGivePlayer(item, entityplayer))
|
|
return null;
|
|
if (!isSlotEnabled(i, entityplayer))
|
|
return null;
|
|
|
|
// Check stock availability
|
|
String playerName = entityplayer.getCommandSenderName();
|
|
if (!role.hasStock(i, playerName, 1)) {
|
|
return null; // Out of stock
|
|
}
|
|
|
|
// Item-based currency
|
|
if (!canBuy(i, entityplayer))
|
|
return null;
|
|
|
|
// Currency cost check (additive to item costs)
|
|
long currencyCost = role.getCurrencyCost(i);
|
|
if (currencyCost > 0) {
|
|
PlayerData data = PlayerData.get(entityplayer);
|
|
if (data.tradeData.getBalance() < currencyCost) {
|
|
return null; // Can't afford currency cost
|
|
}
|
|
}
|
|
|
|
// Consume item currency
|
|
NoppesUtilPlayer.consumeItem(entityplayer, role.inventoryCurrency.getStackInSlot(i), role.ignoreDamage, role.ignoreNBT);
|
|
NoppesUtilPlayer.consumeItem(entityplayer, role.inventoryCurrency.getStackInSlot(i + 18), role.ignoreDamage, role.ignoreNBT);
|
|
|
|
// Withdraw currency cost (after item consumption to maintain order)
|
|
if (currencyCost > 0) {
|
|
PlayerData data = PlayerData.get(entityplayer);
|
|
data.tradeData.withdraw(currencyCost);
|
|
}
|
|
|
|
// Consume stock
|
|
role.consumeStock(i, playerName, 1);
|
|
|
|
ItemStack soldItem = item.copy();
|
|
givePlayer(soldItem, entityplayer);
|
|
role.addPurchase(i, entityplayer.getDisplayName());
|
|
|
|
// Always sync the purchasing player's data (balance + stock) after trade.
|
|
// For shared stocks, consumeStock() syncs stock to other viewers,
|
|
// but the purchasing player's balance still needs an explicit sync.
|
|
if (entityplayer instanceof EntityPlayerMP) {
|
|
role.syncToPlayer((EntityPlayerMP) entityplayer);
|
|
}
|
|
|
|
return soldItem;
|
|
}
|
|
|
|
public boolean isSlotEnabled(int slot, EntityPlayer player) {
|
|
return role.isSlotEnabled(slot, player.getDisplayName());
|
|
}
|
|
|
|
public boolean canBuy(int slot, EntityPlayer player) {
|
|
ItemStack currency = role.inventoryCurrency.getStackInSlot(slot);
|
|
ItemStack currency2 = role.inventoryCurrency.getStackInSlot(slot + 18);
|
|
if (currency == null && currency2 == null)
|
|
return true;
|
|
if (currency == null) {
|
|
currency = currency2;
|
|
currency2 = null;
|
|
}
|
|
if (NoppesUtilPlayer.compareItems(currency, currency2, role.ignoreDamage, role.ignoreNBT)) {
|
|
currency = currency.copy();
|
|
currency.stackSize += currency2.stackSize;
|
|
currency2 = null;
|
|
}
|
|
if (currency2 == null)
|
|
return NoppesUtilPlayer.compareItems(player, currency, role.ignoreDamage, role.ignoreNBT);
|
|
return NoppesUtilPlayer.compareItems(player, currency, role.ignoreDamage, role.ignoreNBT) && NoppesUtilPlayer.compareItems(player, currency2, role.ignoreDamage, role.ignoreNBT);
|
|
|
|
}
|
|
|
|
private boolean canGivePlayer(ItemStack item, EntityPlayer entityplayer) {//check Item being held with the mouse
|
|
ItemStack itemstack3 = entityplayer.inventory.getItemStack();
|
|
if (itemstack3 == null) {
|
|
return true;
|
|
} else if (NoppesUtilPlayer.compareItems(itemstack3, item, false, false)) {
|
|
int k1 = item.stackSize;
|
|
if (k1 > 0 && k1 + itemstack3.stackSize <= itemstack3.getMaxStackSize()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void givePlayer(ItemStack item, EntityPlayer entityplayer) {//set item bought to the held mouse item
|
|
ItemStack itemstack3 = entityplayer.inventory.getItemStack();
|
|
if (itemstack3 == null) {
|
|
entityplayer.inventory.setItemStack(item);
|
|
} else if (NoppesUtilPlayer.compareItems(itemstack3, item, false, false)) {
|
|
|
|
int k1 = item.stackSize;
|
|
if (k1 > 0 && k1 + itemstack3.stackSize <= itemstack3.getMaxStackSize()) {
|
|
itemstack3.stackSize += k1;
|
|
}
|
|
}
|
|
}
|
|
}
|