Passed
Push — master ( 10c2d6...396f30 )
by Vincent
05:38 queued 12s
created

applyDirectDamage(ActiveFighter,Damage,PassiveFighter)   A

Complexity

Conditions 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 2
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 = new Damage(value, element)
88 1
            .percent(target.characteristics().get(element.percentResistance()))
89 1
            .fixed(target.characteristics().get(element.fixedResistance()))
90
        ;
91
92 1
        return applyDirectDamage(caster, damage, target);
93
    }
94
95
    /**
96
     * Apply a damage buff effect
97
     *
98
     * @param buff Buff to apply
99
     *
100
     * @return The real damage value
101
     *
102
     * @see fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onBuffDamage(Buff, Damage) The called buff hook
103
     */
104
    public int apply(Buff buff) {
105 1
        final PassiveFighter target = buff.target();
106 1
        final ActiveFighter caster = buff.caster();
107
108 1
        final Damage damage = computeDamage(caster, buff.effect(), target);
109
110 1
        return applyBuffDamage(buff, damage, target);
111
    }
112
113
    /**
114
     * Apply a fixed (i.e. precomputed) amount of damage on the target from a buff
115
     *
116
     * Like {@link DamageApplier#apply(Buff)} :
117
     * - resistance are applied
118
     * - buff damage buff are called
119
     *
120
     * @param buff Buff to apply
121
     * @param value The damage value. Must be positive. Can be 0 for no damage.
122
     *
123
     * @return The applied damage value. Negative for damage, or positive for heal.
124
     *
125
     * @see fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onBuffDamage(Buff, Damage) The called buff hook
126
     */
127
    public int applyFixed(Buff buff, int value) {
128 1
        final PassiveFighter target = buff.target();
129 1
        final Damage damage = new Damage(value, element)
130 1
            .percent(target.characteristics().get(element.percentResistance()))
131 1
            .fixed(target.characteristics().get(element.fixedResistance()))
132
        ;
133
134 1
        return applyBuffDamage(buff, damage, target);
135
    }
136
137
    /**
138
     * Create the damage object
139
     */
140
    private Damage computeDamage(ActiveFighter caster, SpellEffect effect, PassiveFighter target) {
141 1
        final EffectValue value = new EffectValue(effect)
142 1
            .percent(caster.characteristics().get(element.boost()))
143 1
            .percent(caster.characteristics().get(Characteristic.PERCENT_DAMAGE))
144 1
            .fixed(caster.characteristics().get(Characteristic.FIXED_DAMAGE))
145
        ;
146
147 1
        return new Damage(value.value(), element)
148 1
            .percent(target.characteristics().get(element.percentResistance()))
149 1
            .fixed(target.characteristics().get(element.fixedResistance()))
150
        ;
151
    }
152
153
    /**
154
     * Apply damage to the target for direct damage
155
     *
156
     * This method will call direct damage buff and apply returned damage
157
     *
158
     * @return The life change value. Negative for damage, positive for heal.
159
     */
160
    private int applyDirectDamage(ActiveFighter caster, Damage damage, PassiveFighter target) {
161 1
        target.buffs().onDirectDamage(caster, damage);
162
163 1
        if (!caster.equals(target)) {
164 1
            damage.reflect(target.characteristics().get(Characteristic.COUNTER_DAMAGE));
165
        }
166
167 1
        return applyDamage(caster, damage, target);
168
    }
169
170
    /**
171
     * Apply damage to the target for buff damage
172
     *
173
     * This method will call buff damage buff
174
     *
175
     * @return The life change value. Negative for damage, positive for heal.
176
     */
177
    private int applyBuffDamage(Buff buff, Damage damage, PassiveFighter target) {
178 1
        target.buffs().onBuffDamage(buff, damage);
179
180 1
        return applyDamage(buff.caster(), damage, target);
181
    }
182
183
    /**
184
     * Apply the damage object to the target
185
     *
186
     * @return The life change value. Negative for damage, positive for heal.
187
     */
188
    private int applyDamage(ActiveFighter caster, Damage damage, PassiveFighter target) {
189 1
        if (damage.reducedDamage() > 0) {
190 1
            fight.send(ActionEffect.reducedDamage(target, damage.reducedDamage()));
191
        }
192
193 1
        final int lifeChange = target.life().alter(caster, -damage.value());
194
195 1
        if (lifeChange < 0 && !target.equals(caster) && damage.reflectedDamage() > 0) {
196 1
            applyReflectedDamage(target, caster, damage);
197
        }
198
199 1
        return lifeChange;
200
    }
201
202
    /**
203
     * Apply returned damage on the original caster
204
     *
205
     * Notes:
206
     * - do not handle target change chain
207
     * - use resistance on returned damage ?
208
     *
209
     * @param caster The original spell caster
210
     * @param damage The applied damage
211
     */
212
    private void applyReflectedDamage(PassiveFighter castTarget, ActiveFighter caster, Damage damage) {
213 1
        final ReflectedDamage returnedDamage = new ReflectedDamage(damage, caster);
214 1
        caster.buffs().onReflectedDamage(returnedDamage);
215
216 1
        if (returnedDamage.baseValue() > 0) {
217 1
            fight.send(ActionEffect.reflectedDamage(castTarget, returnedDamage.baseValue()));
218 1
            returnedDamage.target().life().alter(castTarget, -returnedDamage.value());
219
        }
220 1
    }
221
}
222