aboutsummaryrefslogtreecommitdiff
path: root/diplomacy/web/src/gui/utils/province.js
blob: fe54a82b5f1ff6409e9babcd1dfc63549bb5b63e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// ==============================================================================
// Copyright (C) 2019 - Philip Paquette, Steven Bocco
//
//  This program is free software: you can redistribute it and/or modify it under
//  the terms of the GNU Affero General Public License as published by the Free
//  Software Foundation, either version 3 of the License, or (at your option) any
//  later version.
//
//  This program is distributed in the hope that it will be useful, but WITHOUT
//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
//  FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
//  details.
//
//  You should have received a copy of the GNU Affero General Public License along
//  with this program.  If not, see <https://www.gnu.org/licenses/>.
// ==============================================================================
const ProvinceType = {
    WATER: 'WATER',
    COAST: 'COAST',
    PORT: 'PORT',
    LAND: 'LAND'
};

export class Province {
    constructor(name, type, isSupplyCenter) {
        this.name = name;
        this.type = type;
        this.coasts = {};
        this.parent = null;
        this.neighbors = {};
        this.isSupplyCenter = isSupplyCenter;
        this.controller = null; // null or power name.
        this.controlType = null; // null, C (center), I (influence) or U (unit).
        this.unit = null; // null, A or F
        this.retreatController = null;
        this.retreatUnit = null; // null or `{unit type} {loc}`
        this.aliases = [];
    }

    compareControlType(a, b) {
        const controlTypeLevels = {C: 0, I: 1, U: 2};
        return controlTypeLevels[a] - controlTypeLevels[b];
    }

    __set_controller(controller, controlType) {
        this.controller = controller;
        this.controlType = controlType;
        for (let coast of Object.values(this.coasts))
            coast.setController(controller, controlType);
    }

    setController(controller, controlType) {
        if (!['C', 'I', 'U'].includes(controlType))
            throw new Error(`Invalid province control type (${controlType}), expected 'C', 'I' or 'U'.`);
        if (this.controller && this.controller !== controller) {
            const controlTypeComparison = this.compareControlType(controlType, this.controlType);
            if (controlTypeComparison === 0)
                throw new Error(`Found 2 powers (${this.controller}, ${controller}) trying to control same province ` +
                    `(${this.name}) with same control type (${controlType} VS ${this.controlType}).`);
            if (controlTypeComparison > 0)
                this.__set_controller(controller, controlType);
        } else
            this.__set_controller(controller, controlType);
    }

    setCoasts(provinces) {
        const name = this.name.toUpperCase();
        for (let entry of Object.entries(provinces)) {
            const pieces = entry[0].split(/[^A-Za-z0-9]+/);
            if (pieces.length > 1 && pieces[0].toUpperCase() === name) {
                this.coasts[entry[0]] = entry[1];
                entry[1].parent = this;
            }
        }
    }

    setNeighbors(neighborProvinces) {
        for (let province of neighborProvinces)
            this.neighbors[province.name] = province;
    }

    getLocationNames() {
        const arr = Object.keys(this.coasts);
        arr.splice(0, 0, this.name);
        return arr;
    }

    getOccupied(powerName) {
        if (!this.controller)
            return null;
        if (powerName && this.controller !== powerName)
            return null;
        if (this.unit)
            return this;
        for (let coast of Object.values(this.coasts))
            if (coast.unit)
                return coast;
        return null;
    }

    getRetreated(powerName) {
        if (this.retreatController === powerName)
            return this;
        for (let coast of Object.values(this.coasts))
            if (coast.retreatController === powerName)
                return coast;
        return null;
    }

    isCoast() {
        return this.type === ProvinceType.COAST;
    }

    isWater() {
        return this.type === ProvinceType.WATER;
    }
}