Passed
Pull Request — master (#207)
by Vincent
10:53
created

apply(ActiveFighter,SpellEffect,PassiveFighter)   A

Complexity

Conditions 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
dl 0
loc 10
ccs 5
cts 5
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
        target.buffs().onDirectDamage(caster, damage);
67
68 1
        if (!caster.equals(target)) {
69 1
            damage.reflect(target.characteristics().get(Characteristic.COUNTER_DAMAGE));
70
        }
71
72 1
        return applyDamage(caster, damage, target);
73
    }
74
75
    /**
76
     * Apply a damage buff effect
77
     *
78
     * @param buff Buff to apply
79
     *
80
     * @return The real damage value
81
     *
82
     * @see fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buffs#onBuffDamage(Buff, Damage) The called buff hook
83
     */
84
    public int apply(Buff buff) {
85 1
        final PassiveFighter target = buff.target();
86 1
        final ActiveFighter caster = buff.caster();
87
88 1
        final Damage damage = computeDamage(caster, buff.effect(), target);
89 1
        target.buffs().onBuffDamage(buff, damage);
90
91 1
        return applyDamage(caster, damage, target);
92
    }
93
94
    /**
95
     * Create the damage object
96
     */
97
    private Damage computeDamage(ActiveFighter caster, SpellEffect effect, PassiveFighter target) {
98 1
        final EffectValue value = new EffectValue(effect)
99 1
            .percent(caster.characteristics().get(element.boost()))
100 1
            .percent(caster.characteristics().get(Characteristic.PERCENT_DAMAGE))
101 1
            .fixed(caster.characteristics().get(Characteristic.FIXED_DAMAGE))
102
        ;
103
104 1
        return new Damage(value.value(), element)
105 1
            .percent(target.characteristics().get(element.percentResistance()))
106 1
            .fixed(target.characteristics().get(element.fixedResistance()))
107
        ;
108
    }
109
110
    /**
111
     * Apply the damage object to the target
112
     *
113
     * @return The life change value. Negative for damage, positive for heal.
114
     */
115
    private int applyDamage(ActiveFighter caster, Damage damage, PassiveFighter target) {
116 1
        if (damage.reducedDamage() > 0) {
117 1
            fight.send(ActionEffect.reducedDamage(target, damage.reducedDamage()));
118
        }
119
120 1
        final int lifeChange = target.life().alter(caster, -damage.value());
121
122 1
        if (lifeChange < 0 && !target.equals(caster) && damage.reflectedDamage() > 0) {
123 1
            applyReflectedDamage(target, caster, damage);
124
        }
125
126 1
        return lifeChange;
127
    }
128
129
    /**
130
     * Apply returned damage on the original caster
131
     *
132
     * Notes:
133
     * - do not handle target change chain
134
     * - use resistance on returned damage ?
135
     *
136
     * @param caster The original spell caster
137
     * @param damage The applied damage
138
     */
139
    private void applyReflectedDamage(PassiveFighter castTarget, ActiveFighter caster, Damage damage) {
140 1
        final ReflectedDamage returnedDamage = new ReflectedDamage(damage, caster);
141 1
        caster.buffs().onReflectedDamage(returnedDamage);
142
143 1
        if (returnedDamage.baseValue() > 0) {
144 1
            fight.send(ActionEffect.reflectedDamage(castTarget, returnedDamage.baseValue()));
145 1
            returnedDamage.target().life().alter(castTarget, -returnedDamage.value());
146
        }
147 1
    }
148
}
149