Completed
Push — master ( c07396...2dfd0a )
by Oleksandr
01:10
created

_has_markings()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1
Metric Value
cc 1
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 1
rs 10
1
# -*- coding: utf-8 -*-
2
3 1
from il2fb.commons.flight import Formations, RoutePointTypes
4 1
from il2fb.commons.organization import AirForces, Regiments
5 1
from il2fb.commons.spatial import Point3D
6 1
from il2fb.commons.structures import BaseStructure
7
8 1
from ..constants import (
9
    ROUTE_POINT_EXTRA_PARAMETERS_MARK, ROUTE_POINT_RADIO_SILENCE_ON,
10
    ROUTE_POINT_RADIO_SILENCE_OFF,
11
)
12 1
from ..converters import to_skill
13 1
from . import CollectingParser, ValuesParser
14
15
16 1
class WingSectionParser(CollectingParser):
17
    """
18
    Parses ``Wing`` section.
19
    View :ref:`detailed description <wing-section>`.
20
    """
21
22 1
    def check_section_name(self, section_name):
23 1
        return section_name == "Wing"
24
25 1
    def clean(self):
26 1
        return {'wings': self.data}
27
28
29 1
class WingInfoSectionParser(ValuesParser):
30
    """
31
    Parses settings for a moving wing group.
32
    View :ref:`detailed description <wing-info-section>`.
33
    """
34
35 1
    def check_section_name(self, section_name):
36 1
        try:
37 1
            self._decompose_section_name(section_name)
38 1
        except Exception:
39 1
            return False
40
        else:
41 1
            return True
42
43 1
    def init_parser(self, section_name):
44 1
        super(WingInfoSectionParser, self).init_parser(section_name)
45 1
        self.output_key = section_name
46 1
        self.wing_info = self._decompose_section_name(section_name)
47
48 1
    def _decompose_section_name(self, section_name):
49 1
        prefix = section_name[:-2]
50 1
        squadron, wing = section_name[-2:]
51
52 1
        try:
53 1
            regiment = None
54 1
            air_force = AirForces.get_by_flight_prefix(prefix)
55 1
        except ValueError:
56 1
            regiment = Regiments.get_by_code_name(prefix)
57 1
            air_force = regiment.air_force
58
59 1
        return {
60
            'id': section_name,
61
            'air_force': air_force,
62
            'regiment': regiment,
63
            'squadron_index': int(squadron),
64
            'wing_index': int(wing),
65
        }
66
67 1
    def clean(self):
68 1
        count = int(self.data['Planes'])
69 1
        code = self.data['Class'].split('.', 1)[1]
70 1
        aircrafts = []
71
72 1
        def _add_if_present(target, key, value):
73 1
            if value:
74 1
                target[key] = value
75
76 1
        for i in range(count):
77 1
            aircraft = {
78
                'index': i,
79
                'has_markings': self._has_markings(i),
80
                'skill': self._get_skill(i),
81
            }
82 1
            _add_if_present(
83
                aircraft, 'aircraft_skin', self._get_skin('skin', i))
84 1
            _add_if_present(
85
                aircraft, 'nose_art', self._get_skin('nose_art', i))
86 1
            _add_if_present(
87
                aircraft, 'pilot_skin', self._get_skin('pilot', i))
88 1
            _add_if_present(
89
                aircraft, 'spawn_object', self._get_spawn_object_id(i))
90 1
            aircrafts.append(aircraft)
91
92 1
        self.wing_info.update({
93
            'ai_only': 'OnlyAI' in self.data,
94
            'aircrafts': aircrafts,
95
            'code': code,
96
            'fuel': int(self.data['Fuel']),
97
            'with_parachutes': 'Parachute' not in self.data,
98
            'count': count,
99
            'weapons': self.data['weapons'],
100
        })
101
102 1
        return {self.output_key: self.wing_info}
103
104 1
    def _get_skill(self, aircraft_id):
105 1
        if 'Skill' in self.data:
106 1
            return to_skill(self.data['Skill'])
107
        else:
108 1
            return to_skill(self.data['Skill{:}'.format(aircraft_id)])
109
110 1
    def _has_markings(self, aircraft_id):
111 1
        return 'numberOn{:}'.format(aircraft_id) not in self.data
112
113 1
    def _get_skin(self, prefix, aircraft_id):
114 1
        return self.data.get('{:}{:}'.format(prefix, aircraft_id))
115
116 1
    def _get_spawn_object_id(self, aircraft_id):
117 1
        return self.data.get('spawn{:}'.format(aircraft_id))
118
119
120 1
class WingRoutePoint(BaseStructure):
121 1
    __slots__ = ['type', 'pos', 'speed', 'formation', 'radio_silence', ]
122
123 1
    def __init__(self, type, pos, speed, formation, radio_silence):
124 1
        self.type = type
125 1
        self.pos = pos
126 1
        self.speed = speed
127 1
        self.formation = formation
128 1
        self.radio_silence = radio_silence
129
130 1
    def __repr__(self):
131 1
        return ("<{0} '{1};{2};{3}'>"
132
                .format(self.__class__.__name__,
133
                        self.pos.x, self.pos.y, self.pos.z))
134
135
136 1
class WingRouteTakeoffPoint(WingRoutePoint):
137 1
    __slots__ = WingRoutePoint.__slots__ + ['delay', 'spacing', ]
138
139 1
    def __init__(self, type, pos, speed, formation, radio_silence, delay,
140
                 spacing):
141 1
        super(WingRouteTakeoffPoint, self).__init__(
142
            type, pos, speed, formation, radio_silence)
143 1
        self.delay = delay
144 1
        self.spacing = spacing
145
146
147 1
class WingRoutePatrolPoint(WingRoutePoint):
148 1
    __slots__ = WingRoutePoint.__slots__ + [
149
        'patrol_cycles', 'patrol_timeout',
150
        'pattern_angle', 'pattern_side_size', 'pattern_altitude_difference',
151
    ]
152
153 1
    def __init__(self, type, pos, speed, formation, radio_silence,
154
                 patrol_cycles, patrol_timeout, pattern_angle,
155
                 pattern_side_size, pattern_altitude_difference):
156 1
        super(WingRoutePatrolPoint, self).__init__(
157
            type, pos, speed, formation, radio_silence)
158 1
        self.patrol_cycles = patrol_cycles
159 1
        self.patrol_timeout = patrol_timeout
160 1
        self.pattern_angle = pattern_angle
161 1
        self.pattern_side_size = pattern_side_size
162 1
        self.pattern_altitude_difference = pattern_altitude_difference
163
164
165 1
class WingRouteAttackPoint(WingRoutePoint):
166 1
    __slots__ = WingRoutePoint.__slots__ + [
167
        'target_id', 'target_route_point',
168
    ]
169
170 1
    def __init__(self, type, pos, speed, formation, radio_silence, target_id,
171
                 target_route_point):
172 1
        super(WingRouteAttackPoint, self).__init__(
173
            type, pos, speed, formation, radio_silence)
174 1
        self.target_id = target_id
175 1
        self.target_route_point = target_route_point
176
177
178 1
class WingRouteSectionParser(CollectingParser):
179
    """
180
    Parses ``*_Way`` section.
181
    View :ref:`detailed description <wing-route-section>`.
182
    """
183 1
    input_suffix = "_Way"
184 1
    output_prefix = 'wing_route_'
185
186 1
    def check_section_name(self, section_name):
187 1
        return section_name.endswith(self.input_suffix)
188
189 1
    def _extract_wing_code(self, section_name):
190 1
        return section_name[:-len(self.input_suffix)]
191
192 1
    def init_parser(self, section_name):
193 1
        super(WingRouteSectionParser, self).init_parser(section_name)
194 1
        wing_code = self._extract_wing_code(section_name)
195 1
        self.output_key = "{}{}".format(self.output_prefix, wing_code)
196 1
        self.point = None
197 1
        self.point_class = None
198
199 1
    def parse_line(self, line):
200 1
        params = line.split()
201 1
        type_code, params = params[0], params[1:]
202 1
        if type_code == ROUTE_POINT_EXTRA_PARAMETERS_MARK:
203 1
            self._parse_options(params)
204
        else:
205 1
            self._finalize_current_point()
206 1
            pos, speed, params = params[0:3], params[3], params[4:]
207 1
            self.point = {
208
                'type': RoutePointTypes.get_by_value(type_code),
209
                'pos': Point3D(*pos),
210
                'speed': float(speed),
211
            }
212 1
            self._parse_extra(params)
213
214 1
    def _parse_options(self, params):
215 1
        try:
216 1
            cycles, timeout, angle, side_size, altitude_difference = params
217 1
            self.point.update({
218
                'patrol_cycles': int(cycles),
219
                'patrol_timeout': int(timeout),
220
                'pattern_angle': int(angle),
221
                'pattern_side_size': int(side_size),
222
                'pattern_altitude_difference': int(altitude_difference),
223
            })
224 1
            self.point_class = WingRoutePatrolPoint
225 1
        except ValueError:
226 1
            delay, spacing = params[1:3]
227 1
            self.point.update({
228
                'delay': int(delay),
229
                'spacing': int(spacing),
230
            })
231 1
            self.point_class = WingRouteTakeoffPoint
232
233 1
    def _parse_extra(self, params):
234 1
        if WingRouteSectionParser._is_new_game_version(params):
235 1
            radio_silence, formation, params = WingRouteSectionParser._parse_new_version_extra(params)
236 1
            if params:
237 1
                self._parse_target(params)
238
        else:
239 1
            radio_silence = False
240 1
            formation = None
241
242 1
        self.point.update({
243
            'radio_silence': radio_silence,
244
            'formation': formation,
245
        })
246
247 1
    @staticmethod
248
    def _is_new_game_version(params):
249 1
        return (
250
            ROUTE_POINT_RADIO_SILENCE_ON in params
251
            or ROUTE_POINT_RADIO_SILENCE_OFF in params
252
        )
253
254 1
    @staticmethod
255
    def _parse_new_version_extra(params):
256 1
        try:
257 1
            index = params.index(ROUTE_POINT_RADIO_SILENCE_ON)
258 1
        except ValueError:
259 1
            index = params.index(ROUTE_POINT_RADIO_SILENCE_OFF)
260
261 1
        params, radio_silence, extra = params[:index], params[index], params[index+1:]
262
263 1
        radio_silence = radio_silence == ROUTE_POINT_RADIO_SILENCE_ON
264 1
        formation = Formations.get_by_value(extra[0]) if extra else None
265
266 1
        return radio_silence, formation, params
267
268 1
    def _parse_target(self, params):
269 1
        target_id, target_route_point = params[:2]
270
271 1
        self.point.update({
272
            'target_id': target_id,
273
            'target_route_point': int(target_route_point),
274
        })
275
276 1
        if self.point['type'] is RoutePointTypes.normal:
277 1
            self.point['type'] = RoutePointTypes.air_attack
278
279 1
        self.point_class = WingRouteAttackPoint
280
281 1
    def clean(self):
282 1
        self._finalize_current_point()
283 1
        return {self.output_key: self.data}
284
285 1
    def _finalize_current_point(self):
286 1
        if self.point:
287 1
            point_class = getattr(self, 'point_class') or WingRoutePoint
288 1
            self.data.append(point_class(**self.point))
289 1
            self.point = None
290
            self.point_class = None
291