simulate(Spell,CastScope)   A
last analyzed

Complexity

Conditions 5

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 16
c 1
b 0
f 0
dl 0
loc 28
ccs 17
cts 17
cp 1
crap 5
rs 9.1333
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.ai.simulation;
21
22
import fr.quatrevieux.araknemu.game.fight.ai.simulation.effect.EffectSimulator;
23
import fr.quatrevieux.araknemu.game.fight.castable.CastScope;
24
import fr.quatrevieux.araknemu.game.fight.fighter.ActiveFighter;
25
import fr.quatrevieux.araknemu.game.fight.fighter.FighterData;
26
import fr.quatrevieux.araknemu.game.fight.map.BattlefieldCell;
27
import fr.quatrevieux.araknemu.game.fight.turn.action.util.CriticalityStrategy;
28
import fr.quatrevieux.araknemu.game.spell.Spell;
29
30
import java.util.HashMap;
31
import java.util.Map;
32
33
/**
34
 * Perform simulation on fight
35
 */
36
public final class Simulator {
37 1
    private final Map<Integer, EffectSimulator> simulators = new HashMap<>();
38
    private final CriticalityStrategy criticalityStrategy;
39
40 1
    public Simulator(CriticalityStrategy criticalityStrategy) {
41 1
        this.criticalityStrategy = criticalityStrategy;
42 1
    }
43
44
    /**
45
     * Register an effect simulator
46
     *
47
     * @param effectId The effect to simulate
48
     * @param simulator The simulator
49
     */
50
    public void register(int effectId, EffectSimulator simulator) {
51 1
        simulators.put(effectId, simulator);
52 1
    }
53
54
    /**
55
     * Simulate the spell cast
56
     *
57
     * @param spell Spell to cast
58
     * @param caster The caster (current fighter)
59
     * @param target The cell target
60
     *
61
     * @return The simulation result
62
     */
63
    public CastSimulation simulate(Spell spell, ActiveFighter caster, BattlefieldCell target) {
64 1
        final CastSimulation normalSimulation = simulate(spell, new SimulationCastScope(spell, caster, target, spell.effects()));
65 1
        final int hitRate = spell.criticalHit();
66
67 1
        if (hitRate < 2) {
68 1
            return normalSimulation;
69
        }
70
71 1
        final CastSimulation criticalSimulation = simulate(spell, new SimulationCastScope(spell, caster, target, spell.criticalEffects()));
72 1
        final CastSimulation simulation = new CastSimulation(spell, caster, target);
73
74 1
        final int criticalRate = 100 / criticalityStrategy.hitRate(caster, hitRate);
75
76 1
        simulation.merge(normalSimulation, 100 - criticalRate);
0 ignored issues
show
Bug introduced by
Math operands should be cast to prevent unwanted loss of precision when mixing types. Consider casting one of the operands of this subtraction to double.
Loading history...
77 1
        simulation.merge(criticalSimulation, criticalRate);
78
79 1
        return simulation;
80
    }
81
82
    /**
83
     * Simulate a cast result
84
     *
85
     * @param scope The cast scope
86
     */
87
    private CastSimulation simulate(Spell spell, CastScope<FighterData, BattlefieldCell> scope) {
88
        // Remove invisible fighters from simulation
89 1
        scope.targets().forEach(target -> {
90 1
            if (target.hidden()) {
91 1
                scope.removeTarget(target);
92
            }
93 1
        });
94
95 1
        final CastSimulation simulation = new CastSimulation(spell, scope.caster(), scope.target());
96
97 1
        for (CastScope.EffectScope<FighterData> effect : scope.effects()) {
98 1
            final EffectSimulator simulator = simulators.get(effect.effect().effect());
99
100 1
            if (simulator == null) {
101 1
                continue;
102
            }
103
104 1
            if (effect.effect().probability() > 0) {
105 1
                final CastSimulation probableSimulation = new CastSimulation(spell, scope.caster(), scope.target());
106
107 1
                simulator.simulate(probableSimulation, effect);
108 1
                simulation.merge(probableSimulation, effect.effect().probability());
109 1
            } else {
110 1
                simulator.simulate(simulation, effect);
111
            }
112 1
        }
113
114 1
        return simulation;
115
    }
116
}
117