Completed
Push — work-fleets ( 0d1d7f...d58328 )
by SuperNova.WS
06:06
created

UnitList::unitsCount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 1
b 0
f 0
ccs 0
cts 3
cp 0
crap 2
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 = classSupernova::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
   * @version 41a50.14
183
   */
184
  // TODO - Factory
185
  public function _createElement() {
186
    $unit = new Unit();
187
    $unit->setLocatedAt($this);
188
189
    return $unit;
190
  }
191
192
  /**
193
   * Set unit count of $unit_id to $unit_count
194
   * If there is no $unit_id - it will be created and saved to DB on dbSave
195
   *
196
   * @param int $unit_id
197
   * @param int $unit_count
198
   */
199
  public function unitSetCount($unit_id, $unit_count = 0) {
200
    $this->unitAdjustCount($unit_id, $unit_count, true);
201
  }
202
203
  public function unitGetCount($unit_id) {
204
    if (empty($this->mapUnitIdToDb[$unit_id])) {
205
      throw new Exception('Unit [' . $unit_id . '] is not exists in UnitList');
206
    }
207
208
    return $this->mapUnitIdToDb[$unit_id]->count;
209
  }
210
211
  /**
212
   * Adjust unit count of $unit_id by $unit_count - or just replace value
213
   * If there is no $unit_id - it will be created and saved to DB on dbSave
214
   *
215
   * @param int  $unit_id
216
   * @param int  $unit_count
217
   * @param bool $replace_value
218
   */
219
  public function unitAdjustCount($unit_id, $unit_count = 0, $replace_value = false) {
220
    if (empty($this->mapUnitIdToDb[$unit_id])) {
221
      // If unit not exists - creating one and setting all attributes
222
      $this->mapUnitIdToDb[$unit_id] = $this->_createElement();
223
      $this->mapUnitIdToDb[$unit_id]->setUnitId($unit_id);
224
      $this->mapUnitIdToDb[$unit_id]->setLocatedAt($this);
225
    }
226
227
    if ($replace_value) {
228
      $this->mapUnitIdToDb[$unit_id]->count = $unit_count;
229
    } else {
230
      $this->mapUnitIdToDb[$unit_id]->adjustCount($unit_count);
231
    }
232
  }
233
234
  /**
235
   * @return UnitIterator
236
   */
237
  public function getUnitIterator() {
238
    $obj = new ArrayObject($this->mapUnitIdToDb);
239
    $obj->setIteratorClass('UnitIterator');
240
    return $obj->getIterator();
241
  }
242
243
  /**
244
   * @param array $shipCostInMetalPerPiece - cost in metal by unitId
245
   *
246
   * @return float[]
247
   */
248
  public function unitsCostInMetal($shipCostInMetalPerPiece) {
249
    $shipsCostInMetal = array();
250
    foreach($this->mapUnitIdToDb as $ship_id => $ship) {
251
      $shipsCostInMetal[$ship_id] = $ship->count * $shipCostInMetalPerPiece[$ship_id];
252
    }
253
254
    return $shipsCostInMetal;
255
  }
256
257
  public function unitsCountApplyLossMultiplier($ships_lost_multiplier) {
258
    foreach ($this->mapUnitIdToDb as $unit_id => $unit) {
259
      $unit->count = floor($unit->count * $ships_lost_multiplier);
260
    }
261
  }
262
263
  public function unitsCount() {
264
    return $this->unitsPropertySumById(0, 'count');
265
  }
266
267
  /**
268
   * Get count of units in UnitList by unit_id (or all units if unit_id == 0)
269
   *
270
   * @param int $unit_id - 0 - all units
271
   *
272
   * @return int
273
   */
274
  public function unitsCountById($unit_id = 0) {
275
    return $this->unitsPropertySumById($unit_id, 'count');
276
  }
277
278
  /**
279
   * @param int    $unit_id
280
   * @param string $propertyName
281
   *
282
   * @return int
283
   */
284 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...
285
    $result = 0;
286
    foreach ($this->mapUnitIdToDb as $unit) {
287
      if (!$unit_id || $unit->unitId == $unit_id) {
288
        $result += $unit->$propertyName;
289
      }
290
    }
291
292
    return $result;
293
  }
294
295
  // TODO - WRONG FOR STRUCTURES
296
  public function shipsCapacity() {
297
    return $this->shipsPoolPropertySumById(0, 'capacity');
298
  }
299
300
  // TODO - WRONG FOR STRUCTURES
301 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...
302
    $result = 0;
303
    foreach ($this->mapUnitIdToDb as $unit) {
304
      if (!$unit_id || $unit->unitId == $unit_id) {
305
        $result += $unit->$propertyName * $unit->count;
306
      }
307
    }
308
309
    return $result;
310
  }
311
312 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...
313
    foreach ($this->mapUnitIdToDb as $unitId => $unit) {
314
      if ($unit->count > mrc_get_level($dbOwnerRow, $dbPlanetRow, $unit->unitId)) {
315
        return false;
316
      }
317
    }
318
319
    return true;
320
  }
321
322
  /**
323
   * @return array
324
   * @throws Exception
325
   */
326
  public function unitsRender() {
327
    /**
328
     * @var Fleet $objFleet
329
     */
330
    $objFleet = $this->getLocatedAt();
331
    if (empty($objFleet)) {
332
      throw new Exception('No fleet owner on UnitList::unitsRender() in ' . __FILE__ . '@' . __LINE__);
333
    }
334
335
    $tplShips = array();
336
    foreach ($this->mapUnitIdToDb as $unit) {
337
      $ship_id = $unit->unitId;
338
      $ship_count = $unit->count;
339
      if (!UnitShip::is_in_group($ship_id) || $ship_count <= 0) {
340
        continue;
341
      }
342
343
      $ship_base_data = get_ship_data($ship_id, $objFleet->dbOwnerRow);
344
//      $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...
345
      $tplShips[] = array(
346
        'ID'          => $ship_id,
347
        'NAME'        => classLocale::$lang['tech'][$ship_id],
348
        'AMOUNT'      => $ship_count,
349
        'AMOUNT_TEXT' => pretty_number($ship_count),
350
        'CONSUMPTION' => $ship_base_data['consumption'],
351
        'SPEED'       => $ship_base_data['speed'],
352
        'CAPACITY'    => $ship_base_data['capacity'],
353
      );
354
    }
355
356
    return $tplShips;
357
  }
358
359
  /**
360
   * @param $user
361
   *
362
   * @return int|mixed
363
   */
364
  // 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...
365
  public function shipsSpeedMin($user) {
366
    $speeds = array();
367
    if (!empty($this->mapUnitIdToDb)) {
368
      foreach ($this->mapUnitIdToDb as $ship_id => $unit) {
369
        if ($unit->getCount() > 0 && in_array($unit->unitId, Fleet::$snGroupFleetAndMissiles)) {
370
          $single_ship_data = get_ship_data($unit->unitId, $user);
371
          $speeds[] = $single_ship_data['speed'];
372
        }
373
      }
374
    }
375
376
    return empty($speeds) ? 0 : min($speeds);
377
  }
378
379
380
  // 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...
381
  public function travelData($speed_percent = 10, $distance, $dbOwnerRow) {
382
    $consumption = 0;
383
    $capacity = 0;
384
    $duration = 0;
385
386
    $speed_percent = $speed_percent ? max(min($speed_percent, 10), 1) : 10;
387
388
    $game_fleet_speed = flt_server_flight_speed_multiplier();
389
    $fleet_speed = $this->shipsSpeedMin($dbOwnerRow);
390
    $real_speed = $speed_percent * sqrt($fleet_speed);
391
392
    if ($fleet_speed && $game_fleet_speed) {
393
      $duration = max(1, round((35000 / $speed_percent * sqrt($distance * 10 / $fleet_speed) + 10) / $game_fleet_speed));
394
395
      foreach ($this->mapUnitIdToDb as $ship_id => $unit) {
396
        if (!$unit->unitId || $unit->getCount() <= 0) {
397
          continue;
398
        }
399
400
        $single_ship_data = get_ship_data($unit->unitId, $dbOwnerRow);
401
        $single_ship_data['speed'] = $single_ship_data['speed'] < 1 ? 1 : $single_ship_data['speed'];
402
403
        $consumption += $single_ship_data['consumption'] * $unit->getCount() * pow($real_speed / sqrt($single_ship_data['speed']) / 10 + 1, 2);
404
        $capacity += $single_ship_data['capacity'] * $unit->getCount();
405
      }
406
407
      $consumption = round($distance * $consumption / 35000) + 1;
408
    }
409
410
    return array(
411
      'fleet_speed'            => $fleet_speed,
412
      'distance'               => $distance,
413
      'duration'               => $duration,
414
      'consumption'            => $consumption,
415
      'capacity'               => $capacity,
416
      'hold'                   => $capacity - $consumption,
417
      'transport_effectivness' => $consumption ? $capacity / $consumption : 0,
418
    );
419
  }
420
421
  /**
422
   * @param $group
423
   *
424
   * @return bool
425
   */
426
  public function unitsInGroup($group) {
427
    foreach ($this->mapUnitIdToDb as $unitId => $unit) {
428
      if (!in_array($unitId, $group)) {
429
        return false;
430
      }
431
    }
432
433
    return true;
434
  }
435
436 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...
437
    foreach ($this->mapUnitIdToDb as $unitId => $unit) {
438
      $single_ship_data = get_ship_data($unit->unitId, $dbOwnerRow);
439
      if ($single_ship_data['speed'] <= 0) {
440
        return false;
441
      }
442
    }
443
444
    return true;
445
  }
446
447
  public function unitsPositive() {
448
    foreach ($this->mapUnitIdToDb as $unitId => $unit) {
449
      if ($unit->count < 1) {
450
        return false;
451
      }
452
    }
453
454
    return true;
455
  }
456
457
  /**
458
   * @param array $dbOwnerRow
459
   * @param int   $sourcePlanetRowId
460
   *
461
   * @return array
462
   */
463
  public function db_prepare_old_changeset_for_planet($dbOwnerRow, $sourcePlanetRowId) {
464
    $db_changeset = array();
465
    foreach ($this->mapUnitIdToDb as $unit) {
466
      $db_changeset['unit'][] = sn_db_unit_changeset_prepare($unit->unitId, -$unit->count, $dbOwnerRow, $sourcePlanetRowId);
467
    }
468
469
    return $db_changeset;
470
  }
471
472
473
  // TODO - DEBUG - REMOVE =============================================================================================
474
  public function _dump() {
475
    print(__FILE__ . ':' . __LINE__ . "<br />");
476
    print("Located at " . $this->getLocationDbId() . " type " . $this->getLocationType() . "<br />");
477
478
    print('<table border="1">');
479
    print('<tr>');
480
481
    print('<th>');
482
    print('dbId');
483
    print('</th>');
484
485
    print('<th>');
486
    print('type');
487
    print('</th>');
488
489
    print('<th>');
490
    print('unitId');
491
    print('</th>');
492
493
    print('<th>');
494
    print('count');
495
    print('</th>');
496
497
    print('<th>');
498
    print('playerOwnerId');
499
    print('</th>');
500
501
    print('<th>');
502
    print('location');
503
    print('</th>');
504
505
    print('<th>');
506
    print('locationType');
507
    print('</th>');
508
509
    print('<th>');
510
    print('locationDbId');
511
    print('</th>');
512
513
    print('<th>');
514
    print('timeStart');
515
    print('</th>');
516
517
    print('<th>');
518
    print('timeFinish');
519
    print('</th>');
520
521
    print('</tr>');
522
523
    foreach ($this->mapUnitIdToDb as $unit) {
524
      print('<tr>');
525
526
      print('<td>');
527
      print($unit->dbId);
528
      print('</td>');
529
530
      print('<td>');
531
      $type = $unit->getType();
532
      print("[{$type}] " . classLocale::$lang['tech'][$type]);
533
      print('</td>');
534
535
      print('<td>');
536
      print("[{$unit->unitId}] " . classLocale::$lang['tech'][$unit->unitId]);
537
      print('</td>');
538
539
      print('<td>');
540
      print($unit->count);
541
      print('</td>');
542
543
      print('<td>');
544
      print($unit->getPlayerOwnerId());
545
      print('</td>');
546
547
      print('<td>');
548
//      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...
549
      print('</td>');
550
551
      print('<td>');
552
      print($unit->getLocationType());
553
      print('</td>');
554
555
      print('<td>');
556
      print($unit->getLocationDbId());
557
      print('</td>');
558
559
      print('<td>');
560
      print($unit->getTimeStart());
561
      print('</td>');
562
563
      print('<td>');
564
      print($unit->getTimeFinish());
565
      print('</td>');
566
567
      print('</tr>');
568
    }
569
    print('</table>');
570
  }
571
572
  public function unitZeroDbId() {
573
    foreach ($this->mapUnitIdToDb as $unit) {
574
      $unit->zeroDbId();
575
    }
576
  }
577
578
  public function unitZeroCount() {
579
    foreach ($this->mapUnitIdToDb as $unit) {
580
      $unit->count = 0;
581
    }
582
  }
583
584
}
585