diff --git a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/CreditObjectRadial.groovy b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/CreditObjectRadial.groovy index 7d6e1c40d..987d2eb1e 100644 --- a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/CreditObjectRadial.groovy +++ b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/CreditObjectRadial.groovy @@ -34,7 +34,7 @@ import com.projectswg.holocore.resources.objects.SWGObject import com.projectswg.holocore.resources.player.Player import com.projectswg.holocore.scripts.radial.RadialHandlerInterface -class CreditObjectRadial extends SWGObjectRadial implements RadialHandlerInterface { +class CreditObjectRadial extends SWGObjectRadial { def getOptions(List options, Player player, SWGObject target) { options.add(new RadialOption(RadialItem.TRANSFER_CREDITS_TO_BANK_ACCOUNT)) diff --git a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/SWGObjectRadial.groovy b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/SWGObjectRadial.groovy index d1eae1136..0a2988328 100644 --- a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/SWGObjectRadial.groovy +++ b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/SWGObjectRadial.groovy @@ -29,18 +29,116 @@ package com.projectswg.holocore.scripts.radial.object import com.projectswg.common.data.radial.RadialItem import com.projectswg.common.data.radial.RadialOption +import com.projectswg.holocore.intents.chat.SystemMessageIntent +import com.projectswg.holocore.intents.object.ContainerTransferIntent +import com.projectswg.holocore.intents.object.ObjectCreatedIntent import com.projectswg.holocore.resources.objects.SWGObject +import com.projectswg.holocore.resources.objects.tangible.TangibleObject import com.projectswg.holocore.resources.player.Player +import com.projectswg.holocore.resources.sui.SuiInputBox import com.projectswg.holocore.scripts.radial.RadialHandlerInterface +import com.projectswg.holocore.services.objects.ObjectCreator class SWGObjectRadial implements RadialHandlerInterface { def getOptions(List options, Player player, SWGObject target) { + stackOptions(options, target) + } + + def stackOptions(List options, SWGObject target) { + // Verify that target is a tangible + if (target == null || target.getClass() != TangibleObject.class) + return + // Check if the target is not in a container then show no radial options + SWGObject container = target.getParent() + + if (container == null) { + return + } + + def tangibleTarget = (TangibleObject) target + + if (tangibleTarget.getCounter() < 1) { + return + } + + def splitOption = new RadialOption(RadialItem.SERVER_MENU49) + def stackOption = new RadialOption(RadialItem.SERVER_MENU50) + + splitOption.setOverriddenText("@autostack:unstack") + stackOption.setOverriddenText("@autostack:stack") + + options.add(splitOption) + options.add(stackOption) + } + + def split(Player player, SWGObject target) { + // Create input-window + def window = new SuiInputBox("@autostack:unstack", "@autostack:stacksize") + + // Handle button selection + window.addOkButtonCallback("split", {event, parameters -> + String input = SuiInputBox.getEnteredText(parameters) + TangibleObject originalStack = (TangibleObject) target + + try { + int newStackSize = Integer.parseInt(input) + int counter = originalStack.getCounter() + int oldStackSize = counter - newStackSize + + if (oldStackSize < 1) { + SystemMessageIntent.broadcastPersonal(player, "@autostack:zero_size") + return + } else if (oldStackSize >= counter) { + SystemMessageIntent.broadcastPersonal(player, "@autostack:too_big") + return + } + + // Check inventory volume + SWGObject container = target.getParent() + + if (container.getVolume() + 1 > container.getMaxContainerSize()) { + SystemMessageIntent.broadcastPersonal(player, "@autostack:full_container") + return + } + + // Create new object using same template + // TODO needs to copy other stuff as well, such as customization variables and object attributes + String template = originalStack.getTemplate() + TangibleObject newStack = (TangibleObject) ObjectCreator.createObjectFromTemplate(template) + + // Adjust stack sizes + originalStack.setCounter(oldStackSize) + newStack.setCounter(newStackSize) + + // We don't use moveToContainer, because that would trigger auto-stacking. + newStack.systemMove(container) + + ContainerTransferIntent.broadcast(newStack, null, container) + + ObjectCreatedIntent.broadcast(newStack) + } catch (NumberFormatException e) { + SystemMessageIntent.broadcastPersonal(player, "@autostack:number_format_wrong") + } + }) + + // Display the window + window.display(player) + } + + def stack(SWGObject target) { + target.moveToContainer(target.getParent()) // Triggers stacking, if applicable } def handleSelection(Player player, SWGObject target, RadialItem selection) { - + switch (selection) { + case RadialItem.SERVER_MENU49: + split(player, target) + break + case RadialItem.SERVER_MENU50: + stack(target) + break + } } - } diff --git a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/UsableObjectRadial.groovy b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/UsableObjectRadial.groovy index c076b2e9c..20a049565 100644 --- a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/UsableObjectRadial.groovy +++ b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/UsableObjectRadial.groovy @@ -35,6 +35,7 @@ import com.projectswg.holocore.resources.player.Player class UsableObjectRadial extends SWGObjectRadial { def getOptions(List options, Player player, SWGObject target) { + super.getOptions(options, player, target) options.add(new RadialOption(RadialItem.ITEM_USE)) options.add(new RadialOption(RadialItem.EXAMINE)) } diff --git a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/survey/ObjectSurveyToolRadial.groovy b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/survey/ObjectSurveyToolRadial.groovy index 4ae0ab253..04b9cfef4 100644 --- a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/survey/ObjectSurveyToolRadial.groovy +++ b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/survey/ObjectSurveyToolRadial.groovy @@ -33,15 +33,15 @@ import com.projectswg.holocore.intents.crafting.survey.StartSurveyToolIntent import com.projectswg.holocore.resources.objects.SWGObject import com.projectswg.holocore.resources.player.Player import com.projectswg.holocore.scripts.radial.RadialHandlerInterface +import com.projectswg.holocore.scripts.radial.object.UsableObjectRadial -class ObjectSurveyToolRadial implements RadialHandlerInterface { - - def getOptions(List options, Player player, SWGObject target) { - options.add(new RadialOption(RadialItem.ITEM_USE)) - options.add(new RadialOption(RadialItem.EXAMINE)) - } +class ObjectSurveyToolRadial extends UsableObjectRadial { def handleSelection(Player player, SWGObject target, RadialItem selection) { + if (selection != RadialItem.ITEM_USE) { + return + } + new StartSurveyToolIntent(player.getCreatureObject(), target).broadcast() } diff --git a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/uniform/ObjectUniformBoxRadial.groovy b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/uniform/ObjectUniformBoxRadial.groovy index 92485a318..7de0d7116 100644 --- a/src/main/groovy/com/projectswg/holocore/scripts/radial/object/uniform/ObjectUniformBoxRadial.groovy +++ b/src/main/groovy/com/projectswg/holocore/scripts/radial/object/uniform/ObjectUniformBoxRadial.groovy @@ -35,7 +35,7 @@ import com.projectswg.holocore.resources.player.Player import com.projectswg.holocore.scripts.radial.RadialHandlerInterface import com.projectswg.holocore.scripts.radial.object.SWGObjectRadial -class ObjectUniformBoxRadial extends SWGObjectRadial implements RadialHandlerInterface { +class ObjectUniformBoxRadial extends SWGObjectRadial { def handleSelection(Player player, SWGObject target, RadialItem selection) { DestroyObjectIntent.broadcast(target) diff --git a/src/main/groovy/com/projectswg/holocore/scripts/radial/terminal/TerminalCharacterBuilderRadial.groovy b/src/main/groovy/com/projectswg/holocore/scripts/radial/terminal/TerminalCharacterBuilderRadial.groovy index 0e5c4eaa5..cbc08d3e9 100644 --- a/src/main/groovy/com/projectswg/holocore/scripts/radial/terminal/TerminalCharacterBuilderRadial.groovy +++ b/src/main/groovy/com/projectswg/holocore/scripts/radial/terminal/TerminalCharacterBuilderRadial.groovy @@ -33,13 +33,16 @@ import com.projectswg.common.data.radial.RadialItem import com.projectswg.common.data.radial.RadialOption import com.projectswg.common.data.sui.SuiEvent import com.projectswg.holocore.intents.object.CreateStaticItemIntent +import com.projectswg.holocore.intents.object.ObjectCreatedIntent import com.projectswg.holocore.intents.object.ObjectTeleportIntent import com.projectswg.holocore.resources.containers.ContainerPermissionsType import com.projectswg.holocore.resources.objects.SWGObject +import com.projectswg.holocore.resources.objects.tangible.TangibleObject import com.projectswg.holocore.resources.player.Player import com.projectswg.holocore.resources.sui.SuiButtons import com.projectswg.holocore.resources.sui.SuiListBox import com.projectswg.holocore.scripts.radial.RadialHandlerInterface +import com.projectswg.holocore.services.objects.ObjectCreator import com.projectswg.holocore.services.objects.StaticItemService class TerminalCharacterBuilderRadial implements RadialHandlerInterface { @@ -59,6 +62,7 @@ class TerminalCharacterBuilderRadial implements RadialHandlerInterface { listBox.addListItem("Wearables") listBox.addListItem("Tools") listBox.addListItem("Travel") + listBox.addListItem("Stack test") listBox.addCallback(SuiEvent.OK_PRESSED, "handleCategorySelection", { event, parameters -> handleCategorySelection(player, parameters) }) listBox.display(player) @@ -76,6 +80,7 @@ class TerminalCharacterBuilderRadial implements RadialHandlerInterface { case 2: handleWearables(player); break case 3: handleTools(player); break case 4: handleTravel(player); break + case 5: handleStackTest(player); break } } @@ -1387,4 +1392,15 @@ class TerminalCharacterBuilderRadial implements RadialHandlerInterface { static def handleYavGeoCave(Player player) { new ObjectTeleportIntent(player.getCreatureObject(), new Location(-6485d, 83d, -446d, Terrain.YAVIN4)).broadcast() } + + static def handleStackTest(Player player) { + def stackObject = ObjectCreator.createObjectFromTemplate("object/tangible/dice/shared_eqp_chance_cube.iff", TangibleObject.class) + def creature = player.getCreatureObject() + def inventory = creature.getSlottedObject("inventory") + + stackObject.setCounter(6) + stackObject.moveToContainer(inventory) + + ObjectCreatedIntent.broadcast(stackObject) + } } diff --git a/src/main/java/com/projectswg/holocore/resources/commands/callbacks/AttributesCmdCallback.java b/src/main/java/com/projectswg/holocore/resources/commands/callbacks/AttributesCmdCallback.java index 385af3fef..06af83d14 100644 --- a/src/main/java/com/projectswg/holocore/resources/commands/callbacks/AttributesCmdCallback.java +++ b/src/main/java/com/projectswg/holocore/resources/commands/callbacks/AttributesCmdCallback.java @@ -26,8 +26,6 @@ ***********************************************************************************/ package com.projectswg.holocore.resources.commands.callbacks; -import java.util.Map; - import com.projectswg.common.network.packets.swg.zone.spatial.AttributeListMessage; import com.projectswg.holocore.resources.commands.ICmdCallback; @@ -52,11 +50,6 @@ public class AttributesCmdCallback implements ICmdCallback { } private void handleSendItemAttributes(SWGObject object, Player player) { - Map attributes = object.getAttributes(); - if (attributes.size() == 0) - attributes.put("", ""); - - AttributeListMessage message = new AttributeListMessage(object.getObjectId(), attributes); - player.sendPacket(message); + player.sendPacket(new AttributeListMessage(object.getObjectId(), object.getAttributes())); } } diff --git a/src/main/java/com/projectswg/holocore/resources/objects/SWGObject.java b/src/main/java/com/projectswg/holocore/resources/objects/SWGObject.java index a894007df..428854e9c 100644 --- a/src/main/java/com/projectswg/holocore/resources/objects/SWGObject.java +++ b/src/main/java/com/projectswg/holocore/resources/objects/SWGObject.java @@ -546,7 +546,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable getAttributes() { - return attributes; + return Collections.unmodifiableMap(attributes); } public int getContainerType() { diff --git a/src/main/java/com/projectswg/holocore/resources/objects/tangible/TangibleObject.java b/src/main/java/com/projectswg/holocore/resources/objects/tangible/TangibleObject.java index e4502f1ef..2bc8c4576 100644 --- a/src/main/java/com/projectswg/holocore/resources/objects/tangible/TangibleObject.java +++ b/src/main/java/com/projectswg/holocore/resources/objects/tangible/TangibleObject.java @@ -26,6 +26,9 @@ ***********************************************************************************/ package com.projectswg.holocore.resources.objects.tangible; +import java.util.Map; +import java.util.Set; + import com.projectswg.common.data.customization.CustomizationString; import com.projectswg.common.data.customization.CustomizationVariable; import com.projectswg.common.data.encodables.tangible.PvpFaction; @@ -37,6 +40,7 @@ import com.projectswg.common.network.NetBufferStream; import com.projectswg.common.network.packets.swg.zone.baselines.Baseline.BaselineType; import com.projectswg.holocore.intents.FactionIntent; import com.projectswg.holocore.intents.FactionIntent.FactionIntentType; +import com.projectswg.holocore.intents.object.DestroyObjectIntent; import com.projectswg.holocore.resources.collections.SWGMap; import com.projectswg.holocore.resources.collections.SWGSet; import com.projectswg.holocore.resources.network.BaselineBuilder; @@ -44,8 +48,6 @@ import com.projectswg.holocore.resources.objects.SWGObject; import com.projectswg.holocore.resources.objects.creature.CreatureObject; import com.projectswg.holocore.resources.player.Player; -import java.util.Set; - public class TangibleObject extends SWGObject { private CustomizationString appearanceData = new CustomizationString(); @@ -75,6 +77,34 @@ public class TangibleObject extends SWGObject { super(objectId, objectType); } + @Override + public void moveToContainer(SWGObject newParent) { + // Check if object is stackable + if (newParent != null && counter > 0) { + // Scan container for matching stackable item + String ourTemplate = getTemplate(); + Map ourAttributes = getAttributes(); + + for (SWGObject candidate : newParent.getContainedObjects()) { + String theirTemplate = candidate.getTemplate(); + Map theirAttributes = candidate.getAttributes(); + + if (this != candidate && candidate instanceof TangibleObject && ourTemplate.equals(theirTemplate) && ourAttributes.equals(theirAttributes)) { + DestroyObjectIntent.broadcast(this); + + // Increase stack count on matching stackable item + TangibleObject tangibleMatch = (TangibleObject) candidate; + int theirCounter = tangibleMatch.getCounter(); + + tangibleMatch.setCounter(theirCounter + counter); + return; // Stackable and matching item was found + } + } + } + + super.moveToContainer(newParent); // Not stackable, use default behavior + } + public int getMaxHitPoints() { return maxHitPoints; }