Completed
Push — work-fleets ( 77ad6e...489db6 )
by SuperNova.WS
06:17
created

UnitList::unitsIsAllMovable()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 10
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
nc 3
nop 1
dl 10
loc 10
rs 9.4285
c 3
b 0
f 0
ccs 0
cts 9
cp 0
crap 12
1
<?php
2
3
/**
4
 * Class UnitList
5
 * Indexed by DB_ID - as it should be!
6
 *
7
 *
8
 *
9
 * Hints for IDE - inherited from ArrayAccessV2
10
 *
11
 * @method Unit offsetGet($offset)
12
 * @property Unit[] $_container
13
 *
14
 */
15
class UnitList extends ContainerArrayOfObject implements IDbRow, ILocation {
16
17
18
  // Properties ********************************************************************************************************
19
20
  // ILocation implementation ==========================================================================================
21
22
  /**
23
   * Type of this location
24
   *
25
   * @var int $locationType
26
   */
27
  protected static $locationType = LOC_UNIT_LIST;
28
  /**
29
   * @var ILocation $locatedAt
30
   */
31
  protected $locatedAt = null;
32
33
34
  // New properties ====================================================================================================
35
36
  /**
37
   * @var Unit[] $mapUnitIdToDb
38
   */
39
  // Нужно для корректного сохранения новых юнитов. Их db_id = 0, поэтому при добавлении в контейнер они будут перезаписывать друг друга
40
  // Соответственно - при сохраненнии флота надо проходить dbSave именно по $mapUnitIdToDb
41
  protected $mapUnitIdToDb = array();
42
43
44
  // Methods ***********************************************************************************************************
45
46
  // ILocation implementation ==========================================================================================
47
48
  public function getPlayerOwnerId() {
49
    return is_object($this->locatedAt) ? $this->locatedAt->getPlayerOwnerId() : null;
50
  }
51
52
  public function getLocationType() {
53
    return is_object($this->locatedAt) ? $this->locatedAt->getLocationType() : LOC_NONE;
54
  }
55
56
  public function getLocationDbId() {
57
    return is_object($this->locatedAt) ? $this->locatedAt->getLocationDbId() : null;
58
  }
59
60
  // TODO - достаточно установить один раз Unit::LocatedAt на UnitList, что бы затем все юниты автоматически брали наиболее актуальный locatedAt
61
  public function setLocatedAt($location) {
62
    $this->locatedAt = $location;
63
    // TODO - по факту не нужно - достточно один раз поставить на $this
64
//    foreach($this->_container as $unit) {
65
//      $unit->setLocatedAt($this->locatedAt);
66
//    }
67
  }
68
69
  public function getLocatedAt() {
70
    return $this->locatedAt;
71
  }
72
73
  public function getLocatedAtType() {
74
    return is_object($this->locatedAt) ? $this->locatedAt->getLocationType() : LOC_NONE;
75
  }
76
77
  public function getLocatedAtDbId() {
78
    return is_object($this->locatedAt) ? $this->locatedAt->getLocationDbId() : 0;
79
  }
80
81
82
  // ArrayAccessV2 inheritance =========================================================================================
83
84
  /**
85
   * Adds link to unit object also to mapUnitIdToDb
86
   *
87
   * @param mixed $offset
88
   * @param Unit  $value
89
   */
90
  public function offsetSet($offset, $value) {
91
    if (isset($this->mapUnitIdToDb[$value->unitId])) {
92
      classSupernova::$debug->error('UnitList::offsetSet: Unit with UnitId ' . $value->unitId . ' already exists');
93
    }
94
    $this->mapUnitIdToDb[$value->unitId] = $value;
95
    parent::offsetSet($offset, $value);
96
  }
97
98
  public function offsetUnset($offset) {
99
    if (!empty($this[$offset]->unitId)) {
100
//      $unit_id = $this[$offset]->unitId;
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% 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...
101
//      $this->mapUnitIdToDb[$unit_id] = null;
102
//      unset($this->mapUnitIdToDb[$unit_id]);
103
      unset($this->mapUnitIdToDb[$this[$offset]->unitId]);
104
    }
105
    parent::offsetUnset($offset);
106
  }
107
108
109
  // IDbRow implementation =============================================================================================
110
111
  /**
112
   * Loading object from DB by primary ID
113
   * Real location should be set before calling this method
114
   *
115
   * @param int $dbId - dbId is generally unused here. However it works as flag: 0 - just reset; (negative) - just reset; (positive) - proceed with loading
116
   */
117
  public function dbLoad($dbId, $lockSkip = false) {
118
//    $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...
119
120
    if ($dbId <= 0) {
121
      return;
122
    }
123
124
    if (!is_object($this->locatedAt)) {
125
      classSupernova::$debug->error('UnitList::dbLoad have no locatedAt field set');
126
    }
127
128
    $unit_array = DBStaticUnit::db_get_unit_list_by_location(0, $this->getLocationType(), $this->getLocationDbId());
129
    if (!is_array($unit_array)) {
130
      return;
131
    }
132
133
    foreach ($unit_array as $unit_db_row) {
134
      $unit = $this->_createElement();
135
      $unit->dbRowParse($unit_db_row);
136
137
      // TODO - сюда вставить разборку бонусов данного юнитлиста - тех бонусов, которые Grants данный юнит добавить в список бонусов юнит-листа
138
139
      $this[$unit->dbId] = $unit;
140
    }
141
142
    // TODO - Применить бонусы от location
143
    // Точнее - опустить бонусы с юнитлиста (те, которые Grants) на каждый юнит (те, которые receives)
144
    // Вообще-то Receives это будут параметры каждого юнита
145
  }
146
147
  public function dbSave() {
148
    if (!is_object($this->locatedAt)) {
149
      classSupernova::$debug->error('UnitList::dbSave have no locatedAt field set');
150
    }
151
152
    foreach ($this->mapUnitIdToDb as $unit) {
153
      $unit_db_id = $unit->dbId;
154
      $unit->dbSave();
155
156
      if ($unit->isEmpty()) {
157
        // Removing unit object
158
        // TODO - change when there will be common bus for all objects
159
        // ...or should I? If COUNT is empty - it means that object does not exists in DB. So it should be deleted from PHP memory and cache too
160
        unset($this[$unit_db_id]);
161
      } else {
162
        if ($unit->dbId <= 0) {
163
          classSupernova::$debug->error('Error writing unit to DB');
164
        }
165
        // If unit is new then putting unit object to container
166
        if (empty($this->_container[$unit->dbId])) {
167
          $this->_container[$unit->dbId] = $unit;
168
        }
169
      }
170
    }
171
  }
172
173
174
175
176
177
  // Other =============================================================================================================
178
179
  /**
180
   * @return Unit
181
   *
182
   */
183
  // TODO - Factory
184
  public function _createElement() {
185
    $unit = new Unit();
186
    $unit->setLocatedAt($this);
187
188
    return $unit;
189
  }
190
191
  /**
192
   * Set unit count of $unit_id to $unit_count
193
   * If there is no $unit_id - it will be created and saved to DB on dbSave
194
   *
195
   * @param int $unit_id
196
   * @param int $unit_count
197
   */
198
  public function unitSetCount($unit_id, $unit_count = 0) {
199
    $this->unitAdjustCount($unit_id, $unit_count, true);
200
  }
201
202
  public function unitGetCount($unit_id) {
203
    if (empty($this->mapUnitIdToDb[$unit_id])) {
204
      throw new Exception('Unit [' . $unit_id . '] is not exists in UnitList');
205
    }
206
207
    return $this->mapUnitIdToDb[$unit_id]->count;
208
  }
209
210
  /**
211
   * Adjust unit count of $unit_id by $unit_count - or just replace value
212
   * If there is no $unit_id - it will be created and saved to DB on dbSave
213
   *
214
   * @param int  $unit_id
215
   * @param int  $unit_count
216
   * @param bool $replace_value
217
   */
218
  public function unitAdjustCount($unit_id, $unit_count = 0, $replace_value = false) {
219
    if (empty($this->mapUnitIdToDb[$unit_id])) {
220
      // If unit not exists - creating one and setting all attributes
221
      $this->mapUnitIdToDb[$unit_id] = $this->_createElement();
222
      $this->mapUnitIdToDb[$unit_id]->setUnitId($unit_id);
223
      $this->mapUnitIdToDb[$unit_id]->setLocatedAt($this);
224
    }
225
226
    if ($replace_value) {
227
      $this->mapUnitIdToDb[$unit_id]->count = $unit_count;
228
    } else {
229
      $this->mapUnitIdToDb[$unit_id]->adjustCount($unit_count);
230
    }
231
  }
232
233
  /**
234
   * @return UnitIterator
235
   */
236
  public function getUnitIterator() {
237
    $obj = new ArrayObject($this->mapUnitIdToDb);
238
    $obj->setIteratorClass('UnitIterator');
239
    return $obj->getIterator();
240
  }
241
242
  /**
243
   * @param array $shipCostInMetalPerPiece - cost in metal by unitId
244
   *
245
   * @return float[]
246
   */
247
  public function unitsCostInMetal($shipCostInMetalPerPiece) {
248
    $shipsCostInMetal = array();
249
    foreach($this->mapUnitIdToDb as $ship_id => $ship) {
250
      $shipsCostInMetal[$ship_id] = $ship->count * $shipCostInMetalPerPiece[$ship_id];
251
    }
252
253
    return $shipsCostInMetal;
254
  }
255
256
  public function unitsCountApplyLossMultiplier($ships_lost_multiplier) {
257
    foreach ($this->mapUnitIdToDb as $unit_id => $unit) {
258
      $unit->count = floor($unit->count * $ships_lost_multiplier);
259
    }
260
  }
261
262
  public function unitsCount() {
263
    return $this->unitsPropertySumById(0, 'count');
264
  }
265
266
  /**
267
   * Get count of units in UnitList by unit_id (or all units if unit_id == 0)
268
   *
269
   * @param int $unit_id - 0 - all units
270
   *
271
   * @return int
272
   */
273
  public function unitsCountById($unit_id = 0) {
274
    return $this->unitsPropertySumById($unit_id, 'count');
275
  }
276
277
  /**
278
   * @param int    $unit_id
279
   * @param string $propertyName
280
   *
281
   * @return int
282
   */
283 View Code Duplication
  public function unitsPropertySumById($unit_id = 0, $propertyName = 'count') {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
284
    $result = 0;
285
    foreach ($this->mapUnitIdToDb as $unit) {
286
      if (!$unit_id || $unit->unitId == $unit_id) {
287
        $result += $unit->$propertyName;
288
      }
289
    }
290
291
    return $result;
292
  }
293
294
  // TODO - WRONG FOR STRUCTURES
295
  public function shipsCapacity() {
296
    return $this->shipsPoolPropertySumById(0, 'capacity');
297
  }
298
299
  // TODO - WRONG FOR STRUCTURES
300 View Code Duplication
  public function shipsPoolPropertySumById($unit_id = 0, $propertyName = 'count') {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
301
    $result = 0;
302
    foreach ($this->mapUnitIdToDb as $unit) {
303
      if (!$unit_id || $unit->unitId == $unit_id) {
304
        $result += $unit->$propertyName * $unit->count;
305
      }
306
    }
307
308
    return $result;
309
  }
310
311 View Code Duplication
  public function shipsIsEnoughOnPlanet($dbOwnerRow, $dbPlanetRow) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
312
    foreach ($this->mapUnitIdToDb as $unitId => $unit) {
313
      if ($unit->count > mrc_get_level($dbOwnerRow, $dbPlanetRow, $unit->unitId)) {
314
        return false;
315
      }
316
    }
317
318
    return true;
319
  }
320
321
  /**
322
   * @return array
323
   * @throws Exception
324
   */
325
  public function unitsRender() {
326
    /**
327
     * @var Fleet $objFleet
328
     */
329
    $objFleet = $this->getLocatedAt();
330
    if (empty($objFleet)) {
331
      throw new Exception('No fleet owner on UnitList::unitsRender() in ' . __FILE__ . '@' . __LINE__);
332
    }
333
334
    $tplShips = array();
335
    foreach ($this->mapUnitIdToDb as $unit) {
336
      $ship_id = $unit->unitId;
337
      $ship_count = $unit->count;
338
      if (!UnitShip::is_in_group($ship_id) || $ship_count <= 0) {
339
        continue;
340
      }
341
342
      $ship_base_data = get_ship_data($ship_id, $objFleet->dbOwnerRow);
343
//      $template->assign_block_vars('fleets.ships', array(
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
344
      $tplShips[] = array(
345
        'ID'          => $ship_id,
346
        'NAME'        => classLocale::$lang['tech'][$ship_id],
347
        'AMOUNT'      => $ship_count,
348
        'AMOUNT_TEXT' => pretty_number($ship_count),
349
        'CONSUMPTION' => $ship_base_data['consumption'],
350
        'SPEED'       => $ship_base_data['speed'],
351
        'CAPACITY'    => $ship_base_data['capacity'],
352
      );
353
    }
354
355
    return $tplShips;
356
  }
357
358
  /**
359
   * @param $user
360
   *
361
   * @return int|mixed
362
   */
363
  // TODO - REDO!!!!
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% 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...
364
  public function shipsSpeedMin($user) {
365
    $speeds = array();
366
    if (!empty($this->mapUnitIdToDb)) {
367
      foreach ($this->mapUnitIdToDb as $ship_id => $unit) {
368
        if ($unit->count > 0 && in_array($unit->unitId, Fleet::$snGroupFleetAndMissiles)) {
369
          $single_ship_data = get_ship_data($unit->unitId, $user);
370
          $speeds[] = $single_ship_data['speed'];
371
        }
372
      }
373
    }
374
375
    return empty($speeds) ? 0 : min($speeds);
376
  }
377
378
379
  // TODO - REDO!!!!
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% 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...
380
  public function travelData($speed_percent = 10, $distance, $dbOwnerRow) {
381
    $consumption = 0;
382
    $capacity = 0;
383
    $duration = 0;
384
385
    $speed_percent = $speed_percent ? max(min($speed_percent, 10), 1) : 10;
386
387
    $game_fleet_speed = flt_server_flight_speed_multiplier();
388
    $fleet_speed = $this->shipsSpeedMin($dbOwnerRow);
389
    $real_speed = $speed_percent * sqrt($fleet_speed);
390
391
    if ($fleet_speed && $game_fleet_speed) {
392
      $duration = max(1, round((35000 / $speed_percent * sqrt($distance * 10 / $fleet_speed) + 10) / $game_fleet_speed));
393
394
      foreach ($this->mapUnitIdToDb as $ship_id => $unit) {
395
        if (!$unit->unitId || $unit->count <= 0) {
396
          continue;
397
        }
398
399
        $single_ship_data = get_ship_data($unit->unitId, $dbOwnerRow);
400
        $single_ship_data['speed'] = $single_ship_data['speed'] < 1 ? 1 : $single_ship_data['speed'];
401
402
        $consumption += $single_ship_data['consumption'] * $unit->count * pow($real_speed / sqrt($single_ship_data['speed']) / 10 + 1, 2);
403
        $capacity += $single_ship_data['capacity'] * $unit->count;
404
      }
405
406
      $consumption = round($distance * $consumption / 35000) + 1;
407
    }
408
409
    return array(
410
      'fleet_speed'            => $fleet_speed,
411
      'distance'               => $distance,
412
      'duration'               => $duration,
413
      'consumption'            => $consumption,
414
      'capacity'               => $capacity,
415
      'hold'                   => $capacity - $consumption,
416
      'transport_effectivness' => $consumption ? $capacity / $consumption : 0,
417
    );
418
  }
419
420
  /**
421
   * @param $group
422
   *
423
   * @return bool
424
   */
425
  public function unitsInGroup($group) {
426
    foreach ($this->mapUnitIdToDb as $unitId => $unit) {
427
      if (!in_array($unitId, $group)) {
428
        return false;
429
      }
430
    }
431
432
    return true;
433
  }
434
435 View Code Duplication
  public function unitsIsAllMovable($dbOwnerRow) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
436
    foreach ($this->mapUnitIdToDb as $unitId => $unit) {
437
      $single_ship_data = get_ship_data($unit->unitId, $dbOwnerRow);
438
      if ($single_ship_data['speed'] <= 0) {
439
        return false;
440
      }
441
    }
442
443
    return true;
444
  }
445
446
  public function unitsPositive() {
447
    foreach ($this->mapUnitIdToDb as $unitId => $unit) {
448
      if ($unit->count < 1) {
449
        return false;
450
      }
451
    }
452
453
    return true;
454
  }
455
456
  /**
457
   * @param array $dbOwnerRow
458
   * @param int   $sourcePlanetRowId
459
   */
460
  public function dbSubstractUnitsFromPlanet($dbOwnerRow, $sourcePlanetRowId) {
461
    foreach ($this->mapUnitIdToDb as $unit) {
462
      DBStaticUnit::dbUpdateOrInsertUnit($unit->unitId, -$unit->count, $dbOwnerRow, $sourcePlanetRowId);
463
    }
464
  }
465
466
467
  // TODO - DEBUG - REMOVE =============================================================================================
468
  public function _dump() {
469
    print(__FILE__ . ':' . __LINE__ . "<br />");
470
    print("Located at " . $this->getLocationDbId() . " type " . $this->getLocationType() . "<br />");
471
472
    print('<table border="1">');
473
    print('<tr>');
474
475
    print('<th>');
476
    print('dbId');
477
    print('</th>');
478
479
    print('<th>');
480
    print('type');
481
    print('</th>');
482
483
    print('<th>');
484
    print('unitId');
485
    print('</th>');
486
487
    print('<th>');
488
    print('count');
489
    print('</th>');
490
491
    print('<th>');
492
    print('playerOwnerId');
493
    print('</th>');
494
495
    print('<th>');
496
    print('location');
497
    print('</th>');
498
499
    print('<th>');
500
    print('locationType');
501
    print('</th>');
502
503
    print('<th>');
504
    print('locationDbId');
505
    print('</th>');
506
507
    print('<th>');
508
    print('timeStart');
509
    print('</th>');
510
511
    print('<th>');
512
    print('timeFinish');
513
    print('</th>');
514
515
    print('</tr>');
516
517
    foreach ($this->mapUnitIdToDb as $unit) {
518
      print('<tr>');
519
520
      print('<td>');
521
      print($unit->dbId);
522
      print('</td>');
523
524
      print('<td>');
525
      $type = $unit->getType();
526
      print("[{$type}] " . classLocale::$lang['tech'][$type]);
527
      print('</td>');
528
529
      print('<td>');
530
      print("[{$unit->unitId}] " . classLocale::$lang['tech'][$unit->unitId]);
531
      print('</td>');
532
533
      print('<td>');
534
      print($unit->count);
535
      print('</td>');
536
537
      print('<td>');
538
      print($unit->getPlayerOwnerId());
539
      print('</td>');
540
541
      print('<td>');
542
//      print($unit->location);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
543
      print('</td>');
544
545
      print('<td>');
546
      print($unit->getLocationType());
547
      print('</td>');
548
549
      print('<td>');
550
      print($unit->getLocationDbId());
551
      print('</td>');
552
553
      print('<td>');
554
      print($unit->getTimeStart());
555
      print('</td>');
556
557
      print('<td>');
558
      print($unit->getTimeFinish());
559
      print('</td>');
560
561
      print('</tr>');
562
    }
563
    print('</table>');
564
  }
565
566
  public function unitZeroDbId() {
567
    foreach ($this->mapUnitIdToDb as $unit) {
568
      $unit->zeroDbId();
569
    }
570
  }
571
572
  public function unitZeroCount() {
573
    foreach ($this->mapUnitIdToDb as $unit) {
574
      $unit->count = 0;
575
    }
576
  }
577
578
}
579