Java tutorial
/** * This file is part of Aion-Lightning <aion-lightning.org>. * * Aion-Lightning 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. * * Aion-Lightning 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 Aion-Lightning. * If not, see <http://www.gnu.org/licenses/>. */ package com.aionemu.gameserver.services.toypet; import com.aionemu.commons.utils.Rnd; import com.aionemu.gameserver.dataholders.DataManager; import com.aionemu.gameserver.model.templates.pet.PetFeedResult; import com.aionemu.gameserver.model.templates.pet.PetFlavour; import com.aionemu.gameserver.model.templates.pet.PetRewards; import org.apache.commons.lang.ArrayUtils; import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.TreeSet; /** * @author Rolandas */ /** * <b>Current pre-calculated values multiplied by 4; in packet 14 bits. Max * value: 17600 / 4 is 13 bits; feed points as in retail packets.</b><br> * static final byte[][] pointValues = new byte[][] {<br> * // 10 25 40 50 100 200 -- feed max count<br> * { 0, 0, 0, 0, 0, 0 }, // level 1~5 items (feed points 0)<br> * { 80, 200, 320, 400, 800, 1600 }, // level 6~10 items (feed points 8)<br> * { 160, 400, 640, 800, 1600, 3200 }, // level 11~15 items (feed points 16)<br> * { 240, 600, 960, 1200, 2400, 4800 }, // level 16~20 items (feed points * 24)<br> * { 320, 800, 1280, 1600, 3200, 6400 }, // level 21~25 items (feed points * 32)<br> * { 400, 1000, 1600, 2000, 4000, 8000 }, // level 26~30 items (feed points * 40)<br> * { 480, 1200, 1920, 2400, 4800, 9600 }, // level 31~35 items (feed points * 48)<br> * { 560, 1400, 2240, 2800, 5600, 11200 }, // level 36~40 items (feed points * 56)<br> * { 640, 1600, 2560, 3200, 6400, 12800 }, // level 41~45 items (feed points * 64)<br> * { 720, 1800, 2880, 3600, 7200, 14400 }, // level 46~50 items (feed points * 72)<br> * { 800, 2000, 3200, 4000, 8000, 16000 }, // level 51~55 items (feed points * 80)<br> * { 880, 2200, 3520, 4400, 8800, 17600 } // level 56~60 items (feed points * 88)<br> }; */ public final class PetFeedCalculator { static byte ITEM_MAX_LEVEL = 60; static final short[] fullCounts; static final byte[] itemLevels; static final int[][] pointValues; static { TreeSet<Short> counts = new TreeSet<Short>(); for (PetFlavour flavour : DataManager.PET_FEED_DATA.getPetFlavours()) { if (flavour.getFullCount() > 0) { counts.add((short) (flavour.getFullCount() & 0xFFFF)); } } fullCounts = new short[counts.size()]; int i = 0; Iterator<Short> countIter = counts.iterator(); while (countIter.hasNext()) { fullCounts[i++] = countIter.next(); } itemLevels = new byte[ITEM_MAX_LEVEL / 5]; itemLevels[0] = 5; for (int j = 1; j < itemLevels.length; j++) { itemLevels[j] = (byte) (itemLevels[j - 1] + 5); } pointValues = new int[itemLevels.length][fullCounts.length]; calculate(); } /** * Calculate point values for each item levels and each max feed count */ static void calculate() { for (byte levelByte : itemLevels) { short level = (short) (levelByte & 0xFF); if (level < 10) { continue; } int countIndex = 0; for (short countByte : fullCounts) { short count = (short) (countByte & 0xFF); int finalLevel = level; if (finalLevel % 5 == 0) { finalLevel--; } int pointLevel = (int) itemLevels[(finalLevel / 5)]; int feedPoints = Math.max(0, pointLevel - 5) / 5 * 8; // System.out.println("ITEM LEVEL: " + level + ", COUNT: " + count + ", STEP: " + feedPoints); pointValues[finalLevel / 5][countIndex++] = getPoints(feedPoints, count); } } } /** * Formula to calculate pointValues array * * @param feedPoints - feed points for item * @param maxFeedCount - max feeding count * @return byte increment count after all items are fed */ static int getPoints(int feedPoints, int maxFeedCount) { int points = 0; int state = 0; int consumed = 0; while (consumed < maxFeedCount) { boolean needSwitch = false; int oldPoints = points; if ((state == 0 && consumed > maxFeedCount * 0.5f) || (state == 1 && consumed > maxFeedCount * 0.8f) || (state == 2 && consumed > maxFeedCount * 1.05)) { needSwitch = true; } points += feedPoints; if (needSwitch) { state++; if (state == 1 && consumed <= 0.487f * maxFeedCount || state == 2 && consumed <= 0.78f * maxFeedCount) { state--; points = oldPoints; } } consumed++; } return points; } public static void updatePetFeedProgress(@Nonnull PetFeedProgress progress, int itemLevel, int maxFeedCount) { PetHungryLevel currHungryLevel = progress.getHungryLevel(); if (progress.isLovedFeeded()) { // loved food if (progress.getLovedFoodRemaining() == 0) { return; } progress.setHungryLevel(PetHungryLevel.FULL); progress.incrementCount(true); return; } int oldPoints = progress.getTotalPoints(); boolean needSwitch = false; if ((currHungryLevel == PetHungryLevel.HUNGRY && progress.getRegularCount() > maxFeedCount * 0.5f) || (currHungryLevel == PetHungryLevel.CONTENT && progress.getRegularCount() > maxFeedCount * 0.8f) || (currHungryLevel == PetHungryLevel.SEMIFULL && progress.getRegularCount() > maxFeedCount * 1.05)) { // forcefully switch level needSwitch = true; } else { int finalLevel = itemLevel; if (finalLevel % 5 == 0) { finalLevel--; } byte pointLevel = itemLevels[(finalLevel / 5)]; byte pointsEarned = (byte) (Math.max(0, pointLevel - 5) / 5 * 8); int feedProgress = progress.getTotalPoints() + pointsEarned; progress.setTotalPoints(feedProgress); } if (needSwitch) { // just a prevention to not switch level PetHungryLevel nextLevel = progress.getHungryLevel().getNextValue(); if (nextLevel == PetHungryLevel.CONTENT && progress.getRegularCount() <= 0.487f * maxFeedCount || nextLevel == PetHungryLevel.SEMIFULL && progress.getRegularCount() <= 0.78f * maxFeedCount) { progress.setTotalPoints(oldPoints); } else { progress.setHungryLevel(nextLevel); } } progress.incrementCount(false); } public static PetFeedResult getReward(int fullCount, PetRewards rewardGroup, PetFeedProgress progress, int playerLevel) { if (progress.getHungryLevel() != PetHungryLevel.FULL || rewardGroup.getResults().size() == 0) { return null; } int pointsIndex = ArrayUtils.indexOf(fullCounts, (short) fullCount); if (pointsIndex == ArrayUtils.INDEX_NOT_FOUND) { return null; } if (progress.isLovedFeeded()) { // for cash feed if (rewardGroup.getResults().size() == 1) { return rewardGroup.getResults().get(0); } List<PetFeedResult> validRewards = new ArrayList<PetFeedResult>(); int maxLevel = 0; for (PetFeedResult result : rewardGroup.getResults()) { int resultLevel = DataManager.ITEM_DATA.getItemTemplate(result.getItem()).getLevel(); if (resultLevel > playerLevel) { continue; } if (resultLevel > maxLevel) { maxLevel = resultLevel; validRewards.clear(); } validRewards.add(result); } if (validRewards.size() == 0) { return null; } if (validRewards.size() == 1) { return validRewards.get(0); } return validRewards.get(Rnd.get(validRewards.size())); } int rewardIndex = 0; int totalRewards = rewardGroup.getResults().size(); for (int row = 1; row < pointValues.length; row++) { int[] points = pointValues[row]; if (points[pointsIndex] <= progress.getTotalPoints()) { rewardIndex = Math.round((float) totalRewards / (pointValues.length - 1) * row) - 1; } } // Fix rounding discrepancy if (rewardIndex < 0) { rewardIndex = 0; } else if (rewardIndex > rewardGroup.getResults().size() - 1) { rewardIndex = rewardGroup.getResults().size() - 1; } return rewardGroup.getResults().get(rewardIndex); } }