setCurrentFighter(ProxyActiveFighter)   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
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.ai.proxy;
21
22
import fr.quatrevieux.araknemu.game.fight.ai.AI;
23
import fr.quatrevieux.araknemu.game.fight.fighter.ActiveFighter;
24
import fr.quatrevieux.araknemu.game.fight.fighter.FighterData;
25
import fr.quatrevieux.araknemu.game.fight.map.BattlefieldMap;
26
import fr.quatrevieux.araknemu.game.fight.map.FightCell;
27
import fr.quatrevieux.araknemu.game.fight.turn.Turn;
28
import org.checkerframework.checker.index.qual.NonNegative;
29
30
import java.util.Map;
31
import java.util.Optional;
32
import java.util.WeakHashMap;
33
import java.util.stream.Stream;
34
35
/**
36
 * Proxy for AI to allow performing modification without change the real fight
37
 *
38
 * Note: this object is immutable : any change will result to a creation of a new instance
39
 */
40
public final class ProxyAI implements AI<ActiveFighter> {
41
    private final AI<?> ai;
42
43
    private ProxyBattlefield map;
44
    private ProxyActiveFighter fighter;
45
    private ProxyTurn turn;
46
47 1
    private final Map<FighterData, FighterData> fighters = new WeakHashMap<>();
48
49 1
    public ProxyAI(AI<?> ai) {
50 1
        this.ai = ai;
51 1
        this.fighter = new ProxyActiveFighter(ai.fighter());
52 1
        this.map = new ProxyBattlefield(ai.map());
53 1
        this.turn = new ProxyTurn(ai, this.fighter);
54 1
    }
55
56 1
    private ProxyAI(ProxyAI other) {
57 1
        this.ai = other.ai;
58 1
        this.map = other.map;
59 1
        this.fighter = other.fighter;
60 1
        this.turn = other.turn;
61 1
    }
62
63
    @Override
64
    public void start(Turn turn) {
65 1
        throw new UnsupportedOperationException("This is a proxy AI");
66
    }
67
68
    @Override
69
    public ActiveFighter fighter() {
70 1
        return fighter;
71
    }
72
73
    @Override
74
    public BattlefieldMap map() {
75 1
        return map;
76
    }
77
78
    @Override
79
    public Turn turn() {
80 1
        return turn;
81
    }
82
83
    @Override
84
    public Stream<? extends FighterData> fighters() {
85 1
        return ai.fighters().map(this::getProxyFighter);
86
    }
87
88
    @Override
89
    public Optional<? extends FighterData> enemy() {
90 1
        return ai.enemy().map(this::getProxyFighter);
91
    }
92
93
    /**
94
     * Change the current cell of the handled fighter
95
     *
96
     * @param cellId The target cell id
97
     *
98
     * @return The new AI instance with the updated position
99
     *
100
     * @see fr.quatrevieux.araknemu.game.fight.ai.util.AIHelper#withPosition(FightCell)
101
     */
102
    public ProxyAI withPosition(@NonNegative int cellId) {
103 1
        final ProxyAI newAi = new ProxyAI(this);
104
105 1
        newAi.map = newAi.map.modify(modifier -> {
106 1
            newAi.setCurrentFighter(newAi.fighter.withPosition(modifier.get(cellId)));
107
108 1
            modifier.free(fighter().cell().id()).setFighter(cellId, newAi.fighter);
109
110 1
            ai.fighters().filter(other -> other.id() != this.fighter.id()).forEach(other -> {
111 1
                final FighterData proxyFighter = new ProxyPassiveFighter(other, newAi);
112
113 1
                newAi.fighters.put(other, proxyFighter);
114 1
                modifier.setFighter(other.cell().id(), proxyFighter);
115 1
            });
116 1
        });
117
118 1
        return newAi;
119
    }
120
121
    /**
122
     * Get or create the proxy fighter wrapper for a given fighter
123
     *
124
     * @param fighter The real fighter
125
     *
126
     * @return The proxy fighter
127
     */
128
    private FighterData getProxyFighter(FighterData fighter) {
129 1
        if (fighter.id() == this.fighter.id()) {
130 1
            return this.fighter;
131
        }
132
133 1
        return fighters.computeIfAbsent(fighter, f -> new ProxyPassiveFighter(f, this));
134
    }
135
136
    /**
137
     * Redefine the current fighter instance
138
     * This method will also update all related objects
139
     *
140
     * @param fighter New instance to use
141
     */
142
    private void setCurrentFighter(ProxyActiveFighter fighter) {
143 1
        this.fighter = fighter;
144 1
        this.turn = new ProxyTurn(ai, fighter);
145 1
    }
146
}
147