diff --git a/src/main/java/fr/quatrevieux/araknemu/core/event/EventsSubscriber.java b/src/main/java/fr/quatrevieux/araknemu/core/event/EventsSubscriber.java index 2ada528cd..6e4b014f6 100644 --- a/src/main/java/fr/quatrevieux/araknemu/core/event/EventsSubscriber.java +++ b/src/main/java/fr/quatrevieux/araknemu/core/event/EventsSubscriber.java @@ -1,7 +1,5 @@ package fr.quatrevieux.araknemu.core.event; -import java.util.Collection; - /** * Subscribe to events registering listeners */ diff --git a/src/main/java/fr/quatrevieux/araknemu/game/GameModule.java b/src/main/java/fr/quatrevieux/araknemu/game/GameModule.java index caa7d788e..a66e7c205 100644 --- a/src/main/java/fr/quatrevieux/araknemu/game/GameModule.java +++ b/src/main/java/fr/quatrevieux/araknemu/game/GameModule.java @@ -51,6 +51,7 @@ import fr.quatrevieux.araknemu.game.exploration.map.cell.trigger.action.teleport.TeleportFactory; import fr.quatrevieux.araknemu.game.fight.FightService; import fr.quatrevieux.araknemu.game.fight.builder.ChallengeBuilderFactory; +import fr.quatrevieux.araknemu.game.fight.module.RaulebaqueModule; import fr.quatrevieux.araknemu.game.handler.loader.*; import fr.quatrevieux.araknemu.game.item.ItemService; import fr.quatrevieux.araknemu.game.item.SuperType; @@ -425,6 +426,9 @@ private void configureServices(ContainerConfigurator configurator) container.get(fr.quatrevieux.araknemu.core.event.Dispatcher.class), Arrays.asList( new ChallengeBuilderFactory() + ), + Arrays.asList( + RaulebaqueModule::new ) ) ); diff --git a/src/main/java/fr/quatrevieux/araknemu/game/fight/Fight.java b/src/main/java/fr/quatrevieux/araknemu/game/fight/Fight.java index 377afe0e4..15bdd891a 100644 --- a/src/main/java/fr/quatrevieux/araknemu/game/fight/Fight.java +++ b/src/main/java/fr/quatrevieux/araknemu/game/fight/Fight.java @@ -9,6 +9,7 @@ import fr.quatrevieux.araknemu.game.fight.exception.InvalidFightStateException; import fr.quatrevieux.araknemu.game.fight.fighter.Fighter; import fr.quatrevieux.araknemu.game.fight.map.FightMap; +import fr.quatrevieux.araknemu.game.fight.module.FightModule; import fr.quatrevieux.araknemu.game.fight.state.*; import fr.quatrevieux.araknemu.game.fight.team.FightTeam; import fr.quatrevieux.araknemu.game.fight.turn.FightTurnList; @@ -17,6 +18,7 @@ import org.apache.commons.lang3.time.StopWatch; import java.time.Duration; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; import java.util.stream.Collectors; @@ -30,6 +32,7 @@ final public class Fight implements Dispatcher, Sender { final private FightMap map; final private List teams; final private StatesFlow statesFlow; + final private List modules = new ArrayList<>(); final private ListenerAggregate dispatcher = new DefaultListenerAggregate(); final private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); @@ -56,6 +59,16 @@ public Fight(int id, FightType type, FightMap map, List teams) { )); } + /** + * Register a module + */ + public void register(FightModule module) + { + modules.add(module); + dispatcher.register(module); + module.effects(effects); + } + /** * Get the fight id */ @@ -121,6 +134,7 @@ public T state(Class type) { */ public void nextState() { statesFlow.next(this); + modules.forEach(module -> module.stateChanged(statesFlow.current())); } /** diff --git a/src/main/java/fr/quatrevieux/araknemu/game/fight/FightHandler.java b/src/main/java/fr/quatrevieux/araknemu/game/fight/FightHandler.java index 0f4f0b743..f265ad208 100644 --- a/src/main/java/fr/quatrevieux/araknemu/game/fight/FightHandler.java +++ b/src/main/java/fr/quatrevieux/araknemu/game/fight/FightHandler.java @@ -5,6 +5,7 @@ import fr.quatrevieux.araknemu.game.fight.builder.FightBuilder; import fr.quatrevieux.araknemu.game.fight.event.FightCancelled; import fr.quatrevieux.araknemu.game.fight.event.FightStopped; +import fr.quatrevieux.araknemu.game.fight.module.FightModule; import java.util.function.Consumer; @@ -29,6 +30,8 @@ public Fight start(Consumer configuration) { configuration.accept(builder); Fight fight = builder.build(service.newFightId()); + + service.modules(fight).forEach(fight::register); fight.nextState(); fight.dispatcher().register(this); diff --git a/src/main/java/fr/quatrevieux/araknemu/game/fight/FightService.java b/src/main/java/fr/quatrevieux/araknemu/game/fight/FightService.java index 2e03b0cb6..eef5a80ab 100644 --- a/src/main/java/fr/quatrevieux/araknemu/game/fight/FightService.java +++ b/src/main/java/fr/quatrevieux/araknemu/game/fight/FightService.java @@ -10,6 +10,7 @@ import fr.quatrevieux.araknemu.game.fight.builder.FightBuilderFactory; import fr.quatrevieux.araknemu.game.fight.event.FightCreated; import fr.quatrevieux.araknemu.game.fight.map.FightMap; +import fr.quatrevieux.araknemu.game.fight.module.FightModule; import fr.quatrevieux.araknemu.game.listener.player.exploration.LeaveExplorationForFight; import fr.quatrevieux.araknemu.game.listener.player.fight.AttachFighter; import fr.quatrevieux.araknemu.game.player.event.PlayerLoaded; @@ -26,13 +27,15 @@ final public class FightService implements EventsSubscriber { final private MapTemplateRepository mapRepository; final private Dispatcher dispatcher; final private Map builderFactories; + final private Collection moduleFactories; final private Map> fightsByMapId = new HashMap<>(); final private AtomicInteger lastFightId = new AtomicInteger(); - public FightService(MapTemplateRepository mapRepository, Dispatcher dispatcher, Collection factories) { + public FightService(MapTemplateRepository mapRepository, Dispatcher dispatcher, Collection factories, Collection moduleFactories) { this.mapRepository = mapRepository; this.dispatcher = dispatcher; + this.moduleFactories = moduleFactories; this.builderFactories = factories.stream().collect( Collectors.toMap( @@ -155,4 +158,14 @@ synchronized void created(Fight fight) { synchronized void remove(Fight fight) { fightsByMapId.get(fight.map().id()).remove(fight.id()); } + + /** + * Make modules for a fight + */ + Collection modules(Fight fight) { + return moduleFactories.stream() + .map(factory -> factory.create(fight)) + .collect(Collectors.toList()) + ; + } } diff --git a/src/main/java/fr/quatrevieux/araknemu/game/fight/castable/effect/handler/shifting/RaulebaqueHandler.java b/src/main/java/fr/quatrevieux/araknemu/game/fight/castable/effect/handler/shifting/RaulebaqueHandler.java new file mode 100644 index 000000000..70f99ff64 --- /dev/null +++ b/src/main/java/fr/quatrevieux/araknemu/game/fight/castable/effect/handler/shifting/RaulebaqueHandler.java @@ -0,0 +1,49 @@ +package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.shifting; + +import fr.quatrevieux.araknemu.game.fight.Fight; +import fr.quatrevieux.araknemu.game.fight.castable.CastScope; +import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.EffectHandler; +import fr.quatrevieux.araknemu.game.fight.map.FightCell; +import fr.quatrevieux.araknemu.game.fight.module.RaulebaqueModule; +import fr.quatrevieux.araknemu.network.game.out.fight.FighterPositions; + +/** + * Handle the Raulebaque effect + */ +final public class RaulebaqueHandler implements EffectHandler { + final private Fight fight; + final private RaulebaqueModule module; + + public RaulebaqueHandler(Fight fight, RaulebaqueModule module) { + this.fight = fight; + this.module = module; + } + + @Override + public void handle(CastScope cast, CastScope.EffectScope effect) { + module.startPositions().forEach((fighter, startCell) -> { + if (fighter.dead()) { + return; + } + + FightCell lastCell = fighter.cell(); + + if (lastCell.equals(startCell)) { + return; + } + + fighter.move(null); + + // Cell is not free : exchange place + startCell.fighter().ifPresent(other -> other.move(lastCell)); + fighter.move(startCell); + }); + + fight.send(new FighterPositions(fight.fighters())); + } + + @Override + public void buff(CastScope cast, CastScope.EffectScope effect) { + throw new UnsupportedOperationException("Cannot use Raulebaque as buff effect"); + } +} diff --git a/src/main/java/fr/quatrevieux/araknemu/game/fight/fighter/player/PlayerFighter.java b/src/main/java/fr/quatrevieux/araknemu/game/fight/fighter/player/PlayerFighter.java index d5bfa7e4f..da7417bbb 100644 --- a/src/main/java/fr/quatrevieux/araknemu/game/fight/fighter/player/PlayerFighter.java +++ b/src/main/java/fr/quatrevieux/araknemu/game/fight/fighter/player/PlayerFighter.java @@ -72,7 +72,10 @@ public void move(FightCell cell) { this.cell.removeFighter(); } - cell.set(this); + if (cell != null) { + cell.set(this); + } + this.cell = cell; } diff --git a/src/main/java/fr/quatrevieux/araknemu/game/fight/module/FightModule.java b/src/main/java/fr/quatrevieux/araknemu/game/fight/module/FightModule.java new file mode 100644 index 000000000..a07964785 --- /dev/null +++ b/src/main/java/fr/quatrevieux/araknemu/game/fight/module/FightModule.java @@ -0,0 +1,29 @@ +package fr.quatrevieux.araknemu.game.fight.module; + +import fr.quatrevieux.araknemu.core.event.EventsSubscriber; +import fr.quatrevieux.araknemu.game.fight.Fight; +import fr.quatrevieux.araknemu.game.fight.castable.effect.EffectsHandler; +import fr.quatrevieux.araknemu.game.fight.state.FightState; + +/** + * The fight module is used to register new effects, or listeners on the fight for extends its capabilities + * The module instance is dedicated to one fight instance, and can safely be used as state object + */ +public interface FightModule extends EventsSubscriber { + public interface Factory { + /** + * Create the module for the given fight + */ + public FightModule create(Fight fight); + } + + /** + * Register fight effects into the effect handle + */ + public void effects(EffectsHandler handler); + + /** + * The fight has changed its current state + */ + public void stateChanged(FightState newState); +} diff --git a/src/main/java/fr/quatrevieux/araknemu/game/fight/module/RaulebaqueModule.java b/src/main/java/fr/quatrevieux/araknemu/game/fight/module/RaulebaqueModule.java new file mode 100644 index 000000000..e27b79393 --- /dev/null +++ b/src/main/java/fr/quatrevieux/araknemu/game/fight/module/RaulebaqueModule.java @@ -0,0 +1,70 @@ +package fr.quatrevieux.araknemu.game.fight.module; + +import fr.quatrevieux.araknemu.core.event.Listener; +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.shifting.RaulebaqueHandler; +import fr.quatrevieux.araknemu.game.fight.event.FightStarted; +import fr.quatrevieux.araknemu.game.fight.fighter.Fighter; +import fr.quatrevieux.araknemu.game.fight.map.FightCell; +import fr.quatrevieux.araknemu.game.fight.state.FightState; + +import java.util.HashMap; +import java.util.Map; + +/** + * Module for handle Raulebaque spell + * + * This spell will reset all fighters position to the initial one + */ +final public class RaulebaqueModule implements FightModule { + final private Fight fight; + + private Map startPositions; + + public RaulebaqueModule(Fight fight) { + this.fight = fight; + } + + @Override + public void effects(EffectsHandler handler) { + handler.register(784, new RaulebaqueHandler(fight, this)); + } + + @Override + public void stateChanged(FightState newState) { + + } + + public Map startPositions() { + return startPositions; + } + + @Override + public Listener[] listeners() { + return new Listener[] { + new Listener() { + @Override + public void on(FightStarted event) { + loadStartPositions(); + } + + @Override + public Class event() { + return FightStarted.class; + } + } + }; + } + + /** + * Load the start positions + */ + private void loadStartPositions() { + startPositions = new HashMap<>(); + + for (Fighter fighter : fight.fighters()) { + startPositions.put(fighter, fighter.cell()); + } + } +} diff --git a/src/test/java/fr/quatrevieux/araknemu/game/fight/FightBaseCase.java b/src/test/java/fr/quatrevieux/araknemu/game/fight/FightBaseCase.java index 927a26fd2..b415d8126 100644 --- a/src/test/java/fr/quatrevieux/araknemu/game/fight/FightBaseCase.java +++ b/src/test/java/fr/quatrevieux/araknemu/game/fight/FightBaseCase.java @@ -20,8 +20,13 @@ import fr.quatrevieux.araknemu.game.item.type.Weapon; import fr.quatrevieux.araknemu.game.player.GamePlayer; import fr.quatrevieux.araknemu.game.player.inventory.slot.WeaponSlot; +import fr.quatrevieux.araknemu.game.spell.Spell; +import fr.quatrevieux.araknemu.game.spell.SpellConstraints; import fr.quatrevieux.araknemu.game.spell.effect.SpellEffect; +import fr.quatrevieux.araknemu.game.spell.effect.area.CellArea; +import fr.quatrevieux.araknemu.game.spell.effect.target.SpellEffectTarget; import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mockito; import java.sql.SQLException; import java.util.ArrayList; @@ -120,4 +125,22 @@ public void equipWeapon(GamePlayer player) throws ContainerException, InventoryE public CastScope makeCastScope(Fighter caster, Castable castable, SpellEffect effect, FightCell target) { return new CastScope(castable, caster, target).withEffects(Collections.singletonList(effect)); } + + public CastScope makeCastScopeForEffect(int effectId) { + return makeCastScopeForEffect(effectId, player.fighter(), other.fighter().cell()); + } + + public CastScope makeCastScopeForEffect(int effectId, Fighter caster, FightCell target) { + SpellEffect effect = Mockito.mock(SpellEffect.class); + Spell spell = Mockito.mock(Spell.class); + SpellConstraints constraints = Mockito.mock(SpellConstraints.class); + + Mockito.when(effect.effect()).thenReturn(effectId); + Mockito.when(effect.area()).thenReturn(new CellArea()); + Mockito.when(effect.target()).thenReturn(SpellEffectTarget.DEFAULT); + Mockito.when(spell.constraints()).thenReturn(constraints); + Mockito.when(constraints.freeCell()).thenReturn(false); + + return makeCastScope(caster, spell, effect, target); + } } diff --git a/src/test/java/fr/quatrevieux/araknemu/game/fight/FightServiceTest.java b/src/test/java/fr/quatrevieux/araknemu/game/fight/FightServiceTest.java index d4d3653d8..6cb315749 100644 --- a/src/test/java/fr/quatrevieux/araknemu/game/fight/FightServiceTest.java +++ b/src/test/java/fr/quatrevieux/araknemu/game/fight/FightServiceTest.java @@ -2,9 +2,7 @@ import fr.quatrevieux.araknemu.core.di.ContainerException; import fr.quatrevieux.araknemu.core.event.DefaultListenerAggregate; -import fr.quatrevieux.araknemu.core.event.Dispatcher; import fr.quatrevieux.araknemu.data.world.repository.environment.MapTemplateRepository; -import fr.quatrevieux.araknemu.game.GameBaseCase; import fr.quatrevieux.araknemu.core.event.ListenerAggregate; import fr.quatrevieux.araknemu.game.exploration.ExplorationPlayer; import fr.quatrevieux.araknemu.game.exploration.event.ExplorationPlayerCreated; @@ -13,6 +11,9 @@ import fr.quatrevieux.araknemu.game.fight.builder.ChallengeBuilder; import fr.quatrevieux.araknemu.game.fight.builder.ChallengeBuilderFactory; import fr.quatrevieux.araknemu.game.fight.event.FightCreated; +import fr.quatrevieux.araknemu.game.fight.module.FightModule; +import fr.quatrevieux.araknemu.game.fight.module.RaulebaqueModule; +import fr.quatrevieux.araknemu.game.fight.type.ChallengeType; import fr.quatrevieux.araknemu.game.listener.player.exploration.LeaveExplorationForFight; import fr.quatrevieux.araknemu.game.listener.player.fight.AttachFighter; import fr.quatrevieux.araknemu.game.player.event.PlayerLoaded; @@ -20,8 +21,7 @@ import org.junit.jupiter.api.Test; import java.sql.SQLException; -import java.util.Arrays; -import java.util.NoSuchElementException; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; import static org.junit.jupiter.api.Assertions.*; @@ -42,6 +42,9 @@ public void setUp() throws Exception { dispatcher = new DefaultListenerAggregate(), Arrays.asList( new ChallengeBuilderFactory() + ), + Arrays.asList( + RaulebaqueModule::new ) ); } @@ -140,4 +143,14 @@ void fightsByMap() throws ContainerException, SQLException { assertCollectionEquals(service.fightsByMap(10340), fight1, fight2, fight3); } + + @Test + void modules() throws ContainerException { + Fight fight = new Fight(1, new ChallengeType(), service.map(container.get(ExplorationMapService.class).load(10340)), new ArrayList<>()); + + Collection modules = service.modules(fight); + + assertCount(1, modules); + assertContainsType(RaulebaqueModule.class, modules); + } } diff --git a/src/test/java/fr/quatrevieux/araknemu/game/fight/FightTest.java b/src/test/java/fr/quatrevieux/araknemu/game/fight/FightTest.java index 3d71dea5e..bfecf9d60 100644 --- a/src/test/java/fr/quatrevieux/araknemu/game/fight/FightTest.java +++ b/src/test/java/fr/quatrevieux/araknemu/game/fight/FightTest.java @@ -11,6 +11,7 @@ import fr.quatrevieux.araknemu.game.fight.exception.InvalidFightStateException; import fr.quatrevieux.araknemu.game.fight.fighter.player.PlayerFighter; import fr.quatrevieux.araknemu.game.fight.map.FightMap; +import fr.quatrevieux.araknemu.game.fight.module.FightModule; import fr.quatrevieux.araknemu.game.fight.state.NullState; import fr.quatrevieux.araknemu.game.fight.state.PlacementState; import fr.quatrevieux.araknemu.game.fight.team.FightTeam; @@ -19,6 +20,7 @@ import fr.quatrevieux.araknemu.game.fight.type.ChallengeType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import java.time.Duration; import java.util.ArrayList; @@ -199,4 +201,29 @@ void cancel() { assertCount(0, fight.teams()); assertCount(0, fight.fighters()); } + + @Test + void register() { + FightModule module = Mockito.mock(FightModule.class); + + Mockito.when(module.listeners()).thenReturn(new Listener[0]); + + fight.register(module); + + Mockito.verify(module).effects(fight.effects()); + Mockito.verify(module).listeners(); + } + + @Test + void nextStateWillNotifyModules() { + fight.nextState(); + + FightModule module = Mockito.mock(FightModule.class); + Mockito.when(module.listeners()).thenReturn(new Listener[0]); + fight.register(module); + + fight.nextState(); + + Mockito.verify(module).stateChanged(fight.state()); + } } diff --git a/src/test/java/fr/quatrevieux/araknemu/game/fight/builder/FightHandlerTest.java b/src/test/java/fr/quatrevieux/araknemu/game/fight/builder/FightHandlerTest.java index 0de2b0c8e..95e400926 100644 --- a/src/test/java/fr/quatrevieux/araknemu/game/fight/builder/FightHandlerTest.java +++ b/src/test/java/fr/quatrevieux/araknemu/game/fight/builder/FightHandlerTest.java @@ -1,12 +1,17 @@ package fr.quatrevieux.araknemu.game.fight.builder; import fr.quatrevieux.araknemu.core.di.ContainerException; +import fr.quatrevieux.araknemu.core.event.DefaultListenerAggregate; +import fr.quatrevieux.araknemu.core.event.Dispatcher; +import fr.quatrevieux.araknemu.core.event.Listener; +import fr.quatrevieux.araknemu.data.world.repository.environment.MapTemplateRepository; import fr.quatrevieux.araknemu.game.GameBaseCase; import fr.quatrevieux.araknemu.game.exploration.map.ExplorationMap; import fr.quatrevieux.araknemu.game.exploration.map.ExplorationMapService; import fr.quatrevieux.araknemu.game.fight.Fight; import fr.quatrevieux.araknemu.game.fight.FightHandler; import fr.quatrevieux.araknemu.game.fight.FightService; +import fr.quatrevieux.araknemu.game.fight.module.FightModule; import fr.quatrevieux.araknemu.game.fight.state.PlacementState; import fr.quatrevieux.araknemu.game.fight.type.ChallengeType; import fr.quatrevieux.araknemu.network.game.out.fight.exploration.AddTeamFighters; @@ -15,10 +20,13 @@ import fr.quatrevieux.araknemu.network.game.out.fight.exploration.ShowFight; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import java.sql.SQLException; +import java.util.Arrays; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; class FightHandlerTest extends GameBaseCase { private FightService service; @@ -132,4 +140,43 @@ void cancelFightWillRemoveTheFight() throws ContainerException { fight.cancel(); assertCount(0, service.fightsByMap(10340)); } + + @Test + void startWillRegisterModules() throws ContainerException { + DefaultListenerAggregate dispatcher = new DefaultListenerAggregate(); + FightModule module = Mockito.mock(FightModule.class); + + Mockito.when(module.listeners()).thenReturn(new Listener[0]); + + FightHandler handler = new FightHandler<>( + new FightService( + container.get(MapTemplateRepository.class), + dispatcher, + Arrays.asList( + new ChallengeBuilderFactory() + ), + Arrays.asList( + (fight) -> module + ) + ), + new ChallengeBuilder(service) + ); + + Fight fight = handler.start( + builder -> { + try { + builder + .map(container.get(ExplorationMapService.class).load(10340)) + .fighter(makeSimpleGamePlayer(5)) + .fighter(makeSimpleGamePlayer(6)) + ; + } catch (Exception e) { + e.printStackTrace(); + } + } + ); + + Mockito.verify(module).listeners(); + Mockito.verify(module).effects(fight.effects()); + } } diff --git a/src/test/java/fr/quatrevieux/araknemu/game/fight/castable/effect/handler/shifting/RaulebaqueHandlerTest.java b/src/test/java/fr/quatrevieux/araknemu/game/fight/castable/effect/handler/shifting/RaulebaqueHandlerTest.java new file mode 100644 index 000000000..8ac597e7e --- /dev/null +++ b/src/test/java/fr/quatrevieux/araknemu/game/fight/castable/effect/handler/shifting/RaulebaqueHandlerTest.java @@ -0,0 +1,135 @@ +package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.shifting; + +import fr.quatrevieux.araknemu.core.di.ContainerException; +import fr.quatrevieux.araknemu.game.fight.Fight; +import fr.quatrevieux.araknemu.game.fight.FightBaseCase; +import fr.quatrevieux.araknemu.game.fight.castable.CastScope; +import fr.quatrevieux.araknemu.game.fight.exception.JoinFightException; +import fr.quatrevieux.araknemu.game.fight.fighter.Fighter; +import fr.quatrevieux.araknemu.game.fight.fighter.player.PlayerFighter; +import fr.quatrevieux.araknemu.game.fight.module.RaulebaqueModule; +import fr.quatrevieux.araknemu.network.game.out.fight.FighterPositions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.sql.SQLException; + +import static org.junit.jupiter.api.Assertions.*; + +class RaulebaqueHandlerTest extends FightBaseCase { + private Fight fight; + private PlayerFighter caster; + private RaulebaqueHandler handler; + + @Override + @BeforeEach + public void setUp() throws Exception { + super.setUp(); + + fight = createFight(); + RaulebaqueModule module = new RaulebaqueModule(fight); + fight.register(module); + + caster = player.fighter(); + + caster.move(fight.map().get(123)); + other.fighter().move(fight.map().get(321)); + + fight.nextState(); + + handler = new RaulebaqueHandler(fight, module); + + requestStack.clear(); + } + + @Test + void handleSimple() { + caster.move(fight.map().get(125)); + other.fighter().move(fight.map().get(325)); + + CastScope scope = makeCastScopeForEffect(784); + + handler.handle(scope, scope.effects().get(0)); + + requestStack.assertLast(new FighterPositions(fight.fighters())); + + assertEquals(123, caster.cell().id()); + assertEquals(321, other.fighter().cell().id()); + } + + @Test + void handleWillNotTeleportAddedFighters() throws SQLException, ContainerException, JoinFightException { + caster.move(fight.map().get(125)); + other.fighter().move(fight.map().get(325)); + + Fighter newFighter = new PlayerFighter(makeSimpleGamePlayer(10)); + newFighter.move(fight.map().get(235)); + fight.team(0).join(newFighter); + + newFighter.move(fight.map().get(236)); + + CastScope scope = makeCastScopeForEffect(784); + + handler.handle(scope, scope.effects().get(0)); + + requestStack.assertLast(new FighterPositions(fight.fighters())); + + assertEquals(123, caster.cell().id()); + assertEquals(321, other.fighter().cell().id()); + assertEquals(236, newFighter.cell().id()); + } + + @Test + void handleWillExchangePlaceIfTargetIsNotAvailable() throws SQLException, ContainerException, JoinFightException { + caster.move(fight.map().get(125)); + other.fighter().move(fight.map().get(325)); + + Fighter newFighter = new PlayerFighter(makeSimpleGamePlayer(10)); + newFighter.move(fight.map().get(123)); + fight.team(0).join(newFighter); + + CastScope scope = makeCastScopeForEffect(784); + + handler.handle(scope, scope.effects().get(0)); + + requestStack.assertLast(new FighterPositions(fight.fighters())); + + assertEquals(123, caster.cell().id()); + assertEquals(321, other.fighter().cell().id()); + assertEquals(125, newFighter.cell().id()); + } + + @Test + void handleWithoutChanges() { + CastScope scope = makeCastScopeForEffect(784); + + handler.handle(scope, scope.effects().get(0)); + + requestStack.assertLast(new FighterPositions(fight.fighters())); + + assertEquals(123, caster.cell().id()); + assertEquals(321, other.fighter().cell().id()); + } + + @Test + void handleWillNotMoveDeadFighter() { + CastScope scope = makeCastScopeForEffect(784); + + other.fighter().move(fight.map().get(124)); + other.fighter().life().kill(other.fighter()); + + handler.handle(scope, scope.effects().get(0)); + + requestStack.assertLast(new FighterPositions(fight.fighters())); + + assertEquals(123, caster.cell().id()); + assertEquals(124, other.fighter().cell().id()); + } + + @Test + void buff() { + CastScope scope = makeCastScopeForEffect(784); + + assertThrows(UnsupportedOperationException.class, () -> handler.buff(scope, scope.effects().get(0))); + } +} diff --git a/src/test/java/fr/quatrevieux/araknemu/game/fight/fighter/PlayerFighterTest.java b/src/test/java/fr/quatrevieux/araknemu/game/fight/fighter/PlayerFighterTest.java index 24765db5a..935bed28b 100644 --- a/src/test/java/fr/quatrevieux/araknemu/game/fight/fighter/PlayerFighterTest.java +++ b/src/test/java/fr/quatrevieux/araknemu/game/fight/fighter/PlayerFighterTest.java @@ -98,6 +98,15 @@ void moveWillLeaveLastCell() { assertFalse(map.get(123).fighter().isPresent()); } + @Test + void moveRemoveCell() { + fighter.move(map.get(123)); + fighter.move(null); + + assertNull(fighter.cell()); + assertFalse(map.get(123).fighter().isPresent()); + } + @Test void send() { fighter.send("test"); diff --git a/src/test/java/fr/quatrevieux/araknemu/game/fight/module/RaulebaqueModuleTest.java b/src/test/java/fr/quatrevieux/araknemu/game/fight/module/RaulebaqueModuleTest.java new file mode 100644 index 000000000..7066963a7 --- /dev/null +++ b/src/test/java/fr/quatrevieux/araknemu/game/fight/module/RaulebaqueModuleTest.java @@ -0,0 +1,60 @@ +package fr.quatrevieux.araknemu.game.fight.module; + +import fr.quatrevieux.araknemu.game.fight.Fight; +import fr.quatrevieux.araknemu.game.fight.FightBaseCase; +import fr.quatrevieux.araknemu.game.fight.castable.CastScope; +import fr.quatrevieux.araknemu.game.fight.fighter.Fighter; +import fr.quatrevieux.araknemu.game.fight.map.FightCell; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + +/** + * + */ +class RaulebaqueModuleTest extends FightBaseCase { + @Test + void effect() throws Exception { + Fight fight = createFight(false); + + fight.register(new RaulebaqueModule(fight)); + fight.nextState(); + fight.start(); + + FightCell playerCell = player.fighter().cell(); + FightCell otherCell = other.fighter().cell(); + + player.fighter().move(fight.map().get(123)); + other.fighter().move(fight.map().get(321)); + + CastScope scope = makeCastScopeForEffect(784); + + fight.effects().apply(scope); + + assertSame(playerCell, player.fighter().cell()); + assertSame(otherCell, other.fighter().cell()); + } + + @Test + void startPositions() throws Exception { + Fight fight = createFight(false); + RaulebaqueModule module = new RaulebaqueModule(fight); + + fight.register(module); + fight.nextState(); + fight.start(); + + FightCell playerCell = player.fighter().cell(); + FightCell otherCell = other.fighter().cell(); + + Map expected = new HashMap<>(); + expected.put(player.fighter(), playerCell); + expected.put(other.fighter(), otherCell); + + assertEquals(expected, module.startPositions()); + } +}