Completed
Push — work-fleets ( d1f99e...fc0000 )
by SuperNova.WS
06:40
created

classes/UnitList.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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