/*
* This file is part of Matter Overdrive
* Copyright (c) 2015., Simeon Radivoev, All rights reserved.
*
* Matter Overdrive is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Matter Overdrive is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Matter Overdrive. If not, see <http://www.gnu.org/licenses>.
*/
package matteroverdrive.starmap.data;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.network.ByteBufUtils;
import io.netty.buffer.ByteBuf;
import matteroverdrive.MatterOverdrive;
import matteroverdrive.Reference;
import matteroverdrive.api.starmap.*;
import matteroverdrive.client.data.Color;
import matteroverdrive.network.packet.client.starmap.PacketUpdatePlanet;
import matteroverdrive.starmap.GalaxyGenerator;
import matteroverdrive.starmap.gen.ISpaceBodyGen;
import matteroverdrive.util.MOStringHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.world.World;
import org.apache.logging.log4j.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Created by Simeon on 6/13/2015.
*/
public class Planet extends SpaceBody implements IInventory
{
//region Static Vars
public static final int SLOT_COUNT = 4;
//endregion
//region Private Vars
private Star star;
private float size,orbit;
private byte type;
private UUID ownerUUID;
private ItemStack[] inventory;
private List<ItemStack> buildings;
private List<ItemStack> fleet;
private boolean isDirty,homeworld,generated, needsClientUpdate;
private int buildingSpaces,fleetSpaces,seed;
//endregion
//region Constructors
public Planet()
{
super();
init();
}
public Planet(String name,int id)
{
super(name,id);
init();
}
//endregion
private void init()
{
inventory = new ItemStack[SLOT_COUNT];
buildings = new ArrayList();
fleet = new ArrayList();
}
//region Updates
public void update(World world)
{
if (!world.isRemote)
{
if (needsClientUpdate)
{
needsClientUpdate = false;
MatterOverdrive.packetPipeline.sendToDimention(new PacketUpdatePlanet(this), world);
}
for (int i = 0;i < SLOT_COUNT;i++)
{
List<String> buildInfo = new ArrayList<>();
ItemStack buildableStack = getStackInSlot(i);
if (buildableStack != null)
{
if (buildableStack.getItem() instanceof IBuilding)
{
//check if building can be built and if build start is above zero
//if below zero then the building was just put in
if (canBuild((IBuilding) buildableStack.getItem(), buildableStack, buildInfo)) {
if (((IBuilding) buildableStack.getItem()).isReadyToBuild(world, buildableStack, this)) {
buildings.add(buildableStack);
if (getOwnerUUID() != null)
{
((IBuilding)buildableStack.getItem()).setOwner(buildableStack,getOwnerUUID());
}
setInventorySlotContents(i, null);
onBuild((IBuilding)buildableStack.getItem(),buildableStack,world);
markDirty();
}
}else
{
//resets the build start time
((IBuilding) buildableStack.getItem()).setBuildStart(buildableStack,world.getTotalWorldTime());
markDirty();
}
}
else if (buildableStack.getItem() instanceof IShip)
{
//check if ship can be built and if build start is above zero
//if below zero then the ship was just put in
if (canBuild((IShip) buildableStack.getItem(), buildableStack, buildInfo)) {
if (((IShip) buildableStack.getItem()).isReadyToBuild(world, buildableStack, this)) {
fleet.add(buildableStack);
if (getOwnerUUID() != null)
{
((IShip) buildableStack.getItem()).setOwner(buildableStack, getOwnerUUID());
}
setInventorySlotContents(i, null);
onBuild((IShip) buildableStack.getItem(), buildableStack,world);
markDirty();
}
}else
{
//resets the build start time
((IShip) buildableStack.getItem()).setBuildStart(buildableStack,world.getTotalWorldTime());
markDirty();
}
}
}
}
}
}
//endregion
//region Events
public void onSave(File file,World world)
{
isDirty = false;
}
public void onTravelEvent(ItemStack ship,GalacticPosition from,World world)
{
if (!world.isRemote)
{
if (ship.getItem() instanceof IShip)
{
UUID ownerID = ((IShip) ship.getItem()).getOwnerID(ship);
if (ownerID != null)
{
EntityPlayer owner = world.func_152378_a(ownerID);
if (owner != null) {
owner.addChatMessage(
new ChatComponentText(
EnumChatFormatting.GOLD + "[" + Reference.MOD_NAME + "]" +
EnumChatFormatting.RESET + String.format(MOStringHelper.translateToLocal("alert.starmap.ship_arrive"), ship.getDisplayName(), name)
)
);
}
}
((IShip) ship.getItem()).onTravel(ship,this);
if (ship.stackSize <= 0)
{
removeShip(ship);
}
markDirty();
markForUpdate();
}
}
}
public void onBuild(IBuildable buildable,ItemStack buildableStack,World world)
{
UUID ownerID = buildable.getOwnerID(buildableStack);
if (ownerID != null)
{
EntityPlayer entityPlayer = world.func_152378_a(ownerID);
if(entityPlayer != null) {
entityPlayer.addChatMessage(
new ChatComponentText(
EnumChatFormatting.GOLD + "[" + Reference.MOD_NAME + "]" +
EnumChatFormatting.RESET + String.format(MOStringHelper.translateToLocal("alert.starmap.on_build"), buildableStack.getDisplayName(), name)
)
);
}
}
}
//endregion
//region Read - Write
public void writeToNBT(NBTTagCompound tagCompound)
{
super.writeToNBT(tagCompound);
for (int i = 0;i < getSizeInventory();i++)
{
if (getStackInSlot(i) != null)
{
NBTTagCompound itemTag = new NBTTagCompound();
getStackInSlot(i).writeToNBT(itemTag);
tagCompound.setTag("Slot" + i, itemTag);
}
}
for (int i = 0;i < buildings.size();i++)
{
NBTTagCompound buiildingTAG = new NBTTagCompound();
buildings.get(i).writeToNBT(buiildingTAG);
tagCompound.setTag("Building" + i, buiildingTAG);
}
for (int i = 0;i < fleet.size();i++)
{
NBTTagCompound shipTag = new NBTTagCompound();
fleet.get(i).writeToNBT(shipTag);
tagCompound.setTag("Ship"+i,shipTag);
}
if (ownerUUID != null)
tagCompound.setString("OwnerUUID",ownerUUID.toString());
tagCompound.setBoolean("Homeworld", homeworld);
tagCompound.setFloat("Size", size);
tagCompound.setByte("Type", type);
tagCompound.setFloat("Orbit", orbit);
tagCompound.setInteger("BuildingSpaces", buildingSpaces);
tagCompound.setInteger("FleetSpaces",fleetSpaces);
tagCompound.setInteger("Seed", seed);
}
@Override
public void writeToBuffer(ByteBuf byteBuf)
{
super.writeToBuffer(byteBuf);
NBTTagCompound nbtData = new NBTTagCompound();
writeToNBT(nbtData);
ByteBufUtils.writeTag(byteBuf,nbtData);
}
public void readFromNBT(NBTTagCompound tagCompound,GalaxyGenerator generator)
{
super.readFromNBT(tagCompound,generator);
buildings.clear();
fleet.clear();
for (int i = 0;i < getSizeInventory();i++)
{
if (tagCompound.hasKey("Slot" + i,10))
{
setInventorySlotContents(i, ItemStack.loadItemStackFromNBT(tagCompound.getCompoundTag("Slot" + i)));
}
}
buildingSpaces = tagCompound.getInteger("BuildingSpaces");
for (int i = 0;i < getBuildingSpaces();i++)
{
if (tagCompound.hasKey("Building" + i,10))
{
ItemStack buildingStack = ItemStack.loadItemStackFromNBT(tagCompound.getCompoundTag("Building" + i));
if (buildingStack != null) {
addBuilding(buildingStack);
}else
{
MatterOverdrive.log.error("There was a problem loading a building from NBT of planet %s", getName());
}
}
}
fleetSpaces = tagCompound.getInteger("FleetSpaces");
for (int i = 0;i < getFleetSpaces();i++)
{
if (tagCompound.hasKey("Ship"+i,10))
{
ItemStack shipStack = ItemStack.loadItemStackFromNBT(tagCompound.getCompoundTag("Ship" + i));
if (shipStack != null)
{
addShip(shipStack);
}else
{
MatterOverdrive.log.error("There was a problem loading a ship from NBT of planet %s", getName());
}
}
}
if (tagCompound.hasKey("OwnerUUID",8))
{
try {
ownerUUID = UUID.fromString(tagCompound.getString("OwnerUUID"));
}
catch (IllegalArgumentException e)
{
FMLLog.log(Level.ERROR,e,"Invalid planet owner UUID '" + tagCompound.getString("OwnerUUID") +"'",this);
}
}
homeworld = tagCompound.getBoolean("Homeworld");
size = tagCompound.getFloat("Size");
type = tagCompound.getByte("Type");
orbit = tagCompound.getFloat("Orbit");
seed = tagCompound.getInteger("Seed");
generateMissing(tagCompound, generator);
}
@Override
public void readFromBuffer(ByteBuf byteBuf)
{
super.readFromBuffer(byteBuf);
NBTTagCompound nbtData = ByteBufUtils.readTag(byteBuf);
readFromNBT(nbtData,null);
}
public void generateMissing(NBTTagCompound tagCompound,GalaxyGenerator galaxyGenerator)
{
if (galaxyGenerator != null) {
for (ISpaceBodyGen<Planet> starGen : galaxyGenerator.getPlanetGen().getGens()) {
galaxyGenerator.getStarRandom().setSeed(seed);
if (starGen.generateMissing(tagCompound, this, galaxyGenerator.getStarRandom())) {
break;
}
}
}
}
//endregion
//region Getters and Setters
@Override
public SpaceBody getParent() {
return star;
}
public void setStar(Star star)
{
this.star = star;
}
public Star getStar()
{
return star;
}
public UUID getOwnerUUID(){return ownerUUID;}
public void setOwner(EntityPlayer player){ownerUUID = EntityPlayer.func_146094_a(player.getGameProfile());}
public void setOwnerUUID(UUID ownerUUID){this.ownerUUID = ownerUUID;}
public boolean hasOwner(){return ownerUUID != null;}
public boolean isOwner(EntityPlayer player){if (hasOwner()) return getOwnerUUID().equals(EntityPlayer.func_146094_a(player.getGameProfile())); return false; }
public void setHomeworld(boolean homeworld){this.homeworld = homeworld;}
public boolean isHomeworld(){return homeworld;}
public boolean isHomeworld(EntityPlayer player){if (isOwner(player)) return isHomeworld(); else return false;}
public float getSize(){return size;}
public void setSize(float size){this.size = size;}
public byte getType(){return type;}
public void setType(byte type){this.type = type;}
public float getOrbit(){return orbit;}
public void setOrbit(float orbit){this.orbit = orbit;}
public int getBuildingSpaces(){return (int)getStatChangeFromBuildings(PlanetStatType.BUILDINGS_SIZE,buildingSpaces);}
public void setBuildingSpaces(int buildingSpaces){this.buildingSpaces = buildingSpaces;}
public List<ItemStack> getBuildings(){return buildings;}
public List<ItemStack> getFleet(){return fleet;}
public int getFleetSpaces(){return (int)getStatChangeFromBuildings(PlanetStatType.FLEET_SIZE,fleetSpaces);}
public void setFleetSpaces(int fleetSpaces){this.fleetSpaces = fleetSpaces;}
public void setSeed(int seed){this.seed = seed;}
public int getSeed(){return seed;}
public boolean isGenerated(){return generated;}
public void setGenerated(boolean generated){this.generated = generated;}
public ItemStack getShip(int at){return fleet.get(at);}
public int getPopulation(){return (int)getStatChangeFromBuildings(PlanetStatType.POPULATION_COUNT,0);}
public int getPowerProducation(){return (int)getStatChangeFromBuildings(PlanetStatType.ENERGY_PRODUCTION,0);}
public float getMatterProduction(){return getStatChangeFromBuildings(PlanetStatType.MATTER_PRODUCTION,0);}
public float getHappiness(){return getStatChangeFromBuildings(PlanetStatType.HAPPINESS,0);}
public void addShip(ItemStack ship){
if (ship != null) {
if (ship.getItem() instanceof IShip) {
fleet.add(ship);
}else
{
MatterOverdrive.log.error("Trying to add an itemstack to ships, that does not contain a Ship Item");
}
}else
{
MatterOverdrive.log.error("Trying to add a null Ship itemstack to %s", getName());
}
}
public boolean canAddShip(ItemStack ship,@Nullable EntityPlayer player)
{
if (ship != null && ship.getItem() instanceof IShip)
{
if (player != null && hasOwner() && isHomeworld())
{
return isOwner(player);
}
else
{
if (fleetCount() < getFleetCount()) {
return true;
}
}
}
return false;
}
public ItemStack removeShip(int at){if (at < fleet.size()) return fleet.remove(at); else return null;}
public boolean removeShip(ItemStack ship){return fleet.remove(ship);}
public void addBuilding(@Nonnull ItemStack building)
{
if (building != null)
{
if (building.getItem() instanceof IBuilding)
{
this.buildings.add(building);
}else
{
MatterOverdrive.log.error("Trying to add a stack to buildings, that does not contain a Building Item");
}
}else
{
MatterOverdrive.log.error("Trying to add a null building to planet %s", getName());
}
}
public int fleetCount(){return fleet.size();}
public static Color getGuiColor(Planet planet)
{
if (planet.hasOwner()) {
if (planet.getOwnerUUID().equals(EntityPlayer.func_146094_a(Minecraft.getMinecraft().thePlayer.getGameProfile()))) {
if (planet.isHomeworld())
{
return Reference.COLOR_HOLO_YELLOW;
}else
{
return Reference.COLOR_HOLO_GREEN;
}
}else
{
return Reference.COLOR_HOLO_RED;
}
}else
{
return Reference.COLOR_HOLO;
}
}
public void markForUpdate(){
needsClientUpdate = true;
}
public boolean canBuild(IBuildable buildable,ItemStack stack,List<String> info)
{
if (buildable instanceof IBuilding)
{
return canBuild((IBuilding)buildable,stack,info);
}
else if (buildable instanceof IShip)
{
return canBuild((IShip)buildable,stack,info);
}
else return false;
}
public boolean canBuild(IBuilding building,ItemStack stack,List<String> info)
{
if (buildings.size() < getBuildingSpaces())
{
if (hasBuildingType(BuildingType.BASE))
{
return building.canBuild(stack,this,info);
}
info.add(MOStringHelper.translateToLocal("gui.tooltip.starmap.no_base"));
}
info.add(MOStringHelper.translateToLocal("gui.tooltip.starmap.no_building_space"));
return false;
}
public boolean canBuild(IShip ship,ItemStack stack,List<String> info)
{
if (fleet.size() < getFleetCount())
{
if (hasBuildingType(BuildingType.SHIP_FACTORY))
{
return ship.canBuild(stack,this,info);
}
info.add(MOStringHelper.translateToLocal("gui.tooltip.starmap.no_ship_factory"));
}else
{
info.add(MOStringHelper.translateToLocal("gui.tooltip.starmap.no_ship_space"));
}
return false;
}
public boolean hasBuildingType(BuildingType buildingType)
{
for (ItemStack building : getBuildings())
{
if (building.getItem() instanceof IBuilding && ((IBuilding) building.getItem()).getType(building) == buildingType)
{
return true;
}
}
return false;
}
public float getStatChangeFromBuildings(PlanetStatType statType,float original)
{
for (ItemStack building : getBuildings())
{
if (building.getItem() instanceof IPlanetStatChange)
{
original = ((IPlanetStatChange) building.getItem()).changeStat(building,this,statType,original);
}
}
return original;
}
public boolean isDirty(){return this.isDirty;}
//endregion
//region Inventory
@Override
public int getSizeInventory()
{
return SLOT_COUNT;
}
@Override
public ItemStack getStackInSlot(int slot)
{
if(slot >= 0 && slot < getSizeInventory())
{
return inventory[slot];
}
return null;
}
@Override
public ItemStack decrStackSize(int slot, int size)
{
if (inventory[slot] != null)
{
ItemStack itemstack;
if (inventory[slot].stackSize <= size)
{
itemstack = inventory[slot];
inventory[slot] = null;
return itemstack;
}
else
{
itemstack = inventory[slot].splitStack(size);
if (inventory[slot].stackSize == 0)
{
inventory[slot] = null;
}
return itemstack;
}
}
else
{
return null;
}
}
@Override
public ItemStack getStackInSlotOnClosing(int slot) {
if(inventory[slot] != null)
{
ItemStack stack = inventory[slot];
inventory[slot] = null;
return stack;
}
return null;
}
public int getFactoryCount()
{
return buildings.size();
}
public int getFleetCount()
{
return fleet.size();
}
@Override
public void setInventorySlotContents(int slot, ItemStack stack)
{
if (slot < inventory.length)
{
inventory[slot] = stack;
if (stack != null && stack.stackSize > this.getInventoryStackLimit()) {
stack.stackSize = this.getInventoryStackLimit();
}
}
}
@Override
public String getInventoryName() {
return getName();
}
@Override
public boolean hasCustomInventoryName() {
return true;
}
@Override
public int getInventoryStackLimit() {
return 1;
}
@Override
public void markDirty()
{
isDirty = true;
markForUpdate();
}
@Override
public boolean isUseableByPlayer(EntityPlayer player)
{
if (hasOwner())
{
return getOwnerUUID().equals(EntityPlayer.func_146094_a(player.getGameProfile()));
}
return true;
}
@Override
public void openInventory()
{
}
@Override
public void closeInventory() {
}
@Override
public boolean isItemValidForSlot(int slot, ItemStack stack)
{
if (slot < SLOT_COUNT/2)
{
return stack.getItem() instanceof IBuilding;
}else
{
return stack.getItem() instanceof IShip;
}
}
//endregion
}