fighter()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
dl 0
loc 3
ccs 1
cts 1
cp 1
crap 1
rs 10
c 1
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-2020 Vincent Quatrevieux
18
 */
19
20
package fr.quatrevieux.araknemu.game.fight.ai;
21
22
import fr.quatrevieux.araknemu.game.fight.Fight;
23
import fr.quatrevieux.araknemu.game.fight.ai.action.ActionGenerator;
24
import fr.quatrevieux.araknemu.game.fight.ai.action.FightAiActionFactoryAdapter;
25
import fr.quatrevieux.araknemu.game.fight.ai.util.AIHelper;
26
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
27
import fr.quatrevieux.araknemu.game.fight.fighter.FighterData;
28
import fr.quatrevieux.araknemu.game.fight.map.BattlefieldMap;
29
import fr.quatrevieux.araknemu.game.fight.turn.Turn;
30
import fr.quatrevieux.araknemu.game.fight.turn.action.Action;
31
import org.checkerframework.checker.nullness.qual.NonNull;
32
import org.checkerframework.checker.nullness.qual.Nullable;
33
34
import java.time.Duration;
35
import java.util.Optional;
36
import java.util.stream.Stream;
37
38
/**
39
 * Base class to handle AI actions
40
 *
41
 * Note: The AI execution is deferred, each action is executed by the fight executor,
42
 *       and the next action is scheduled after the last one.
43
 *       So the AI execution is not blocking, and executed in parallel of the turn timer.
44
 */
45
public final class FighterAI implements Runnable, AI<Fighter> {
46
    private final Fighter fighter;
47
    private final Fight fight;
48
    private final ActionGenerator<Fighter> generator;
49
    private final AIHelper helper;
50
51
    private @Nullable Turn turn;
52
53
    /**
54
     * Creates the AI
55
     *
56
     * @param fighter The fighter to control
57
     * @param generator The action generator
58
     */
59
    @SuppressWarnings({"argument", "assignment"})
60 1
    public FighterAI(Fighter fighter, Fight fight, ActionGenerator<Fighter> generator) {
61 1
        this.fighter = fighter;
62 1
        this.fight = fight;
63 1
        this.generator = generator;
64 1
        this.helper = new AIHelper(this);
65 1
    }
66
67
    @Override
68
    public void start(Turn turn) {
69 1
        this.turn = turn;
70
71 1
        generator.initialize(this);
72 1
        fight.execute(this);
73 1
    }
74
75
    @Override
76
    public void run() {
77 1
        if (turn == null) {
78 1
            throw new IllegalStateException("AI#start() must be called before run()");
79
        }
80
81 1
        final Turn currentTurn = turn;
82
83 1
        if (!currentTurn.active()) {
84 1
            turn = null;
85 1
            return;
86
        }
87
88 1
        final Optional<Action> action = generator.generate(
89
            this,
90
            new FightAiActionFactoryAdapter(
91
                fighter,
92
                fight,
93 1
                fight.actions()
94
            )
95
        );
96
97 1
        if (action.isPresent()) {
98 1
            currentTurn.perform(action.get());
99 1
            currentTurn.later(() -> fight.schedule(this, Duration.ofMillis(800)));
100 1
            return;
101
        }
102
103 1
        turn = null;
104 1
        currentTurn.stop();
105 1
    }
106
107
    @Override
108
    public Fighter fighter() {
109 1
        return fighter;
110
    }
111
112
    @Override
113
    public BattlefieldMap map() {
114 1
        return fight.map();
115
    }
116
117
    @Override
118
    public @NonNull Turn turn() {
119 1
        final Turn turn = this.turn;
0 ignored issues
show
Comprehensibility introduced by
The variable turnshadows a field with the same name declared in line 51. Consider renaming it.
Loading history...
120
121 1
        if (turn == null) {
122 1
            throw new IllegalStateException("AI must be started");
123
        }
124
125 1
        return turn;
126
    }
127
128
    @Override
129
    public Stream<? extends FighterData> fighters() {
130 1
        return fight.fighters().stream().filter(other -> !other.dead());
131
    }
132
133
    @Override
134
    public Optional<? extends FighterData> enemy() {
135 1
        return helper.enemies().nearest();
136
    }
137
138
    @Override
139
    public AIHelper helper() {
140 1
        return helper;
141
    }
142
}
143