Skip to content

Commit

Permalink
feat(fight): End turn glyph effect Arakne#27
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent4vx committed Jul 10, 2023
1 parent 09b13b6 commit 60a6027
Show file tree
Hide file tree
Showing 14 changed files with 677 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* This file is part of Araknemu.
*
* Araknemu is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Araknemu 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 Lesser General Public License for more details.
*
* 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-2023 Vincent Quatrevieux
*/

package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.object;

import fr.quatrevieux.araknemu.game.fight.Fight;
import fr.quatrevieux.araknemu.game.fight.castable.FightCastScope;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
import fr.quatrevieux.araknemu.game.fight.map.BattlefieldObject;
import fr.quatrevieux.araknemu.game.fight.map.FightCell;
import fr.quatrevieux.araknemu.game.spell.Spell;
import fr.quatrevieux.araknemu.network.game.out.fight.action.ActionEffect;
import fr.quatrevieux.araknemu.network.game.out.fight.battlefield.RemoveZone;
import org.checkerframework.checker.index.qual.GTENegativeOne;
import org.checkerframework.checker.index.qual.NonNegative;

/**
* Base glyph object.
* Implementations must call {@link #trigger(Fighter)} on the hook method corresponding to the glyph type (start or end turn)
*/
abstract class AbstractGlyph implements BattlefieldObject {
private final Fight fight;
private final FightCell cell;
private final Fighter caster;
private final @NonNegative int size;
private final int color;
private final Spell spell;
private @GTENegativeOne int remainingTurns;

/**
* @param fight The current fight
* @param cell The cell where the glyph is
* @param caster The caster of the glyph
* @param size The size of the glyph. 0 is for a single cell glyph
* @param color The color of the glyph. Used by the client as layer for identifying the glyph
* @param remainingTurns The remaining turns of the glyph. -1 for infinite.
* @param spell The spell that is applied when a fighter is on the glyph at the start of his turn
*/
public AbstractGlyph(Fight fight, FightCell cell, Fighter caster, @NonNegative int size, int color, @GTENegativeOne int remainingTurns, Spell spell) {
this.fight = fight;
this.cell = cell;
this.caster = caster;
this.size = size;
this.color = color;
this.remainingTurns = remainingTurns;
this.spell = spell;
}

@Override
public final FightCell cell() {
return cell;
}

@Override
public final Fighter caster() {
return caster;
}

@Override
public final @NonNegative int size() {
return size;
}

@Override
public final int color() {
return color;
}

@Override
public final boolean refresh() {
if (remainingTurns == -1) {
return true;
}

if (remainingTurns == 0) {
return false;
}

return --remainingTurns > 0;
}

@Override
public final void disappear() {
fight.send(new RemoveZone(this));
}

/**
* Trigger the glyph effects on the given fighter
*/
protected final void trigger(Fighter fighter) {
final FightCastScope castScope = FightCastScope.fromCell(spell, caster, cell, fighter.cell(), spell.effects());

fight.send(ActionEffect.glyphTriggered(caster, fighter, cell, spell));
fight.effects().apply(castScope);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* This file is part of Araknemu.
*
* Araknemu is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Araknemu 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 Lesser General Public License for more details.
*
* 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-2023 Vincent Quatrevieux
*/

package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.object;

import fr.quatrevieux.araknemu.game.fight.Fight;
import fr.quatrevieux.araknemu.game.fight.castable.BaseCastScope;
import fr.quatrevieux.araknemu.game.fight.castable.FightCastScope;
import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.EffectHandler;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
import fr.quatrevieux.araknemu.game.fight.map.FightCell;
import fr.quatrevieux.araknemu.game.spell.SpellService;
import fr.quatrevieux.araknemu.game.spell.effect.SpellEffect;
import fr.quatrevieux.araknemu.network.game.out.fight.action.ActionEffect;
import fr.quatrevieux.araknemu.network.game.out.fight.battlefield.AddZones;
import fr.quatrevieux.araknemu.util.Asserter;

/**
* Add a glyph on the target cell
* The glyph will trigger the related spell on end turn of each fighter in its area
*
* Arguments:
* - min: spell ID
* - max: spell level
* - special: glyph color
*
* This effect will also take in account:
* - The effect duration as glyph duration
* - The effect area as glyph size
*
* Remaining turns of the glyph are decreased at the start of the caster turn.
* So it will disappear just before the caster turn.
*
* @see EndTurnGlyph
*/
public final class AddEndTurnGlyphHandler implements EffectHandler {
private final Fight fight;
private final SpellService spellService;

public AddEndTurnGlyphHandler(Fight fight, SpellService spellService) {
this.fight = fight;
this.spellService = spellService;
}

@Override
public void handle(FightCastScope cast, BaseCastScope<Fighter, FightCell>.EffectScope effect) {
throw new UnsupportedOperationException("AddEndTurnGlyphHandler must have a duration");
}

@Override
public void buff(FightCastScope cast, BaseCastScope<Fighter, FightCell>.EffectScope effect) {
final Fighter caster = cast.caster();
final SpellEffect spellEffect = effect.effect();

final EndTurnGlyph glyph = new EndTurnGlyph(
fight,
cast.target(),
caster,
spellEffect.area().size(),
spellEffect.special(),
spellEffect.duration(),
spellService
.get(spellEffect.min())
.level(Asserter.assertPositive(spellEffect.max()))
);

fight.map().objects().add(glyph);
fight.send(ActionEffect.packet(caster, new AddZones(glyph)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* This file is part of Araknemu.
*
* Araknemu is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Araknemu 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 Lesser General Public License for more details.
*
* 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-2023 Vincent Quatrevieux
*/

package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.object;

import fr.quatrevieux.araknemu.game.fight.Fight;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
import fr.quatrevieux.araknemu.game.fight.map.FightCell;
import fr.quatrevieux.araknemu.game.spell.Spell;
import org.checkerframework.checker.index.qual.GTENegativeOne;
import org.checkerframework.checker.index.qual.NonNegative;

/**
* Glyph object which is triggered at end of turn, created by {@link AddEndTurnGlyphHandler}
*/
final class EndTurnGlyph extends AbstractGlyph {
/**
* @param fight The current fight
* @param cell The cell where the glyph is
* @param caster The caster of the glyph
* @param size The size of the glyph. 0 is for a single cell glyph
* @param color The color of the glyph. Used by the client as layer for identifying the glyph
* @param remainingTurns The remaining turns of the glyph. -1 for infinite.
* @param spell The spell that is applied when a fighter is on the glyph at the start of his turn
*/
public EndTurnGlyph(Fight fight, FightCell cell, Fighter caster, @NonNegative int size, int color, @GTENegativeOne int remainingTurns, Spell spell) {
super(fight, cell, caster, size, color, remainingTurns, spell);
}

@Override
public void onEndTurnInArea(Fighter fighter) {
trigger(fighter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,16 @@
package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.object;

import fr.quatrevieux.araknemu.game.fight.Fight;
import fr.quatrevieux.araknemu.game.fight.castable.FightCastScope;
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
import fr.quatrevieux.araknemu.game.fight.map.BattlefieldObject;
import fr.quatrevieux.araknemu.game.fight.map.FightCell;
import fr.quatrevieux.araknemu.game.spell.Spell;
import fr.quatrevieux.araknemu.network.game.out.fight.action.ActionEffect;
import fr.quatrevieux.araknemu.network.game.out.fight.battlefield.RemoveZone;
import org.checkerframework.checker.index.qual.GTENegativeOne;
import org.checkerframework.checker.index.qual.NonNegative;

/**
* Glyph object, created by {@link AddGlyphHandler}
*/
final class Glyph implements BattlefieldObject {
private final Fight fight;
private final FightCell cell;
private final Fighter caster;
private final @NonNegative int size;
private final int color;
private final Spell spell;
private @GTENegativeOne int remainingTurns;

final class Glyph extends AbstractGlyph {
/**
* @param fight The current fight
* @param cell The cell where the glyph is
Expand All @@ -52,58 +40,11 @@ final class Glyph implements BattlefieldObject {
* @param spell The spell that is applied when a fighter is on the glyph at the start of his turn
*/
public Glyph(Fight fight, FightCell cell, Fighter caster, @NonNegative int size, int color, @GTENegativeOne int remainingTurns, Spell spell) {
this.fight = fight;
this.cell = cell;
this.caster = caster;
this.size = size;
this.color = color;
this.remainingTurns = remainingTurns;
this.spell = spell;
}

@Override
public FightCell cell() {
return cell;
}

@Override
public Fighter caster() {
return caster;
}

@Override
public @NonNegative int size() {
return size;
}

@Override
public int color() {
return color;
}

@Override
public boolean refresh() {
if (remainingTurns == -1) {
return true;
}

if (remainingTurns == 0) {
return false;
}

return --remainingTurns > 0;
super(fight, cell, caster, size, color, remainingTurns, spell);
}

@Override
public void onStartTurnInArea(Fighter fighter) {
final FightCastScope castScope = FightCastScope.fromCell(spell, caster, cell, fighter.cell(), spell.effects());

fight.send(ActionEffect.glyphTriggered(caster, fighter, cell, spell));
fight.effects().apply(castScope);
}

@Override
public void disappear() {
fight.send(new RemoveZone(this));
trigger(fighter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ public default boolean refresh() {
*/
public default void onStartTurnInArea(Fighter fighter) {}

/**
* The given fighter has ended his turn in the area of the object
*
* @see BattlefieldObjects#onEndTurn(Fighter) Called by this method
*/
public default void onEndTurnInArea(Fighter fighter) {}

/**
* The given fighter has moved into the area of the object
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,23 @@ public void onStartTurn(Fighter fighter) {
}
}

/**
* Apply end turn effects from objects if the fighter is on area
*
* @param fighter The fighter who end his turn
*
* @see BattlefieldObject#onEndTurnInArea(Fighter) To apply end turn effects
*/
public void onEndTurn(Fighter fighter) {
for (Iterator<BattlefieldObject> it = iterator(); it.hasNext();) {
final BattlefieldObject object = it.next();

if (object.isOnArea(fighter)) {
object.onEndTurnInArea(fighter);
}
}
}

/**
* Apply object effects when the fighter enters the object area after a move
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import fr.quatrevieux.araknemu.game.fight.Fight;
import fr.quatrevieux.araknemu.game.fight.castable.effect.EffectsHandler;
import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.misc.ApplySpellOnStartTurnHandler;
import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.object.AddEndTurnGlyphHandler;
import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.object.AddGlyphHandler;
import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.object.AddTrapHandler;
import fr.quatrevieux.araknemu.game.fight.spectator.Spectator;
Expand All @@ -48,8 +49,9 @@ public IndirectSpellApplyEffectsModule(Fight fight, SpellService spellService) {
@Override
public void effects(EffectsHandler handler) {
handler.register(787, new ApplySpellOnStartTurnHandler(fight, spellService));
handler.register(401, new AddGlyphHandler(fight, spellService));
handler.register(400, new AddTrapHandler(fight, spellService));
handler.register(401, new AddGlyphHandler(fight, spellService));
handler.register(402, new AddEndTurnGlyphHandler(fight, spellService));
}

@Override
Expand Down
Loading

0 comments on commit 60a6027

Please sign in to comment.