Passed
Pull Request — master (#281)
by Vincent
15:23
created

applyCastTarget(FightCastScope)   B

Complexity

Conditions 6

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 26
ccs 11
cts 11
cp 1
rs 8.6666
cc 6
crap 6
1
/*
2
 * This file is part of Araknemu.
3
 *
4
 * Araknemu is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * Araknemu is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with Araknemu.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2019 Vincent Quatrevieux
18
 */
19
20
package fr.quatrevieux.araknemu.game.fight.castable.effect;
21
22
import fr.quatrevieux.araknemu.game.fight.castable.CastScope;
23
import fr.quatrevieux.araknemu.game.fight.castable.FightCastScope;
24
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buff;
25
import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.EffectHandler;
26
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
27
import fr.quatrevieux.araknemu.game.fight.fighter.FighterData;
28
29
import java.util.Collections;
30
import java.util.HashMap;
31
import java.util.Map;
32
import java.util.Set;
33
34
/**
35
 * Handle fight effects
36
 */
37 1
public final class EffectsHandler {
38 1
    private final Map<Integer, EffectHandler> handlers = new HashMap<>();
39
40
    public void register(int effectId, EffectHandler applier) {
41 1
        handlers.put(effectId, applier);
42 1
    }
43
44
    /**
45
     * Apply a cast to the fight
46
     *
47
     * First, this method will call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffHook#onCast(Buff, FightCastScope)} to caster
48
     * Then call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffHook#onCastTarget(Buff, FightCastScope)} to all targets
49
     *
50
     * After that, all effects will be applied by calling :
51
     * - {@link EffectHandler#handle(FightCastScope, FightCastScope.EffectScope)} if duration is 0
52
     * - {@link EffectHandler#buff(FightCastScope, FightCastScope.EffectScope)} if the effect has a duration
53
     */
54
    public void apply(FightCastScope cast) {
55 1
        cast.caster().buffs().onCast(cast);
56
57 1
        applyCastTarget(cast);
58
59 1
        for (FightCastScope.EffectScope effect : cast.effects()) {
60 1
            final EffectHandler handler = handlers.get(effect.effect().effect());
61
            // @todo Warning if handler is not found
0 ignored issues
show
introduced by
Comment matches to-do format '(TODO:)|(@todo )'.
Loading history...
62 1
            if (handler != null) {
63 1
                if (effect.effect().duration() == 0) {
64 1
                    handler.handle(cast, effect);
65
                } else {
66 1
                    handler.buff(cast, effect);
67
                }
68
            }
69 1
        }
70 1
    }
71
72
    /**
73
     * Call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onCastTarget(FightCastScope)}
74
     * on each target.
75
     *
76
     * If a target is changed (by calling {@link CastScope#replaceTarget(FighterData, FighterData)}),
77
     * new targets will also be called
78
     */
79
    private void applyCastTarget(FightCastScope cast) {
80 1
        Set<Fighter> visitedTargets = Collections.emptySet();
81
82
        for (;;) {
83 1
            final Set<Fighter> currentTargets = cast.targets();
84
85 1
            boolean hasChanged = false;
86
87 1
            for (Fighter target : currentTargets) {
88
                // Ignore already called targets
89 1
                if (!visitedTargets.contains(target)) {
90 1
                    if (!target.buffs().onCastTarget(cast)) {
91
                        // The hook notify a target change
92 1
                        hasChanged = true;
93
                    }
94
                }
95 1
            }
96
97
            // There is no new targets, we can stop here
98 1
            if (!hasChanged) {
99 1
                return;
100
            }
101
102
            // cast#targets() always contains all resolved targets, including removed ones
103
            // so simple change visitedTargets by this value is enough to keep track of all already called fighters
104 1
            visitedTargets = currentTargets;
105 1
        }
106
    }
107
}
108