Completed
Push — trunk ( 0d0bfe...e6cc80 )
by SuperNova.WS
03:47
created

MissionExplore::outcomeShipsFound()   C

Complexity

Conditions 7
Paths 18

Size

Total Lines 36
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 23
nc 18
nop 0
dl 0
loc 36
ccs 0
cts 28
cp 0
crap 56
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by Gorlum 07.12.2017 13:44
4
 */
5
6
namespace Fleet;
7
8
use \classSupernova;
9
use Common\OutcomeManager;
10
11
/**
12
 * Class MissionExplore
13
 * @package Fleet
14
 */
15
class MissionExplore extends MissionData {
16
  // -------------------------------------------------------------------------------------------------------------------
17
  /**
18
   * @var float[] $rates
19
   */
20
  protected static $rates;
21
22
  // -------------------------------------------------------------------------------------------------------------------
23
  /**
24
   * @var int $hardDmLimit
25
   */
26
  protected $hardDmLimit = 10000;
27
28
  /**
29
   * @var int $hardResourcesLimit
30
   */
31
  protected $hardResourcesLimit = 10000000;
32
33
  /**
34
   * @var int $hardShipCostResourceLimit
35
   */
36
  protected $hardShipCostResourceLimit = 10000000;
37
38
  /**
39
   * List of ships which should be excluded from found list
40
   *
41
   * @var int[] $shipsToRemove
42
   */
43
  protected $shipsToRemove = [SHIP_COLONIZER, SHIP_SPY,];
44
45
  // -------------------------------------------------------------------------------------------------------------------
46
  /**
47
   * @var array $outcome
48
   */
49
  protected $outcome = [];
50
51
  /**
52
   * Primary outcome ID
53
   *
54
   * Shows global outcome
55
   *
56
   * @var int $outcomeType
57
   */
58
  protected $outcomeType = FLT_EXPEDITION_OUTCOME_NONE;
59
60
  /**
61
   * Secondary outcome data
62
   *
63
   * @var array $secondaryInfo
64
   */
65
  protected $secondaryInfo;
66
67
  /**
68
   * @var int $darkMatterFound
69
   */
70
  protected $darkMatterFound = 0;
71
72
  /**
73
   * How much ships LOST in expedition
74
   *
75
   * @var float[] $shipsLost
76
   */
77
  protected $shipsLost = [];
78
79
  /**
80
   * How much ships FOUND in expedition
81
   *
82
   * @var float[] $shipsFound
83
   */
84
  protected $shipsFound = [];
85
86
  /**
87
   * @var float[] $resourcesFound
88
   */
89
  protected $resourcesFound = [];
90
91
  /**
92
   * @var string[] $message
93
   */
94
  protected $message = [];
95
96
97
  /**
98
   * MissionExplore constructor.
99
   *
100
   * @param array $missionArray
101
   */
102
  public function __construct($missionArray) {
103
    parent::__construct($missionArray);
104
105
    if (empty(static::$rates)) {
106
      static::$rates = classSupernova::$gc->economicHelper->getResourcesExchange();
107
    }
108
109
    $this->shipsFound = [];
110
  }
111
112
  /**
113
   * @param float $multiplier
114
   */
115
  protected function applyShipLoss($multiplier) {
116
    foreach ($this->fleetRecord->getShipList() as $unit_id => $unit_amount) {
117
      $shipsLost = ceil($unit_amount * $multiplier);
118
      $this->shipsLost[$unit_id] += $shipsLost;
119
    }
120
  }
121
122
  /**
123
   * Mission outcome: Lost all ships
124
   */
125
  protected function outcomeShipsLostAll() {
126
    $this->applyShipLoss(1);
127
  }
128
129
  /**
130
   * Mission outcome: Lost some ships
131
   */
132
  protected function outcomeShipsLostPart() {
133
    $this->applyShipLoss(1 / mt_rand(1, 3));
134
  }
135
136
137
  protected function outcomeShipsFound() {
138
    // Рассчитываем эквивалент найденного флота в метале
139
    $found_in_metal = min(
140
      $this->secondaryInfo[P_MULTIPLIER] * $this->fleetRecord->getCostInMetal(),
141
      $this->getGameMiningSpeed() * $this->hardShipCostResourceLimit
142
    );
143
    //  13 243 754 000 g x1
144
    //  60 762 247 000 a x10
145
    // 308 389 499 488 000 b x500
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% 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...
146
147
    // TODO - убрать рассовые корабли
148
    $manager = new OutcomeManager();
149
    $can_be_found = $this->possibleShipsCosts();
150
    foreach ($can_be_found as $unitId => $temp) {
151
      $manager->add($unitId, 1);
152
    }
153
154
    $foundFleet = [];
155
    while (count($manager) && $found_in_metal >= 0) {
156
      $foundUnitId = $manager->rollOutcome();
157
      $found_ship_cost = $can_be_found[$foundUnitId];
158
      if ($found_ship_cost > $found_in_metal) {
159
        unset($can_be_found[$foundUnitId]);
160
        $manager->remove($foundUnitId);
161
      } else {
162
        $found_ship_count = mt_rand(1, floor($found_in_metal / $found_ship_cost));
163
        $foundFleet[$foundUnitId] += $found_ship_count;
164
        $found_in_metal -= $found_ship_count * $found_ship_cost;
165
      }
166
    }
167
168
    if (empty($foundFleet)) {
169
      $this->message[] = $this->lang['flt_mission_expedition']['outcomes'][$this->outcomeType]['no_result'];
170
    } else {
171
      foreach ($foundFleet as $unit_id => $unit_amount) {
172
        $this->shipsFound[$unit_id] += $unit_amount;
173
      }
174
    }
175
176
  }
177
178
  /**
179
   *
180
   */
181
  protected function outcomeResourcesFound() {
182
    // Рассчитываем количество найденных ресурсов
183
    $found_in_metal = ceil(
184
      min(
185
      // Resources found
186
        $this->secondaryInfo[P_MULTIPLIER] * $this->fleetRecord->getCostInMetal(),
187
        // Not more then maximum fleet capacity
188
        $this->fleetRecord->getCapacity(),
189
        // Hard limit
190
        $this->getGameMiningSpeed() * $this->hardResourcesLimit
191
      )
192
      // Randomizing from 90% to 110%
193
      * $this->getRandomFoundResourcesMultiplier()
194
    );
195
196
    $resourcesFound = [];
197
    // 30-70%% - metal
198
    $resourcesFound[RES_METAL] = floor($found_in_metal * $this->getRandomFoundMetalMultiplier());
199
    $found_in_metal -= $resourcesFound[RES_METAL];
200
201
    // 50-100%% of rest - is crystal
202
    $found_in_crystal = floor($found_in_metal * static::$rates[RES_METAL] / static::$rates[RES_CRYSTAL]);
203
    $resourcesFound[RES_CRYSTAL] = floor($this->getRandomFoundCrystalMultiplier() * $found_in_crystal);
204
    $found_in_crystal -= $resourcesFound[RES_CRYSTAL];
205
206
    // Rest - deuterium
207
    $resourcesFound[RES_DEUTERIUM] = floor($found_in_crystal * static::$rates[RES_CRYSTAL] / static::$rates[RES_DEUTERIUM]);
208
209
    if (array_sum($resourcesFound) <= 0) {
210
      $this->message = $this->lang['flt_mission_expedition']['outcomes'][$this->outcomeType]['no_result'];
211
    } else {
212
      foreach ($resourcesFound as $resourceId => $foundAmount) {
213
        $this->resourcesFound += $resourcesFound;
214
      }
215
    }
216
  }
217
218
  /**
219
   *
220
   */
221
  protected function outcomeDmFound() {
222
    // Рассчитываем количество найденной ТМ
223
    $this->darkMatterFound = floor(
224
      min(
225
        $this->secondaryInfo[P_MULTIPLIER] * $this->fleetRecord->getCostInMetal() / static::$rates[RES_DARK_MATTER],
226
        // Hard limit - not counting game speed
227
        $this->hardDmLimit
228
      )
229
      // 75-100%%
230
      * $this->getRandomFoundDmMultiplier()
231
    );
232
233
    if (!$this->darkMatterFound) {
234
      $this->message[] = $this->lang['flt_mission_expedition']['outcomes'][$this->outcomeType]['no_result'];
235
    }
236
  }
237
238
239
  protected function prependMainMessage() {
240
    $messages = $this->lang['flt_mission_expedition']['outcomes'][$this->outcomeType]['messages'];
241
    // There is variants and one variant selected
242
    if (isset($this->secondaryInfo[P_MESSAGE_ID]) && !empty($messages[$this->secondaryInfo[P_MESSAGE_ID]])) {
243
      // Selecting selected variant
244
      $messages = $messages[$this->secondaryInfo[P_MESSAGE_ID]];
245
    }
246
    $message =
247
      // If there is only one string message - just adding it
248
      is_string($messages)
249
        ? $messages
250
        // If there is array of possible messages - selecting one of them randomly
251
        : (is_array($messages) ? $messages[mt_rand(0, count($messages) - 1)] : '');
252
253
    // Adding outcome message to the front of other info
254
    array_unshift($this->message, $message);
255
  }
256
257
  /**
258
   * @param array $mission_data
259
   */
260
  public function process() {
261
    if (!isset($this->fleet_event) || $this->fleet_event != EVENT_FLT_ACOMPLISH) {
0 ignored issues
show
introduced by
The condition ! IssetNode || $this->fl...eet\EVENT_FLT_ACOMPLISH can never be false.
Loading history...
262
      return;
263
    }
264
265
    $this->outcome = $this->rollOutcome();
266
    $this->outcomeType = $this->outcome[P_MISSION_EXPEDITION_OUTCOME];
267
    if (!empty($this->outcome[P_MISSION_EXPEDITION_OUTCOME_SECONDARY])) {
268
      // $this->rollSecondaryOutcome($this->outcome[P_MISSION_EXPEDITION_OUTCOME_SECONDARY]);
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...
269
      $this->secondaryInfo = OutcomeManager::rollArray($this->outcome[P_MISSION_EXPEDITION_OUTCOME_SECONDARY]);
270
    }
271
272
    switch ($this->outcomeType) {
273
      case FLT_EXPEDITION_OUTCOME_LOST_FLEET_ALL:
274
        $this->outcomeShipsLostAll();
275
      break;
276
277
      case FLT_EXPEDITION_OUTCOME_LOST_FLEET:
278
        $this->outcomeShipsLostPart();
279
      break;
280
281
      case FLT_EXPEDITION_OUTCOME_FOUND_FLEET:
282
        $this->outcomeShipsFound();
283
      break;
284
285
      case FLT_EXPEDITION_OUTCOME_FOUND_RESOURCES:
286
        $this->outcomeResourcesFound();
287
      break;
288
289
      case FLT_EXPEDITION_OUTCOME_FOUND_DM:
290
        $this->outcomeDmFound();
291
      break;
292
293
      case FLT_EXPEDITION_OUTCOME_FOUND_ARTIFACT:
294
      break;
295
296
      case FLT_EXPEDITION_OUTCOME_NONE:
297
      default:
298
      break;
299
    }
300
301
302
    // TODO - ДОПИСАТЬ В МОДУЛЕ!
303
    flt_mission_explore_addon_object($this);
304
305
306
    $this->dbPlayerUpdateExpeditionExpirience();
307
    if (!empty($this->darkMatterFound)) {
308
      $this->dbPlayerChangeDarkMatterAmount();
309
    }
310
    foreach ($this->shipsFound as $shipsFoundId => $shipsFoundAmount) {
311
      $this->fleetRecord->changeShipCount($shipsFoundId, $shipsFoundAmount);
312
    }
313
    foreach ($this->shipsLost as $shipsLostId => $shipsLostAmount) {
314
      $this->fleetRecord->changeShipCount($shipsLostId, -$shipsLostAmount);
315
    }
316
    foreach ($this->resourcesFound as $resourceId => $foundAmount) {
317
      $this->fleetRecord->changeResource($resourceId, $foundAmount);
318
    }
319
    $this->dbFleetRecordUpdate();
320
321
    $this->prependMainMessage();
322
    $this->messageDumpUnits('found_dark_matter_new', [RES_DARK_MATTER => $this->darkMatterFound]);
323
    $this->messageDumpUnits('lost_fleet_new', $this->shipsLost);
324
    $this->messageDumpUnits('found_fleet_new', $this->shipsFound);
325
    $this->messageDumpUnits('found_resources_new', $this->resourcesFound);
326
    $this->messageOutcome();
327
  }
328
329
  /**
330
   * @return mixed|null
331
   */
332
  protected function rollOutcome() {
333
    $possibleOutcomes = sn_get_groups(GROUP_MISSION_EXPLORE_OUTCOMES);
334
335
    // Calculating chance that nothing happens
336
    $flt_stay_hours = ($this->fleetRecord->fleet_end_stay - $this->fleetRecord->fleet_start_time) / 3600 * $this->getGameExpeditionSpeed();
337
    $nothingHappenChance = ceil($possibleOutcomes[FLT_EXPEDITION_OUTCOME_NONE]['chance'] / pow($flt_stay_hours, 1 / 1.7));
338
    $possibleOutcomes[FLT_EXPEDITION_OUTCOME_NONE]['chance'] = $nothingHappenChance;
339
340
    return OutcomeManager::rollArray($possibleOutcomes);
341
  }
342
343
  /**
344
   * @return int[] - [(int)$shipId => (int)costInMetal]
345
   */
346
  protected function possibleShipsCosts() {
347
    // Рассчитываем стоимость самого дорого корабля в металле
348
    $max_metal_cost = 0;
349
    foreach ($this->fleetRecord->getShipList() as $ship_id => $ship_amount) {
350
      $max_metal_cost = max($max_metal_cost, $this->fleetRecord->getShipCostInMetal($ship_id));
351
    }
352
353
    // Ограничиваем корабли только теми, чья стоимость в металле меньше или равно стоимости самого дорогого корабля
354
    $can_be_found = [];
355
    foreach ($this->fleetRecord->getShipList() as $shipId => $shipAmount) {
356
      $metalCost = $this->fleetRecord->getShipCostInMetal($shipId);
357
      if (!empty($metalCost) && $metalCost < $max_metal_cost && empty(get_unit_param($shipId, 'player_race'))) {
358
        $can_be_found[$ship_id] = $metalCost;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ship_id seems to be defined by a foreach iteration on line 349. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
359
      }
360
    }
361
362
    // Убираем колонизаторы и шпионов - миллиарды шпионов и колонизаторов нам не нужны
363
    foreach ($this->shipsToRemove as $unitId) {
364
      unset($can_be_found[$unitId]);
365
    }
366
367
    return $can_be_found;
368
  }
369
370
  /**
371
   * @param int   $messageSubId
372
   * @param array $unitArray - [(int)unitSnId => (float)unitAmount]
373
   */
374
  protected function messageDumpUnits($messageSubId, $unitArray) {
375
    if (empty($unitArray)) {
376
      return;
377
    }
378
379
    $this->message[] = $this->lang['flt_mission_expedition'][$messageSubId];
380
    foreach ($unitArray as $unitSnId => $unitAmount) {
381
      if (empty($unitAmount)) {
382
        continue;
383
      }
384
385
      $this->message[] = $this->lang['tech'][$unitSnId] . ' x ' . $unitAmount;
386
    }
387
  }
388
389
  protected function messageOutcome() {
390
    $msg_text = sprintf(implode("\r\n", $this->message), $this->fleetRecord->id, uni_render_coordinates($this->fleet, 'fleet_end_'));
391
    $msg_sender = classSupernova::$lang['flt_mission_expedition']['msg_sender'];
392
    $msg_title = classSupernova::$lang['flt_mission_expedition']['msg_title'];
393
    $this->msgSendMessage($msg_sender, $msg_title, $msg_text);
394
  }
395
396
397
  // Wrappers to mock ==================================================================================================
398
399
  // DB wrappers -------------------------------------------------------------------------------------------------------
400
  protected function dbFleetRecordUpdate() {
401
    $this->fleetRecord->update();
402
  }
403
404
  protected function dbPlayerUpdateExpeditionExpirience() {
405
    db_user_set_by_id($this->fleetRecord->fleet_owner, "`player_rpg_explore_xp` = `player_rpg_explore_xp` + 1");
0 ignored issues
show
Deprecated Code introduced by
The function db_user_set_by_id() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

405
    /** @scrutinizer ignore-deprecated */ db_user_set_by_id($this->fleetRecord->fleet_owner, "`player_rpg_explore_xp` = `player_rpg_explore_xp` + 1");
Loading history...
406
  }
407
408
  protected function dbPlayerChangeDarkMatterAmount() {
409
    rpg_points_change($this->fleet['fleet_owner'], RPG_EXPEDITION, $this->darkMatterFound, 'Expedition Bonus');
410
  }
411
412
413
  // Global procedures wrappers ----------------------------------------------------------------------------------------
414
415
  /**
416
   * Wrapper for game expedition speed
417
   *
418
   * @return float|int
419
   */
420
  protected function getGameExpeditionSpeed() {
421
    return classSupernova::$config->game_speed_expedition ? classSupernova::$config->game_speed_expedition : 1;
422
  }
423
424
  protected function getGameMiningSpeed() {
425
    return game_resource_multiplier(true);
426
  }
427
428
  /**
429
   * Wrapper to send message
430
   *
431
   * @param $msg_sender
432
   * @param $msg_title
433
   * @param $msg_text
434
   */
435
  protected function msgSendMessage($msg_sender, $msg_title, $msg_text) {
436
    msg_send_simple_message($this->fleetRecord->fleet_owner, '', $this->fleetRecord->fleet_end_stay, MSG_TYPE_EXPLORE, $msg_sender, $msg_title, $msg_text);
437
  }
438
439
440
  // Randomizers -------------------------------------------------------------------------------------------------------
441
442
  /**
443
   * @param int $min
444
   * @param int $max
445
   *
446
   * @return int
447
   */
448
  protected function getRandomOutcomeValue($min, $max) {
449
    return mt_rand($min, $max);
450
  }
451
452
  /**
453
   * @return float|int
454
   */
455
  protected function getRandomFoundDmMultiplier() {
456
    return mt_rand(750000, 1000000) / 1000000;
457
  }
458
459
  /**
460
   * @return float|int
461
   */
462
  protected function getRandomFoundResourcesMultiplier() {
463
    return mt_rand(900000, 1100000) / 1000000;
464
  }
465
466
  /**
467
   * @return float|int
468
   */
469
  protected function getRandomFoundMetalMultiplier() {
470
    return mt_rand(300000, 700000) / 1000000;
471
  }
472
473
  /**
474
   * @return float|int
475
   */
476
  protected function getRandomFoundCrystalMultiplier() {
477
    return mt_rand(500000, 1000000) / 1000000;
478
  }
479
480
  /**
481
   * @return float|int
482
   */
483
  protected function getRandomFleetPartLostMultiplier() {
484
    return mt_rand(1, 3) * mt_rand(200000, 300000) / 1000000;
485
  }
486
487
}
488