Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(spell): Allow to define critical effect target #337

Merged
merged 1 commit into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading