Passed
Pull Request — master (#224)
by Vincent
11:59
created

apply(Buff)   A

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
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.handler.damage;
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.effect.EffectValue;
25
import fr.quatrevieux.araknemu.game.fight.castable.effect.Element;
26
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buff;
27
import fr.quatrevieux.araknemu.game.fight.fighter.ActiveFighter;
28
import fr.quatrevieux.araknemu.game.fight.fighter.PassiveFighter;
29
import fr.quatrevieux.araknemu.game.spell.effect.SpellEffect;
30
import fr.quatrevieux.araknemu.network.game.out.fight.action.ActionEffect;
31
32
/**
33
 * Apply simple damage to fighter
34
 *
35
 * Returns the effect damage value.
36
 * When applies damage, a negative value will be returned (-50 => The target lose 50 LP)
37
 * When no effect, zero will be returned
38
 * When damage is transformed to heal, will return a positive value (50 => The target win 50 LP)
39
 */
40
public final class DamageApplier {
41
    private final Element element;
42
    private final Fight fight;
43
44 1
    public DamageApplier(Element element, Fight fight) {
45 1
        this.element = element;
46 1
        this.fight = fight;
47 1
    }
48
49
    /**
50
     * Apply a direct damage effect to a fighter
51
     *
52
     * Note: do not use this method for a buff, it will call the invalid buff hook
53
     *
54
     * @param caster The spell caster
55
     * @param effect The effect to apply
56
     * @param target The target
57
     *
58
     * @return The real damage value
59
     *
60
     * @see DamageApplier#apply(Buff) For apply a buff damage (i.e. poison)
61
     * @see fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onDirectDamage(ActiveFighter, Damage) The called buff hook
62
     */
63
    public int apply(ActiveFighter caster, SpellEffect effect, PassiveFighter target) {
64 1
        final Damage damage = computeDamage(caster, effect, target);
65
66 1
        return applyDirectDamage(caster, damage, target);
67
    }
68
69
    /**
70
     * Apply a fixed (i.e. precomputed) amount of damage on the target
71
     *
72
     * Like {@link DamageApplier#apply(ActiveFighter, SpellEffect, PassiveFighter)} :
73
     * - resistance are applied
74
     * - direct damage buff are called
75
     * - returned damage are applied
76
     *
77
     * @param caster The spell caster
78
     * @param value The damage value. Must be positive. Can be 0 for no damage.
79
     * @param target The cast target
80
     *
81
     * @return The applied damage value. Negative for damage, or positive for heal.
82
     *
83
     * @see DamageApplier#applyFixed(Buff, int) For apply a precomputed damage buff
84
     * @see fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onDirectDamage(ActiveFighter, Damage) The called buff hook
85
     */
86
    public int applyFixed(ActiveFighter caster, int value, PassiveFighter target) {
87 1
        final Damage damage = createDamage(caster, target, value);
88
89 1
        return applyDirectDamage(caster, damage, target);
90
    }
91
92
    /**
93
     * Apply a damage buff effect
94
     *
95
     * @param buff Buff to apply
96
     *
97
     * @return The real damage value
98
     *
99
     * @see fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onBuffDamage(Buff, Damage) The called buff hook
100
     */
101
    public int apply(Buff buff) {
102 1
        final PassiveFighter target = buff.target();
103 1
        final ActiveFighter caster = buff.caster();
104
105 1
        final Damage damage = computeDamage(caster, buff.effect(), target);
106
107 1
        return applyBuffDamage(buff, damage, target);
108
    }
109
110
    /**
111
     * Apply a fixed (i.e. precomputed) amount of damage on the target from a buff
112
     *
113
     * Like {@link DamageApplier#apply(Buff)} :
114
     * - resistance are applied
115
     * - buff damage buff are called
116
     *
117
     * @param buff Buff to apply
118
     * @param value The damage value. Must be positive. Can be 0 for no damage.
119
     *
120
     * @return The applied damage value. Negative for damage, or positive for heal.
121
     *
122
     * @see fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onBuffDamage(Buff, Damage) The called buff hook
123
     */
124
    public int applyFixed(Buff buff, int value) {
125 1
        final PassiveFighter target = buff.target();
126 1
        final Damage damage = createDamage(buff.caster(), target, value);
127
128 1
        return applyBuffDamage(buff, damage, target);
129
    }
130
131
    /**
132
     * Create the damage object
133
     */
134
    private Damage computeDamage(ActiveFighter caster, SpellEffect effect, PassiveFighter target) {
135 1
        final EffectValue value = EffectValue.create(effect, caster, target)
136 1
            .percent(caster.characteristics().get(element.boost()))
137 1
            .percent(caster.characteristics().get(Characteristic.PERCENT_DAMAGE))
138 1
            .fixed(caster.characteristics().get(Characteristic.FIXED_DAMAGE))
139
        ;
140
141 1
        return createDamage(caster, target, value.value());
142
    }
143
144
    /**
145
     * Apply damage to the target for direct damage
146
     *
147
     * This method will call direct damage buff and apply returned damage
148
     *
149
     * @return The life change value. Negative for damage, positive for heal.
150
     */
151
    private int applyDirectDamage(ActiveFighter caster, Damage damage, PassiveFighter target) {
152 1
        target.buffs().onDirectDamage(caster, damage);
153
154 1
        if (!caster.equals(target)) {
155 1
            damage.reflect(target.characteristics().get(Characteristic.COUNTER_DAMAGE));
156
        }
157
158 1
        return applyDamage(caster, damage, target);
159
    }
160
161
    /**
162
     * Apply damage to the target for buff damage
163
     *
164
     * This method will call buff damage buff
165
     *
166
     * @return The life change value. Negative for damage, positive for heal.
167
     */
168
    private int applyBuffDamage(Buff buff, Damage damage, PassiveFighter target) {
169 1
        target.buffs().onBuffDamage(buff, damage);
170
171 1
        return applyDamage(buff.caster(), damage, target);
172
    }
173
174
    /**
175
     * Apply the damage object to the target
176
     *
177
     * @return The life change value. Negative for damage, positive for heal.
178
     */
179
    private int applyDamage(ActiveFighter caster, Damage damage, PassiveFighter target) {
180 1
        if (damage.reducedDamage() > 0) {
181 1
            fight.send(ActionEffect.reducedDamage(target, damage.reducedDamage()));
182
        }
183
184 1
        final int lifeChange = target.life().alter(caster, -damage.value());
185
186 1
        if (lifeChange < 0 && !target.equals(caster) && damage.reflectedDamage() > 0) {
187 1
            applyReflectedDamage(target, caster, damage);
188
        }
189
190 1
        return lifeChange;
191
    }
192
193
    /**
194
     * Apply returned damage on the original caster
195
     *
196
     * Notes:
197
     * - do not handle target change chain
198
     * - use resistance on returned damage ?
199
     *
200
     * @param caster The original spell caster
201
     * @param damage The applied damage
202
     */
203
    private void applyReflectedDamage(PassiveFighter castTarget, ActiveFighter caster, Damage damage) {
204 1
        final ReflectedDamage returnedDamage = new ReflectedDamage(damage, caster);
205 1
        caster.buffs().onReflectedDamage(returnedDamage);
206
207 1
        if (returnedDamage.baseValue() > 0) {
208 1
            fight.send(ActionEffect.reflectedDamage(castTarget, returnedDamage.baseValue()));
209 1
            returnedDamage.target().life().alter(castTarget, -returnedDamage.value());
210
        }
211 1
    }
212
213
    /**
214
     * Create the damage object, and call {@link fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onCastDamage(Damage, PassiveFighter)}
215
     *
216
     * @param caster The spell caster
217
     * @param target The effect target
218
     * @param value Raw damage value
219
     *
220
     * @return The damage object to apply
221
     */
222
    private Damage createDamage(ActiveFighter caster, PassiveFighter target, int value) {
223 1
        final Damage damage = new Damage(value, element)
224 1
            .percent(target.characteristics().get(element.percentResistance()))
225 1
            .fixed(target.characteristics().get(element.fixedResistance()))
226
        ;
227
228 1
        caster.buffs().onCastDamage(damage, target);
229
230 1
        return damage;
231
    }
232
}
233