So yeah, I saw a post in the help section regarding this subject and I thought why not release a snippet. What this does is chain a life state on an item. I left the functionality of decreasing the health out, because this can be done in various ways. You still need to do the actual functionality of decreasing the health yourself.
Replace your item class with this. (What I did was make the class non-final, make some methods final which shouldn't be modified in sub-classes)
Code:
package net.ar.game.item;
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.Iterables;
/**
* The container class that represents an item that can be interacted with.
* @author lare96 <http://github.com/lare96>
*/
public class Item {
/**
* The identification of this item.
*/
private int id;
/**
* The quantity of this item.
*/
private int amount;
/**
* Creates a new {@link Item}.
* @param id the identification of this item.
* @param amount the quantity of this item.
*/
public Item(int id, int amount) {
if(amount < 0)
amount = 0;
this.id = id;
this.amount = amount;
}
/**
* Creates a new {@link Item} with an quantity of {@code 1}.
* @param id the identification of this item.
*/
public Item(int id) {
this(id, 1);
}
@Override
public final String toString() {
return "ITEM[id= " + id + ", amount= " + amount + ", degradable= " + degradable + "]";
}
@Override
public final int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + amount;
result = prime * result + id;
return result;
}
@Override
public final boolean equals(Object obj) {
if(this == obj)
return true;
if(obj == null)
return false;
if(!(obj instanceof Item))
return false;
Item other = (Item) obj;
if(amount != other.amount)
return false;
if(id != other.id)
return false;
return true;
}
/**
* Converts an int array into an {@link Item} array.
* @param id the array to convert into an item array.
* @return the item array containing the values from the int array.
*/
public static final Item[] convert(int... id) {
List<Item> items = new ArrayList<>();
for(int identifier : id) {
items.add(new Item(identifier));
}
return Iterables.toArray(items, Item.class);
}
/**
* Determines if {@code item} is valid. In other words, determines if
* {@code item} is not {@code null} and the {@link Item#id} and
* {@link Item#amount} are above {@code 0}.
* @param item the item to determine if valid.
* @return {@code true} if the item is valid, {@code false} otherwise.
*/
public static final boolean valid(Item item) {
return item != null && item.id > 0 && item.amount > 0;
}
/**
* A substitute for {@link Object#clone()} that creates another 'copy' of
* this instance. The created copy <i>safe</i> meaning it does not hold
* <b>any</b> references to the original instance.
* @return the copy of this instance that does not hold any references.
*/
public Item copy() {
return new Item(id, amount);
}
/**
* Increments the amount by {@code 1}.
*/
public final void incrementAmount() {
incrementAmountBy(1);
}
/**
* Decrements the amount by {@code 1}.
*/
public final void decrementAmount() {
decrementAmountBy(1);
}
/**
* Increments the amount by {@code amount}.
* @param amount the amount to increment by.
*/
public final void incrementAmountBy(int amount) {
this.amount += amount;
}
/**
* Decrements the amount by {@code amount}
* @param amount the amount to decrement by.
*/
public final void decrementAmountBy(int amount) {
if((this.amount - amount) < 1) {
this.amount = 0;
} else {
this.amount -= amount;
}
}
/**
* Gets the item definition for the item identifier.
* @return the item definition.
*/
public final ItemDefinition getDefinition() {
return ItemDefinition.DEFINITIONS[id];
}
/**
* Gets the identification of this item.
* @return the identification.
*/
public final int getId() {
return id;
}
/**
* Sets the identification of this item.
* @param id the new identification of this item.
*/
public final void setId(int id) {
this.id = id;
}
/**
* Gets the quantity of this item.
* @return the quantity.
*/
public final int getAmount() {
return amount;
}
/**
* Sets the quantity of this item.
* @param amount the new quantity of this item.
*/
public final void setAmount(int amount) {
if(amount < 0)
amount = 0;
this.amount = amount;
}
}
and here is the DegradableItem class.
Code:
package net.ar.game.item;
import java.util.function.Consumer;
import net.ar.game.character.player.Player;
/**
* Represents a single degradable item.
* @author <a href="http://www.rune-server.ee/members/stand+up/">Stand Up</a>
*/
public final class DegradableItem extends Item {
/**
* The health of this degradable item.
*/
private final int health;
/**
* The action to complete on degradation.
*/
private final Consumer<Player> action;
/**
* Constructs a new {@link DegradableItem}
* @param id {@link #getId()}
* @param health {@link #health}.
* @param action {@link #action}.
*/
public DegradableItem(int id, int health, Consumer<Player> action) {
super(id, 1);
this.health = health;
this.action = action;
this.setDegradable(true);
}
/**
* Constructs a new {@link DegradableItem}
* @param item the item this degradable instance is being created for.
* @param amount {@link #getAmount()}.
* @param health {@link #health}.
* @param action {@link #action}.
*/
public DegradableItem(Item item, int health, Consumer<Player> action) {
this(item.getId(), health, action);
}
@Override
public Item copy() {
return new DegradableItem(getId(), getAmount(), action);
}
/**
* @return the health
*/
public int getHealth() {
return health;
}
/**
* @return the action
*/
public Consumer<Player> getAction() {
return action;
}
}
I wouldn't suggest removing the consumer, you can accept the action when the item degrades. Perhaps overload the constructor to define a standard action on degradation.