Passed
Push — master ( 6700dd...d2c69e )
by Vincent
05:34 queued 12s
created

AbstractPointLostApplier(Fight,AlterPointHook,Characteristic,Characteristic,int)   A

Complexity

Conditions 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 6
ccs 6
cts 6
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-2021 Vincent Quatrevieux
18
 */
19
20
package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.characteristic.point;
21
22
import fr.arakne.utils.value.helper.RandomUtil;
23
import fr.quatrevieux.araknemu.data.constant.Characteristic;
24
import fr.quatrevieux.araknemu.game.fight.Fight;
25
import fr.quatrevieux.araknemu.game.fight.castable.CastScope;
26
import fr.quatrevieux.araknemu.game.fight.castable.effect.EffectValue;
27
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buff;
28
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffEffect;
29
import fr.quatrevieux.araknemu.game.fight.fighter.ActiveFighter;
30
import fr.quatrevieux.araknemu.game.fight.fighter.PassiveFighter;
31
import fr.quatrevieux.araknemu.game.player.characteristic.ComputedCharacteristics;
32
import fr.quatrevieux.araknemu.game.spell.effect.SpellEffect;
33
import fr.quatrevieux.araknemu.network.game.out.fight.action.ActionEffect;
34
35
/**
36
 * Compute and apply turn point lost (action or movement)
37
 *
38
 * Formula: ([current points] / [base points]) * ([caster wisdom / 10] / [target dodge]) * 1/2
39
 * Each removal will be considered (and computed) independently : 2 AP loose with one spell is equivalent to two spells with 1 AP loose
40
 *
41
 * See: https://forums.jeuxonline.info/sujet/801243/les-formules-de-calcul-dans-dofus#titre_7
42
 */
43
public abstract class AbstractPointLostApplier {
44
    public static final int USE_SPELL_EFFECT = 0;
45
46
    private final Fight fight;
47
    private final AlterPointHook hook;
48
    private final Characteristic characteristic;
49
    private final Characteristic resistance;
50
    private final int removalPointEffect;
51
52 1
    private final RandomUtil random = new RandomUtil();
53
54 1
    protected AbstractPointLostApplier(Fight fight, AlterPointHook hook, Characteristic characteristic, Characteristic resistance, int removalPointEffect) {
55 1
        this.fight = fight;
56 1
        this.hook = hook;
57 1
        this.characteristic = characteristic;
58 1
        this.resistance = resistance;
59 1
        this.removalPointEffect = removalPointEffect;
60 1
    }
61
62
    /**
63
     * Apply the point lost effect
64
     *
65
     * A buff will be added and applied if the target do not dodge all points loose
66
     * If the target dodge a point lost, a message will be sent to the fight
67
     *
68
     * @param cast The cast action
69
     * @param target The fighter target
70
     * @param effect Effect to apply
71
     *
72
     * @return Number of lost points
73
     */
74
    public final int apply(CastScope cast, PassiveFighter target, SpellEffect effect)  {
75 1
        final ActiveFighter caster = cast.caster();
76
77 1
        final int baseValue = new EffectValue(effect).value();
78 1
        final int lost = computePointLost(caster, target, baseValue);
79 1
        final int dodge = baseValue - lost;
80
81 1
        if (dodge > 0) {
82 1
            fight.send(dodgeMessage(caster, target, dodge));
83
        }
84
85 1
        if (lost > 0) {
86 1
            target.buffs().add(new Buff(buffEffect(effect, lost), cast.action(), caster, target, hook));
87
        }
88
89 1
        return lost;
90
    }
91
92
    /**
93
     * The packet to send when the target dodge the point lost
94
     */
95
    protected abstract ActionEffect dodgeMessage(PassiveFighter caster, PassiveFighter target, int value);
96
97
    /**
98
     * Create the buff effect for the given point lost
99
     */
100
    private SpellEffect buffEffect(SpellEffect baseEffect, int pointLost) {
101 1
        return removalPointEffect == USE_SPELL_EFFECT
102 1
            ? BuffEffect.fixed(baseEffect, pointLost)
103 1
            : BuffEffect.withCustomEffect(baseEffect, removalPointEffect, pointLost)
104
        ;
105
    }
106
107
    /**
108
     * Compute how many points will be loose
109
     *
110
     * @param caster The spell caster
111
     * @param target The effect target
112
     * @param value The base buff value
113
     *
114
     * @return Number of lost points. Can be 0 if dodge all loose, and cannot exceed value parameter.
115
     */
116
    private int computePointLost(ActiveFighter caster, PassiveFighter target, int value) {
117 1
        final int maxPoints = target.characteristics().initial().get(this.characteristic);
118 1
        final int currentPoints = target.characteristics().get(this.characteristic);
119
120
        // Can't lose points anymore
121 1
        if (currentPoints <= 0) {
122 1
            return 0;
123
        }
124
125
        // The fighter has only boosted points (ignore division by 0)
126 1
        if (maxPoints <= 0) {
127 1
            return Math.min(currentPoints, value);
128
        }
129
130 1
        final int resistance = Math.max(target.characteristics().get(this.resistance), 1);
0 ignored issues
show
Comprehensibility introduced by
The variable resistanceshadows a field with the same name declared in line 49. Consider renaming it.
Loading history...
131 1
        final int wisdom = Math.max(caster.characteristics().get(Characteristic.WISDOM) / ComputedCharacteristics.POINT_RESISTANCE_FACTOR, 1);
132 1
        final int resistanceRate = 50 * wisdom / resistance;
133
134 1
        int lost = 0;
135
136
        // Compute point lost one by one
137 1
        for (int i = 0; i < value; ++i) {
138 1
            final int afterLost = currentPoints - lost;
139
140
            // All points are lost
141 1
            if (afterLost <= 0) {
142 1
                break;
143
            }
144
145 1
            int chance = resistanceRate * afterLost / maxPoints;
146
147
            // Bound chance between 10% and 90%
148
            // See: https://web.archive.org/web/20100111082721/http://devblog.dofus.com/fr/billets/46-nouvelle-formule-esquive-equilibrage-xelor.html
149 1
            chance = Math.min(chance, 90);
150 1
            chance = Math.max(chance, 10);
151
152 1
            if (random.bool(chance)) {
153 1
                ++lost;
154
            }
155
        }
156
157 1
        return lost;
158
    }
159
}
160