package com.lyndir.omicron.api; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; import static com.lyndir.omicron.api.Security.*; import com.google.common.base.Preconditions; import com.google.common.collect.*; import com.lyndir.lhunath.opal.math.Vec2; import com.lyndir.lhunath.opal.system.util.*; import com.lyndir.omicron.api.util.Maybe; import java.util.*; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * <i>10 07, 2012</i> * * @author lhunath */ @ObjectMeta(useFor = { }) public class Tile extends MetaObject implements ITile { @Nullable private GameObject contents; @ObjectMeta(useFor = ObjectMeta.For.all) private final Vec2 position; @ObjectMeta(useFor = ObjectMeta.For.all) private final Level level; @ObjectMeta(useFor = ObjectMeta.For.all) private final Map<ResourceType, Integer> resourceQuantities = Collections.synchronizedMap( new EnumMap<>( ResourceType.class ) ); Tile(final Vec2 position, final Level level) { this.position = position; this.level = level; } Tile(final int x, final int y, final Level level) { this( Vec2.create( x, y ), level ); } @Override public int hashCode() { return Objects.hash( position, level ); } @Override public boolean equals(final Object obj) { if (obj == this) return true; if (!(obj instanceof Tile)) return false; Tile o = (Tile) obj; return position.equals( o.position ) && level.equals( o.level ); } @Override @Nonnull public Maybe<? extends IGameObject> getContents() { if (!isGod() && !currentPlayer().canObserve( this ).isTrue()) // Cannot observe tile. return Maybe.unknown(); return Maybe.ofNullable( contents ); } void setContents(@Nullable final GameObject contents) { if (contents != null) Preconditions.checkState( this.contents == null || this.contents.equals( contents ), "Cannot put object on tile that is not empty: %s", this ); replaceContents( contents ); } void replaceContents(@SuppressWarnings("ParameterHidesMemberVariable") @Nullable final GameObject contents) { Change.From<IGameObject> contentsChange = Change.<IGameObject>from( this.contents ); this.contents = contents; if (contents != null) contents.setLocation( this ); Security.currentGame().getController().fireIfObservable( this ) // .onTileContents( this, contentsChange.to( this.contents ) ); } @Override public Vec2 getPosition() { return position; } @Override public Level getLevel() { return level; } void setResourceQuantity(final ResourceType resourceType, final int resourceQuantity) { Preconditions.checkArgument( resourceQuantity >= 0, "Resource quantity cannot be less than zero: %s", resourceQuantity ); ChangeInt.From quantityChange; if (resourceQuantity > 0) quantityChange = ChangeInt.from( resourceQuantities.put( resourceType, resourceQuantity ) ); else quantityChange = ChangeInt.from( resourceQuantities.remove( resourceType ) ); Security.currentGame().getController().fireIfObservable( this ) // .onTileResources( this, resourceType, quantityChange.to( resourceQuantity ) ); } void addResourceQuantity(final ResourceType resourceType, final int resourceQuantity) { setResourceQuantity( resourceType, ifNotNullElse( resourceQuantities.get( resourceType ), 0 ) + resourceQuantity ); } @Override public ImmutableMap<ResourceType, Maybe<Integer>> getQuantitiesByResourceType() { boolean observable = isGod() || currentPlayer().canObserve( this ).isTrue(); ImmutableMap.Builder<ResourceType, Maybe<Integer>> builder = ImmutableMap.builder(); for (final ResourceType resourceType : ResourceType.values()) if (observable) builder.put( resourceType, Maybe.ofNullable( resourceQuantities.get( resourceType ) ) ); else builder.put( resourceType, Maybe.unknown() ); return Maps.immutableEnumMap( builder.build() ); } @Override public Optional<? extends IPlayer> getOwner() { return contents == null? Optional.empty(): contents.getOwner(); } @Override public Maybe<? extends ITile> getLocation() { boolean observable = !isGod() && !currentPlayer().canObserve( this ).isTrue(); return observable? Maybe.of( this ): Maybe.unknown(); } public static Tile cast(final ITile tile) { return (Tile) tile; } @SuppressWarnings("unchecked") public static Iterable<Tile> cast(final Iterable<? extends ITile> neighbours) { return (Iterable<Tile>) neighbours; } }