Skip to content

Commit

Permalink
Merge pull request #356 from vincent4vx/chore-interface-for-buff
Browse files Browse the repository at this point in the history
chore(fight): Add Buff interfaces to seprate AI and fight types
  • Loading branch information
vincent4vx authored Jul 9, 2024
2 parents 6fbd3bb + 9f79759 commit b350d4a
Show file tree
Hide file tree
Showing 151 changed files with 1,222 additions and 1,164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package fr.quatrevieux.araknemu.game.fight.ai.proxy;

import fr.arakne.utils.maps.constant.Direction;
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buff;
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs;
import fr.quatrevieux.araknemu.game.fight.fighter.ActiveFighter;
import fr.quatrevieux.araknemu.game.fight.fighter.FighterCharacteristics;
Expand Down Expand Up @@ -102,7 +103,7 @@ public Life life() {
}

@Override
public Buffs buffs() {
public Buffs<? extends Buff> buffs() {
return fighter.buffs();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import fr.arakne.utils.maps.constant.Direction;
import fr.quatrevieux.araknemu.game.fight.ai.AI;
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buff;
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs;
import fr.quatrevieux.araknemu.game.fight.fighter.FighterCharacteristics;
import fr.quatrevieux.araknemu.game.fight.fighter.FighterData;
Expand Down Expand Up @@ -77,7 +78,7 @@ public Life life() {
}

@Override
public Buffs buffs() {
public Buffs<? extends Buff> buffs() {
return fighter.buffs();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public SpellScore score(Spell spell, Characteristics characteristics) {
*
* @return The modified damage
*
* @see BuffEffectSimulator#onReduceableDamage(CastSimulation simulation, Buff, FighterData, Damage) The called buff method
* @see BuffEffectSimulator#onReduceableDamage(CastSimulation, Buff, FighterData, Damage) The called buff method
*/
public Damage applyReduceableDamageBuffs(CastSimulation simulation, FighterData target, Damage damage) {
for (Buff buff : target.buffs()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public final class GivePercentLifeSimulator implements EffectSimulator {
@Override
public void simulate(CastSimulation simulation, AI ai, CastScope.EffectScope<? extends FighterData, ? extends BattlefieldCell> effect) {
final FighterData caster = ai.fighter();
final int heal = EffectValue.create(effect.effect(), caster, caster).value() * caster.life().current() / 100;
final int heal = new EffectValue(effect.effect()).value() * caster.life().current() / 100;

simulation.addDamage(Interval.of(heal), caster);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void simulate(CastSimulation simulation, AI ai, CastScope.EffectScope<? e

for (FighterData target : effect.targets()) {
final SpellEffect spellEffect = effect.effect();
final Interval value = EffectValue.create(spellEffect, simulation.caster(), target)
final Interval value = new EffectValue(spellEffect)
.percent(boost)
.fixed(fixed)
.interval()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void simulate(CastSimulation simulation, AI ai, CastScope.EffectScope<? e

final int targetResistance = Math.max(target.characteristics().get(resistanceCharacteristic), 1);
final double percent = Math.min(0.5 * casterChance / targetResistance, 1.0);
final double value = multiplier * EffectValue.create(effect.effect(), simulation.caster(), target).interval().average();
final double value = multiplier * new EffectValue(effect.effect()).interval().average();
final double maxValue = currentPoints * multiplier;

simulation.addBoost(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import fr.arakne.utils.value.Interval;
import fr.arakne.utils.value.helper.RandomUtil;
import fr.quatrevieux.araknemu.game.fight.fighter.FighterData;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
import fr.quatrevieux.araknemu.game.spell.effect.SpellEffect;
import org.checkerframework.checker.index.qual.NonNegative;

Expand Down Expand Up @@ -187,13 +187,13 @@ protected EffectValue clone() {
* Create and configure an effect value for a given caster and target
*
* @param effect The spell effect
* @param caster The spell caster on which {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onEffectValueCast(EffectValue)} will be called
* @param target The target on which {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onEffectValueTarget(EffectValue)} will be called
* @param caster The spell caster on which {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffListHooks#onEffectValueCast(EffectValue)} will be called
* @param target The target on which {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffListHooks#onEffectValueTarget(EffectValue)} will be called
*
* @return The configured effect
* @todo Use Fighter instead of FighterData
*/
public static EffectValue create(SpellEffect effect, FighterData caster, FighterData target) {
public static EffectValue create(SpellEffect effect, Fighter caster, Fighter target) {
final EffectValue value = new EffectValue(effect);

caster.buffs().onEffectValueCast(value);
Expand All @@ -206,7 +206,7 @@ public static EffectValue create(SpellEffect effect, FighterData caster, Fighter
* Create and configure multiple effect values for multiple targets
*
* Only one "dice" will be used for all targets, but each target will receive their own EffectValue,
* configured using {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onEffectValueTarget(EffectValue)}.
* configured using {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffListHooks#onEffectValueTarget(EffectValue)}.
*
* So {@link EffectValue#minimize()} and {@link EffectValue#maximize()} are effective, without change the effects value of others targets
*
Expand All @@ -221,11 +221,11 @@ public static EffectValue create(SpellEffect effect, FighterData caster, Fighter
* }</pre>
*
* @param effect The spell effect
* @param caster The spell caster on which {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onEffectValueCast(EffectValue)} will be called
* @param targets Targets used to configure the effect value using {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onEffectValueTarget(EffectValue)}
* @param caster The spell caster on which {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffListHooks#onEffectValueCast(EffectValue)} will be called
* @param targets Targets used to configure the effect value using {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffListHooks#onEffectValueTarget(EffectValue)}
* @param action Action to perform on each target, with their related effect value
*/
public static <F extends FighterData> void forEachTargets(SpellEffect effect, FighterData caster, Iterable<F> targets, BiConsumer<F, EffectValue> action) {
public static <F extends Fighter> void forEachTargets(SpellEffect effect, Fighter caster, Iterable<F> targets, BiConsumer<F, EffectValue> action) {
final Context context = preRoll(effect, caster);

for (F target : targets) {
Expand All @@ -238,7 +238,7 @@ public static <F extends FighterData> void forEachTargets(SpellEffect effect, Fi
*
* The "dice" will be rolled and configured for the caster, and a factory will be returned
* to configure the effect value for each target.
* The final effect value is configured using {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onEffectValueTarget(EffectValue)}.
* The final effect value is configured using {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffListHooks#onEffectValueTarget(EffectValue)}.
*
* So {@link EffectValue#minimize()} and {@link EffectValue#maximize()} are effective, without change the effects value of others targets
*
Expand All @@ -258,9 +258,9 @@ public static <F extends FighterData> void forEachTargets(SpellEffect effect, Fi
* }</pre>
*
* @param effect The spell effect
* @param caster The spell caster on which {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onEffectValueCast(EffectValue)} will be called
* @param caster The spell caster on which {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffListHooks#onEffectValueCast(EffectValue)} will be called
*/
public static Context preRoll(SpellEffect effect, FighterData caster) {
public static Context preRoll(SpellEffect effect, Fighter caster) {
final EffectValue value = new EffectValue(effect);

caster.buffs().onEffectValueCast(value);
Expand Down Expand Up @@ -310,6 +310,6 @@ public interface Context {
*
* @return The new instance of effect value, configured for the target
*/
public EffectValue forTarget(FighterData target);
public EffectValue forTarget(Fighter target);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import fr.quatrevieux.araknemu.game.fight.castable.CastScope;
import fr.quatrevieux.araknemu.game.fight.castable.Castable;
import fr.quatrevieux.araknemu.game.fight.castable.FightCastScope;
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buff;
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.FightBuff;
import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.EffectHandler;
import fr.quatrevieux.araknemu.game.fight.castable.effect.hook.EffectHookHandler;
import fr.quatrevieux.araknemu.game.fight.castable.validator.CastConstraintValidator;
Expand Down Expand Up @@ -98,8 +98,8 @@ public void registerHook(int hookId, EffectHookHandler applier) {
/**
* Apply a cast to the fight
*
* First, this method will call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffHook#onCast(Buff, FightCastScope)} to caster
* Then call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffHook#onCastTarget(Buff, FightCastScope)} to all targets
* First, this method will call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffHook#onCast(FightBuff, FightCastScope)} to caster
* Then call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffHook#onCastTarget(FightBuff, FightCastScope)} to all targets
*
* After that, all effects will be applied by calling :
* - Checking if the effect has a hook with {@link EffectTarget#isHook()}
Expand Down Expand Up @@ -145,7 +145,7 @@ public void apply(FightCastScope cast) {
}

/**
* Call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onCastTarget(FightCastScope)}
* Call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffListHooks#onCastTarget(FightCastScope)}
* on each target.
*
* If a target is changed (by calling {@link CastScope#replaceTarget(FighterData, FighterData)}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,124 +14,34 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Araknemu. If not, see <https://www.gnu.org/licenses/>.
*
* Copyright (c) 2017-2019 Vincent Quatrevieux
* Copyright (c) 2017-2024 Vincent Quatrevieux
*/

package fr.quatrevieux.araknemu.game.fight.castable.effect.buff;

import fr.quatrevieux.araknemu.game.fight.castable.Castable;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
import fr.quatrevieux.araknemu.game.fight.fighter.FighterData;
import fr.quatrevieux.araknemu.game.spell.effect.SpellEffect;
import org.checkerframework.checker.index.qual.GTENegativeOne;

/**
* Persistent effect
* Base type for buff applied to a fighter
*
* The duration will be taken from the effect.
* For overload the buff effect value (or duration), you must create a new effect instance
* This interface is used by both AI and fight system,
* and its intended to be overridden to use appropriate types (e.g. fighter type)
*/
public final class Buff {
private final SpellEffect effect;
private final Castable action;
private final Fighter caster;
private final Fighter target;
private final BuffHook hook;
private final boolean canBeDispelled;

private @GTENegativeOne int remainingTurns;

public Buff(SpellEffect effect, Castable action, Fighter caster, Fighter target, BuffHook hook) {
this(effect, action, caster, target, hook, true);
}

public Buff(SpellEffect effect, Castable action, Fighter caster, Fighter target, BuffHook hook, boolean canBeDispelled) {
this.effect = effect;
this.action = action;
this.caster = caster;
this.target = target;
this.hook = hook;
this.canBeDispelled = canBeDispelled;

this.remainingTurns = effect.duration();
}

public interface Buff {
/**
* Get the buff effect
* For most cases, {@link SpellEffect#min()} is used as the buff value, and {@link SpellEffect#max()} set to 0
*/
public SpellEffect effect() {
return effect;
}

/**
* Get the action which generates this buff
*/
public Castable action() {
return action;
}

/**
* Get the buff caster
*/
public Fighter caster() {
return caster;
}

/**
* Get the buff target
*/
public Fighter target() {
return target;
}

/**
* Remaining turns for the buff effect
*
* When this value reached 0, the buff should be removed
* In case of infinite effect, the returned value is -1
*/
public @GTENegativeOne int remainingTurns() {
return remainingTurns;
}

/**
* Decrements the remaining turns
*
* You should call {@link Buff#valid()} for check if the buff is still valid or not
*/
public void decrementRemainingTurns() {
if (remainingTurns > 0) {
--remainingTurns;
}
}

/**
* Increment remaining turns
* Use this method when a self-buff is added
*/
public void incrementRemainingTurns() {
if (remainingTurns != -1) {
++remainingTurns;
}
}

/**
* Get the related hook for the buff
*/
public BuffHook hook() {
return hook;
}
public SpellEffect effect();

/**
* Check if the buff is still valid
* Get the buff caster (i.e. the fighter who cast the spell that applied the buff)
*/
public boolean valid() {
return remainingTurns != 0;
}
public FighterData caster();

/**
* Check if the buff can be removed
* Get the buff target (i.e. the fighter who is affected by the buff)
*/
public boolean canBeDispelled() {
return canBeDispelled;
}
public FighterData target();
}
Loading

0 comments on commit b350d4a

Please sign in to comment.