public void useWeapon(final WeaponItem weapon, final IFighter caster, short targetCellId) throws FightException { final FightCell targetCell = cells[targetCellId]; int distance = Pathfinding.distanceBetween( caster.getCurrentCell().getPosition(), targetCell.getPosition()); if (caster.getStatistics().get(CharacteristicType.ActionPoints).getTotal() < weapon.getTemplate().getCost()) { throw new FightException("Invalid request: not enough AP."); } else if (distance < weapon.getTemplate().getMinRange() || distance > weapon.getTemplate().getMaxRange()) { throw new FightException("Invalid request: too close or to far from target."); } else { caster.getHandler().notifyRefreshStatistics(); AppendableFightHandlerAction action = new AppendableFightHandlerAction( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyStartAction(caster.getId()); } }); boolean failure = FightUtils.computeFailure(weapon.getTemplate().getCriticalFailureRate(), caster), critical = !failure && FightUtils.computeCritical(weapon.getTemplate().getCriticalRate(), caster); if (failure) { action.append( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyBasicAction(ActionTypeEnum.SPELL_FAILURE, caster, 0); } }); } else { action.append( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyUseWeapon(caster, targetCell); } }); if (critical) { action.append( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyBasicAction(ActionTypeEnum.SPELL_CRITICAL, caster, 0); } }); } Collection<Effect> effects = critical ? weapon.getWeaponEffects() : weapon.getWeaponEffectsCritic(); Collection<FightCell> targetCells = (critical ? weapon.getZone() : weapon.getCriticalZone()) .filter( caster.getCurrentCell(), targetCell, cells, map.getWidth(), map.getHeight()); for (Effect effect : effects) { for (FightCell cell : targetCells) { effect.apply(action, caster, cell); } } } caster .getStatistics() .get(CharacteristicType.ActionPoints) .addContext((short) -weapon.getTemplate().getCost()); action.append( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyBasicAction( ActionTypeEnum.AP_CHANGEMENT, caster, (int) caster.getId(), -weapon.getTemplate().getCost()); obj.notifyEndAction(EndActionTypeEnum.SPELL, caster); } }); foreach(action); } }
public void castSpell(final Spell spell, final IFighter caster, short targetCellId, FightLog logs) throws FightException { final FightCell targetCell = cells[targetCellId]; final ISpellLevel infos = spell.getInfos(); final int distance = Pathfinding.distanceBetween( caster.getCurrentCell().getPosition(), targetCell.getPosition()); if (caster.getStatistics().get(CharacteristicType.ActionPoints).getTotal() < infos.getCost()) { throw new SpellException("Invalid request: not enough AP."); } else if (distance > infos.getMaxRange() || distance < infos.getMinRange()) { throw new SpellException("Invalid request: you're too close or too far from the target."); } else if (caster.getLogs().castBySpell(spell.getTemplate()).size() > infos.getMaxPerTurn()) { throw new SpellException("Invalid request: too many cast of this spell."); } else { caster.getHandler().notifyRefreshStatistics(); AppendableFightHandlerAction action = new AppendableFightHandlerAction( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyStartAction(caster.getId()); } }); boolean failure = FightUtils.computeFailure(infos.getCriticalFailRate(), caster), critical = infos.getCriticalEffects().size() > 0 && !failure && FightUtils.computeCritical(infos.getCriticRate(), caster); if (failure) { action.append( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyBasicAction( ActionTypeEnum.SPELL_FAILURE, caster, spell.getTemplate().getId()); } }); } else { action.append( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyCastSpell(caster, spell, targetCell); } }); if (critical) { action.append( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyBasicAction( ActionTypeEnum.SPELL_CRITICAL, caster, spell.getTemplate().getId()); } }); } if (targetCell.getCurrentFighter() != null && caster .getLogs() .castBySpell(spell.getTemplate()) .castByTarget(targetCell.getCurrentFighter()) .size() > infos.getMaxPerPlayer()) { throw new SpellException( "Invalid request: too many cast of this spell on the same target."); } Collection<Effect> effects = critical ? infos.getCriticalEffects() : infos.getEffects(); for (Effect effect : effects) { List<IFighter> alreadyApplied = new ArrayList<>(); Collection<FightCell> targetCells = effect .getZone() .filter( caster.getCurrentCell(), targetCell, cells, map.getWidth(), map.getHeight()); for (FightCell cell : targetCells) { if (cell.getCurrentFighter() != null) { if (alreadyApplied.contains(cell.getCurrentFighter())) continue; alreadyApplied.add(cell.getCurrentFighter()); } if (effect.getNbTurns() > 0) { if (cell.getCurrentFighter() != null) { if (!effect.getFilter().filter(caster, cell.getCurrentFighter())) continue; if (effect instanceof BuffMaker) { cell.getCurrentFighter() .getBuffs() .add(((BuffMaker) effect).make(caster, cell.getCurrentFighter())); } else { cell.getCurrentFighter() .getBuffs() .add( new EffectContainerBuff( caster, cell.getCurrentFighter(), spell.getTemplate(), effect)); } } else { // todo: trap, glyph } } else { effect.apply(action, caster, cell); } } } if (targetCell.getCurrentFighter() != null) { logs.add(new FightLog.SpellCast(targetCell.getCurrentFighter(), spell.getTemplate())); } } caster .getStatistics() .get(CharacteristicType.ActionPoints) .addContext((short) -infos.getCost()); action.append( new FightHandlerAction() { @Override public void call(IFightHandler obj) throws FightException { obj.notifyBasicAction( ActionTypeEnum.AP_CHANGEMENT, caster, (int) caster.getId(), -infos.getCost()); obj.notifyEndAction(EndActionTypeEnum.SPELL, caster); } }); foreach(action); } }