package com.bioxx.tfc2.core; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.bioxx.tfc2.Core; import com.bioxx.tfc2.api.types.EnumFoodGroup; public class FoodStatsTFC { /** The player's food level. This measures how much food the player can handle.*/ public float stomachLevel = 100; private float stomachMax = 100.0f; private float prevFoodLevel = 100; public float nutrFruit = 1.0f; public float nutrVeg = 1.0f; public float nutrGrain = 1.0f; public float nutrDairy = 0.0f; public float nutrProtein = 1.0f; private boolean sendUpdate = true; public long soberTime; /**This is how full the player is from the food that they've eaten. * It could also be how happy they are with what they've eaten*/ private float satisfaction; private float foodExhaustionLevel; //private float waterExhaustionLevel; /** The player's food timer value. */ public long foodTimer; public long foodHealTimer; public float waterLevel = 100f;//TFC_Time.DAY_LENGTH*2; public long waterTimer; public EntityPlayer player; private long nameSeed = Long.MIN_VALUE; private boolean satFruit; private boolean satVeg; private boolean satGrain; private boolean satProtein; private boolean satDairy; public FoodStatsTFC(EntityPlayer player) { this.player = player; //waterTimer = Math.max(TFC_Time.getTotalTicks(),TFC_Time.startTime); //foodTimer = Math.max(TFC_Time.getTotalTicks(),TFC_Time.startTime); //foodHealTimer = Math.max(TFC_Time.getTotalTicks(),TFC_Time.startTime); } /** * Handles the food game logic. */ public void onUpdate(EntityPlayer player) { if(!player.worldObj.isRemote) { Timekeeper time = Timekeeper.instance; /* * Standard filling reduction based upon time. */ if (time.getTotalTicks() - this.foodTimer >= Timekeeper.HOUR_LENGTH && !player.capabilities.isCreativeMode) { //Increase our timer this.foodTimer += Timekeeper.HOUR_LENGTH; float drainMult = 1.0f; //We dont want the player to starve to death while sleeping if(player.isPlayerSleeping()) { drainMult = 0.50f; } //Water if(player.isSprinting()) waterLevel -= 5; if(!player.capabilities.isCreativeMode) waterLevel -= 1; //Food float hunger = (1 + foodExhaustionLevel) * drainMult; if(this.satisfaction >= hunger) { satisfaction -= hunger; hunger = 0; foodExhaustionLevel = 0; } else { hunger -= satisfaction; satisfaction = 0; foodExhaustionLevel = 0; } this.stomachLevel = Math.max(this.stomachLevel - hunger, 0); if(satisfaction == 0) { satProtein = false; satFruit = false; satVeg = false; satDairy = false; satGrain = false; } /* * Reduce nutrients */ if (this.stomachLevel <= 0) { reduceNutrition(0.0024F);//3x penalty for starving } else if(this.satisfaction <= 0) { reduceNutrition(0.0008F); } else { if(this.satProtein) this.addNutrition(EnumFoodGroup.Protein, this.satisfaction*((1-this.nutrProtein)/100), false); if(this.satGrain) this.addNutrition(EnumFoodGroup.Grain, this.satisfaction*((1-this.nutrGrain)/100), false); if(this.satVeg) this.addNutrition(EnumFoodGroup.Vegetable, this.satisfaction*((1-this.nutrVeg)/100), false); if(this.satFruit) this.addNutrition(EnumFoodGroup.Fruit, this.satisfaction*((1-this.nutrFruit)/100), false); if(this.satDairy) this.addNutrition(EnumFoodGroup.Dairy, this.satisfaction*((1-this.nutrDairy)/100), false); } sendUpdate = true; } if(!player.capabilities.isCreativeMode) { for(;waterTimer < time.getTotalTicks(); waterTimer++) { //Reduce the player's water for normal living waterLevel -= 1; if(waterLevel < 0) waterLevel = 0; /*if(!Core.isPlayerInDebugMode(player) && waterLevel == 0 && temp > 35) player.attackEntityFrom(new DamageSource("heatStroke").setDamageBypassesArmor().setDamageIsAbsolute(), 2);*/ } } //Heal or hurt the player based on hunger. if (time.getTotalTicks() - this.foodHealTimer >= Timekeeper.HOUR_LENGTH/2) { this.foodHealTimer += Timekeeper.HOUR_LENGTH/2; if (this.stomachLevel >= this.getMaxStomach(player)/4 && player.shouldHeal()) { //Player heals 1% per 30 in game minutes player.heal((int) (player.getMaxHealth() * 0.01f)); } else if (this.stomachLevel <= 0 && getNutritionHealthModifier() < 0.85f && !Core.isPlayerInDebugMode(player) && player.getSleepTimer() == 0) { //Players loses health at a rate of 5% per 30 minutes if they are starving //Disabled so that the penalty for not eating is now entirely based upon nutrition. //player.attackEntityFrom(DamageSource.starve, Math.max((int) (player.getMaxHealth() * 0.05f), 10)); } } } } protected void reduceNutrition(float amount) { nutrFruit = Math.max(this.nutrFruit - (amount + foodExhaustionLevel), 0); nutrVeg = Math.max(this.nutrVeg - (amount + foodExhaustionLevel), 0); nutrGrain = Math.max(this.nutrGrain - (amount + foodExhaustionLevel), 0); nutrProtein = Math.max(this.nutrProtein - (amount + foodExhaustionLevel), 0); nutrDairy = Math.max(this.nutrDairy - (amount + foodExhaustionLevel), 0); sendUpdate = true; } public int getMaxWater(EntityPlayer player) { return 100;//return TFC_Time.DAY_LENGTH * 2 + 200 * player.experienceLevel; } public float getMaxStomach(EntityPlayer player) { return this.stomachMax; } /** * Get the player's food level. */ public float getFoodLevel() { return this.stomachLevel; } @SideOnly(Side.CLIENT) public float getPrevFoodLevel() { return this.prevFoodLevel ; } /** * If foodLevel is not max. */ public boolean needFood() { return this.stomachLevel < getMaxStomach(this.player) && (getMaxStomach(this.player) - stomachLevel) > 0.1; } public boolean needDrink() { return this.waterLevel < getMaxWater(this.player) - 500; } /** * Reads food stats from an NBT object. */ public void readNBT(NBTTagCompound par1NBTTagCompound) { if (par1NBTTagCompound.hasKey("foodCompound")) { NBTTagCompound foodCompound = par1NBTTagCompound.getCompoundTag("foodCompound"); this.waterLevel = foodCompound.getFloat("waterLevel"); this.stomachLevel = foodCompound.getFloat("foodLevel"); this.foodTimer = foodCompound.getLong("foodTickTimer"); this.foodHealTimer = foodCompound.getLong("foodHealTimer"); this.waterTimer = foodCompound.getLong("waterTimer"); this.soberTime = foodCompound.getLong("soberTime"); this.satisfaction = foodCompound.getFloat("foodSaturationLevel"); this.foodExhaustionLevel = foodCompound.getFloat("foodExhaustionLevel"); this.nutrFruit = foodCompound.getFloat("nutrFruit"); this.nutrVeg = foodCompound.getFloat("nutrVeg"); this.nutrGrain = foodCompound.getFloat("nutrGrain"); this.nutrProtein = foodCompound.getFloat("nutrProtein"); this.nutrDairy = foodCompound.getFloat("nutrDairy"); this.sendUpdate = foodCompound.getBoolean("shouldSendUpdate"); this.satFruit = foodCompound.getBoolean("satFruit"); this.satVeg = foodCompound.getBoolean("satVeg"); this.satGrain = foodCompound.getBoolean("satGrain"); this.satProtein = foodCompound.getBoolean("satProtein"); this.satDairy = foodCompound.getBoolean("satDairy"); } } /** * Writes food stats to an NBT object. */ public void writeNBT(NBTTagCompound nbt) { NBTTagCompound foodNBT = new NBTTagCompound(); foodNBT.setFloat("waterLevel", this.waterLevel); foodNBT.setFloat("foodLevel", this.stomachLevel); foodNBT.setLong("foodTickTimer", this.foodTimer); foodNBT.setLong("foodHealTimer", this.foodHealTimer); foodNBT.setLong("waterTimer", this.waterTimer); foodNBT.setLong("soberTime", this.soberTime); foodNBT.setFloat("foodSaturationLevel", this.satisfaction); foodNBT.setFloat("foodExhaustionLevel", this.foodExhaustionLevel); foodNBT.setFloat("nutrFruit", nutrFruit); foodNBT.setFloat("nutrVeg", nutrVeg); foodNBT.setFloat("nutrGrain", nutrGrain); foodNBT.setFloat("nutrProtein", nutrProtein); foodNBT.setFloat("nutrDairy", nutrDairy); foodNBT.setBoolean("shouldSendUpdate", sendUpdate); foodNBT.setBoolean("satFruit", satFruit); foodNBT.setBoolean("satVeg", satVeg); foodNBT.setBoolean("satGrain", satGrain); foodNBT.setBoolean("satProtein", satProtein); foodNBT.setBoolean("satDairy", satDairy); nbt.setTag("foodCompound", foodNBT); } public void addFoodExhaustion(float par1) { this.foodExhaustionLevel = par1; } /*public void addWaterExhaustion(float par1) { this.waterExhaustionLevel = par1; }*/ public float getSatisfaction() { return this.satisfaction; } public void setFoodLevel(float par1) { if(par1 != this.stomachLevel) sendUpdate = true; this.stomachLevel = par1; } public void setSatisfaction(float par1, int[] fg) { this.satisfaction = Math.min(par1, 10); } public long getPlayerFoodSeed() { /*if(nameSeed == Long.MIN_VALUE) { long seed = 0; byte[] nameBytes = player.getCommandSenderName().getBytes(); for(byte b : nameBytes) seed+=b; nameSeed = seed + player.worldObj.getSeed(); } return nameSeed;*/ return 0; } public float getNutritionHealthModifier() { float nMod = 0.00f; nMod += 0.1f * nutrFruit; nMod += 0.4f * nutrVeg; nMod += 0.3f * nutrGrain; nMod += 0.2f * nutrProtein; return Math.max(nMod, 0.05f); } public static float getMaxHealth(EntityPlayer player) { /*return Math.min(20+(player.experienceLevel * TFCOptions.healthGainRate), TFCOptions.healthGainCap) * Core.getPlayerFoodStats(player).getNutritionHealthModifier() * (1+0.2f * Core.getPlayerFoodStats(player).nutrDairy); */ return 0; } /** * * @return return true if the itemstack should be consumed, else return false */ public static boolean reduceFood(ItemStack is, float amount) { /*if(is.hasTagCompound()) { float weight = is.getTagCompound().getFloat("foodWeight"); float decay = is.getTagCompound().hasKey("foodDecay") ? is.getTagCompound().getFloat("foodDecay") : 0; if(decay >= 0 && (weight - decay) - amount <= 0) return true; else if(decay <= 0 && weight - amount <= 0) return true; else { is.getTagCompound().setFloat("foodWeight", Helper.roundNumber(weight - amount, 10)); //is.getTagCompound().setFloat("foodDecay", Helper.roundNumber(decay - amount, 10)); } }*/ return false; } public void addNutrition(EnumFoodGroup fg, float foodAmt) { addNutrition(fg, foodAmt, true); } public void addNutrition(EnumFoodGroup fg, float foodAmt, boolean shouldDoMath) { float amount = foodAmt; if(shouldDoMath) amount = foodAmt/5f/50f;//converts it to 5% if it is 5oz of food switch(fg) { case Dairy: this.nutrDairy = Math.min(nutrDairy + amount, 1.0f); break; case Fruit: this.nutrFruit = Math.min(nutrFruit + amount, 1.0f); break; case Grain: this.nutrGrain = Math.min(nutrGrain + amount, 1.0f); break; case Protein: this.nutrProtein = Math.min(nutrProtein + amount, 1.0f); break; case Vegetable: this.nutrVeg = Math.min(nutrVeg + amount, 1.0f); break; default: break; } } public boolean shouldSendUpdate() { return sendUpdate; } public void restoreWater(EntityPlayer player, int w) { this.waterLevel = Math.min(this.waterLevel + w, this.getMaxWater(player)); sendUpdate = true; this.writeNBT(player.getEntityData()); } public void resetTimers() { //waterTimer = TFC_Time.getTotalTicks(); //foodTimer = TFC_Time.getTotalTicks(); //foodHealTimer = TFC_Time.getTotalTicks(); } public void consumeAlcohol() { //TODO: Add a parameter for alcohol strength /*if(soberTime <= TFC_Time.getTotalTicks()) soberTime = TFC_Time.getTotalTicks() + player.worldObj.rand.nextInt(1000) + 400; else soberTime += player.worldObj.rand.nextInt(1000) + 400; sendUpdate = true;*/ } }