/*
* Copyright 2016 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.rendering.nui.layers.ingame.inventory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.input.Keyboard;
import org.terasology.input.MouseInput;
import org.terasology.input.device.KeyboardDevice;
import org.terasology.logic.characters.CharacterComponent;
import org.terasology.logic.inventory.InventoryComponent;
import org.terasology.logic.inventory.InventoryManager;
import org.terasology.logic.inventory.InventoryUtils;
import org.terasology.logic.players.LocalPlayer;
import org.terasology.registry.CoreRegistry;
import org.terasology.rendering.nui.BaseInteractionListener;
import org.terasology.rendering.nui.Canvas;
import org.terasology.rendering.nui.InteractionListener;
import org.terasology.rendering.nui.LayoutConfig;
import org.terasology.rendering.nui.databinding.Binding;
import org.terasology.rendering.nui.databinding.DefaultBinding;
import org.terasology.rendering.nui.events.NUIMouseClickEvent;
import org.terasology.rendering.nui.events.NUIMouseWheelEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Adds interaction between an inventory slot and the player.
*/
public class InventoryCell extends ItemCell {
private static final Logger logger = LoggerFactory.getLogger(InventoryCell.class);
@LayoutConfig
private Binding<Integer> targetSlot = new DefaultBinding<>(0);
private Binding<EntityRef> targetInventory = new DefaultBinding<>(EntityRef.NULL);
private InteractionListener interactionListener = new BaseInteractionListener() {
@Override
public boolean onMouseClick(NUIMouseClickEvent event) {
MouseInput mouseButton = event.getMouseButton();
if (mouseButton == MouseInput.MOUSE_LEFT) {
if (event.getKeyboard().isKeyDown(Keyboard.Key.LEFT_SHIFT.getId())) {
moveItemSmartly();
} else {
swapItem();
}
} else if (mouseButton == MouseInput.MOUSE_RIGHT) {
int stackSize = InventoryUtils.getStackCount(getTargetItem());
if (stackSize > 0 && getTransferItem().getClass() != getTargetItem().getClass()) {
giveAmount((stackSize + 1) / 2);
} else {
int transferStackSize = InventoryUtils.getStackCount(getTransferItem());
if (transferStackSize > 0) {
takeAmount(1);
}
}
}
return true;
}
@Override
public boolean onMouseWheel(NUIMouseWheelEvent event) {
KeyboardDevice keyboard = event.getKeyboard();
int amount = (keyboard.isKeyDown(Keyboard.KeyId.RIGHT_CTRL) || keyboard.isKeyDown(Keyboard.KeyId.LEFT_CTRL)) ? 2 : 1;
//move item to the transfer slot
if (event.getWheelTurns() > 0) {
giveAmount(amount);
} else {
//get item from transfer slot
takeAmount(amount);
}
return true;
}
};
public InventoryCell() {
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.addInteractionRegion(interactionListener, icon.getTooltip(), canvas.getRegion());
}
@Override
public EntityRef getTargetItem() {
return InventoryUtils.getItemAt(getTargetInventory(), getTargetSlot());
}
public void bindTargetInventory(Binding<EntityRef> binding) {
targetInventory = binding;
}
public EntityRef getTargetInventory() {
return targetInventory.get();
}
public void setTargetInventory(EntityRef val) {
targetInventory.set(val);
}
public void bindTargetSlot(Binding<Integer> binding) {
targetSlot = binding;
}
public int getTargetSlot() {
return targetSlot.get();
}
public void setTargetSlot(int val) {
targetSlot.set(val);
}
private void swapItem() {
EntityRef characterEntity = CoreRegistry.get(LocalPlayer.class).getCharacterEntity();
InventoryManager inventoryManager = CoreRegistry.get(InventoryManager.class);
inventoryManager.switchItem(getTransferEntity(), characterEntity, 0, getTargetInventory(), getTargetSlot());
}
private void giveAmount(int amount) {
EntityRef characterEntity = CoreRegistry.get(LocalPlayer.class).getCharacterEntity();
InventoryManager inventoryManager = CoreRegistry.get(InventoryManager.class);
inventoryManager.moveItem(getTargetInventory(), characterEntity, getTargetSlot(), getTransferEntity(), 0, amount);
}
private void takeAmount(int amount) {
EntityRef characterEntity = CoreRegistry.get(LocalPlayer.class).getCharacterEntity();
InventoryManager inventoryManager = CoreRegistry.get(InventoryManager.class);
inventoryManager.moveItem(getTransferEntity(), characterEntity, 0, getTargetInventory(), getTargetSlot(), amount);
}
private void moveItemSmartly() {
EntityRef fromEntity = getTargetInventory();
int fromSlot = getTargetSlot();
EntityRef playerEntity = CoreRegistry.get(LocalPlayer.class).getCharacterEntity();
InventoryComponent playerInventory = playerEntity.getComponent(InventoryComponent.class);
if (playerInventory == null) {
return;
}
CharacterComponent characterComponent = playerEntity.getComponent(CharacterComponent.class);
if (characterComponent == null) {
logger.error("Character entity of player had no character component");
return;
}
int totalSlotCount = playerInventory.itemSlots.size();
EntityRef interactionTarget = characterComponent.predictedInteractionTarget;
InventoryComponent interactionTargetInventory = interactionTarget.getComponent(InventoryComponent.class);
EntityRef targetEntity;
List<Integer> toSlots = new ArrayList<>(totalSlotCount);
if (fromEntity.equals(playerEntity)) {
if (interactionTarget.exists() && interactionTargetInventory != null) {
targetEntity = interactionTarget;
toSlots = numbersBetween(0, interactionTargetInventory.itemSlots.size());
} else {
targetEntity = playerEntity;
int hudSlotCount = 10; // TODO use a constant once there is one
boolean fromHud = (fromSlot < hudSlotCount);
boolean toHud = !fromHud;
if (toHud) {
toSlots = numbersBetween(0, hudSlotCount);
} else {
toSlots = numbersBetween(hudSlotCount, totalSlotCount);
}
}
} else {
targetEntity = playerEntity;
toSlots = numbersBetween(0, totalSlotCount);
}
CoreRegistry.get(InventoryManager.class).moveItemToSlots(getTransferEntity(), fromEntity, fromSlot, targetEntity, toSlots);
}
private List<Integer> numbersBetween(int start, int exclusiveEnd) {
List<Integer> numbers = new ArrayList<>();
for (int number = start; number < exclusiveEnd; number++) {
numbers.add(number);
}
return numbers;
}
private EntityRef getTransferEntity() {
return CoreRegistry.get(LocalPlayer.class).getCharacterEntity().getComponent(CharacterComponent.class).movingItem;
}
private EntityRef getTransferItem() {
return InventoryUtils.getItemAt(getTransferEntity(), 0);
}
}