Completed
Push — work-fleets ( fc0000...961997 )
by SuperNova.WS
59:17
created

Fleet::printErrorIfNoShips()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 5
ccs 0
cts 5
cp 0
crap 6
rs 9.4285
1
<?php
2
use DBStatic\DBStaticFleetACS;
3
use DBStatic\DBStaticNote;
4
use DBStatic\DBStaticPlanet;
5
use DBStatic\DBStaticUnit;
6
use DBStatic\DBStaticUser;
7
use Exception\ExceptionFleetInvalid;
8
use Exception\ExceptionPropertyAccess;
9
use Vector\Vector;
10
11
/**
12
 * Class Fleet
13
 *
14
 * @property int dbId
15
 * @property int playerOwnerId
16
 * @property int group_id
17
 * @property int mission_type
18
 * @property int target_owner_id
19
 * @property int is_returning
20
 *
21
 * @property int time_launch
22
 * @property int time_arrive_to_target
23
 * @property int time_mission_job_complete
24
 * @property int time_return_to_source
25
 *
26
 * @property int fleet_start_planet_id
27
 * @property int fleet_start_galaxy
28
 * @property int fleet_start_system
29
 * @property int fleet_start_planet
30
 * @property int fleet_start_type
31
 *
32
 * @property int fleet_end_planet_id
33
 * @property int fleet_end_galaxy
34
 * @property int fleet_end_system
35
 * @property int fleet_end_planet
36
 * @property int fleet_end_type
37
 *
38
 */
39
class Fleet extends UnitContainer {
40
41
  // DBRow inheritance *************************************************************************************************
42
43
  /**
44
   * Table name in DB
45
   *
46
   * @var string
47
   */
48
  protected static $_table = 'fleets';
49
  /**
50
   * Name of ID field in DB
51
   *
52
   * @var string
53
   */
54
  protected static $_dbIdFieldName = 'fleet_id';
55
  /**
56
   * DB_ROW to Class translation scheme
57
   *
58
   * @var array
59
   */
60
  protected $_properties = array(
61
    'dbId'          => array(
62
      P_DB_FIELD => 'fleet_id',
63
    ),
64
    'playerOwnerId' => array(
65
      P_METHOD_EXTRACT => 'ownerExtract',
66
      P_METHOD_INJECT  => 'ownerInject',
67
//      P_DB_FIELD => 'fleet_owner',
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
68
    ),
69
    'mission_type'  => array(
70
      P_DB_FIELD   => 'fleet_mission',
71
      P_FUNC_INPUT => 'intval',
72
    ),
73
74
    'target_owner_id' => array(
75
      P_DB_FIELD => 'fleet_target_owner',
76
    ),
77
    'group_id'        => array(
78
      P_DB_FIELD => 'fleet_group',
79
    ),
80
    'is_returning'    => array(
81
      P_DB_FIELD   => 'fleet_mess',
82
      P_FUNC_INPUT => 'intval',
83
    ),
84
85
    'shipCount' => array(
86
      P_DB_FIELD  => 'fleet_amount',
87
// TODO - CHECK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
88
//      P_FUNC_OUTPUT => 'get_ship_count',
89
//      P_DB_FIELDS_LINKED => array(
90
//        'fleet_amount',
91
//      ),
92
      P_READ_ONLY => true,
93
    ),
94
95
    'time_launch' => array(
96
      P_DB_FIELD => 'start_time',
97
    ),
98
99
    'time_arrive_to_target'     => array(
100
      P_DB_FIELD => 'fleet_start_time',
101
    ),
102
    'time_mission_job_complete' => array(
103
      P_DB_FIELD => 'fleet_end_stay',
104
    ),
105
    'time_return_to_source'     => array(
106
      P_DB_FIELD => 'fleet_end_time',
107
    ),
108
109
    'fleet_start_planet_id' => array(
110
      P_DB_FIELD   => 'fleet_start_planet_id',
111
      P_FUNC_INPUT => 'nullIfEmpty',
112
    ),
113
114
    'fleet_start_galaxy' => array(
115
      P_DB_FIELD => 'fleet_start_galaxy',
116
    ),
117
    'fleet_start_system' => array(
118
      P_DB_FIELD => 'fleet_start_system',
119
    ),
120
    'fleet_start_planet' => array(
121
      P_DB_FIELD => 'fleet_start_planet',
122
    ),
123
    'fleet_start_type'   => array(
124
      P_DB_FIELD => 'fleet_start_type',
125
    ),
126
127
    'fleet_end_planet_id' => array(
128
      P_DB_FIELD   => 'fleet_end_planet_id',
129
      P_FUNC_INPUT => 'nullIfEmpty',
130
    ),
131
    'fleet_end_galaxy'    => array(
132
      P_DB_FIELD => 'fleet_end_galaxy',
133
    ),
134
    'fleet_end_system'    => array(
135
      P_DB_FIELD => 'fleet_end_system',
136
    ),
137
    'fleet_end_planet'    => array(
138
      P_DB_FIELD => 'fleet_end_planet',
139
    ),
140
    'fleet_end_type'      => array(
141
      P_DB_FIELD => 'fleet_end_type',
142
    ),
143
144
    'resource_list' => array(
145
      P_METHOD_EXTRACT   => 'resourcesExtract',
146
      P_METHOD_INJECT    => 'resourcesInject',
147
      P_DB_FIELDS_LINKED => array(
148
        'fleet_resource_metal',
149
        'fleet_resource_crystal',
150
        'fleet_resource_deuterium',
151
      ),
152
    ),
153
  );
154
155
156
  // UnitContainer inheritance *****************************************************************************************
157
  /**
158
   * Type of this location
159
   *
160
   * @var int $locationType
161
   */
162
  protected static $locationType = LOC_FLEET;
163
164
165
  // New properties ****************************************************************************************************
166
  /**
167
   * `fleet_owner`
168
   *
169
   * @var int
170
   */
171
  protected $_playerOwnerId = 0;
172
  /**
173
   * `fleet_group`
174
   *
175
   * @var int
176
   */
177
  protected $_group_id = 0;
178
  public $acs = array();
179
180
  /**
181
   * `fleet_mission`
182
   *
183
   * @var int
184
   */
185
  protected $_mission_type = 0;
186
187
  /**
188
   * `fleet_target_owner`
189
   *
190
   * @var int
191
   */
192
  protected $_target_owner_id = null;
193
194
  /**
195
   * @var array
196
   */
197
  public $resource_list = array(
198
    RES_METAL     => 0,
199
    RES_CRYSTAL   => 0,
200
    RES_DEUTERIUM => 0,
201
  );
202
203
204
  /**
205
   * `fleet__mess` - Флаг возвращающегося флота
206
   *
207
   * @var int
208
   */
209
  protected $_is_returning = 0;
210
  /**
211
   * `start_time` - Время отправления - таймштамп взлёта флота из точки отправления
212
   *
213
   * @var int $_time_launch
214
   */
215
  protected $_time_launch = 0; // `start_time` = SN_TIME_NOW
216
  /**
217
   * `fleet_start_time` - Время прибытия в точку миссии/время начала выполнения миссии
218
   *
219
   * @var int $_time_arrive_to_target
220
   */
221
  protected $_time_arrive_to_target = 0; // `fleet_start_time` = SN_TIME_NOW + $time_travel
222
  /**
223
   * `fleet_end_stay` - Время окончания миссии в точке назначения
224
   *
225
   * @var int $_time_mission_job_complete
226
   */
227
  protected $_time_mission_job_complete = 0; // `fleet_end_stay`
228
  /**
229
   * `fleet_end_time` - Время возвращения флота после окончания миссии
230
   *
231
   * @var int $_time_return_to_source
232
   */
233
  protected $_time_return_to_source = 0; // `fleet_end_time`
234
235
236
  protected $_fleet_start_planet_id = null;
237
  protected $_fleet_start_galaxy = 0;
238
  protected $_fleet_start_system = 0;
239
  protected $_fleet_start_planet = 0;
240
  protected $_fleet_start_type = PT_ALL;
241
242
  protected $_fleet_end_planet_id = null;
243
  protected $_fleet_end_galaxy = 0;
244
  protected $_fleet_end_system = 0;
245
  protected $_fleet_end_planet = 0;
246
  protected $_fleet_end_type = PT_ALL;
247
248
  // Missile properties
249
  public $missile_target = 0;
250
251
  // Fleet event properties
252
  public $fleet_start_name = '';
253
  public $fleet_end_name = '';
254
  public $ov_label = '';
255
  public $ov_this_planet = '';
256
  public $event_time = 0;
257
258
  protected $resource_delta = array();
259
  protected $resource_replace = array();
260
261
262
//
263
264
265
  /**
266
   * @var array $allowed_missions
267
   */
268
  public $allowed_missions = array();
269
  /**
270
   * @var array $exists_missions
271
   */
272
  public $exists_missions = array();
273
  public $allowed_planet_types = array(
274
    // PT_NONE => PT_NONE,
275
    PT_PLANET => PT_PLANET,
276
    PT_MOON   => PT_MOON,
277
    PT_DEBRIS => PT_DEBRIS
278
  );
279
280
  // TODO - Move to Player
281
  public $dbOwnerRow = array();
282
  public $dbSourcePlanetRow = array();
283
284
  /**
285
   * GSPT coordinates of target
286
   *
287
   * @var Vector
288
   */
289
  public $targetVector = array();
290
  /**
291
   * Target planet row
292
   *
293
   * @var array
294
   */
295
  public $dbTargetRow = array();
296
  public $dbTargetOwnerRow = array();
297
298
  /**
299
   * Fleet speed - old in 1/10 of 100%
300
   *
301
   * @var int
302
   */
303
  public $oldSpeedInTens = 0;
304
305
  public $tempPlayerMaxFleets = 0;
306
  public $travelData = array();
307
308
  public $isRealFlight = false;
309
310
  /**
311
   * @var int $targetedUnitId
312
   */
313
  public $targetedUnitId = 0;
314
315
  /**
316
   * @var array $captain
317
   */
318
  public $captain = array();
319
  /**
320
   * @var int $captainId
321
   */
322
  public $captainId = 0;
323
324
  /**
325
   * @var FleetValidator $validator
326
   */
327
  public $validator;
328
329
330
  /**
331
   * @var UnitList $unitList
332
   */
333
  protected $unitList = null;
334
335
  /**
336
   * @var \Planet\PlanetRenderer $planetRenderer
337
   */
338
  protected $planetRenderer;
339
340
  /**
341
   * @var FleetRenderer
342
   */
343
  protected $fleetRenderer;
344
345
346
  /**
347
   * Fleet constructor.
348
   */
349
  public function __construct() {
350
    parent::__construct();
351
    $this->exists_missions = sn_get_groups('missions');
352
    $this->validator = new FleetValidator($this);
353
354
    $this->planetRenderer = classSupernova::$gc->planetRenderer;
0 ignored issues
show
Documentation Bug introduced by
It seems like \classSupernova::$gc->planetRenderer can also be of type object<Closure>. However, the property $planetRenderer is declared as type object<Planet\PlanetRenderer>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
355
    $this->fleetRenderer = classSupernova::$gc->fleetRenderer;
0 ignored issues
show
Documentation Bug introduced by
It seems like \classSupernova::$gc->fleetRenderer can also be of type object<Closure>. However, the property $fleetRenderer is declared as type object<FleetRenderer>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
356
  }
357
358
  /**
359
   * @return UnitList
360
   */
361
  public function getUnitList() {
362
    return $this->unitList;
363
  }
364
365
  public function isEmpty() {
366
    return !$this->resourcesGetTotal() && !$this->shipsGetTotal();
367
  }
368
369
//  public function getPlayerOwnerId() {
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
370
//    return $this->playerOwnerId;
371
//  }
372
373
  /**
374
   * Initializes Fleet from user params and posts it to DB
375
   */
376
  public function dbInsert() {
377
    // WARNING! MISSION TIMES MUST BE SET WITH set_times() method!
378
    // TODO - more checks!
379
    if (empty($this->_time_launch)) {
380
      die('Fleet time not set!');
381
    }
382
383
    parent::dbInsert();
384
  }
385
386
387
  /* FLEET DB ACCESS =================================================================================================*/
388
389
  /**
390
   * LOCK - Lock all records which can be used with mission
391
   *
392
   * @param $mission_data
393
   *
394
   * @return array|bool|mysqli_result|null
395
   */
396
  public function dbLockFlying(&$mission_data) {
397
    // Тупо лочим всех юзеров, чьи флоты летят или улетают с координат отбытия/прибытия $fleet_row
398
    // Что бы делать это умно - надо учитывать fleet__mess во $fleet_row и в таблице fleets
399
400
    $fleet_id_safe = idval($this->_dbId);
401
402
    return classSupernova::$db->doSelect(
403
    // Блокировка самого флота
404
      "SELECT 1 FROM {{fleets}} AS f " .
405
406
      // Блокировка всех юнитов, принадлежащих этому флоту
407
      "LEFT JOIN {{unit}} as unit ON unit.unit_location_type = " . static::$locationType . " AND unit.unit_location_id = f.fleet_id " .
408
409
      // Блокировка всех прилетающих и улетающих флотов, если нужно
410
      // TODO - lock fleets by COORDINATES
411
      ($mission_data['dst_fleets'] ? "LEFT JOIN {{fleets}} AS fd ON fd.fleet_end_planet_id = f.fleet_end_planet_id OR fd.fleet_start_planet_id = f.fleet_end_planet_id " : '') .
412
      // Блокировка всех юнитов, принадлежащих прилетающим и улетающим флотам - ufd = unit_fleet_destination
413
      ($mission_data['dst_fleets'] ? "LEFT JOIN {{unit}} AS ufd ON ufd.unit_location_type = " . static::$locationType . " AND ufd.unit_location_id = fd.fleet_id " : '') .
414
415
      ($mission_data['dst_user'] || $mission_data['dst_planet'] ? "LEFT JOIN {{users}} AS ud ON ud.id = f.fleet_target_owner " : '') .
416
      // Блокировка всех юнитов, принадлежащих владельцу планеты-цели
417
      ($mission_data['dst_user'] || $mission_data['dst_planet'] ? "LEFT JOIN {{unit}} AS unit_player_dest ON unit_player_dest.unit_player_id = ud.id " : '') .
418
      // Блокировка планеты-цели
419
      ($mission_data['dst_planet'] ? "LEFT JOIN {{planets}} AS pd ON pd.id = f.fleet_end_planet_id " : '') .
420
      // Блокировка всех юнитов, принадлежащих планете-цели - НЕ НУЖНО. Уже залочили ранее, как принадлежащие игроку-цели
421
//      ($mission_data['dst_planet'] ? "LEFT JOIN {{unit}} AS upd ON upd.unit_location_type = " . LOC_PLANET . " AND upd.unit_location_id = pd.id " : '') .
422
423
424
      ($mission_data['src_user'] || $mission_data['src_planet'] ? "LEFT JOIN {{users}} AS us ON us.id = f.fleet_owner " : '') .
425
      // Блокировка всех юнитов, принадлежащих владельцу флота
426
      ($mission_data['src_user'] || $mission_data['src_planet'] ? "LEFT JOIN {{unit}} AS unit_player_src ON unit_player_src.unit_player_id = us.id " : '') .
427
      // Блокировка планеты отправления
428
      ($mission_data['src_planet'] ? "LEFT JOIN {{planets}} AS ps ON ps.id = f.fleet_start_planet_id " : '') .
429
      // Блокировка всех юнитов, принадлежащих планете с которой юниты были отправлены - НЕ НУЖНО. Уже залочили ранее, как принадлежащие владельцу флота
430
//      ($mission_data['src_planet'] ? "LEFT JOIN {{unit}} AS ups ON ups.unit_location_type = " . LOC_PLANET . " AND ups.unit_location_id = ps.id " : '') .
431
432
      "WHERE f.fleet_id = {$fleet_id_safe} GROUP BY 1 FOR UPDATE"
433
    );
434
  }
435
436
  /**
437
   * Lock all fields that belongs to operation
438
   *
439
   * @param $dbId
440
   */
441
  // TODO = make static
442
  public function dbGetLockById($dbId) {
443
    classSupernova::$db->doSelect(
444
    // Блокировка самого флота
445
      "SELECT 1 FROM {{fleets}} AS FLEET0 " .
446
      // Lock fleet owner
447
      "LEFT JOIN {{users}} as USER0 on USER0.id = FLEET0.fleet_owner " .
448
      // Блокировка всех юнитов, принадлежащих этому флоту
449
      "LEFT JOIN {{unit}} as UNIT0 ON UNIT0.unit_location_type = " . LOC_FLEET . " AND UNIT0.unit_location_id = FLEET0.fleet_id " .
450
451
      // Без предварительной выборки неизвестно - куда летит этот флот.
452
      // Поэтому надо выбирать флоты, чьи координаты прибытия ИЛИ отбытия совпадают с координатами прибытия ИЛИ отбытия текущего флота.
453
      // Получаем матрицу 2х2 - т.е. 4 подзапроса.
454
      // При блокировке всегда нужно выбирать И лпанету, И луну - поскольку при бое на орбите луны обломки падают на орбиту планеты.
455
      // Поэтому тип планеты не указывается
456
457
      // Lock fleet heading to destination planet. Only if FLEET0.fleet_mess == 0
458
      "LEFT JOIN {{fleets}} AS FLEET1 ON
459
        FLEET1.fleet_mess = 0 AND FLEET0.fleet_mess = 0 AND
460
        FLEET1.fleet_end_galaxy = FLEET0.fleet_end_galaxy AND
461
        FLEET1.fleet_end_system = FLEET0.fleet_end_system AND
462
        FLEET1.fleet_end_planet = FLEET0.fleet_end_planet
463
      " .
464
      // Блокировка всех юнитов, принадлежащих этим флотам
465
      "LEFT JOIN {{unit}} as UNIT1 ON UNIT1.unit_location_type = " . LOC_FLEET . " AND UNIT1.unit_location_id = FLEET1.fleet_id " .
466
      // Lock fleet owner
467
      "LEFT JOIN {{users}} as USER1 on USER1.id = FLEET1.fleet_owner " .
468
469
      "LEFT JOIN {{fleets}} AS FLEET2 ON
470
        FLEET2.fleet_mess = 1   AND FLEET0.fleet_mess = 0 AND
471
        FLEET2.fleet_start_galaxy = FLEET0.fleet_end_galaxy AND
472
        FLEET2.fleet_start_system = FLEET0.fleet_end_system AND
473
        FLEET2.fleet_start_planet = FLEET0.fleet_end_planet
474
      " .
475
      // Блокировка всех юнитов, принадлежащих этим флотам
476
      "LEFT JOIN {{unit}} as UNIT2 ON
477
        UNIT2.unit_location_type = " . LOC_FLEET . " AND
478
        UNIT2.unit_location_id = FLEET2.fleet_id
479
      " .
480
      // Lock fleet owner
481
      "LEFT JOIN {{users}} as USER2 on
482
        USER2.id = FLEET2.fleet_owner
483
      " .
484
485
      // Lock fleet heading to source planet. Only if FLEET0.fleet_mess == 1
486
      "LEFT JOIN {{fleets}} AS FLEET3 ON
487
        FLEET3.fleet_mess = 0 AND FLEET0.fleet_mess = 1 AND
488
        FLEET3.fleet_end_galaxy = FLEET0.fleet_start_galaxy AND
489
        FLEET3.fleet_end_system = FLEET0.fleet_start_system AND
490
        FLEET3.fleet_end_planet = FLEET0.fleet_start_planet
491
      " .
492
      // Блокировка всех юнитов, принадлежащих этим флотам
493
      "LEFT JOIN {{unit}} as UNIT3 ON
494
        UNIT3.unit_location_type = " . LOC_FLEET . " AND
495
        UNIT3.unit_location_id = FLEET3.fleet_id
496
      " .
497
      // Lock fleet owner
498
      "LEFT JOIN {{users}} as USER3 on USER3.id = FLEET3.fleet_owner " .
499
500
      "LEFT JOIN {{fleets}} AS FLEET4 ON
501
        FLEET4.fleet_mess = 1   AND FLEET0.fleet_mess = 1 AND
502
        FLEET4.fleet_start_galaxy = FLEET0.fleet_start_galaxy AND
503
        FLEET4.fleet_start_system = FLEET0.fleet_start_system AND
504
        FLEET4.fleet_start_planet = FLEET0.fleet_start_planet
505
      " .
506
      // Блокировка всех юнитов, принадлежащих этим флотам
507
      "LEFT JOIN {{unit}} as UNIT4 ON
508
        UNIT4.unit_location_type = " . LOC_FLEET . " AND
509
        UNIT4.unit_location_id = FLEET4.fleet_id
510
      " .
511
      // Lock fleet owner
512
      "LEFT JOIN {{users}} as USER4 on
513
        USER4.id = FLEET4.fleet_owner
514
      " .
515
516
517
      // Locking start planet
518
      "LEFT JOIN {{planets}} AS PLANETS5 ON
519
        FLEET0.fleet_mess = 1 AND
520
        PLANETS5.galaxy = FLEET0.fleet_start_galaxy AND
521
        PLANETS5.system = FLEET0.fleet_start_system AND
522
        PLANETS5.planet = FLEET0.fleet_start_planet
523
      " .
524
      // Lock planet owner
525
      "LEFT JOIN {{users}} as USER5 on
526
        USER5.id = PLANETS5.id_owner
527
      " .
528
      // Блокировка всех юнитов, принадлежащих этой планете
529
      "LEFT JOIN {{unit}} as UNIT5 ON
530
        UNIT5.unit_location_type = " . LOC_PLANET . " AND
531
        UNIT5.unit_location_id = PLANETS5.id
532
      " .
533
534
535
      // Locking destination planet
536
      "LEFT JOIN {{planets}} AS PLANETS6 ON
537
        FLEET0.fleet_mess = 0 AND
538
        PLANETS6.galaxy = FLEET0.fleet_end_galaxy AND
539
        PLANETS6.system = FLEET0.fleet_end_system AND
540
        PLANETS6.planet = FLEET0.fleet_end_planet
541
      " .
542
      // Lock planet owner
543
      "LEFT JOIN {{users}} as USER6 on
544
        USER6.id = PLANETS6.id_owner
545
      " .
546
      // Блокировка всех юнитов, принадлежащих этой планете
547
      "LEFT JOIN {{unit}} as UNIT6 ON
548
        UNIT6.unit_location_type = " . LOC_PLANET . " AND
549
        UNIT6.unit_location_id = PLANETS6.id
550
      " .
551
      "WHERE FLEET0.fleet_id = {$dbId} GROUP BY 1 FOR UPDATE"
552
    );
553
  }
554
555
556
  public function dbRowParse($db_row) {
557
    parent::dbRowParse($db_row); // TODO: Change the autogenerated stub
558
    $player = new Player();
559
    $player->dbLoad($db_row['fleet_owner']);
560
    $this->setLocatedAt($player);
561
  }
562
563
  /* FLEET HELPERS =====================================================================================================*/
564
  /**
565
   * Forcibly returns fleet before time outs
566
   */
567
  public function commandReturn() {
568
    $ReturnFlyingTime = ($this->_time_mission_job_complete != 0 && $this->_time_arrive_to_target < SN_TIME_NOW ? $this->_time_arrive_to_target : SN_TIME_NOW) - $this->_time_launch + SN_TIME_NOW + 1;
569
570
    // Считаем, что флот уже долетел TODO
571
    $this->time_arrive_to_target = SN_TIME_NOW;
572
    // Убираем флот из группы
573
    $this->group_id = 0;
574
    // Отменяем работу в точке назначения
575
    $this->time_mission_job_complete = 0;
576
    // TODO - правильно вычслять время возвращения - по проделанному пути, а не по старому времени возвращения
577
    $this->time_return_to_source = $ReturnFlyingTime;
578
579
    // Записываем изменения в БД
580
    $this->markReturnedAndSave();
581
582
    if ($this->_group_id) {
583
      // TODO: Make here to delete only one AKS - by adding aks_fleet_count to AKS table
584
      DBStaticFleetACS::db_fleet_aks_purge();
585
    }
586
  }
587
588
589
  /**
590
   * @return array
591
   */
592
  public function target_coordinates_without_type() {
593
    return array(
594
      'galaxy' => $this->_fleet_end_galaxy,
595
      'system' => $this->_fleet_end_system,
596
      'planet' => $this->_fleet_end_planet,
597
    );
598
  }
599
600
  /**
601
   * @return array
602
   */
603
  public function target_coordinates_typed() {
604
    return array(
605
      'galaxy' => $this->_fleet_end_galaxy,
606
      'system' => $this->_fleet_end_system,
607
      'planet' => $this->_fleet_end_planet,
608
      'type'   => $this->_fleet_end_type,
609
    );
610
  }
611
612
  /**
613
   * @return array
614
   */
615
  public function launch_coordinates_typed() {
616
    return array(
617
      'galaxy' => $this->_fleet_start_galaxy,
618
      'system' => $this->_fleet_start_system,
619
      'planet' => $this->_fleet_start_planet,
620
      'type'   => $this->_fleet_start_type,
621
    );
622
  }
623
624
  public function isReturning() {
625
    return FLEET_FLAG_RETURNING == $this->_is_returning;
626
  }
627
628
  /**
629
   * Sets object fields for fleet return
630
   */
631
  public function markReturnedAndSave() {
632
    // TODO - Проверка - а не возвращается ли уже флот?
633
    $this->is_returning = FLEET_FLAG_RETURNING;
634
    $this->dbSave();
635
  }
636
637
  /**
638
   * Parses extended unit_array which can include not only ships but resources, captains etc
639
   *
640
   * @param $unit_array
641
   *
642
   * @throws Exception
643
   */
644
  // TODO - separate shipList and unitList
645
  public function unitsSetFromArray($unit_array) {
646
    if (empty($unit_array) || !is_array($unit_array)) {
647
      return;
648
    }
649
    foreach ($unit_array as $unit_id => $unit_count) {
650
      $unit_count = floatval($unit_count);
651
      if (!$unit_count) {
652
        continue;
653
      }
654
655
      if ($this->isShip($unit_id) || $this->isMissile($unit_id)) {
656
        $this->unitList->unitSetCount($unit_id, $unit_count);
657
      } elseif ($this->isResource($unit_id)) {
658
        $this->resource_list[$unit_id] = $unit_count;
659
      } else {
660
        throw new Exception('Trying to pass to fleet non-resource and non-ship ' . var_export($unit_array, true), FLIGHT_SHIPS_UNIT_WRONG);
661
      }
662
    }
663
  }
664
665
666
  /**
667
   * Sets fleet timers based on flight duration, time on mission (HOLD/EXPLORE) and fleet departure time.
668
   *
669
   * @param int $time_to_travel - flight duration in seconds
670
   * @param int $time_on_mission - time on mission in seconds
671
   * @param int $flight_departure - fleet departure from source planet timestamp. Allows to send fleet in future or in past
672
   */
673
  public function set_times($time_to_travel, $time_on_mission = 0, $flight_departure = SN_TIME_NOW) {
674
    $this->_time_launch = $flight_departure;
675
676
    $this->_time_arrive_to_target = $this->_time_launch + $time_to_travel;
677
    $this->_time_mission_job_complete = $time_on_mission ? $this->_time_arrive_to_target + $time_on_mission : 0;
678
    $this->_time_return_to_source = ($this->_time_mission_job_complete ? $this->_time_mission_job_complete : $this->_time_arrive_to_target) + $time_to_travel;
679
  }
680
681
682
  public function parse_missile_db_row($missile_db_row) {
683
//    $this->_reset();
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
684
685
    if (empty($missile_db_row) || !is_array($missile_db_row)) {
686
      return;
687
    }
688
689
//      $planet_start = db_planet_by_vector($irak_original, FLEET_START_PREFIX, false, 'name');
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
690
//      $irak_original['fleet_start_name'] = $planet_start['name'];
691
    $this->missile_target = $missile_db_row['primaer'];
692
693
    $this->_dbId = -$missile_db_row['id'];
694
    $this->_playerOwnerId = $missile_db_row['fleet_owner'];
695
    $this->_mission_type = MT_MISSILE;
696
697
    $this->_target_owner_id = $missile_db_row['fleet_target_owner'];
698
699
    $this->_group_id = 0;
700
    $this->_is_returning = 0;
701
702
    $this->_time_launch = 0; // $irak['start_time'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
703
    $this->_time_arrive_to_target = 0; // $irak['fleet_start_time'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
704
    $this->_time_mission_job_complete = 0; // $irak['fleet_end_stay'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
705
    $this->_time_return_to_source = $missile_db_row['fleet_end_time'];
706
707
    $this->_fleet_start_planet_id = !empty($missile_db_row['fleet_start_planet_id']) ? $missile_db_row['fleet_start_planet_id'] : null;
708
    $this->_fleet_start_galaxy = $missile_db_row['fleet_start_galaxy'];
709
    $this->_fleet_start_system = $missile_db_row['fleet_start_system'];
710
    $this->_fleet_start_planet = $missile_db_row['fleet_start_planet'];
711
    $this->_fleet_start_type = $missile_db_row['fleet_start_type'];
712
713
    $this->_fleet_end_planet_id = !empty($missile_db_row['fleet_end_planet_id']) ? $missile_db_row['fleet_end_planet_id'] : null;
714
    $this->_fleet_end_galaxy = $missile_db_row['fleet_end_galaxy'];
715
    $this->_fleet_end_system = $missile_db_row['fleet_end_system'];
716
    $this->_fleet_end_planet = $missile_db_row['fleet_end_planet'];
717
    $this->_fleet_end_type = $missile_db_row['fleet_end_type'];
718
719
    $this->unitList->unitSetCount(UNIT_DEF_MISSILE_INTERPLANET, $missile_db_row['fleet_amount']);
720
  }
721
722
723
  /**
724
   * @param $from
725
   */
726
  public function set_start_planet($from) {
727
    $this->fleet_start_planet_id = intval($from['id']) ? $from['id'] : null;
728
    $this->fleet_start_galaxy = $from['galaxy'];
729
    $this->fleet_start_system = $from['system'];
730
    $this->fleet_start_planet = $from['planet'];
731
    $this->fleet_start_type = $from['planet_type'];
732
  }
733
734
  /**
735
   * @param $to
736
   */
737
  public function set_end_planet($to) {
738
    $this->target_owner_id = intval($to['id_owner']) ? $to['id_owner'] : 0;
739
    $this->fleet_end_planet_id = intval($to['id']) ? $to['id'] : null;
740
    $this->fleet_end_galaxy = $to['galaxy'];
741
    $this->fleet_end_system = $to['system'];
742
    $this->fleet_end_planet = $to['planet'];
743
    $this->fleet_end_type = $to['planet_type'];
744
  }
745
746
  /**
747
   * @param Vector $to
748
   */
749
  public function setTargetFromVectorObject($to) {
750
    $this->_fleet_end_galaxy = $to->galaxy;
751
    $this->_fleet_end_system = $to->system;
752
    $this->_fleet_end_planet = $to->planet;
753
    $this->_fleet_end_type = $to->type;
754
  }
755
756
  /**
757
   * @param array $db_row
758
   */
759
  protected function ownerExtract(array &$db_row) {
760
    $player = new Player();
761
    $player->dbLoad($db_row['fleet_owner']);
762
    $this->setLocatedAt($player);
763
  }
764
765
  /**
766
   * @param array $db_row
767
   */
768
  protected function ownerInject(array &$db_row) {
769
    $db_row['fleet_owner'] = $this->getPlayerOwnerId();
770
  }
771
772
773
774
775
  // UnitList/Ships access ***************************************************************************************************
776
777
  // TODO - перекрывать пожже - для миссайл-флотов и дефенс-флотов
778
  protected function isShip($unit_id) {
779
    return UnitShip::is_in_group($unit_id);
780
  }
781
782
  protected function isMissile($unit_id) {
783
    return isInGroup(GROUP_STR_MISSILES, $unit_id);
784
  }
785
786
  /**
787
   * Set unit count of $unit_id to $unit_count
788
   * If there is no $unit_id - it will be created and saved to DB on dbSave
789
   *
790
   * @param int $unit_id
791
   * @param int $unit_count
792
   */
793
  public function shipSetCount($unit_id, $unit_count = 0) {
794
    pdump(__CLASS__ . '->' . __FUNCTION__);
795
    $this->shipAdjustCount($unit_id, $unit_count, true);
796
  }
797
798
  /**
799
   * Adjust unit count of $unit_id by $unit_count - or just replace value
800
   * If there is no $unit_id - it will be created and saved to DB on dbSave
801
   *
802
   * @param int  $unit_id
803
   * @param int  $unit_count
804
   * @param bool $replace_value
805
   */
806
  public function shipAdjustCount($unit_id, $unit_count = 0, $replace_value = false) {
807
    $this->unitList->unitAdjustCount($unit_id, $unit_count, $replace_value);
808
  }
809
810
  public function shipGetCount($unit_id) {
811
    return $this->unitList->unitGetCount($unit_id);
812
  }
813
814
  public function shipsCountApplyLossMultiplier($ships_lost_multiplier) {
815
    $this->unitList->unitsCountApplyLossMultiplier($ships_lost_multiplier);
816
  }
817
818
  /**
819
   * Returns fleet ships cost in metal
820
   *
821
   * @param array $shipCostInMetalPerPiece
822
   *
823
   * @return float[]
824
   */
825
  public function shipsCostInMetal($shipCostInMetalPerPiece) {
826
    return $this->unitList->unitsCostInMetal($shipCostInMetalPerPiece);
827
  }
828
829
  /**
830
   * @return UnitIterator
831
   */
832
  public function shipsIterator() {
833
    return $this->unitList->getUnitIterator();
834
  }
835
836
  public function shipsGetTotal() {
837
    return $this->unitList->unitsCount();
838
  }
839
840
  public function shipsGetCapacity() {
841
    return $this->unitList->shipsCapacity();
842
  }
843
844
  public function shipsGetHoldFree() {
845
    return max(0, $this->shipsGetCapacity() - $this->resourcesGetTotal());
846
  }
847
848
  /**
849
   * Get count of ships with $ship_id
850
   *
851
   * @param int $ship_id
852
   *
853
   * @return int
854
   */
855
  public function shipsGetTotalById($ship_id) {
856
    return $this->unitList->unitsCountById($ship_id);
857
  }
858
859
  /**
860
   * Возвращает ёмкость переработчиков во флоте
861
   *
862
   * @param array $recycler_info
863
   *
864
   * @return int
865
   *
866
   */
867
  public function shipsGetCapacityRecyclers($recycler_info) {
868
    $recyclers_incoming_capacity = 0;
869
    foreach ($this->shipsIterator() as $unitId => $unit) {
870
      if (!empty(classSupernova::$gc->groupRecyclers[$unitId]) && $unit->count >= 1) {
871
        $recyclers_incoming_capacity += $unit->count * $recycler_info[$unitId]['capacity'];
872
      }
873
    }
874
875
    return $recyclers_incoming_capacity;
876
  }
877
878
  /**
879
   * @return bool
880
   */
881
  // TODO - А если не на планете????
882
  public function shipsIsEnoughOnPlanet() {
883
    return $this->unitList->shipsIsEnoughOnPlanet($this->dbOwnerRow, $this->dbSourcePlanetRow);
884
  }
885
886
  /**
887
   * @return bool
888
   */
889
  public function shipsAllPositive() {
890
    return $this->unitList->unitsPositive();
891
  }
892
893
  /**
894
   * @return bool
895
   */
896
  public function shipsAllFlying() {
897
    return $this->unitList->unitsInGroup(classSupernova::$gc->groupFleetAndMissiles);
898
  }
899
900
  /**
901
   * @return bool
902
   */
903
  public function shipsAllMovable() {
904
    return $this->unitList->unitsIsAllMovable($this->dbOwnerRow);
905
  }
906
907
  /**
908
   * Restores fleet or resources to planet
909
   *
910
   * @param bool $start
911
   * @param int  $result
912
   */
913
  // TODO - split to functions
914
  public function shipsLand($start = true) {
915
    sn_db_transaction_check(true);
916
917
    // Если флот уже обработан - не существует или возращается - тогда ничего не делаем
918
    if ($this->isEmpty()) {
919
      return;
920
    }
921
922
    $coordinates = $start ? $this->launch_coordinates_typed() : $this->target_coordinates_typed();
923
924
    // Поскольку эта функция может быть вызвана не из обработчика флотов - нам надо всё заблокировать вроде бы НЕ МОЖЕТ!!!
925
    // TODO Проверить от многократного срабатывания !!!
926
    // Тут не блокируем пока - сначала надо заблокировать пользователя, что бы не было дедлока
927
    // TODO поменять на владельца планеты - когда его будут возвращать всегда !!!
928
929
    // Узнаем ИД владельца планеты.
930
    // С блокировкой, поскольку эта функция может быть вызвана только из менеджера летящих флотов.
931
    // А там уже всё заблокировано как надо и повторная блокировка не вызовет дедлок.
932
    $planet_arrival = DBStaticPlanet::db_planet_by_vector($coordinates, '', true);
933
    // Блокируем пользователя
934
    // TODO - вообще-то нам уже известен пользователь в МЛФ - так что можно просто передать его сюда
935
    $user = DBStaticUser::db_user_by_id($planet_arrival['id_owner'], true);
936
937
    // TODO - Проверка, что планета всё еще существует на указанных координатах, а не телепортировалась, не удалена хозяином, не уничтожена врагом
938
    // Флот, который возвращается на захваченную планету, пропадает
939
    // Ship landing is possible only to fleet owner's planet
940
    if ($this->getPlayerOwnerId() == $planet_arrival['id_owner']) {
941
      // Adjusting ship amount on planet
942
      foreach ($this->shipsIterator() as $ship_id => $ship) {
943
        if ($ship->count) {
944
          DBStaticUnit::dbUpdateOrInsertUnit($ship_id, $ship->count, $user, $planet_arrival['id']);
945
        }
946
      }
947
948
      // Restoring resources to planet
949
      $this->resourcesUnload($start);
950
    }
951
952
    RestoreFleetToPlanet($this, $start);
953
954
    $this->dbDelete();
955
  }
956
957
958
  // Resources access ***************************************************************************************************
959
960
  /**
961
   * Extracts resources value from db_row
962
   *
963
   * @param array $db_row
964
   */
965
  protected function resourcesExtract(array &$db_row) {
966
    $this->resource_list = array(
967
      RES_METAL     => !empty($db_row['fleet_resource_metal']) ? floor($db_row['fleet_resource_metal']) : 0,
968
      RES_CRYSTAL   => !empty($db_row['fleet_resource_crystal']) ? floor($db_row['fleet_resource_crystal']) : 0,
969
      RES_DEUTERIUM => !empty($db_row['fleet_resource_deuterium']) ? floor($db_row['fleet_resource_deuterium']) : 0,
970
    );
971
  }
972
973
  protected function resourcesInject(array &$db_row) {
974
    $db_row['fleet_resource_metal'] = $this->resource_list[RES_METAL];
975
    $db_row['fleet_resource_crystal'] = $this->resource_list[RES_CRYSTAL];
976
    $db_row['fleet_resource_deuterium'] = $this->resource_list[RES_DEUTERIUM];
977
  }
978
979
  /**
980
   * Set current resource list from array of units
981
   *
982
   * @param array $resource_list
983
   */
984
  public function resourcesSet($resource_list) {
985
    if (!empty($this->propertiesAdjusted['resource_list'])) {
986
      throw new ExceptionPropertyAccess('Property "resource_list" already was adjusted so no SET is possible until dbSave in ' . get_called_class() . '::unitSetResourceList', ERR_ERROR);
987
    }
988
    $this->resourcesAdjust($resource_list, true);
989
  }
990
991
  /**
992
   * Updates fleet resource list with deltas
993
   *
994
   * @param array $resource_delta_list
995
   * @param bool  $replace_value
996
   *
997
   * @throws Exception
998
   */
999
  public function resourcesAdjust($resource_delta_list, $replace_value = false) {
1000
    !is_array($resource_delta_list) ? $resource_delta_list = array() : false;
1001
1002
    foreach ($resource_delta_list as $resource_id => $unit_delta) {
1003
      if (!UnitResourceLoot::is_in_group($resource_id) || !($unit_delta = floor($unit_delta))) {
1004
        // Not a resource or no resources - continuing
1005
        continue;
1006
      }
1007
1008
      if ($replace_value) {
1009
        $this->resource_list[$resource_id] = $unit_delta;
1010
      } else {
1011
        $this->resource_list[$resource_id] += $unit_delta;
1012
        // Preparing changes
1013
        $this->resource_delta[$resource_id] += $unit_delta;
1014
        $this->propertiesAdjusted['resource_list'] = 1;
1015
      }
1016
1017
      // Check for negative unit value
1018
      if ($this->resource_list[$resource_id] < 0) {
1019
        // TODO
1020
        throw new Exception('Resource ' . $resource_id . ' will become negative in ' . get_called_class() . '::unitAdjustResourceList', ERR_ERROR);
1021
      }
1022
    }
1023
  }
1024
1025
  public function resourcesGetTotal() {
1026
    return empty($this->resource_list) || !is_array($this->resource_list) ? 0 : array_sum($this->resource_list);
1027
  }
1028
1029
  /**
1030
   * @param array $rate
1031
   *
1032
   * @return float
1033
   */
1034
  public function resourcesGetTotalInMetal(array $rate) {
1035
    return
1036
      $this->resource_list[RES_METAL] * $rate[RES_METAL]
1037
      + $this->resource_list[RES_CRYSTAL] * $rate[RES_CRYSTAL] / $rate[RES_METAL]
1038
      + $this->resource_list[RES_DEUTERIUM] * $rate[RES_DEUTERIUM] / $rate[RES_METAL];
1039
  }
1040
1041
  /**
1042
   * Returns resource list in fleet
1043
   */
1044
  // TODO
1045
  public function resourcesGetList() {
1046
    return $this->resource_list;
1047
  }
1048
1049
  public function resourcesReset() {
1050
    $this->resourcesSet(array(
1051
      RES_METAL     => 0,
1052
      RES_CRYSTAL   => 0,
1053
      RES_DEUTERIUM => 0,
1054
    ));
1055
  }
1056
1057
  /**
1058
   * Restores fleet or resources to planet
1059
   *
1060
   * @param bool $start
1061
   * @param bool $only_resources
0 ignored issues
show
Bug introduced by
There is no parameter named $only_resources. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1062
   * @param int  $result
0 ignored issues
show
Bug introduced by
There is no parameter named $result. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1063
   */
1064
  public function resourcesUnload($start = true) {
1065
    sn_db_transaction_check(true);
1066
1067
    // Если флот уже обработан - не существует или возращается - тогда ничего не делаем
1068
    if (!$this->resourcesGetTotal()) {
1069
      return;
1070
    }
1071
1072
    $coordinates = $start ? $this->launch_coordinates_typed() : $this->target_coordinates_typed();
1073
1074
    // Поскольку эта функция может быть вызвана не из обработчика флотов - нам надо всё заблокировать вроде бы НЕ МОЖЕТ!!!
1075
    // TODO Проверить от многократного срабатывания !!!
1076
    // Тут не блокируем пока - сначала надо заблокировать пользователя, что бы не было дедлока
1077
    // TODO поменять на владельца планеты - когда его будут возвращать всегда !!!
1078
1079
1080
    // Узнаем ИД владельца планеты.
1081
    // С блокировкой, поскольку эта функция может быть вызвана только из менеджера летящих флотов.
1082
    // А там уже всё заблокировано как надо и повторная блокировка не вызовет дедлок.
1083
    $planet_arrival = DBStaticPlanet::db_planet_by_vector($coordinates, '', true);
1084
1085
    // TODO - Проверка, что планета всё еще существует на указанных координатах, а не телепортировалась, не удалена хозяином, не уничтожена врагом
1086
1087
    // Restoring resources to planet
1088
    if ($this->resourcesGetTotal()) {
1089
      $fleet_resources = $this->resourcesGetList();
1090
      DBStaticPlanet::db_planet_update_adjust_by_id(
1091
        $planet_arrival['id'],
1092
        array(
1093
          'metal'     => +$fleet_resources[RES_METAL],
1094
          'crystal'   => +$fleet_resources[RES_CRYSTAL],
1095
          'deuterium' => +$fleet_resources[RES_DEUTERIUM],
1096
        )
1097
      );
1098
    }
1099
1100
    $this->resourcesReset();
1101
  }
1102
1103
1104
  protected function isResource($unit_id) {
1105
    return UnitResourceLoot::is_in_group($unit_id);
1106
  }
1107
1108
  /**
1109
   * @param int $speed_percent
1110
   *
1111
   * @return array
1112
   */
1113
  protected function flt_travel_data($speed_percent = 10) {
1114
    $distance = $this->targetVector->distanceFromCoordinates($this->dbSourcePlanetRow);
1115
1116
    return $this->unitList->travelData($speed_percent, $distance, $this->dbOwnerRow);
1117
  }
1118
1119
1120
  /**
1121
   * @param array  $dbPlayerRow
1122
   * @param array  $dbPlanetRow
1123
   * @param Vector $targetVector
1124
   *
1125
   */
1126
  public function initDefaults($dbPlayerRow, $dbPlanetRow, $targetVector, $mission, $ships, $fleet_group_mr, $oldSpeedInTens = 10, $targetedUnitId = 0, $captainId = 0, $resources = array()) {
0 ignored issues
show
Unused Code introduced by
The parameter $resources is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1127
    $objFleet5Player = new Player();
1128
    $objFleet5Player->dbRowParse($dbPlayerRow);
1129
    $this->setLocatedAt($objFleet5Player);
1130
1131
    $this->mission_type = $mission;
1132
1133
    $this->dbOwnerRow = $dbPlayerRow;
1134
1135
    $this->set_start_planet($dbPlanetRow);
1136
    $this->dbSourcePlanetRow = $dbPlanetRow;
1137
1138
    $this->setTargetFromVectorObject($targetVector);
1139
    $this->targetVector = $targetVector;
1140
1141
//    if ($this->mission_type != MT_NONE) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1142
//      $this->restrictTargetTypeByMission();
1143
//
1144
//      // TODO - Нельзя тут просто менять тип планеты или координат!
1145
//      // If current planet type is not allowed on mission - switch planet type
1146
//      if (empty($this->allowed_planet_types[$this->targetVector->type])) {
1147
//        $targetPlanetCoords->type = reset($this->allowed_planet_types);
1148
//      }
1149
//    }
1150
1151
    $this->populateTargetPlanetAndOwner();
1152
1153
    $this->unitsSetFromArray($ships);
1154
1155
    $this->_group_id = intval($fleet_group_mr);
1156
1157
    $this->oldSpeedInTens = $oldSpeedInTens;
1158
1159
    $this->targetedUnitId = $targetedUnitId;
1160
1161
    $this->captainId = $captainId;
1162
1163
    $this->_time_launch = SN_TIME_NOW;
1164
1165
    $this->fleetRenderer->renderParamCoordinates($this);
1166
1167
  }
1168
1169
  protected function restrictTargetTypeByMission() {
1170
    if ($this->_mission_type == MT_MISSILE) {
1171
      $this->allowed_planet_types = array(PT_PLANET => PT_PLANET);
1172
    } elseif ($this->_mission_type == MT_COLONIZE || $this->_mission_type == MT_EXPLORE) {
1173
      // TODO - PT_NONE
1174
      $this->allowed_planet_types = array(PT_PLANET => PT_PLANET);
1175
    } elseif ($this->_mission_type == MT_RECYCLE) {
1176
      $this->allowed_planet_types = array(PT_DEBRIS => PT_DEBRIS);
1177
    } elseif ($this->_mission_type == MT_DESTROY) {
1178
      $this->allowed_planet_types = array(PT_MOON => PT_MOON);
1179
    } else {
1180
      $this->allowed_planet_types = array(PT_PLANET => PT_PLANET, PT_MOON => PT_MOON);
1181
    }
1182
  }
1183
1184
  protected function populateTargetPlanetAndOwner() {
1185
    // If vector points to no exact object OR debris - then getting planet on coordinates
1186
    $targetVector = clone $this->targetVector;
1187
    if ($targetVector->type == PT_DEBRIS || $targetVector == PT_NONE) {
1188
      $targetVector->type = PT_PLANET;
1189
    }
1190
1191
    $this->dbTargetRow = DBStaticPlanet::db_planet_by_vector_object($targetVector);
1192 View Code Duplication
    if (!empty($this->dbTargetRow['id_owner'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1193
      $this->dbTargetOwnerRow = DBStaticUser::db_user_by_id($this->dbTargetRow['id_owner'], true);
0 ignored issues
show
Documentation Bug introduced by
It seems like \DBStatic\DBStaticUser::...tRow['id_owner'], true) can also be of type false. However, the property $dbTargetOwnerRow is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1194
    }
1195
  }
1196
1197
  /**
1198
   *
1199
   */
1200
  public function fleetPage0(array $template_result) {
1201
    lng_include('overview');
1202
1203
    if (empty($this->dbSourcePlanetRow)) {
1204
      message(classLocale::$lang['fl_noplanetrow'], classLocale::$lang['fl_error']);
1205
    }
1206
1207
    // TODO - redo to unitlist render/unit render
1208
    $template_result['.']['ships'] = $this->planetRenderer->renderAvailableShips($this->dbOwnerRow, $this->dbSourcePlanetRow);
1209
1210
    $this->fleetRenderer->renderShipSortOptions($template_result);
1211
1212
    /**
1213
     * @var Player $playerOwner
1214
     */
1215
    $playerOwner = $this->getLocatedAt();
1216
1217
    $template_result += array(
1218
      'FLYING_FLEETS'      => $playerOwner->fleetsFlying(),
1219
      'MAX_FLEETS'         => $playerOwner->fleetsMax(),
1220
      'FREE_FLEETS'        => $playerOwner->fleetsMax() - $playerOwner->fleetsFlying(),
1221
      'FLYING_EXPEDITIONS' => $playerOwner->expeditionsFlying(),
1222
      'MAX_EXPEDITIONS'    => $playerOwner->expeditionsMax(),
1223
      'FREE_EXPEDITIONS'   => $playerOwner->expeditionsMax() - $playerOwner->expeditionsFlying(),
1224
      'COLONIES_CURRENT'   => $playerOwner->coloniesCurrent(),
1225
      'COLONIES_MAX'       => $playerOwner->coloniesMax(),
1226
1227
      'TYPE_NAME' => classLocale::$lang['fl_planettype'][$this->targetVector->type],
1228
1229
      'speed_factor' => flt_server_flight_speed_multiplier(),
1230
1231
      'PLANET_RESOURCES' => pretty_number($this->dbSourcePlanetRow['metal'] + $this->dbSourcePlanetRow['crystal'] + $this->dbSourcePlanetRow['deuterium']),
1232
      'PLANET_DEUTERIUM' => pretty_number($this->dbSourcePlanetRow['deuterium']),
1233
1234
      'PLAYER_OPTION_FLEET_SHIP_SELECT_OLD'       => classSupernova::$user_options[PLAYER_OPTION_FLEET_SHIP_SELECT_OLD],
1235
      'PLAYER_OPTION_FLEET_SHIP_HIDE_SPEED'       => classSupernova::$user_options[PLAYER_OPTION_FLEET_SHIP_HIDE_SPEED],
1236
      'PLAYER_OPTION_FLEET_SHIP_HIDE_CAPACITY'    => classSupernova::$user_options[PLAYER_OPTION_FLEET_SHIP_HIDE_CAPACITY],
1237
      'PLAYER_OPTION_FLEET_SHIP_HIDE_CONSUMPTION' => classSupernova::$user_options[PLAYER_OPTION_FLEET_SHIP_HIDE_CONSUMPTION],
1238
    );
1239
1240
    $template = gettemplate('fleet0', true);
1241
    $template->assign_recursive($template_result);
1242
    display($template, classLocale::$lang['fl_title']);
1243
  }
1244
1245
  /**
1246
   *
1247
   */
1248
  public function fleetPage1() {
1249
    global $template_result;
1250
1251
    $template_result['.']['fleets'][] = $this->fleetRenderer->renderFleet($this, SN_TIME_NOW);
1252
    $template_result['.']['possible_planet_type_id'] = $this->fleetRenderer->renderAllowedPlanetTypes($this->allowed_planet_types);
1253
    $template_result['.']['colonies'] = $this->planetRenderer->renderOwnPlanets($this->dbOwnerRow, $this->dbSourcePlanetRow);
1254
    $template_result['.']['shortcut'] = $this->planetRenderer->renderPlanetShortcuts($this->dbOwnerRow);
1255
    $template_result['.']['acss'] = $this->planetRenderer->renderACSList($this->dbOwnerRow);
1256
1257
    $template_result += array(
1258
      'speed_factor' => flt_server_flight_speed_multiplier(),
1259
1260
      'fleet_speed'    => $this->fleetSpeed(),
1261
      'fleet_capacity' => $this->shipsGetCapacity(),
1262
1263
      'PLANET_DEUTERIUM' => pretty_number($this->dbSourcePlanetRow['deuterium']),
1264
1265
      'PAGE_HINT' => classLocale::$lang['fl_page1_hint'],
1266
    );
1267
1268
    $template = gettemplate('fleet1', true);
1269
    $template->assign_recursive($template_result);
1270
    display($template, classLocale::$lang['fl_title']);
1271
  }
1272
1273
  public function fleetSpeed() {
1274
    $maxSpeed = array();
1275
    foreach ($this->shipsIterator() as $ship_id => $unit) {
1276 View Code Duplication
      if ($unit->count > 0 && !empty(classSupernova::$gc->groupFleetAndMissiles[$ship_id])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1277
        $single_ship_data = get_ship_data($ship_id, $this->dbOwnerRow);
1278
        $maxSpeed[$ship_id] = $single_ship_data['speed'];
1279
      }
1280
    }
1281
1282
    return empty($maxSpeed) ? 0 : min($maxSpeed);
1283
  }
1284
1285
  /**
1286
   * @param array $planetResourcesWithoutConsumption
1287
   */
1288
  public function fleetPage2Prepare($planetResourcesWithoutConsumption) {
0 ignored issues
show
Unused Code introduced by
The parameter $planetResourcesWithoutConsumption is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1289
    $this->travelData = $this->flt_travel_data($this->oldSpeedInTens);
1290
1291
//    /**
1292
//     * @var array $allowed_missions
1293
//     */
1294
//    public $allowed_missions = array();
1295
//    /**
1296
//     * @var array $exists_missions
1297
//     */
1298
//    public $exists_missions = array();
1299
//    public $allowed_planet_types = array(
1300
//      // PT_NONE => PT_NONE,
1301
//      PT_PLANET => PT_PLANET,
1302
//      PT_MOON   => PT_MOON,
1303
//      PT_DEBRIS => PT_DEBRIS
1304
//    );
1305
1306
//    $this->exists_missions = array(
1307
////      MT_EXPLORE => MT_EXPLORE,
1308
////      MT_MISSILE => MT_MISSILE,
1309
//      MT_COLONIZE => MT_COLONIZE,
1310
//    );  // TODO
1311
    $this->allowed_missions = array();
1312
1313
    if ($this->mission_type != MT_NONE && empty($this->exists_missions[$this->mission_type])) {
1314
      throw new ExceptionFleetInvalid(FLIGHT_MISSION_UNKNOWN, FLIGHT_MISSION_UNKNOWN);
1315
    }
1316
1317
    $this->validator->validateGlobals();
1318
1319
    $validateResult = array();
1320
    foreach ($this->exists_missions as $missionType => $missionData) {
1321
//print('qwe');
1322
      $mission = \Mission\MissionFactory::build($missionType, $this);
1323
//print('wer');
1324
      $validateResult[$missionType] = $mission->validate();
1325
      if (FLIGHT_ALLOWED == $validateResult[$missionType]) {
1326
        $this->allowed_missions[$missionType] = $mission;
1327
      } else {
1328
        if($missionType == $this->mission_type) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1329
        }
1330
        unset($this->allowed_missions[$missionType]);
1331
      }
1332
    }
1333
1334
    if(empty($this->allowed_missions)) {
1335
      if($this->mission_type != MT_NONE && isset($validateResult[$this->mission_type])) {
1336
        throw new ExceptionFleetInvalid($validateResult[$this->mission_type], $validateResult[$this->mission_type]);
1337
      } else {
1338
        throw new ExceptionFleetInvalid(FLIGHT_MISSION_IMPOSSIBLE, FLIGHT_MISSION_IMPOSSIBLE);
1339
      }
1340
    }
1341
1342
//    $this->validator->validate();
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1343
  }
1344
1345
  /**
1346
   * @param array $planetResourcesWithoutConsumption
1347
   */
1348
  public function fleetPage3Prepare($planetResourcesWithoutConsumption) {
0 ignored issues
show
Unused Code introduced by
The parameter $planetResourcesWithoutConsumption is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1349
    $this->travelData = $this->flt_travel_data($this->oldSpeedInTens);
1350
1351
    if (empty($this->exists_missions[$this->mission_type])) {
1352
      throw new ExceptionFleetInvalid(FLIGHT_MISSION_UNKNOWN, FLIGHT_MISSION_UNKNOWN);
1353
    }
1354
1355
    $this->validator->validateGlobals();
1356
1357
    $mission = \Mission\MissionFactory::build($this->mission_type, $this);
1358
    $result = $mission->validate();
1359
    if (FLIGHT_ALLOWED != $result) {
1360
      throw new ExceptionFleetInvalid($result, $result);
1361
    }
1362
1363
  }
1364
1365
  /**
1366
   *
1367
   */
1368
  public function fleetPage2() {
1369
    global $template_result;
1370
1371
    $planetResourcesTotal = DBStaticPlanet::getResources($this->dbOwnerRow, $this->dbSourcePlanetRow);
1372
    $planetResourcesWithoutConsumption = $this->resourcesSubstractConsumption($planetResourcesTotal);
1373
1374
    try {
1375
      $this->fleetPage2Prepare($planetResourcesWithoutConsumption);
1376
    } catch (Exception $e) {
1377
      // TODO - MESSAGE BOX
1378 View Code Duplication
      if ($e instanceof ExceptionFleetInvalid) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1379
        sn_db_transaction_rollback();
1380
        pdie(classLocale::$lang['fl_attack_error'][$e->getCode()]);
1381
      } else {
1382
        throw $e;
1383
      }
1384
    }
1385
1386
    // Flight allowed here
1387
    pdump('FLIGHT_ALLOWED', FLIGHT_ALLOWED);
1388
//    pdump('// TODO - Сделать flletvalidator DI - внутре контейнер для методов, а методы - анонимные функции, вызывающие другие методы же', FLIGHT_ALLOWED);
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1389
1390
    ksort($this->allowed_missions);
1391
    // If mission is not set - setting first mission from allowed
1392
    if (empty($this->_mission_type) && is_array($this->allowed_missions)) {
1393
      reset($this->allowed_missions);
1394
      $this->_mission_type = key($this->allowed_missions);
1395
    }
1396
    $template_result['.']['missions'] = $this->fleetRenderer->renderAllowedMissions($this->allowed_missions);
1397
1398
    $template_result['.']['fleets'][] = $this->fleetRenderer->renderFleet($this, SN_TIME_NOW);
1399
1400
    $max_duration =
1401
      $this->_mission_type == MT_EXPLORE
1402
        ? get_player_max_expedition_duration($this->dbOwnerRow)
1403
        : (isset($this->allowed_missions[MT_HOLD]) ? 12 : 0);
1404
    $template_result['.']['duration'] = $this->fleetRenderer->renderDuration($this->_mission_type, $max_duration);
1405
1406
    $this->captain = $this->captainGet();
1407
    $template_result += $this->renderCaptain($this->captain);
1408
1409
    $template_result['.']['resources'] = $this->fleetRenderer->renderPlanetResources($planetResourcesWithoutConsumption);
1410
1411
    $template_result += array(
1412
      'planet_metal'     => $planetResourcesWithoutConsumption[RES_METAL],
1413
      'planet_crystal'   => $planetResourcesWithoutConsumption[RES_CRYSTAL],
1414
      'planet_deuterium' => $planetResourcesWithoutConsumption[RES_DEUTERIUM],
1415
1416
      'fleet_capacity' => $this->shipsGetCapacity() - $this->travelData['consumption'],
1417
      'speed'          => $this->oldSpeedInTens,
1418
      'fleet_group'    => $this->_group_id,
1419
1420
      'MAX_DURATION'          => $max_duration,
1421
1422
      // TODO - remove
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1423
//      'IS_TRANSPORT_MISSIONS' => !empty($this->allowed_missions[$this->_mission_type]['transport']),
1424
      'IS_TRANSPORT_MISSIONS' => true,
1425
1426
      'PLAYER_COLONIES_CURRENT' => get_player_current_colonies($this->dbOwnerRow),
1427
      'PLAYER_COLONIES_MAX'     => get_player_max_colonies($this->dbOwnerRow),
1428
    );
1429
1430
    $template = gettemplate('fleet2', true);
1431
    $template->assign_recursive($template_result);
1432
    display($template, classLocale::$lang['fl_title']);
1433
  }
1434
1435
  /**
1436
   *
1437
   */
1438
  public function fleetPage3() {
1439
    global $template_result;
1440
1441
    $this->isRealFlight = true;
1442
1443
    sn_db_transaction_start();
1444
1445
    DBStaticUser::db_user_lock_with_target_owner_and_acs($this->dbOwnerRow, $this->dbTargetRow);
1446
1447
    // Checking for group
1448
    $this->groupCheck();
1449
1450
    $this->dbOwnerRow = DBStaticUser::db_user_by_id($this->dbOwnerRow['id'], true);
0 ignored issues
show
Documentation Bug introduced by
It seems like \DBStatic\DBStaticUser::...dbOwnerRow['id'], true) can also be of type false. However, the property $dbOwnerRow is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1451
    $this->dbSourcePlanetRow = DBStaticPlanet::db_planet_by_id($this->dbSourcePlanetRow['id'], true);
0 ignored issues
show
Documentation Bug introduced by
It seems like \DBStatic\DBStaticPlanet...ePlanetRow['id'], true) can be null. However, the property $dbSourcePlanetRow is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
1452
    if (!empty($this->dbTargetRow['id'])) {
1453
      $this->dbTargetRow = DBStaticPlanet::db_planet_by_id($this->dbTargetRow['id'], true);
0 ignored issues
show
Documentation Bug introduced by
It seems like \DBStatic\DBStaticPlanet...bTargetRow['id'], true) can be null. However, the property $dbTargetRow is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
1454
    }
1455
    // TODO - deprecated! Filled in populateTargetPlanetAndOwner
1456 View Code Duplication
    if (!empty($this->dbTargetRow['id_owner'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1457
      $this->dbTargetOwnerRow = DBStaticUser::db_user_by_id($this->dbTargetRow['id_owner'], true);
0 ignored issues
show
Documentation Bug introduced by
It seems like \DBStatic\DBStaticUser::...tRow['id_owner'], true) can also be of type false. However, the property $dbTargetOwnerRow is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1458
    }
1459
1460
    $this->resource_list = array(
1461
      RES_METAL     => max(0, floor(sys_get_param_float('resource0'))),
1462
      RES_CRYSTAL   => max(0, floor(sys_get_param_float('resource1'))),
1463
      RES_DEUTERIUM => max(0, floor(sys_get_param_float('resource2'))),
1464
    );
1465
1466
    $this->captain = $this->captainGet();
1467
1468
    $this->travelData = $this->flt_travel_data($this->oldSpeedInTens);
1469
1470
    $planetResourcesTotal = DBStaticPlanet::getResources($this->dbOwnerRow, $this->dbSourcePlanetRow);
0 ignored issues
show
Security Bug introduced by
It seems like $this->dbOwnerRow can also be of type false; however, DBStatic\DBStaticPlanet::getResources() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
Bug introduced by
It seems like $this->dbSourcePlanetRow can also be of type null; however, DBStatic\DBStaticPlanet::getResources() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1471
    $planetResourcesWithoutConsumption = $this->resourcesSubstractConsumption($planetResourcesTotal);
1472
1473
    try {
1474
      $this->fleetPage3Prepare($planetResourcesWithoutConsumption);
1475
    } catch (Exception $e) {
1476
      // TODO - MESSAGE BOX
1477 View Code Duplication
      if ($e instanceof ExceptionFleetInvalid) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1478
        sn_db_transaction_rollback();
1479
        pdie(classLocale::$lang['fl_attack_error'][$e->getCode()]);
1480
      } else {
1481
        throw $e;
1482
      }
1483
    }
1484
1485
//    try {
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1486
//      $validator = new FleetValidator($this);
1487
//      $validator->validate();
1488
//    } catch (Exception $e) {
1489
//      // TODO - MESSAGE BOX
1490
//      if($e instanceof Exception\ExceptionFleetInvalid) {
1491
//        sn_db_transaction_rollback();
1492
//        pdie(classLocale::$lang['fl_attack_error'][$e->getCode()]);
1493
//      } else {
1494
//        throw $e;
1495
//      }
1496
//    }
1497
1498
    // TODO - check if mission is not 0 and in ALLOWED_MISSIONS
1499
1500
    // Flight allowed here
1501
    pdump('FLIGHT_ALLOWED', FLIGHT_ALLOWED);
1502
//    pdump('// TODO - Сделать flletvalidator DI - внутре контейнер для методов, а методы - анонимные функции, вызывающие другие методы же', FLIGHT_ALLOWED);
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1503
1504
1505
    $timeMissionJob = 0;
1506
    // TODO check for empty mission AKA mission allowed
1507
    /*
1508
        if ($this->_mission_type == MT_ACS && $aks) {
1509
          $acsTimeToArrive = $aks['ankunft'] - SN_TIME_NOW;
1510
          if ($acsTimeToArrive < $this->travelData['duration']) {
1511
            message(classLocale::$lang['fl_aks_too_slow'] . 'Fleet arrival: ' . date(FMT_DATE_TIME, SN_TIME_NOW + $this->travelData['duration']) . " AKS arrival: " . date(FMT_DATE_TIME, $aks['ankunft']), classLocale::$lang['fl_error']);
1512
          }
1513
          // Set time to travel to ACS' TTT
1514
          $this->travelData['duration'] = $acsTimeToArrive;
1515
    */
1516
    if ($this->_mission_type != MT_ACS) {
1517
      if ($this->_mission_type == MT_EXPLORE || $this->_mission_type == MT_HOLD) {
1518
        $max_duration = $this->_mission_type == MT_EXPLORE ? get_player_max_expedition_duration($this->dbOwnerRow) : ($this->_mission_type == MT_HOLD ? 12 : 0);
1519
        if ($max_duration) {
1520
          $mission_time_in_hours = sys_get_param_id('missiontime');
1521
          if ($mission_time_in_hours > $max_duration || $mission_time_in_hours < 1) {
1522
            classSupernova::$debug->warning('Supplying wrong mission time', 'Hack attempt', 302, array('base_dump' => true));
1523
            die();
1524
          }
1525
          $timeMissionJob = ceil($mission_time_in_hours * 3600 / ($this->_mission_type == MT_EXPLORE && classSupernova::$config->game_speed_expedition ? classSupernova::$config->game_speed_expedition : 1));
1526
        }
1527
      }
1528
    }
1529
1530
    //
1531
    //
1532
    //
1533
    //
1534
    //
1535
    //
1536
    //
1537
    //
1538
    // ---------------- END OF CHECKS ------------------------------------------------------
1539
1540
    $this->set_times($this->travelData['duration'], $timeMissionJob);
1541
    $this->dbInsert();
1542
    $this->unitList->dbSubstractUnitsFromPlanet($this->dbOwnerRow, $this->dbSourcePlanetRow['id']);
1543
1544
    DBStaticPlanet::db_planet_update_adjust_by_id(
1545
      $this->dbSourcePlanetRow['id'],
1546
      array(
1547
        'metal'     => -$this->resource_list[RES_METAL],
1548
        'crystal'   => -$this->resource_list[RES_CRYSTAL],
1549
        'deuterium' => -$this->resource_list[RES_DEUTERIUM] - $this->travelData['consumption'],
1550
      )
1551
    );
1552
1553
    if (!empty($this->captain['unit_id'])) {
1554
      DBStaticUnit::db_unit_set_by_id(
1555
        $this->captain['unit_id'],
1556
        array(
1557
          'unit_location_type' => LOC_FLEET,
1558
          'unit_location_id'   => $this->_dbId,
1559
        ),
1560
        array()
1561
      );
1562
    }
1563
1564
//    return $this->fleet->acs['ankunft'] - $this->fleet->time_launch >= $this->fleet->travelData['duration'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1565
//
1566
//    // Set time to travel to ACS' TTT
1567
//    $this->fleet->travelData['duration'] = $acsTimeToArrive;
1568
1569
1570
    $template_result['.']['fleets'][] = $this->fleetRenderer->renderFleet($this, SN_TIME_NOW, $timeMissionJob);
1571
1572
    $template_result += array(
1573
      'mission'         => classLocale::$lang['type_mission'][$this->_mission_type] . ($this->_mission_type == MT_EXPLORE || $this->_mission_type == MT_HOLD ? ' ' . pretty_time($timeMissionJob) : ''),
1574
      'dist'            => pretty_number($this->travelData['distance']),
1575
      'speed'           => pretty_number($this->travelData['fleet_speed']),
1576
      'deute_need'      => pretty_number($this->travelData['consumption']),
1577
      'from'            => "{$this->dbSourcePlanetRow['galaxy']}:{$this->dbSourcePlanetRow['system']}:{$this->dbSourcePlanetRow['planet']}",
1578
      'time_go'         => date(FMT_DATE_TIME, $this->_time_arrive_to_target),
1579
      'time_go_local'   => date(FMT_DATE_TIME, $this->_time_arrive_to_target + SN_CLIENT_TIME_DIFF),
1580
      'time_back'       => date(FMT_DATE_TIME, $this->_time_return_to_source),
1581
      'time_back_local' => date(FMT_DATE_TIME, $this->_time_return_to_source + SN_CLIENT_TIME_DIFF),
1582
    );
1583
1584
    $this->dbSourcePlanetRow = DBStaticPlanet::db_planet_by_id($this->dbSourcePlanetRow['id']);
0 ignored issues
show
Documentation Bug introduced by
It seems like \DBStatic\DBStaticPlanet...bSourcePlanetRow['id']) can be null. However, the property $dbSourcePlanetRow is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
1585
1586
    pdie('Stop for debug');
1587
1588
    sn_db_transaction_commit();
1589
1590
    $template = gettemplate('fleet3', true);
1591
    $template->assign_recursive($template_result);
1592
    display($template, classLocale::$lang['fl_title']);
1593
  }
1594
1595
  protected function groupCheck() {
1596
    if (empty($this->_group_id)) {
1597
      return;
1598
    }
1599
1600
    // ACS attack must exist (if acs fleet has arrived this will also return false (2 checks in 1!!!)
1601
    $this->acs = DBStaticFleetACS::db_acs_get_by_group_id($this->_group_id);
1602
    if (empty($this->acs)) {
1603
      $this->_group_id = 0;
1604
    } else {
1605
      $this->targetVector->convertToVector($this->acs);
1606
    }
1607
  }
1608
1609
  /**
1610
   * @param array $planetResources
1611
   *
1612
   * @return array
1613
   */
1614
  protected function resourcesSubstractConsumption($planetResources) {
1615
    !isset($planetResources[RES_DEUTERIUM]) ? $planetResources[RES_DEUTERIUM] = 0 : false;
1616
1617
    if ($this->travelData['consumption'] >= 0) {
1618
      $planetResources[RES_DEUTERIUM] -= ceil($this->travelData['consumption']);
1619
    }
1620
1621
    return $planetResources;
1622
  }
1623
1624
  /**
1625
   */
1626
  public function captainGet() {
1627
    $result = array();
1628
1629
    /**
1630
     * @var unit_captain $moduleCaptain
1631
     */
1632
    if (sn_module::isModuleActive('unit_captain')) {
1633
      $moduleCaptain = sn_module::getModule('unit_captain');
1634
      $result = $moduleCaptain->unit_captain_get($this->dbSourcePlanetRow['id']);
0 ignored issues
show
Bug introduced by
The method unit_captain_get() does not seem to exist on object<sn_module>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1635
    }
1636
1637
    return $result;
1638
  }
1639
1640
  /**
1641
   * @return array
1642
   */
1643
  protected function renderCaptain($captainUnit) {
1644
    $result = array();
1645
1646
    if (!empty($captainUnit['unit_id']) && $captainUnit['unit_location_type'] == LOC_PLANET) {
1647
      $result = array(
1648
        'CAPTAIN_ID'     => $captainUnit['unit_id'],
1649
        'CAPTAIN_LEVEL'  => $captainUnit['captain_level'],
1650
        'CAPTAIN_SHIELD' => $captainUnit['captain_shield'],
1651
        'CAPTAIN_ARMOR'  => $captainUnit['captain_armor'],
1652
        'CAPTAIN_ATTACK' => $captainUnit['captain_attack'],
1653
      );
1654
    }
1655
1656
    return $result;
1657
  }
1658
1659
}
1660