Completed
Push — work-fleets ( 6d7489...ab257a )
by SuperNova.WS
05:48
created

UnitList::unitsPropertySumById()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 10
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 10
loc 10
rs 9.2
cc 4
eloc 6
nc 3
nop 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 ArrayAccessV2 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 41a6.79
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
    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
   * Get unit list in array as $unit_id => $unit_count
235
   *
236
   * @return array
237
   */
238
  public function unitsGetArray() {
239
    $result = array();
240
    foreach($this->mapUnitIdToDb as $unit) {
241
      $result[$unit->unitId] = $unit->count;
242
    }
243
244
    return $result;
245
  }
246
247
  public function unitsCountApplyLossMultiplier($ships_lost_multiplier) {
248
    foreach($this->mapUnitIdToDb as $unit_id => $unit) {
249
      $unit->count = floor($unit->count * $ships_lost_multiplier);
250
    }
251
  }
252
253
  public function unitsCount() {
254
    return $this->unitsPropertySumById(0, 'count');
255
  }
256
257
  /**
258
   * Get count of units in UnitList by unit_id (or all units if unit_id == 0)
259
   *
260
   * @param int $unit_id - 0 - all units
261
   *
262
   * @return int
263
   */
264
  public function unitsCountById($unit_id = 0) {
265
    return $this->unitsPropertySumById($unit_id, 'count');
266
  }
267
268 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...
269
    $result = 0;
270
    foreach($this->mapUnitIdToDb as $unit) {
271
      if(!$unit_id || $unit->unitId == $unit_id) {
272
        $result += $unit->$propertyName;
273
      }
274
    }
275
276
    return $result;
277
  }
278
279
  // TODO - WRONG FOR STRUCTURES
280
  public function shipsCapacity() {
281
    return $this->shipsPoolPropertySumById(0, 'capacity');
282
  }
283
284
  // TODO - WRONG FOR STRUCTURES
285 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...
286
    $result = 0;
287
    foreach($this->mapUnitIdToDb as $unit) {
288
      if(!$unit_id || $unit->unitId == $unit_id) {
289
        $result += $unit->$propertyName * $unit->count;
290
      }
291
    }
292
293
    return $result;
294
  }
295
296
  public function shipsIsEnoughOnPlanet($dbPlanetRow) {
297
    $player = null;
298
    foreach($this->mapUnitIdToDb as $unitId => $unit) {
299
      if($unit->count < mrc_get_level($player, $dbPlanetRow, $unit->unitId)) {
0 ignored issues
show
Bug introduced by
It seems like $player defined by null on line 297 can also be of type null; however, mrc_get_level() 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...
300
        return false;
301
      }
302
    }
303
304
    return true;
305
  }
306
307
  /**
308
   * @return array
309
   * @throws Exception
310
   */
311
  public function unitsRender() {
312
    /**
313
     * @var Fleet $objFleet
314
     */
315
    $objFleet = $this->getLocatedAt();
316
    if(empty($objFleet)) {
317
      throw new Exception('No fleet owner on UnitList::unitsRender() in ' . __FILE__ . '@' . __LINE__);
318
    }
319
320
    $tplShips = array();
321
    foreach($this->mapUnitIdToDb as $unit) {
322
      $ship_id = $unit->unitId;
323
      $ship_count = $unit->count;
324
      if(!UnitShip::is_in_group($ship_id) || $ship_count <= 0) {
325
        continue;
326
      }
327
328
      $ship_base_data = get_ship_data($ship_id, $objFleet->dbOwnerRow);
329
//      $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...
330
      $tplShips[] = array(
331
        'ID'          => $ship_id,
332
        'NAME'        => classLocale::$lang['tech'][$ship_id],
333
        'AMOUNT'      => $ship_count,
334
        'AMOUNT_TEXT' => pretty_number($ship_count),
335
        'CONSUMPTION' => $ship_base_data['consumption'],
336
        'SPEED'       => $ship_base_data['speed'],
337
        'CAPACITY'    => $ship_base_data['capacity'],
338
      );
339
    }
340
341
    return $tplShips;
342
  }
343
344
  /**
345
   * @param $user
346
   *
347
   * @return int|mixed
348
   */
349
  // 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...
350
  public function shipsSpeedMin($user) {
351
    $speeds = array();
352
    if(!empty($this->mapUnitIdToDb)) {
353
      foreach($this->mapUnitIdToDb as $ship_id => $unit) {
354
        if($unit->getCount() > 0 && in_array($unit->unitId, sn_get_groups(array('fleet', 'missile')))) {
355
          $single_ship_data = get_ship_data($unit->unitId, $user);
356
          $speeds[] = $single_ship_data['speed'];
357
        }
358
      }
359
    }
360
361
    return empty($speeds) ? 0 : min($speeds);
362
  }
363
364
365
  // 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...
366
  public function travelData($speed_percent = 10, $distance, $dbOwnerRow) {
367
    $consumption = 0;
368
    $capacity = 0;
369
    $duration = 0;
370
371
    $speed_percent = $speed_percent ? max(min($speed_percent, 10), 1) : 10;
372
373
    $game_fleet_speed = flt_server_flight_speed_multiplier();
374
    $fleet_speed = $this->shipsSpeedMin($dbOwnerRow);
375
    $real_speed = $speed_percent * sqrt($fleet_speed);
376
377
    if($fleet_speed && $game_fleet_speed) {
378
      $duration = max(1, round((35000 / $speed_percent * sqrt($distance * 10 / $fleet_speed) + 10) / $game_fleet_speed));
379
380
      foreach($this->mapUnitIdToDb as $ship_id => $unit) {
381
        if(!$unit->unitId || $unit->getCount() <= 0) {
382
          continue;
383
        }
384
385
        $single_ship_data = get_ship_data($unit->unitId, $dbOwnerRow);
386
        $single_ship_data['speed'] = $single_ship_data['speed'] < 1 ? 1 : $single_ship_data['speed'];
387
388
        $consumption += $single_ship_data['consumption'] * $unit->getCount() * pow($real_speed / sqrt($single_ship_data['speed']) / 10 + 1, 2);
389
        $capacity += $single_ship_data['capacity'] * $unit->getCount();
390
      }
391
392
      $consumption = round($distance * $consumption / 35000) + 1;
393
    }
394
395
    return array(
396
      'fleet_speed'            => $fleet_speed,
397
      'distance'               => $distance,
398
      'duration'               => $duration,
399
      'consumption'            => $consumption,
400
      'capacity'               => $capacity,
401
      'hold'                   => $capacity - $consumption,
402
      'transport_effectivness' => $consumption ? $capacity / $consumption : 0,
403
    );
404
  }
405
406
  /**
407
   * @param $group
408
   *
409
   * @return bool
410
   */
411
  public function unitsInGroup($group) {
412
    foreach($this->mapUnitIdToDb as $unitId => $unit) {
413
      if(!in_array($unitId, $group)) {
414
        return false;
415
      }
416
    }
417
418
    return true;
419
  }
420
421
  public function unitsIsAllMovable($dbOwnerRow) {
422
    foreach($this->mapUnitIdToDb as $unitId => $unit) {
423
      $single_ship_data = get_ship_data($unit->unitId, $dbOwnerRow);
424
      if($single_ship_data['speed'] <= 0) {
425
        return false;
426
      }
427
    }
428
429
    return true;
430
  }
431
432
433
434
  // TODO - DEBUG - REMOVE =============================================================================================
435
  public function _dump() {
436
    print(__FILE__ . ':' . __LINE__ . "<br />");
437
    print("Located at " . $this->getLocationDbId() . " type " . $this->getLocationType() . "<br />");
438
439
    print('<table border="1">');
440
    print('<tr>');
441
442
    print('<th>');
443
    print('dbId');
444
    print('</th>');
445
446
    print('<th>');
447
    print('type');
448
    print('</th>');
449
450
    print('<th>');
451
    print('unitId');
452
    print('</th>');
453
454
    print('<th>');
455
    print('count');
456
    print('</th>');
457
458
    print('<th>');
459
    print('playerOwnerId');
460
    print('</th>');
461
462
    print('<th>');
463
    print('location');
464
    print('</th>');
465
466
    print('<th>');
467
    print('locationType');
468
    print('</th>');
469
470
    print('<th>');
471
    print('locationDbId');
472
    print('</th>');
473
474
    print('<th>');
475
    print('timeStart');
476
    print('</th>');
477
478
    print('<th>');
479
    print('timeFinish');
480
    print('</th>');
481
482
    print('</tr>');
483
484
    foreach($this->mapUnitIdToDb as $unit) {
485
      print('<tr>');
486
487
      print('<td>');
488
      print($unit->dbId);
489
      print('</td>');
490
491
      print('<td>');
492
      $type = $unit->getType();
493
      print("[{$type}] " . classLocale::$lang['tech'][$type]);
494
      print('</td>');
495
496
      print('<td>');
497
      print("[{$unit->unitId}] " . classLocale::$lang['tech'][$unit->unitId]);
498
      print('</td>');
499
500
      print('<td>');
501
      print($unit->count);
502
      print('</td>');
503
504
      print('<td>');
505
      print($unit->getPlayerOwnerId());
506
      print('</td>');
507
508
      print('<td>');
509
//      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...
510
      print('</td>');
511
512
      print('<td>');
513
      print($unit->getLocationType());
514
      print('</td>');
515
516
      print('<td>');
517
      print($unit->getLocationDbId());
518
      print('</td>');
519
520
      print('<td>');
521
      print($unit->getTimeStart());
522
      print('</td>');
523
524
      print('<td>');
525
      print($unit->getTimeFinish());
526
      print('</td>');
527
528
      print('</tr>');
529
    }
530
    print('</table>');
531
  }
532
  public function unitZeroDbId() {
533
    foreach($this->mapUnitIdToDb as $unit) {
534
      $unit->zeroDbId();
535
    }
536
  }
537
  public function unitZeroCount() {
538
    foreach($this->mapUnitIdToDb as $unit) {
539
      $unit->count = 0;
540
    }
541
  }
542
543
}
544