All Downloads are FREE. Search and download functionalities are using the official Maven repository.

simple.client.entity.ClientEntity Maven / Gradle / Ivy

The newest version!
package simple.client.entity;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import marauroa.common.game.RPAction;
import marauroa.common.game.RPObject;
import marauroa.common.game.RPSlot;
import simple.server.core.event.RPObjectChangeListener;

/**
 *
 * @author Javier A. Ortiz Bultron
 */
public class ClientEntity implements RPObjectChangeListener {

    /**
     * Animated property.
     */
    public static final Property PROP_ANIMATED = new Property();
    /**
     * ClientEntity class/subclass property.
     */
    public static final Property PROP_CLASS = new Property();
    /**
     * Name property.
     */
    public static final Property PROP_NAME = new Property();
    /**
     * Position property.
     */
    public static final Property PROP_POSITION = new Property();
    /**
     * Size property.
     */
    public static final Property PROP_SIZE = new Property();
    /**
     * Title property.
     */
    public static final Property PROP_TITLE = new Property();
    /**
     * Type property.
     */
    public static final Property PROP_TYPE = new Property();
    /**
     * Visibility property.
     */
    public static final Property PROP_VISIBILITY = new Property();
    /**
     * an array of sounds. out of these randomnly chosen sounds are played while
     * moving.
     */
    protected String[] moveSounds;
    /** The current x location of this entity. */
    protected double x;
    /** The current y location of this entity. */
    protected double y;
    /**
     * The entity width.
     */
    private double width;
    /**
     * The entity height.
     */
    private double height;
    /**
     * Amount of entity-to-entity resistance (0-100).
     */
    protected int resistance;
    /**
     * The entity visibility.
     */
    protected int visibility;
    /**
     * Change listeners.
     */
    protected EntityChangeListener[] changeListeners;
    /** The arianne object associated with this game entity. */
    protected RPObject rpObject;
    /**
     * The entity class.
     */
    protected String clazz;
    /**
     * The entity name.
     */
    protected String name;
    /**
     * The entity sub-class.
     */
    protected String subclazz;
    /**
     * The entity title.
     */
    protected String title;
    /**
     * The entity type.
     */
    protected String type;
    /**
     * Defines the distance in which the entity is heard by Player.
     */
    protected double audibleRange = Double.POSITIVE_INFINITY;
    /**
     * Quick work-around to prevent fireMovementEvent() from calling in
     * onChangedAdded() from other initialize() hack.
     */
    protected boolean inAdd;

    ClientEntity() {
        clazz = null;
        name = null;
        subclazz = null;
        title = null;
        type = null;
        x = 0.0;
        y = 0.0;

        changeListeners = new EntityChangeListener[0];
    }

    //
    // ClientEntity
    //
    /**
     * Add a change listener.
     *
     * @param listener
     *            The listener.
     */
    public void addChangeListener(final EntityChangeListener listener) {
        EntityChangeListener[] newListeners;

        int len = changeListeners.length;

        newListeners = new EntityChangeListener[len + 1];
        System.arraycopy(changeListeners, 0, newListeners, 0, len);
        newListeners[len] = listener;

        changeListeners = newListeners;
    }

    /**
     * Fill the action with the entity's target info. This will set the
     * baseobject, baseslot and
     * baseitem respective the target attributes
     * for uncontained objects.
     *
     * @param action
     *            The RP action.
     */
    public void fillTargetInfo(RPAction action) {
        int id = rpObject.getID().getObjectID();

        if (rpObject.isContained()) {
            action.put("baseobject",
                    rpObject.getContainer().getID().getObjectID());
            action.put("baseslot", rpObject.getContainerSlot().getName());
            action.put("baseitem", id);
        } else {
            StringBuilder target = new StringBuilder();
            target.append(Integer.toString(id));
            action.put("target", target.toString());
        }
    }

    /**
     * Fire change to all registered listeners.
     *
     * @param property
     *            The changed property.
     */
    protected void fireChange(final Property property) {
        EntityChangeListener[] listeners = changeListeners;

        for (EntityChangeListener l : listeners) {
            l.entityChanged(this, property);
        }
    }

    /**
     * Get the area the entity occupies.
     *
     * @return A rectange (in world coordinate units).
     */
    public Rectangle2D getArea() {
        return new Rectangle.Double(getX(), getY(), getWidth(), getHeight());
    }

    /**
     * Get the entity visibility.
     *
     * @return The entity visibility (0 - 100).
     */
    public int getVisibility() {
        return visibility;
    }

    /**
     * Get the entity height.
     *
     * @return The height.
     */
    public double getHeight() {
        return height;
    }

    /** @return the represented arianne object id. */
    public final RPObject.ID getID() {
        if (rpObject == null) {
            return null;
        } else {
            return rpObject.getID();
        }
    }

    /**
     * Get the entity class.
     *
     * @return The entity class.
     */
    public String getEntityClass() {
        return clazz;
    }

    /**
     * Get the name.
     *
     * @return The name.
     */
    public String getName() {
        return name;
    }

    /**
     * Get the entity sub-class.
     *
     * @return The entity sub-class.
     */
    public String getEntitySubClass() {
        return subclazz;
    }

    /**
     * Get the nicely formatted entity title.
     *
     * This searches the follow attribute order: title, name (w/o underscore),
     * type (w/o underscore).
     *
     * @return The title, or null if unknown.
     */
    public String getTitle() {
        if (title != null) {
            return title;
        } else if (name != null) {
            return name;
        } else if (type != null) {
            return type;
        } else {
            return null;
        }
    }

    /**
     * Get the entity type.
     *
     * @return The type.
     */
    public String getType() {
        return type;
    }

    /**
     * Get the X coordinate.
     *
     * @return The X coordinate.
     */
    public double getX() {
        return x;
    }

    /**
     * Get the Y coordinate.
     *
     * @return The Y coordinate.
     */
    public double getY() {
        return y;
    }

    /**
     * Get the RPObject this represents.
     *
     * @return The RPObject.
     */
    public RPObject getRPObject() {
        return rpObject;
    }

    /**
     * Get the entity width.
     *
     * @return The width.
     */
    public double getWidth() {
        return width;
    }

    /**
     * Determine if this entity represents an instance of an RPClass.
     *
     * @param clazz
     *            The class name.
     *
     * @return true if the entity represents that class, or a
     *         subclass.
     */
    public boolean isInstanceOf(String clazz) {
        return rpObject.getRPClass().subclassOf(clazz);
    }

    /**
     * Determine if this entity is on the ground.
     *
     * @return true if the entity is on the ground.
     */
    public boolean isOnGround() {
        return !rpObject.isContained();
    }

    /**
     * @return the absolute world area (coordinates) to which audibility of
     * entity sounds is confined. Returns null if confines do not exist
     * (audible everywhere).
     */
    public Rectangle2D getAudibleArea() {
        if (audibleRange == Double.POSITIVE_INFINITY) {
            return null;
        }

        double tempWidth = audibleRange * 2;
        return new Rectangle2D.Double(getX() - audibleRange, getY() - audibleRange, tempWidth, tempWidth);
    }

    /**
     * Sets the audible range as radius distance from this entity's position,
     * expressed in coordinate units. This reflects an abstract capacity of this
     * unit to emit sounds and influences the result of
     * getAudibleArea().
     *
     * @param range
     *            double audibility area radius in coordinate units
     */
    public void setAudibleRange(final double range) {
        audibleRange = range;
    }

    /**
     * Process attribute changes that may affect positioning. This is needed
     * because different entities may want to process coordinate changes more
     * gracefully.
     *
     * @param base
     *            The previous values.
     * @param diff
     *            The changes.
     */
    protected void processPositioning(final RPObject base, final RPObject diff) {
        boolean moved = false;

        if (diff.has("x")) {
            int nx = diff.getInt("x");

            if (nx != x) {
                x = nx;
                moved = true;
            }
        }

        if (diff.has("y")) {
            int ny = diff.getInt("y");

            if (ny != y) {
                y = ny;
                moved = true;
            }
        }

        if (moved) {
            onPosition(x, y);
        }
    }

    /**
     * When the entity's position changed.
     *
     * @param x
     *            The new X coordinate.
     * @param y
     *            The new Y coordinate.
     */
    protected void onPosition(final double x, final double y) {
        fireChange(PROP_POSITION);
    }

    /**
     * Get the resistance this has on other entities (0-100).
     *
     * @return The resistance.
     */
    public int getResistance() {
        return resistance;
    }

    /**
     * Get the amount of resistance between this and another entity (0-100).
     *
     * @param entity
     *            The entity to check against.
     *
     * @return The effective resistance.
     */
    public int getResistance(final ClientEntity entity) {
        return ((getResistance() * entity.getResistance()) / 100);
    }

    /**
     * Gets the slot specified by name.
     * @param name of the slot
     *
     * @return    the specified slot or null if the entity does not
     * have this slot
     */
    public RPSlot getSlot(final String name) {
        if (rpObject.hasSlot(name)) {
            return rpObject.getSlot(name);
        }

        return null;
    }

    /**
     * Initialize this entity for an object.
     *
     * @param object
     *            The object.
     *
     * @see #release()
     */
    public void initialize(final RPObject object) {
        rpObject = object;

        /*
         * Class
         */
        if (object.has("class")) {
            clazz = object.get("class");
        } else {
            clazz = null;
        }

        /*
         * Name
         */
        if (object.has("name")) {
            name = object.get("name");
        } else {
            name = null;
        }

        /*
         * Sub-Class
         */
        if (object.has("subclass")) {
            subclazz = object.get("subclass");
        } else {
            subclazz = null;
        }

        /*
         * Size
         */
        if (object.has("height")) {
            height = object.getDouble("height");
        } else {
            height = 1.0;
        }

        if (object.has("width")) {
            width = object.getDouble("width");
        } else {
            width = 1.0;
        }

        /*
         * Title
         */
        if (object.has("title")) {
            title = object.get("title");
        } else {
            title = null;
        }

        /*
         * Type
         */
        if (object.has("type")) {
            type = object.get("type");
        } else {
            type = null;
        }

        /*
         * Resistance
         */
        if (object.has("resistance")) {
            resistance = object.getInt("resistance");
        } else {
            resistance = 0;
        }

        /*
         * Visibility
         */
        if (object.has("visibility")) {
            visibility = object.getInt("visibility");
        } else {
            visibility = 100;
        }

        /*
         * Coordinates
         */
        if (object.has("x")) {
            x = object.getInt("x");
        } else {
            x = 0.0;
        }

        if (object.has("y")) {
            y = object.getInt("y");
        } else {
            y = 0.0;
        }

        /*
         * Notify placement
         */
        onPosition(x, y);

        inAdd = true;
        onChangedAdded(new RPObject(), object);
        inAdd = false;
    }

    /**
     * Determine if this is an obstacle for another entity.
     *
     * @param entity
     *            The entity to check against.
     *
     * @return true the entity can not enter this entity's area.
     */
    public boolean isObstacle(final ClientEntity entity) {
        // >= 30% resistance = stall on client (simulates resistance)
        return ((entity != this) && (getResistance(entity) >= 30));
    }

    /**
     * Release this entity. This should clean anything that isn't automatically
     * released (such as unregister callbacks, cancel external operations, etc).
     *
     * @see #initialize(RPObject)
     */
    public void release() {
        
    }

    /**
     * Remove a change listener.
     *
     * @param listener
     *            The listener.
     */
    public void removeChangeListener(final EntityChangeListener listener) {
        EntityChangeListener[] newListeners;
        int idx;

        idx = changeListeners.length;

        while (idx-- != 0) {
            if (changeListeners[idx] == listener) {
                newListeners = new EntityChangeListener[changeListeners.length - 1];

                if (idx != 0) {
                    System.arraycopy(changeListeners, 0, newListeners, 0, idx);
                }

                if (++idx != changeListeners.length) {
                    System.arraycopy(changeListeners, idx, newListeners,
                            idx - 1, changeListeners.length - idx);
                }

                changeListeners = newListeners;
                break;
            }
        }
    }

    /**
     * Update cycle.
     *
     * @param delta
     *            The time (in ms) since last call.
     */
    public void update(final int delta) {
    }

    //
    // RPObjectChangeListener
    //
    /**
     * An object was added.
     *
     * @param object
     *            The object.
     */
    @Override
    public final void onAdded(final RPObject object) {
        // DEPRECATED - Moving to different listener. Use initialize().
    }

    /**
     * The object added/changed attribute(s).
     *
     * @param object
     *            The base object.
     * @param changes
     *            The changes.
     */
    @Override
    public void onChangedAdded(final RPObject object, final RPObject changes) {
        if (inAdd) {
            return;
        }

        /*
         * Class
         */
        if (changes.has("class")) {
            clazz = changes.get("class");
            fireChange(PROP_CLASS);
        }

        /*
         * Name
         */
        if (changes.has("name")) {
            name = changes.get("name");
            fireChange(PROP_NAME);
            fireChange(PROP_TITLE);
        }

        /*
         * Sub-Class
         */
        if (changes.has("subclass")) {
            subclazz = changes.get("subclass");
            fireChange(PROP_CLASS);
        }

        /*
         * Size
         */
        boolean sizeChange = false;

        if (changes.has("width")) {
            width = changes.getDouble("width");
            sizeChange = true;
        }

        if (changes.has("height")) {
            height = changes.getDouble("height");
            sizeChange = true;
        }

        if (sizeChange) {
            fireChange(PROP_SIZE);
        }

        /*
         * Title
         */
        if (changes.has("title")) {
            title = changes.get("title");
            fireChange(PROP_TITLE);
        }

        /*
         * Type
         */
        if (changes.has("type")) {
            type = changes.get("type");
            fireChange(PROP_TYPE);
            fireChange(PROP_TITLE);
        }

        /*
         * Resistance
         */
        if (changes.has("resistance")) {
            resistance = changes.getInt("resistance");
        }

        /*
         * ClientEntity visibility
         */
        if (changes.has("visibility")) {
            visibility = changes.getInt("visibility");
            fireChange(PROP_VISIBILITY);
        }

        /*
         * Position changes
         */
        processPositioning(object, changes);
    }

    /**
     * The object removed attribute(s).
     *
     * @param object
     *            The base object.
     * @param changes
     *            The changes.
     */
    @Override
    public void onChangedRemoved(final RPObject object, final RPObject changes) {
        /*
         * Class
         */
        if (changes.has("class")) {
            clazz = null;
            fireChange(PROP_CLASS);
        }

        /*
         * Name
         */
        if (changes.has("name")) {
            name = null;
            fireChange(PROP_NAME);
            fireChange(PROP_TITLE);
        }

        /*
         * Sub-Class
         */
        if (changes.has("subclass")) {
            subclazz = null;
            fireChange(PROP_CLASS);
        }

        /*
         * Size
         */
        boolean sizeChange = false;

        if (changes.has("width")) {
            width = 1.0;
            sizeChange = true;
        }

        if (changes.has("height")) {
            height = 1.0;
            sizeChange = true;
        }

        if (sizeChange) {
            fireChange(PROP_SIZE);
        }

        /*
         * Title
         */
        if (changes.has("title")) {
            title = null;
            fireChange(PROP_TITLE);
        }

        /*
         * Type
         */
        if (changes.has("type")) {
            type = null;
            fireChange(PROP_TYPE);
            fireChange(PROP_TITLE);
        }

        /*
         * Resistance
         */
        if (changes.has("resistance")) {
            resistance = 0;
        }

        /*
         * Visibility
         */
        if (changes.has("visibility")) {
            visibility = 100;
            fireChange(PROP_VISIBILITY);
        }
    }

    /**
     * An object was removed.
     *
     * @param object
     *            The object.
     * @deprecated Moving to different listener. Use release().
     */
    @Deprecated
    @Override
    public final void onRemoved(final RPObject object) {
    }

    /**
     * A slot object was added.
     *
     * @param object
     *            The container object.
     * @param slotName
     *            The slot name.
     * @param sobject
     *            The slot object.
     */
    @Override
    public void onSlotAdded(final RPObject object, final String slotName,
            final RPObject sobject) {
    }

    /**
     * A slot object added/changed attribute(s).
     *
     * @param object
     *            The base container object.
     * @param slotName
     *            The container's slot name.
     * @param sobject
     *            The slot object.
     * @param schanges
     *            The slot object changes.
     */
    @Override
    public void onSlotChangedAdded(final RPObject object,
            final String slotName, final RPObject sobject,
            final RPObject schanges) {
    }

    /**
     * A slot object removed attribute(s).
     *
     * @param object
     *            The base container object.
     * @param slotName
     *            The container's slot name.
     * @param sobject
     *            The slot object.
     * @param schanges
     *            The slot object changes.
     */
    @Override
    public void onSlotChangedRemoved(final RPObject object,
            final String slotName, final RPObject sobject,
            final RPObject schanges) {
    }

    /**
     * A slot object was removed.
     *
     * @param object
     *            The container object.
     * @param slotName
     *            The slot name.
     * @param sobject
     *            The slot object.
     */
    @Override
    public void onSlotRemoved(final RPObject object, final String slotName,
            final RPObject sobject) {
    }

    //
    // Object
    //
    @Override
    public String toString() {
        StringBuilder sbuf = new StringBuilder();

        sbuf.append(getClass().getName());

        /*
         * Technically not all entities have 'name', but enough to debug most
         * when used
         */
        if ((rpObject != null) && rpObject.has("name")) {
            sbuf.append('[');
            sbuf.append(rpObject.get("name"));
            sbuf.append(']');
        }

        sbuf.append('@');
        sbuf.append(System.identityHashCode(this));

        return sbuf.toString();
    }

    @Override
    public RPObject onRPEvent(RPObject object) {
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy