Browse Source

Merge branch 'feature/placement'

Bastien Sevajol 5 years ago
parent
commit
f6d91fb421

+ 6 - 2
README.md View File

@@ -33,13 +33,17 @@ You also need a running redis server (used db number is `0`, soon configurable).
33 33
 
34 34
 Start troops selection GUI with:
35 35
 
36
-    python select_troops.py --country URSS --country DE
36
+    python select_troops.py --country USSR --country DE
37
+
38
+Select troops for every countries then generate s troops file.
37 39
 
38 40
 ## Troops Placement phase
39 41
 
40 42
 You must: specify a map and a state and `--placement` option:
41 43
 
42
-    python run.py maps/001 --state maps/001/state1.xml --placement
44
+    python run.py maps/001 --troops troops.xml --placement
45
+
46
+`troops.xml` must be previously (at `Troops selection` phase) generated troops file.
43 47
 
44 48
 Map will be loaded with state file troops and you will be able
45 49
 to move (drag and drop with your mouse) troops.

+ 2 - 0
config.yaml View File

@@ -31,6 +31,8 @@ global:
31 31
     units_schema: "opencombat/strategy/units.xsd"
32 32
     troop_dumper: "opencombat.strategy.troops.TroopDumper"
33 33
     troop_schema: "opencombat/strategy/troops.xsd"
34
+    units: "opencombat/strategy/units.xml"
35
+    teams: "opencombat/strategy/teams.xml"
34 36
     cache_dir_path: 'cache'
35 37
     include_path:
36 38
       maps:

+ 3 - 3
maps/001/state1.xml View File

@@ -16,7 +16,7 @@
16 16
                 </item>
17 17
                 <item>
18 18
                     <key>FLAG</key>
19
-                    <value>FLAG_URSS</value>
19
+                    <value>FLAG_USSR</value>
20 20
                 </item>
21 21
                 <item>
22 22
                     <key>SIDE</key>
@@ -36,7 +36,7 @@
36 36
                 </item>
37 37
                 <item>
38 38
                     <key>FLAG</key>
39
-                    <value>FLAG_URSS</value>
39
+                    <value>FLAG_USSR</value>
40 40
                 </item>
41 41
                 <item>
42 42
                     <key>SIDE</key>
@@ -56,7 +56,7 @@
56 56
                 </item>
57 57
                 <item>
58 58
                     <key>FLAG</key>
59
-                    <value>FLAG_URSS</value>
59
+                    <value>FLAG_USSR</value>
60 60
                 </item>
61 61
                 <item>
62 62
                     <key>SIDE</key>

+ 1 - 0
opencombat/ai/__init__.py View File

@@ -0,0 +1 @@
1
+# coding: utf-8

+ 39 - 0
opencombat/ai/placement.py View File

@@ -0,0 +1,39 @@
1
+# coding: utf-8
2
+import typing
3
+
4
+from synergine2.config import Config
5
+
6
+from opencombat.const import SIDE
7
+from opencombat.simulation.base import TileStrategySimulation
8
+
9
+if typing.TYPE_CHECKING:
10
+    from opencombat.simulation.subject import TileSubject
11
+
12
+
13
+class Placement(object):
14
+    """
15
+    Place troops on a map
16
+    """
17
+    def __init__(
18
+        self,
19
+        config: Config,
20
+        simulation: TileStrategySimulation,
21
+    ) -> None:
22
+        self._config = config
23
+        self._simulation = simulation
24
+
25
+    def place(self) -> None:
26
+        # For now it is an extremely simple way to do it
27
+        subject_by_sides = {}  # type: typing.Dict[str, typing.List[TileSubject]]  # nopep8
28
+        for subject in self._simulation.subjects:
29
+            subject_by_sides.setdefault(subject.properties[SIDE], []).append(
30
+                subject,
31
+            )
32
+
33
+        x, y = 0, 0
34
+        for side, subjects in subject_by_sides.items():
35
+            y += 2
36
+            for subject in subjects:
37
+                x += 2
38
+
39
+                subject.position = (x, y)

+ 11 - 2
opencombat/const.py View File

@@ -2,14 +2,23 @@
2 2
 
3 3
 COLLECTION_ALIVE = 'ALIVE'
4 4
 
5
+SELECTION_COLOR_RGB = 'SELECTION_COLOR_RGB'
6
+
5 7
 FLAG = 'FLAG'
6 8
 FLAG_DE = 'FLAG_DE'
7
-FLAG_URSS = 'FLAG_URSS'
9
+FLAG_USSR = 'FLAG_USSR'
8 10
 
9 11
 SIDE = 'SIDE'
12
+SIDE_ALLIES = 'SIDE_ALLIES'
13
+SIDE_AXIS = 'SIDE_AXIS'
14
+
15
+COUNTRY = 'COUNTRY'
16
+COUNTRY_USSR = 'USSR'
17
+COUNTRY_DE = 'DE'
18
+
10 19
 COMBAT_MODE = 'COMBAT_MODE'
11 20
 COMBAT_MODE_DEFEND = 'COMBAT_MODE_DEFEND'
12 21
 COMBAT_MODE_HIDE = 'COMBAT_MODE_HIDE'
13 22
 
14 23
 DE_COLOR = (0, 81, 211)
15
-URSS_COLOR = (204, 0, 0)
24
+USSR_COLOR = (204, 0, 0)

+ 1 - 1
opencombat/game/const.py View File

@@ -6,4 +6,4 @@ FLAG_DE = 'DE'
6 6
 FLAG_COLORS = {
7 7
     FLAG_DE
8 8
 }
9
-FLAG_URSS = 'URSS'
9
+FLAG_USSR = 'USSR'

+ 28 - 0
opencombat/simulation/base.py View File

@@ -1,5 +1,16 @@
1 1
 # coding: utf-8
2 2
 from opencombat.const import COLLECTION_ALIVE
3
+from opencombat.const import COUNTRY_USSR
4
+from opencombat.const import FLAG_USSR
5
+from opencombat.const import FLAG_DE
6
+from opencombat.const import SIDE_ALLIES
7
+from opencombat.const import SIDE_AXIS
8
+from opencombat.const import COUNTRY_DE
9
+from opencombat.const import USSR_COLOR
10
+from opencombat.const import DE_COLOR
11
+from opencombat.const import SIDE
12
+from opencombat.const import FLAG
13
+from opencombat.const import SELECTION_COLOR_RGB
3 14
 from opencombat.simulation.physics import TilePhysics
4 15
 from synergine2.config import Config
5 16
 from synergine2.simulation import SubjectBehaviour
@@ -14,6 +25,23 @@ class TileStrategySimulation(XYZSimulation):
14 25
 
15 26
     ]
16 27
 
28
+    @classmethod
29
+    def get_default_properties_for_country(cls, country: str) -> dict:
30
+        if country == COUNTRY_USSR:
31
+            return {
32
+                SELECTION_COLOR_RGB: USSR_COLOR,
33
+                FLAG: FLAG_USSR,
34
+                SIDE: SIDE_ALLIES,
35
+            }
36
+        elif country == COUNTRY_DE:
37
+            return {
38
+                SELECTION_COLOR_RGB: DE_COLOR,
39
+                FLAG: FLAG_DE,
40
+                SIDE: SIDE_AXIS,
41
+            }
42
+
43
+        raise NotImplementedError('Unknown country "{}"'.format(country))
44
+
17 45
     def __init__(
18 46
         self,
19 47
         config: Config,

+ 9 - 6
opencombat/state.py View File

@@ -14,6 +14,9 @@ from opencombat.util import get_class_from_string_path
14 14
 from opencombat.util import pretty_xml
15 15
 from opencombat.util import get_text_xml_element
16 16
 from opencombat.xml import XmlValidator
17
+from opencombat.const import SIDE
18
+from opencombat.const import FLAG
19
+from opencombat.const import SELECTION_COLOR_RGB
17 20
 
18 21
 
19 22
 class State(object):
@@ -93,9 +96,9 @@ class State(object):
93 96
 
94 97
     def _get_decode_properties_map(self) -> typing.Dict[str, typing.Callable[[str], typing.Any]]:  # nopep8
95 98
         return {
96
-            'SELECTION_COLOR_RGB': lambda v: tuple(map(int, v.split(','))),
97
-            'FLAG': str,
98
-            'SIDE': str,
99
+            SELECTION_COLOR_RGB: lambda v: tuple(map(int, v.split(','))),
100
+            FLAG: str,
101
+            SIDE: str,
99 102
         }
100 103
 
101 104
 
@@ -179,9 +182,9 @@ class StateDumper(object):
179 182
 
180 183
     def _get_encode_properties_map(self) -> typing.Dict[str, typing.Callable[[typing.Any], str]]:  # nopep8:
181 184
         return {
182
-            'SELECTION_COLOR_RGB': lambda v: ','.join(map(str, v)),
183
-            'FLAG': str,
184
-            'SIDE': str,
185
+            SELECTION_COLOR_RGB: lambda v: ','.join(map(str, v)),
186
+            FLAG: str,
187
+            SIDE: str,
185 188
         }
186 189
 
187 190
 

+ 2 - 2
opencombat/strategy/teams.xml View File

@@ -1,7 +1,7 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2 2
 <teams>
3
-    <team id="std_team" country="URSS">
4
-        <name>Standard URSS team</name>
3
+    <team id="std_team" country="USSR">
4
+        <name>Standard USSR team</name>
5 5
         <units>
6 6
             <unit>
7 7
                 <id>std_soldier</id>

+ 121 - 0
opencombat/strategy/troops.py View File

@@ -1,15 +1,73 @@
1 1
 # coding: utf-8
2 2
 import typing
3
+from _elementtree import Element
3 4
 
4 5
 from lxml import etree
5 6
 
6 7
 from synergine2.config import Config
7 8
 from synergine2.log import get_logger
8 9
 
10
+from opencombat.simulation.base import TileStrategySimulation
11
+from opencombat.simulation.subject import TileSubject
9 12
 from opencombat.strategy.team.model import TeamModel
10 13
 from opencombat.strategy.team.stash import TeamStash
11 14
 from opencombat.strategy.unit.stash import UnitStash
12 15
 from opencombat.util import get_class_from_string_path, pretty_xml
16
+from opencombat.xml import XmlValidator
17
+
18
+
19
+class Troop(object):
20
+    def __init__(
21
+        self,
22
+        config: Config,
23
+        state_root: Element,
24
+        simulation: TileStrategySimulation,
25
+    ) -> None:
26
+        self._config = config
27
+        self._state_root = state_root
28
+        self._subjects = None  # type: typing.List[TileSubject]
29
+        self._simulation = simulation
30
+        self._builder = TroopClassBuilder(config)
31
+
32
+    @property
33
+    def subjects(self) -> typing.List[TileSubject]:
34
+        if self._subjects is None:
35
+            self._subjects = self._get_computed_subjects()
36
+
37
+        return self._subjects
38
+
39
+    def _get_computed_subjects(self) -> typing.List[TileSubject]:
40
+        units_file_path = self._config.get(
41
+            'global.units',
42
+            'opencombat/strategy/units.xml',
43
+        )
44
+        teams_file_path = self._config.get(
45
+            'global.teams',
46
+            'opencombat/strategy/teams.xml',
47
+        )
48
+
49
+        team_stash = self._builder.get_team_stash(
50
+            units_file_path,
51
+            teams_file_path,
52
+        )
53
+
54
+        # Parse team, build Subjects
55
+        subjects = []  # type: typing.List[TileSubject]
56
+        for troop in self._state_root.findall('troop'):
57
+            country = troop.attrib['country']
58
+            team_id = troop.attrib['team_id']
59
+            team = team_stash.get_team(team_id, country)
60
+
61
+            for unit in team.units:
62
+                subject = unit.class_(self._config, self._simulation)
63
+                properties = \
64
+                    self._simulation.get_default_properties_for_country(
65
+                        country,
66
+                    )
67
+                subject.properties.update(properties)
68
+                subjects.append(subject)
69
+
70
+        return subjects
13 71
 
14 72
 
15 73
 class TroopDumper(object):
@@ -109,3 +167,66 @@ class TroopClassBuilder(object):
109 167
         return class_(
110 168
             self._config,
111 169
         )
170
+
171
+
172
+class TroopLoader(object):
173
+    def __init__(
174
+        self,
175
+        config: Config,
176
+        simulation: TileStrategySimulation,
177
+    ) -> None:
178
+        self._logger = get_logger('TroopLoader', config)
179
+        self._config = config
180
+        self._simulation = simulation
181
+
182
+        schema_file_path = self._config.get(
183
+            'global.troop_schema',
184
+            'opencombat/strategy/troops.xsd',
185
+        )
186
+        self._xml_validator = XmlValidator(
187
+            config,
188
+            schema_file_path,
189
+        )
190
+
191
+    def get_troop(
192
+        self,
193
+        troop_file_path: str,
194
+    ) -> Troop:
195
+        return Troop(
196
+            self._config,
197
+            self._validate_and_return_state_element(troop_file_path),
198
+            self._simulation,
199
+        )
200
+
201
+    def _validate_and_return_state_element(
202
+        self,
203
+        troop_file_path: str,
204
+    ) -> Element:
205
+        return self._xml_validator.validate_and_return(troop_file_path)
206
+
207
+
208
+class TroopConstructorBuilder(object):
209
+    def __init__(
210
+        self,
211
+        config: Config,
212
+        simulation: TileStrategySimulation,
213
+    ) -> None:
214
+        self._logger = get_logger('TroopConstructorBuilder', config)
215
+        self._config = config
216
+        self._simulation = simulation
217
+
218
+    def get_troop_loader(
219
+        self,
220
+    ) -> TroopLoader:
221
+        class_address = self._config.resolve(
222
+            'global.troop_loader',
223
+            'opencombat.strategy.troops.TroopLoader',
224
+        )
225
+        troop_loader_class = get_class_from_string_path(
226
+            self._config,
227
+            class_address,
228
+        )
229
+        return troop_loader_class(
230
+            self._config,
231
+            self._simulation,
232
+        )

+ 17 - 0
opencombat/strategy/troops.xsd View File

@@ -0,0 +1,17 @@
1
+<?xml version="1.0" encoding="UTF-8" ?>
2
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3
+
4
+    <xs:element name="troops" type="troopstype"/>
5
+
6
+    <xs:complexType name="troopstype">
7
+        <xs:sequence>
8
+            <xs:element name="troop" type="trooptype" maxOccurs="unbounded"/>
9
+        </xs:sequence>
10
+    </xs:complexType>
11
+
12
+    <xs:complexType name="trooptype">
13
+        <xs:attribute name="country" type="xs:string" use="required"/>
14
+        <xs:attribute name="team_id" type="xs:string" use="required"/>
15
+    </xs:complexType>
16
+
17
+</xs:schema>

+ 1 - 1
opencombat/strategy/units.xml View File

@@ -1,6 +1,6 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2 2
 <units>
3
-    <unit id="std_soldier" country="URSS">
3
+    <unit id="std_soldier" country="USSR">
4 4
         <name>Standard soldier</name>
5 5
         <type>opencombat.simulation.subject.ManSubject</type>
6 6
     </unit>

+ 38 - 1
run.py View File

@@ -1,6 +1,7 @@
1 1
 # coding: utf-8
2 2
 import argparse
3 3
 import logging
4
+import sys
4 5
 from random import seed
5 6
 
6 7
 from synergine2.log import get_default_logger
@@ -10,9 +11,11 @@ from synergine2.core import Core
10 11
 from synergine2.cycle import CycleManager
11 12
 from synergine2.terminals import TerminalManager
12 13
 
14
+from opencombat.ai.placement import Placement
13 15
 from opencombat.simulation.base import TileStrategySimulation
14 16
 from opencombat.simulation.base import TileStrategySubjects
15 17
 from opencombat.state import StateConstructorBuilder
18
+from opencombat.strategy.troops import TroopConstructorBuilder
16 19
 from opencombat.terminal.base import CocosTerminal
17 20
 
18 21
 
@@ -20,9 +23,13 @@ def main(
20 23
     map_dir_path: str,
21 24
     seed_value: int=None,
22 25
     state_file_path: str=None,
26
+    troops_file_path: str=None,
23 27
     state_save_dir: str='.',
24 28
     placement_mode: bool = False,
25 29
 ):
30
+    assert not (state_file_path and troops_file_path),\
31
+        'Do not provide troops file when state file given'
32
+
26 33
     if seed_value is not None:
27 34
         seed(seed_value)
28 35
 
@@ -42,6 +49,7 @@ def main(
42 49
 
43 50
     simulation = TileStrategySimulation(config, map_file_path=map_file_path)
44 51
     subjects = TileStrategySubjects(simulation=simulation)
52
+    simulation.subjects = subjects
45 53
 
46 54
     if state_file_path:
47 55
         state_loader_builder = StateConstructorBuilder(config, simulation)
@@ -49,7 +57,14 @@ def main(
49 57
         state = state_loader.get_state(state_file_path)
50 58
         subjects.extend(state.subjects)
51 59
 
52
-    simulation.subjects = subjects
60
+    elif troops_file_path:
61
+        troop_loader_builder = TroopConstructorBuilder(config, simulation)
62
+        troop_loader = troop_loader_builder.get_troop_loader()
63
+        placement = Placement(config, simulation)
64
+
65
+        troops = troop_loader.get_troop(troops_file_path)
66
+        subjects.extend(troops.subjects)
67
+        placement.place()
53 68
 
54 69
     core = Core(
55 70
         config=config,
@@ -76,6 +91,7 @@ if __name__ == '__main__':
76 91
     )
77 92
     parser.add_argument('map_dir_path', help='map directory path')
78 93
     parser.add_argument('--seed', dest='seed', default=None)
94
+    parser.add_argument('--troops', dest='troops', default=None)
79 95
     parser.add_argument('--state', dest='state', default=None)
80 96
     parser.add_argument(
81 97
         '--state-save-dir',
@@ -90,10 +106,31 @@ if __name__ == '__main__':
90 106
 
91 107
     args = parser.parse_args()
92 108
 
109
+    if args.troops and args.state:
110
+        print(
111
+            'Cannot load state "{}" because you provide troops file "{}". '
112
+            'You must provide only one of them.'.format(
113
+                args.state,
114
+                args.troops,
115
+            ),
116
+            file=sys.stderr,
117
+        )
118
+        exit(1)
119
+
120
+    if args.troops and not args.placement:
121
+        print(
122
+            'Cannot load troops "{}" without activate placement mode.'.format(
123
+                args.state,
124
+            ),
125
+            file=sys.stderr,
126
+        )
127
+        exit(1)
128
+
93 129
     main(
94 130
         args.map_dir_path,
95 131
         seed_value=args.seed,
96 132
         state_file_path=args.state,
133
+        troops_file_path=args.troops,
97 134
         state_save_dir=args.state_save_dir,
98 135
         placement_mode=args.placement,
99 136
     )

+ 9 - 0
select_troops.py View File

@@ -1,5 +1,6 @@
1 1
 # coding: utf-8
2 2
 import argparse
3
+import sys
3 4
 import typing
4 5
 from tkinter import Tk
5 6
 
@@ -62,6 +63,14 @@ if __name__ == '__main__':
62 63
     )
63 64
     args = parser.parse_args()
64 65
 
66
+    if not args.countries:
67
+        print(
68
+            'You must choose one or more countries with parameters '
69
+            '--country, eg. `--country USSR --country DE`',
70
+            file=sys.stderr,
71
+        )
72
+        exit(1)
73
+
65 74
     main(
66 75
         units_file_path=args.units_file_path,
67 76
         teams_file_path=args.teams_file_path,

+ 1 - 1
tests/fixtures/state_ok.xml View File

@@ -16,7 +16,7 @@
16 16
                 </item>
17 17
                 <item>
18 18
                     <key>FLAG</key>
19
-                    <value>FLAG_URSS</value>
19
+                    <value>FLAG_USSR</value>
20 20
                 </item>
21 21
                 <item>
22 22
                     <key>SIDE</key>

+ 2 - 2
tests/fixtures/teams.xml View File

@@ -1,7 +1,7 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2 2
 <teams>
3
-    <team id="std_team" country="URSS">
4
-        <name>Standard URSS team</name>
3
+    <team id="std_team" country="USSR">
4
+        <name>Standard USSR team</name>
5 5
         <units>
6 6
             <unit>
7 7
                 <id>std_soldier</id>

+ 1 - 1
tests/fixtures/units.xml View File

@@ -1,6 +1,6 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2 2
 <units>
3
-    <unit id="std_soldier" country="URSS">
3
+    <unit id="std_soldier" country="USSR">
4 4
         <name>Standard soldier</name>
5 5
         <type>opencombat.simulation.subject.ManSubject</type>
6 6
     </unit>

+ 3 - 3
tests/strategy/test_teams.py View File

@@ -46,7 +46,7 @@ def test_team_stash__ok__get_teams(
46 46
 
47 47
     assert 'std_team' == stash.teams[0].id
48 48
     assert 'Standard team' == stash.teams[0].name
49
-    assert 'URSS' == stash.teams[0].country
49
+    assert 'USSR' == stash.teams[0].country
50 50
     assert stash.teams[0].units
51 51
     assert 4 == len(stash.teams[0].units)
52 52
     assert isinstance(stash.teams[0].units[0], UnitModel)
@@ -76,7 +76,7 @@ def test_teams_stash__ok__get_unit(
76 76
         'tests/fixtures/teams.xml',
77 77
         unit_stash=unit_stash,
78 78
     )
79
-    assert stash.get_team('std_team', 'URSS')
79
+    assert stash.get_team('std_team', 'USSR')
80 80
 
81 81
 
82 82
 def test_teams_stash__error__get_team_wrong_country(
@@ -104,4 +104,4 @@ def test_teams_stash__error__get_team_wrong_id(
104 104
     )
105 105
 
106 106
     with pytest.raises(NotFoundException):
107
-        stash.get_team('unknown', 'URSS')
107
+        stash.get_team('unknown', 'USSR')

+ 3 - 3
tests/strategy/test_units.py View File

@@ -31,7 +31,7 @@ def test_units_stash__ok__get_units(
31 31
 
32 32
     assert 'std_soldier' == stash.units[0].id
33 33
     assert 'Standard soldier' == stash.units[0].name
34
-    assert 'URSS' == stash.units[0].country
34
+    assert 'USSR' == stash.units[0].country
35 35
     assert ManSubject == stash.units[0].class_
36 36
 
37 37
     assert 'std_soldier' == stash.units[1].id
@@ -47,7 +47,7 @@ def test_units_stash__ok__get_unit(
47 47
         config,
48 48
         'tests/fixtures/units.xml',
49 49
     )
50
-    assert stash.get_unit('std_soldier', 'URSS')
50
+    assert stash.get_unit('std_soldier', 'USSR')
51 51
 
52 52
 
53 53
 def test_units_stash__error__get_unit_wrong_country(
@@ -71,4 +71,4 @@ def test_units_stash__error__get_unit_wrong_id(
71 71
     )
72 72
 
73 73
     with pytest.raises(NotFoundException):
74
-        stash.get_unit('unknown', 'URSS')
74
+        stash.get_unit('unknown', 'USSR')

+ 10 - 8
tests/test_state.py View File

@@ -16,8 +16,10 @@ from opencombat.const import FLAG
16 16
 from opencombat.const import SIDE
17 17
 from opencombat.const import FLAG_DE
18 18
 from opencombat.const import DE_COLOR
19
-from opencombat.const import URSS_COLOR
20
-from opencombat.const import FLAG_URSS
19
+from opencombat.const import USSR_COLOR
20
+from opencombat.const import FLAG_USSR
21
+from opencombat.const import SIDE_ALLIES
22
+from opencombat.const import SIDE_AXIS
21 23
 
22 24
 
23 25
 class MyStateLoader(StateLoader):
@@ -44,16 +46,16 @@ def simulation_for_dump(config) -> TileStrategySimulation:
44 46
     man1.properties = OrderedDict([
45 47
         (SELECTION_COLOR_RGB, DE_COLOR),
46 48
         (FLAG, FLAG_DE),
47
-        (SIDE, 'AXIS'),
49
+        (SIDE, SIDE_AXIS),
48 50
     ])
49 51
 
50 52
     man2 = ManSubject(config, simulation)
51 53
     man2.position = (16, 8)
52 54
     man2.direction = 197
53 55
     man2.properties = OrderedDict([
54
-        (SELECTION_COLOR_RGB, URSS_COLOR),
55
-        (FLAG, FLAG_URSS),
56
-        (SIDE, 'ALLIES'),
56
+        (SELECTION_COLOR_RGB, USSR_COLOR),
57
+        (FLAG, FLAG_USSR),
58
+        (SIDE, SIDE_ALLIES),
57 59
     ])
58 60
 
59 61
     subjects.append(man1)
@@ -116,7 +118,7 @@ def test_state__ok__subjects(
116 118
 
117 119
     assert {
118 120
                'SELECTION_COLOR_RGB': (204, 0, 0),
119
-               'FLAG': 'FLAG_URSS',
121
+               'FLAG': 'FLAG_USSR',
120 122
                'SIDE': 'ALLIES',
121 123
            } == state.subjects[0].properties
122 124
     assert {
@@ -170,7 +172,7 @@ def test_state__ok__dump(
170 172
                 </item>
171 173
                 <item>
172 174
                     <key>FLAG</key>
173
-                    <value>FLAG_URSS</value>
175
+                    <value>FLAG_USSR</value>
174 176
                 </item>
175 177
                 <item>
176 178
                     <key>SIDE</key>