Skip to content

Commit

Permalink
Merge pull request #337 from vincent4vx/feature-critical-effect-target
Browse files Browse the repository at this point in the history
feat(spell): Allow to define critical effect target
  • Loading branch information
vincent4vx authored Mar 10, 2024
2 parents 9cfd786 + 224a4c1 commit f90c21e
Show file tree
Hide file tree
Showing 12 changed files with 299 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* 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-2024 Vincent Quatrevieux
*/

package fr.quatrevieux.araknemu.data.transformer;

import fr.quatrevieux.araknemu.data.value.SpellTarget;
import org.checkerframework.checker.nullness.qual.PolyNull;

/**
* Transformer for spell effect target flags
*
* Parse format: "normal,critical;normal;..."
* Example: "1,2;3;4,5"
*
* When critical is not specified, it's the same as normal
*/
public final class SpellTargetsTransformer implements Transformer<SpellTarget[]> {
@Override
public @PolyNull String serialize(SpellTarget @PolyNull [] value) {
throw new UnsupportedOperationException("Not implemented");
}

@Override
public SpellTarget @PolyNull [] unserialize(@PolyNull String serialize) throws TransformerException {
if (serialize == null) {
return null;
}

final String[] parts = serialize.split(";");

if (parts.length == 1 && parts[0].isEmpty()) {
return new SpellTarget[0];
}

final SpellTarget[] targets = new SpellTarget[parts.length];

for (int i = 0; i < parts.length; i++) {
final String[] subParts = parts[i].split(",", 2);

final int normal = Integer.parseInt(subParts[0]);
final int critical;

if (subParts.length > 1) {
critical = Integer.parseInt(subParts[1]);
} else {
critical = normal;
}

targets[i] = new SpellTarget(normal, critical);
}

return targets;
}
}
47 changes: 47 additions & 0 deletions src/main/java/fr/quatrevieux/araknemu/data/value/SpellTarget.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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-2024 Vincent Quatrevieux
*/

package fr.quatrevieux.araknemu.data.value;

/**
* Target flags for a spell effect
*/
public final class SpellTarget {
private final int normal;
private final int critical;

public SpellTarget(int normal, int critical) {
this.normal = normal;
this.critical = critical;
}

/**
* Target flags for normal spell effect
*/
public int normal() {
return normal;
}

/**
* Target flags for critical spell effect
*/
public int critical() {
return critical;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import fr.arakne.utils.value.Interval;
import fr.quatrevieux.araknemu.data.value.EffectArea;
import fr.quatrevieux.araknemu.data.value.SpellTarget;
import fr.quatrevieux.araknemu.data.value.SpellTemplateEffect;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.Nullable;
Expand All @@ -36,9 +37,9 @@ public final class SpellTemplate {
private final int sprite;
private final String spriteArgs;
private final @Nullable Level[] levels;
private final int[] targets;
private final SpellTarget[] targets;

public SpellTemplate(int id, String name, int sprite, String spriteArgs, @Nullable Level[] levels, int[] targets) {
public SpellTemplate(int id, String name, int sprite, String spriteArgs, @Nullable Level[] levels, SpellTarget[] targets) {
this.id = id;
this.name = name;
this.sprite = sprite;
Expand Down Expand Up @@ -67,7 +68,7 @@ public String spriteArgs() {
return levels;
}

public int[] targets() {
public SpellTarget[] targets() {
return targets;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import fr.quatrevieux.araknemu.core.dbal.repository.RepositoryException;
import fr.quatrevieux.araknemu.core.dbal.repository.RepositoryUtils;
import fr.quatrevieux.araknemu.data.transformer.Transformer;
import fr.quatrevieux.araknemu.data.value.SpellTarget;
import fr.quatrevieux.araknemu.data.world.entity.SpellTemplate;
import fr.quatrevieux.araknemu.data.world.repository.SpellTemplateRepository;
import org.checkerframework.checker.nullness.qual.Nullable;
Expand All @@ -41,10 +42,13 @@ final class SqlSpellTemplateRepository implements SpellTemplateRepository {
private final RepositoryUtils<SpellTemplate> utils;

private final Transformer<SpellTemplate.Level> levelTransformer;
private final Transformer<SpellTarget[]> spellTargetsTransformer;

public SqlSpellTemplateRepository(QueryExecutor executor, Transformer<SpellTemplate.Level> levelTransformer) {
public SqlSpellTemplateRepository(QueryExecutor executor, Transformer<SpellTemplate.Level> levelTransformer, Transformer<SpellTarget[]> spellTargetsTransformer) {
this.executor = executor;
this.levelTransformer = levelTransformer;
this.spellTargetsTransformer = spellTargetsTransformer;

utils = new RepositoryUtils<>(this.executor, new SqlSpellTemplateRepository.Loader());
}

Expand Down Expand Up @@ -126,7 +130,7 @@ public SpellTemplate create(Record record) throws SQLException {
record.nullableUnserialize("SPELL_LVL_5", levelTransformer),
record.nullableUnserialize("SPELL_LVL_6", levelTransformer),
},
record.getIntArray("SPELL_TARGET", ';')
record.unserialize("SPELL_TARGET", spellTargetsTransformer)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import fr.quatrevieux.araknemu.core.di.ContainerConfigurator;
import fr.quatrevieux.araknemu.core.di.ContainerModule;
import fr.quatrevieux.araknemu.data.transformer.ImmutableCharacteristicsTransformer;
import fr.quatrevieux.araknemu.data.transformer.SpellTargetsTransformer;
import fr.quatrevieux.araknemu.data.world.repository.SpellTemplateRepository;
import fr.quatrevieux.araknemu.data.world.repository.character.PlayerExperienceRepository;
import fr.quatrevieux.araknemu.data.world.repository.character.PlayerRaceRepository;
Expand Down Expand Up @@ -144,7 +145,8 @@ public void configure(ContainerConfigurator configurator) {
SpellTemplateRepository.class,
container -> new SqlSpellTemplateRepository(
executor,
container.get(SpellTemplateLevelTransformer.class)
container.get(SpellTemplateLevelTransformer.class),
container.get(SpellTargetsTransformer.class)
)
);

Expand Down Expand Up @@ -287,5 +289,6 @@ public void configure(ContainerConfigurator configurator) {
);

configurator.persist(WeaponsAbilitiesTransformer.class, container -> new WeaponsAbilitiesTransformer());
configurator.persist(SpellTargetsTransformer.class, container -> new SpellTargetsTransformer());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package fr.quatrevieux.araknemu.game.player.race;

import fr.arakne.utils.value.constant.Race;
import fr.quatrevieux.araknemu.data.value.SpellTarget;
import fr.quatrevieux.araknemu.data.world.entity.SpellTemplate;
import fr.quatrevieux.araknemu.data.world.entity.character.PlayerRace;
import fr.quatrevieux.araknemu.data.world.repository.character.PlayerRaceRepository;
Expand Down Expand Up @@ -89,8 +90,8 @@ private GamePlayerRace create(PlayerRace entity) {
private DefaultCloseCombat createDefaultCloseCombat(SpellTemplate.Level characteristics) {
return new DefaultCloseCombat(
characteristics,
effectService.makeAll(characteristics.effects(), characteristics.effectAreas(), new int[0]),
effectService.makeAll(characteristics.criticalEffects(), characteristics.effectAreas(), new int[0])
effectService.makeAll(characteristics.effects(), characteristics.effectAreas(), new SpellTarget[0]),
effectService.makeAll(characteristics.criticalEffects(), characteristics.effectAreas(), new SpellTarget[0])
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,12 @@ private Spell makeLevel(@Positive int level, SpellTemplate template, SpellTempla
level,
template,
data,
effectService.makeAll(data.effects(), data.effectAreas(), template.targets()),
effectService.makeAll(data.effects(), data.effectAreas(), template.targets(), false),
effectService.makeAll(
data.criticalEffects(),
data.effectAreas().subList(data.effects().size(), data.effectAreas().size()),
template.targets()
template.targets(),
true
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package fr.quatrevieux.araknemu.game.spell.effect;

import fr.quatrevieux.araknemu.data.value.EffectArea;
import fr.quatrevieux.araknemu.data.value.SpellTarget;
import fr.quatrevieux.araknemu.data.value.SpellTemplateEffect;
import fr.quatrevieux.araknemu.game.spell.effect.area.CellArea;
import fr.quatrevieux.araknemu.game.spell.effect.area.CheckboardArea;
Expand Down Expand Up @@ -78,11 +79,31 @@ public SpellEffect make(SpellTemplateEffect template, EffectArea area, SpellEffe
* @param areas The effects areas
* @param targets The effects targets
*/
public List<SpellEffect> makeAll(List<SpellTemplateEffect> templates, List<EffectArea> areas, int[] targets) {
public List<SpellEffect> makeAll(List<SpellTemplateEffect> templates, List<EffectArea> areas, SpellTarget[] targets) {
return makeAll(templates, areas, targets, false);
}

/**
* Make an effect list
*
* @param templates List of effects
* @param areas The effects areas
* @param targets The effects targets
* @param critical Is the effect critical
*/
public List<SpellEffect> makeAll(List<SpellTemplateEffect> templates, List<EffectArea> areas, SpellTarget[] targets, boolean critical) {
final List<SpellEffect> effects = new ArrayList<>(templates.size());

for (int i = 0; i < templates.size(); ++i) {
effects.add(make(templates.get(i), areas.get(i), targets.length > i ? new SpellEffectTarget(targets[i]) : SpellEffectTarget.DEFAULT));
final SpellEffectTarget target;

if (targets.length > i) {
target = new SpellEffectTarget(critical ? targets[i].critical() : targets[i].normal());
} else {
target = SpellEffectTarget.DEFAULT;
}

effects.add(make(templates.get(i), areas.get(i), target));
}

return effects;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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-2024 Vincent Quatrevieux
*/

package fr.quatrevieux.araknemu.data.transformer;

import fr.quatrevieux.araknemu.data.value.SpellTarget;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class SpellTargetsTransformerTest {
@Test
void serialize() {
assertThrows(UnsupportedOperationException.class, () -> new SpellTargetsTransformer().serialize(null));
}

@Test
void unserializeNull() {
assertNull(new SpellTargetsTransformer().unserialize(null));
}

@Test
void unserializeEmpty() {
assertArrayEquals(new SpellTarget[0], new SpellTargetsTransformer().unserialize(""));
}

@Test
void unserializeSimple() {
SpellTarget[] parsed = new SpellTargetsTransformer().unserialize("1");

assertEquals(1, parsed.length);
assertEquals(1, parsed[0].normal());
assertEquals(1, parsed[0].critical());
}

@Test
void unserializeMultiple() {

SpellTarget[] parsed = new SpellTargetsTransformer().unserialize("1;4;0");

assertEquals(3, parsed.length);
assertEquals(1, parsed[0].normal());
assertEquals(1, parsed[0].critical());
assertEquals(4, parsed[1].normal());
assertEquals(4, parsed[1].critical());
assertEquals(0, parsed[2].normal());
assertEquals(0, parsed[2].critical());
}

@Test
void unserializeMultipleWithExplicitCritical() {

SpellTarget[] parsed = new SpellTargetsTransformer().unserialize("1,5;4;0,1");

assertEquals(3, parsed.length);
assertEquals(1, parsed[0].normal());
assertEquals(5, parsed[0].critical());
assertEquals(4, parsed[1].normal());
assertEquals(4, parsed[1].critical());
assertEquals(0, parsed[2].normal());
assertEquals(1, parsed[2].critical());
}
}
Loading

0 comments on commit f90c21e

Please sign in to comment.