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

currentBoostValue(Buff,FighterData)   B

Complexity

Conditions 6

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 16
ccs 9
cts 9
cp 1
c 0
b 0
f 0
cc 6
crap 6
rs 8.6666
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-2022 Vincent Quatrevieux
18
 */
19
20
package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.characteristic;
21
22
import fr.quatrevieux.araknemu.data.constant.Characteristic;
23
import fr.quatrevieux.araknemu.game.fight.Fight;
24
import fr.quatrevieux.araknemu.game.fight.castable.FightCastScope;
25
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buff;
26
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffEffect;
27
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffHook;
28
import fr.quatrevieux.araknemu.game.fight.castable.effect.handler.EffectHandler;
29
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
30
import fr.quatrevieux.araknemu.game.fight.fighter.FighterData;
31
import fr.quatrevieux.araknemu.game.spell.effect.SpellEffect;
32
import fr.quatrevieux.araknemu.util.Asserter;
33
import org.checkerframework.checker.index.qual.NonNegative;
34
import org.checkerframework.checker.index.qual.Positive;
35
36
import java.util.HashMap;
37
import java.util.Map;
38
39
/**
40
 * Effect handler for punishment
41
 *
42
 * Add a characteristic boost when the fight suffer from direct damage
43
 * Characteristics mapping must be added using {@link AddCharacteristicOnDamageHandler#register(int, Characteristic)} method
44
 *
45
 * Parameters:
46
 * - first (i.e. min) is the effect used as characteristic boost
47
 * - second (i.e. max) is the maximal boost value per turn
48
 * - third (i.e. special) is the boost duration
49
 *
50
 * Note: this buff cannot be dispelled, but the boosted characteristics can
51
 */
52
public final class AddCharacteristicOnDamageHandler implements EffectHandler, BuffHook {
53
    private final Fight fight;
54
55
    /**
56
     * Map first effect parameter to related characteristic hook
57
     */
58 1
    private final Map<Integer, AlterCharacteristicHook> hooksMapping = new HashMap<>();
59
60 1
    public AddCharacteristicOnDamageHandler(Fight fight) {
61 1
        this.fight = fight;
62 1
    }
63
64
    @Override
65
    public void handle(FightCastScope cast, FightCastScope.EffectScope effect) {
66 1
        throw new UnsupportedOperationException("Alter characteristic effect must be used as a buff");
67
    }
68
69
    @Override
70
    public void buff(FightCastScope cast, FightCastScope.EffectScope effect) {
71 1
        final SpellEffect spellEffect = effect.effect();
72 1
        final Fighter caster = cast.caster();
73
74 1
        for (Fighter target : cast.targets()) {
75 1
            target.buffs().add(new Buff(
76
                spellEffect,
77 1
                cast.action(),
78
                caster,
79
                target,
80
                this,
81
                false
82
            ));
83 1
        }
84 1
    }
85
86
    /**
87
     * Register an handled characteristic
88
     *
89
     * @param effectId Handled effect id. This is the first parameter of the spell effect
90
     * @param hook Alter characteristic hook to use
91
     *
92
     * @return This instance
93
     */
94
    public AddCharacteristicOnDamageHandler register(int effectId, AlterCharacteristicHook hook) {
95 1
        hooksMapping.put(effectId, hook);
96
97 1
        return this;
98
    }
99
100
    /**
101
     * Register an handled characteristic
102
     *
103
     * @param effectId Handled effect id. This is the first parameter of the spell effect
104
     * @param characteristic The mapped characteristic
105
     *
106
     * @return This instance
107
     */
108
    public AddCharacteristicOnDamageHandler register(int effectId, Characteristic characteristic) {
109 1
        return register(effectId, AlterCharacteristicHook.add(fight, characteristic));
110
    }
111
112
    @Override
113
    public void onDirectDamageApplied(Buff buff, Fighter caster, @Positive int damage) {
114 1
        final Fighter target = buff.target();
115 1
        final int boostEffectId = buff.effect().min();
116 1
        final AlterCharacteristicHook hook = hooksMapping.get(boostEffectId);
117
118 1
        if (hook == null) {
119 1
            throw new IllegalArgumentException("Unsupported effect " + boostEffectId + " for punishment effect");
120
        }
121
122 1
        final int maximalValue = buff.effect().max() - currentBoostValue(buff, target);
123
124 1
        if (maximalValue <= 0) {
125 1
            return;
126
        }
127
128 1
        target.buffs().add(new Buff(
129 1
            BuffEffect.withCustomEffectAndDuration(buff.effect(), boostEffectId, Math.min(maximalValue, damage), Asserter.assertGTENegativeOne(buff.effect().special())),
130 1
            buff.action(),
131 1
            buff.caster(),
132
            target,
133
            hook
134
        ));
135 1
    }
136
137
    private @NonNegative int currentBoostValue(Buff buff, FighterData target) {
138
        // Add 1 to duration in case of self damage
139 1
        final int expectedEffectDuration = buff.effect().special() + (target.equals(fight.turnList().currentFighter()) ? 1 : 0);
140
141 1
        int boost = 0;
142
143 1
        for (Buff activeBuff : target.buffs()) {
144 1
            if (activeBuff.effect().effect() == buff.effect().min()
145 1
                && activeBuff.remainingTurns() == expectedEffectDuration
146 1
                && activeBuff.action().equals(buff.action())
147
            ) {
148 1
                boost += activeBuff.effect().min();
149
            }
150 1
        }
151
152 1
        return boost;
153
    }
154
}
155