/** * Copyright 2008 - 2011 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:ceponline@yahoo.com.cn * @version 0.1 */ package loon.srpg.ability; import java.util.ArrayList; import loon.srpg.SRPGType; import loon.srpg.actor.SRPGActor; import loon.srpg.actor.SRPGActors; import loon.srpg.actor.SRPGStatus; import loon.srpg.effect.SRPGEffect; import loon.srpg.field.SRPGField; import loon.srpg.field.SRPGFieldElement; import loon.srpg.field.SRPGFieldMove; import loon.utils.CollectionUtils; import loon.utils.MathUtils; public class SRPGAbilityFactory { boolean flag = false; boolean isDamage = true; boolean isDamageUpdate = true; boolean isHitUpdate = true; boolean isHit = true; boolean isStatus = false; boolean isSetStatus = true; int atk, def, damageValue, hitRate; SRPGStatus status, status1, status2; int damageChange = 100; int[] statasFlag; private static SRPGAbilityFactory instance; final static ArrayList<SRPGAbility> lazyAbilityClass = new ArrayList<SRPGAbility>( 24); public static SRPGAbilityFactory getInstance(int number) { if (instance == null) { instance = new SRPGAbilityFactory(number); } else { instance.set(number); } return instance; } public static void putAbility(SRPGAbility ability) { lazyAbilityClass.add(ability); } public static void setAbility(int index, SRPGAbility ability) { lazyAbilityClass.set(index, ability); } public static void makeDefAbilitys() { if (lazyAbilityClass.size() == 0) { SRPGAbilityTemp.make(); } } private int number; SRPGAbilityFactory() { } private SRPGAbilityFactory(int i) { set(i); } public void set(int i) { number = i; } public int getNumber() { return number; } public String getAbilityName() { return getAbility().abilityName; } public String getAbilityHelp() { return getAbility().abilityAbout; } public int getMinLength() { return getAbility().minLength; } public int getMaxLength() { return getAbility().maxLength; } public int getMP() { return getAbility().mp; } public SRPGAbility getAbility(int index) { return lazyAbilityClass.get(index); } public SRPGAbility getAbility() { return getAbility(number); } public int getMP(SRPGStatus status) { int i = getAbility().mp; int j = 0; if (status.checkSkill(SRPGStatus.SKILL_CARRY) || status.status[SRPGStatus.STATUS_GOODEND] != 0) { j = i / 2; } return i - j; } public int getRange() { return getAbility(number).range; } public int getTarget() { return getAbility(number).target; } public int getDirect() { return getAbility(number).direct; } public int getSelectNeed() { return getAbility(number).selectNeed; } public int getCounter() { return getAbility(number).counter; } public int getGenre() { return getAbility(number).genre; } public static int getOptimizeAbility(int[] range, SRPGField field, SRPGActors actors, int atk, int def) { if (range == null) { return -1; } boolean flag = false; int rangeSize = -1; int limit = -1; int original = 0; int mp = 0; for (int j = 0; j < range.length; j++) { boolean result = false; SRPGAbilityFactory ability = SRPGAbilityFactory .getInstance(range[j]); int[] res = ability.getOptimizeOriginal(field, actors, atk, def); int value = (res[0] * res[1]) / 100; if (res[0] >= actors.find(def).getActorStatus().hp) { if (flag && res[1] <= original) { continue; } result = true; } else if (flag || value < limit || value == limit && mp < ability.getMP(actors.find(atk).getActorStatus())) { continue; } rangeSize = range[j]; limit = value; original = res[1]; mp = ability.getMP(actors.find(atk).getActorStatus()); flag = result; } return rangeSize; } public static int getOptimizePoint(int i, SRPGField field, SRPGActors actors, int atk, int def) { if (i == -1) { return -1; } else { return (new SRPGAbilityFactory(i)).getOptimizePoint(field, actors, atk, def); } } public int getOptimizePoint(SRPGField field, SRPGActors actors, int atk, int def) { return getOptimizeAll(field, actors, atk, def)[0]; } public int[] getOptimizeOriginal(SRPGField field, SRPGActors actors, int atk, int def) { SRPGDamageData damagedata = getDamageExpect(field, actors, atk, def); int damage = damagedata.getBeforeRandomDamage(); int hit = damagedata.getBeforeRandomHitrate(); if (damagedata.getGenre() == SRPGType.GENRE_HELPER && damagedata.getGenre() == SRPGType.GENRE_CURE) { damage = 0; } SRPGStatus status = actors.find(def).getActorStatus(); if (damagedata.getGenre() == SRPGType.GENRE_ATTACK) { if (damage > status.hp && status.hp > 0) damage = status.hp; } else if (damagedata.getGenre() == SRPGType.GENRE_RECOVERY) { if (status.hp + damage > status.max_hp) { damage = status.max_hp - status.hp; } } int[] res = { damage, hit }; return res; } public int[] getOptimizeAll(SRPGField field, SRPGActors actors, int atk, int def) { int[] res = getOptimizeOriginal(field, actors, atk, def); res[0] = (res[0] * res[1]) / 100; return res; } /** * 计算角色造成的伤害 * * @param field * @param actors * @param i * @param j * @return */ public SRPGDamageData getDamageExpect(SRPGField field, SRPGActors actors, int attackerIndex, int defenderIndex) { SRPGDamageData damageData = new SRPGDamageData(); SRPGActor attacker = actors.find(attackerIndex); SRPGActor defender = actors.find(defenderIndex); this.status = new SRPGStatus(attacker.getActorStatus()); this.status1 = new SRPGStatus(defender.getActorStatus()); this.status2 = new SRPGStatus(status1); this.status.statusChange(); this.status1.statusChange(); SRPGFieldElement atkElement = field.getPosMapElement( attacker.getPosX(), attacker.getPosY()); if (atkElement != null) { this.atk = atkElement.atk; } else { this.atk = 1; } SRPGFieldElement defElement = field.getPosMapElement( defender.getPosX(), defender.getPosY()); if (atkElement != null) { this.def = defElement.def; } else { this.def = 1; } this.damageValue = ((status.dexterity / 2 + status.strength / 2) * atk) / 100 + (status1.vitality * def) / 1000; this.hitRate = ((status.agility + status.mind / 2) * 50 * atk) / 100 / (((status1.agility + status1.dexterity / 4) * def) / 100); this.damageChange = 100; this.flag = false; this.isDamage = true; this.isDamageUpdate = true; this.isHitUpdate = true; this.isHit = true; this.isStatus = false; this.isSetStatus = true; damageData.setGenre(getGenre()); if (getGenre() == SRPGType.GENRE_HELPER) { damageData.setDamageExpect(-1); } this.statasFlag = new int[15]; getAbility().runDamageExpect(attacker, defender, this, field, damageData, actors); int[] immunity = defender.getActorStatus().immunity; if (immunity != null) { for (int i = 0; i < immunity.length; i++) { if (damageData.getElement(immunity[i])) { damageValue = 0; hitRate = 0; } } } if (!status1.moveCheck() && isHit) { hitRate = 100; for (int j = 0; j < statasFlag.length; j++) { statasFlag[j] = 100; } } if (damageData.getHelper() == null) { int i = 0; do { if (i >= SRPGStatus.STATUS_MAX) break; if (damageData.getStatus(i) != 0) { damageData.setHelperString(SRPGStatus.STATUS_NAME[i]); break; } i++; } while (true); } for (int i = 0; i < SRPGStatus.STATUS_MAX; i++) { damageData.setStatusExpect(i, damageData.getStatus(i)); } boolean result = false; int value = 0; int[] guardelement = status1.guardelement; if (guardelement != null) { for (int i = 0; i < guardelement.length; i++) { if (!damageData.getElement(i)) { continue; } if (value < guardelement[i]) { value = guardelement[i]; } result = true; } } if (!result) { value = 100; } float f = damageValue * value; f /= 100F; damageValue = (int) (f + 0.5F); if (damageValue < 0) { damageValue = 0; } if (isDamage) { int d = attacker.getDirectionStatus(defender); int v = 100; int v1 = 100; if (d == SRPGType.MOVE_DOWN) { v = 100; v1 = 100; } else if (d == SRPGType.MOVE_RIGHT) { v = 120; v1 = 150; } else { v = 110; v1 = 125; } if (isDamageUpdate) { damageValue = (damageValue * v) / 100; } if (isHitUpdate) { hitRate = (hitRate * v1) / 100; } if (isStatus && isSetStatus) { for (int j = 0; j < SRPGStatus.STATUS_MAX; j++) { statasFlag[j] = (statasFlag[j] * v1) / 100; } } } if (isStatus) { for (int j = 0; j < SRPGStatus.STATUS_MAX; j++) { if (damageData.getStatus(j) != 0 && statasFlag[j] <= MathUtils.random.nextInt(100)) { damageData.setStatus(j, 0); } } } if (status1.checkSkill(SRPGStatus.SKILL_STATUSINVALID)) { for (int j = 9; j < SRPGStatus.STATUS_MAX; j++) { damageData.setStatus(j); } } if (status1.status[SRPGStatus.STATUS_DIMENSION] != 0 && (status1.checkSkill(SRPGStatus.SKILL_UNDEAD) || status1.hp > 0)) { hitRate = 0; } if (!flag) { if (damageData.getDamageExpect() != -1) { damageData.setDamageExpect(damageValue); } if (damageData.getHitrateExpect() != -1) { damageData.setHitrateExpect(hitRate); } } if (damageData.getGenre() != SRPGType.GENRE_HELPER) { damageData.setBeforeRandomDamage(damageValue); } damageData.setBeforeRandomHitrate(hitRate); if (hitRate <= MathUtils.random.nextInt(100)) { damageData.setHit(false); } else { damageData.setHit(true); } if (damageChange > 0 && damageValue > 0) { int r = MathUtils.random.nextInt(damageValue); r = (r * damageChange) / 10000 - (damageValue * r) / 2 / 10000; damageValue += r; } damageData.setDamage(damageValue); damageData.setHitrate(hitRate); { if (damageData.isHit()) { damageData.setActorStatus(damageInput(damageData, status2)); } else { damageData.setActorStatus(new SRPGStatus(defender .getActorStatus())); } } return damageData; } /** * 平均伤害判定 * * @param damageaverage * @param status * @return */ public SRPGDamageData dataInput(SRPGDamageAverage damageaverage, SRPGStatus status) { SRPGDamageData damageData = new SRPGDamageData(); damageData.setHit(true); damageData.setGenre(0); SRPGStatus status1 = new SRPGStatus(status); Object o = this.getAbility().dataInput(damageaverage, damageData, status); if (o == null) { return null; } damageData.setActorStatus(damageInput(damageData, status1)); return damageData; } public int[] getAbilitySkill() { return getAbility().getAbilitySkill(); } public boolean checkAbilitySkill(int i) { int[] res = getAbilitySkill(); if (res == null) { return false; } for (int j = 0; j < res.length; j++) { if (res[j] == i) { return true; } } return false; } public SRPGEffect getAbilityEffect(SRPGActor actor, int i, int j) { return getAbilityEffect(number, actor, i, j); } /** * 使用技能 * * @param i * @param actor * @param j * @param k * @return */ public static SRPGEffect getAbilityEffect(int index, SRPGActor actor, int j, int k) { SRPGAbilityFactory ability = SRPGAbilityFactory.getInstance(index); SRPGEffect o = ability.getAbility() .runAbilityEffect(index, actor, j, k); return o == null ? new SRPGEffect() : o; } public static SRPGStatus damageInput(SRPGDamageData damage, SRPGStatus status) { if (damage.isHit()) { switch (damage.getGenre()) { // 无动作 case SRPGType.GENRE_HELPER: case SRPGType.GENRE_CURE: default: break; // 伤害 case SRPGType.GENRE_ATTACK: status.hp -= damage.getDamage(); break; // 恢复 case SRPGType.GENRE_RECOVERY: status.hp += damage.getDamage(); if (status.hp > status.max_hp) { status.hp = status.max_hp; } break; // 减魔 case SRPGType.GENRE_MPDAMAGE: status.mp -= damage.getDamage(); if (status.mp < 0) { status.mp = 0; } break; // 补魔 case SRPGType.GENRE_MPRECOVERY: status.mp += damage.getDamage(); if (status.mp > status.max_mp) { status.mp = status.max_mp; } break; // 减魔减血 case SRPGType.GENRE_ALLDAMAGE: status.hp -= damage.getDamage(); status.mp -= damage.getMP(); if (status.mp < 0) { status.mp = 0; } break; // 回魔回血 case SRPGType.GENRE_ALLRECOVERY: status.hp += damage.getDamage(); if (status.hp > status.max_hp) { status.hp = status.max_hp; } status.mp += damage.getMP(); if (status.mp > status.max_mp) { status.mp = status.max_mp; } break; } for (int i = 0; i < 15; i++) { if (status.status[i] < damage.status[i] && status.status[i] != -1 || damage.status[i] == -1) { status.status[i] = damage.status[i]; } status.substatus[i] = damage.substatus[i]; } } return status; } public static int[] filtedAbility(int[] abilitys, SRPGStatus status, boolean flag) { int[] res = status.status; boolean flag1 = false; if (res != null && res[SRPGStatus.STATUS_SILENCE] != 0) { flag1 = true; } int[] result = new int[0]; int index = 0; for (int j = 0; j < abilitys.length; j++) { if (abilitys[j] == -1) { continue; } SRPGAbilityFactory ability = SRPGAbilityFactory .getInstance(abilitys[j]); if ((ability.getMP(status) <= status.mp || status.mp == -1) && (ability.getMP() <= 0 || !flag1) && (flag ? ability.getCounter() != 2 : ability.getCounter() != 1 && ability.getTarget() != 1)) { result = (int[]) CollectionUtils.expand(result, 1); result[index] = abilitys[j]; index++; } } if (index == 0) { return null; } return result; } public boolean filtedActor(SRPGActor actor, SRPGActor actor1) { int target = getTarget(); if (target == 2) { return true; } if (actor.getActorStatus().group == actor1.getActorStatus().group) { if (target == 1) { return true; } } else if (target == 0) { return true; } return false; } public static int[] filtedRange(int[] range, SRPGField field, int x1, int y1, int x2, int y2) { if (range == null) { return null; } int[] result = new int[0]; int index = 0; for (int j = 0; j < range.length; j++) { if (range[j] == -1) { continue; } SRPGAbilityFactory ability = SRPGAbilityFactory .getInstance(range[j]); if (ability.checkTargetTrue(field, x1, y1, x2, y2)) { result = (int[]) CollectionUtils.expand(result, 1); result[index] = range[j]; index++; } } if (index == 0) { return null; } if (index == range.length) { return result; } return result; } public static int[] filtedRange(int[] range, int x1, int y1, int x2, int y2) { int x = x1 - x2; int y = y1 - y2; if (x < 0) { x *= -1; } if (y < 0) { y *= -1; } return filtedRange(range, x + y); } public static int[] filtedRange(int[] range, int i) { if (range == null) { return null; } int[] result = new int[0]; int index = 0; for (int j = 0; j < range.length; j++) { if (range[j] == -1) { continue; } SRPGAbilityFactory ability = SRPGAbilityFactory .getInstance(range[j]); if (ability.getMinLength() <= i && ability.getMaxLength() >= i) { result = (int[]) CollectionUtils.expand(result, 1); result[index] = range[j]; index++; } } if (index == 0) { return null; } if (index == range.length) { return range; } return result; } public boolean checkTargetTrue(SRPGField field, int x1, int y1, int x2, int y2) { int r = setAttackRange(field, x1, y1)[y2][x2]; return r != -1 && r >= getMinLength() && r <= getMaxLength(); } public static int[][] setAttackRange(int[] range, SRPGField field, int x, int y) { SRPGFieldMove fieldMove = SRPGFieldMove.getInstance(field .getMoveSpace(19)); int[][] result = new int[field.getHeight()][field.getWidth()]; int index = 1; for (int j = 0; j < range.length; j++) { if (range[j] == -1) { continue; } int n = (SRPGAbilityFactory.getInstance(range[j])).getMaxLength(); if (index < n) { index = n; } } int[][] moves = fieldMove.movePower(x, y, index); again: for (int j = 0; j < range.length; j++) { if (range[j] == -1) { continue; } SRPGAbilityFactory ability = SRPGAbilityFactory .getInstance(range[j]); int t = ability.getTarget() + 1; int d = ability.getMaxLength(); int d1 = ability.getMinLength(); int count = 0; do { if (count >= result.length) { continue again; } for (int c = 0; c < result[0].length; c++) { if (moves[count][c] >= d1 && moves[count][c] <= d) { result[count][c] |= t; } } count++; } while (true); } return result; } public int[][] setAttackRange(SRPGField field, int x, int y) { SRPGFieldMove fieldmove = SRPGFieldMove.getInstance(field .getMoveSpace(19)); return fieldmove.movePower(x, y, getMaxLength()); } public boolean[][] setTrueRange(SRPGField field, int x, int y) { int[][] range = setAttackRange(field, x, y); boolean[][] res = new boolean[field.getHeight()][field.getWidth()]; int max = getMaxLength(); int min = getMinLength(); for (int j = 0; j < field.getHeight(); j++) { for (int i = 0; i < field.getWidth(); i++) { if (range[j][i] >= min && range[j][i] <= max && range[j][i] != -1) { res[j][i] = true; } else { res[j][i] = false; } } } return res; } public static int[][] setTargetRange(SRPGAbilityFactory ability, SRPGField field, int x, int y) { return ability.setTargetRange(field, x, y); } public int[][] setTargetRange(SRPGField field, int x, int y) { SRPGFieldMove fieldmove = SRPGFieldMove.getInstance(field .getMoveSpace(19)); return fieldmove.movePower(x, y, getRange()); } public static int[] getTargetTrue(int[] target, int x, int y) { if (target == null) { return null; } int[] result = new int[0]; int index = 0; for (int j = 0; j < target.length; j++) { if (target[j] != -1 && (SRPGAbilityFactory.getInstance(target[j])) .getTargetTrue(x, y)) { result = (int[]) CollectionUtils.expand(result, 1); result[index] = target[j]; index++; } } if (index == 0) { return null; } return result; } public boolean getTargetTrue(int x, int y) { int target = getTarget(); return (target != 0 || x != y) && (target != 1 || x == y); } }