Completed
Push — trunk ( 8dcff2...338765 )
by SuperNova.WS
04:11
created

getStackableUnitsCost()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 10
nc 8
nop 2
dl 0
loc 20
rs 8.8571
c 1
b 0
f 0
1
<?php
2
3
use Unit\DBStaticUnit;
4
5
/**
6
 * Created by Gorlum 04.12.2017 4:32
7
 */
8
9
function eco_get_total_cost($unit_id, $unit_level) {
10
  static $rate, $sn_group_resources_all, $sn_group_resources_loot;
11
  if (!$rate) {
12
    $sn_group_resources_all = sn_get_groups('resources_all');
13
    $sn_group_resources_loot = sn_get_groups('resources_loot');
14
15
    $rate[RES_METAL] = SN::$config->rpg_exchange_metal;
0 ignored issues
show
Bug Best Practice introduced by
The property rpg_exchange_metal does not exist on classConfig. Since you implemented __get, consider adding a @property annotation.
Loading history...
16
    $rate[RES_CRYSTAL] = SN::$config->rpg_exchange_crystal / SN::$config->rpg_exchange_metal;
0 ignored issues
show
Bug Best Practice introduced by
The property rpg_exchange_crystal does not exist on classConfig. Since you implemented __get, consider adding a @property annotation.
Loading history...
17
    $rate[RES_DEUTERIUM] = SN::$config->rpg_exchange_deuterium / SN::$config->rpg_exchange_metal;
0 ignored issues
show
Bug Best Practice introduced by
The property rpg_exchange_deuterium does not exist on classConfig. Since you implemented __get, consider adding a @property annotation.
Loading history...
18
  }
19
20
  $unit_cost_data = get_unit_param($unit_id, 'cost');
21
  if (!is_array($unit_cost_data)) {
22
    return array('total' => 0);
23
  }
24
  $factor = isset($unit_cost_data['factor']) ? $unit_cost_data['factor'] : 1;
25
  $cost_array = array(BUILD_CREATE => array(), 'total' => 0);
26
  $unit_level = $unit_level > 0 ? $unit_level : 0;
27
  foreach ($unit_cost_data as $resource_id => $resource_amount) {
28
    if (!in_array($resource_id, $sn_group_resources_all)) {
29
      continue;
30
    }
31
    $cost_array[BUILD_CREATE][$resource_id] = round($resource_amount * ($factor == 1 ? $unit_level : ((1 - pow($factor, $unit_level)) / (1 - $factor))));
32
    if (in_array($resource_id, $sn_group_resources_loot)) {
33
      $cost_array['total'] += $cost_array[BUILD_CREATE][$resource_id] * $rate[$resource_id];
34
    }
35
  }
36
37
  return $cost_array;
38
}
39
40
function sn_unit_purchase($unit_id) { }
41
42
function sn_unit_relocate($unit_id, $from, $to) { }
43
44
/**
45
 * @param array $user
46
 * @param array $planet     ([])
47
 * @param int   $unit_id
48
 * @param bool  $for_update (false)
49
 * @param bool  $plain      (false)
50
 *
51
 * @return int|float|bool
52
 */
53
function mrc_get_level(&$user, $planet = [], $unit_id, $for_update = false, $plain = false) {
54
  $result = null;
55
56
  return sn_function_call(__FUNCTION__, [&$user, $planet, $unit_id, $for_update, $plain, &$result]);
57
}
58
59
function sn_mrc_get_level(&$user, $planet = [], $unit_id, $for_update = false, $plain = false, &$result) {
60
  $mercenary_level = 0;
61
  $unit_db_name = pname_resource_name($unit_id);
62
63
  if (in_array($unit_id, sn_get_groups(array('plans', 'mercenaries', 'tech', 'artifacts')))) {
64
    $unit = !empty($user['id']) ? DBStaticUnit::db_unit_by_location($user['id'], LOC_USER, $user['id'], $unit_id) : 0;
65
    $mercenary_level = !empty($unit['unit_level']) ? $unit['unit_level'] : 0;
66
  } elseif (in_array($unit_id, sn_get_groups(array('structures', 'fleet', 'defense')))) {
67
    $unit = DBStaticUnit::db_unit_by_location(is_array($user) ? $user['id'] : $planet['id_owner'], LOC_PLANET, $planet['id'], $unit_id);
68
    $mercenary_level = !empty($unit['unit_level']) ? $unit['unit_level'] : 0;
69
  } elseif (in_array($unit_id, sn_get_groups('governors'))) {
70
    $mercenary_level = $unit_id == $planet['PLANET_GOVERNOR_ID'] ? $planet['PLANET_GOVERNOR_LEVEL'] : 0;
71
  } elseif ($unit_id == RES_DARK_MATTER) {
72
    $mercenary_level = $user[$unit_db_name] + ($plain || $user['user_as_ally'] ? 0 : SN::$auth->account->account_metamatter);
73
  } elseif ($unit_id == RES_METAMATTER) {
74
    $mercenary_level = SN::$auth->account->account_metamatter; //$user[$unit_db_name];
75
  } elseif (in_array($unit_id, sn_get_groups(array('resources_loot'))) || $unit_id == UNIT_SECTOR) {
76
    $mercenary_level = !empty($planet[$unit_db_name]) ? $planet[$unit_db_name] : $user[$unit_db_name];
77
  }
78
79
  return $result = $mercenary_level;
80
}
81
82
function mrc_modify_value(&$user, $planet = array(), $mercenaries, $value) { return sn_function_call('mrc_modify_value', array(&$user, $planet, $mercenaries, $value)); }
83
84
function sn_mrc_modify_value(&$user, $planet = array(), $mercenaries, $value, $base_value = null) {
85
  if (!is_array($mercenaries)) {
86
    $mercenaries = array($mercenaries);
87
  }
88
89
  $base_value = isset($base_value) ? $base_value : $value;
90
91
  foreach ($mercenaries as $mercenary_id) {
92
    $mercenary_level = mrc_get_level($user, $planet, $mercenary_id);
93
94
    $mercenary = get_unit_param($mercenary_id);
95
    $mercenary_bonus = $mercenary[P_BONUS_VALUE];
96
97
    switch ($mercenary[P_BONUS_TYPE]) {
98
      case BONUS_PERCENT:
99
        $mercenary_level = $mercenary_bonus < 0 && $mercenary_level * $mercenary_bonus < -90 ? -90 / $mercenary_bonus : $mercenary_level;
100
        $value += $base_value * $mercenary_level * $mercenary_bonus / 100;
101
      break;
102
103
      case BONUS_ADD:
104
        $value += $mercenary_level * $mercenary_bonus;
105
      break;
106
107
      case BONUS_ABILITY:
108
        $value = $mercenary_level ? $mercenary_level : 0;
109
      break;
110
111
      default:
112
      break;
113
    }
114
  }
115
116
  return $value;
117
}
118
119
function sys_unit_str2arr($fleet_string) {
120
  $fleet_array = array();
121
  if (!empty($fleet_string)) {
122
    $arrTemp = explode(';', $fleet_string);
123
    foreach ($arrTemp as $temp) {
124
      if ($temp) {
125
        $temp = explode(',', $temp);
126
        if (!empty($temp[0]) && !empty($temp[1])) {
127
          $fleet_array[$temp[0]] += $temp[1];
128
        }
129
      }
130
    }
131
  }
132
133
  return $fleet_array;
134
}
135
136
function sys_unit_arr2str($unit_list) {
137
  $fleet_string = array();
138
  if (isset($unit_list)) {
139
    if (!is_array($unit_list)) {
140
      $unit_list = array($unit_list => 1);
141
    }
142
143
    foreach ($unit_list as $unit_id => $unit_count) {
144
      if ($unit_id && $unit_count) {
145
        $fleet_string[] = "{$unit_id},{$unit_count}";
146
      }
147
    }
148
  }
149
150
  return implode(';', $fleet_string);
151
}
152
153
// TODO Для полноценного функионирования апдейтера пакет функций, включая эту должен быть вынесен раньше - или грузить general.php до апдейтера
154
function sys_get_unit_location($user, $planet, $unit_id) { return sn_function_call('sys_get_unit_location', array($user, $planet, $unit_id)); }
155
156
function sn_sys_get_unit_location($user, $planet, $unit_id) {
157
  return get_unit_param($unit_id, 'location');
158
}
159
160
161
function get_engine_data($user, $engine_info, $user_tech_level = null) {
162
  $sn_data_tech_bonus = get_unit_param($engine_info['tech'], P_BONUS_VALUE);
163
164
  $user_tech_level = $user_tech_level === null ? intval(mrc_get_level($user, false, $engine_info['tech'])) : $user_tech_level;
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type array expected by parameter $planet of mrc_get_level(). ( Ignorable by Annotation )

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

164
  $user_tech_level = $user_tech_level === null ? intval(mrc_get_level($user, /** @scrutinizer ignore-type */ false, $engine_info['tech'])) : $user_tech_level;
Loading history...
165
166
  $engine_info['speed_base'] = $engine_info['speed'];
167
  $tech_bonus = ($user_tech_level - $engine_info['min_level']) * $sn_data_tech_bonus / 100;
168
  $tech_bonus = $tech_bonus < -0.9 ? -0.95 : $tech_bonus;
169
  $engine_info['speed'] = floor(mrc_modify_value($user, false, array(MRC_NAVIGATOR), $engine_info['speed']) * (1 + $tech_bonus));
170
171
  $engine_info['consumption_base'] = $engine_info['consumption'];
172
  $tech_bonus = ($user_tech_level - $engine_info['min_level']) * $sn_data_tech_bonus / 1000;
173
  $tech_bonus = $tech_bonus > 0.5 ? 0.5 : ($tech_bonus < 0 ? $tech_bonus * 2 : $tech_bonus);
174
  $engine_info['consumption'] = ceil($engine_info['consumption'] * (1 - $tech_bonus));
175
176
  return $engine_info;
177
}
178
179
function get_ship_data($ship_id, $user) {
180
  $ship_data = array();
181
  if (in_array($ship_id, sn_get_groups(array('fleet', 'missile')))) {
182
    foreach (get_unit_param($ship_id, 'engine') as $engine_info) {
183
      $tech_level = intval(mrc_get_level($user, false, $engine_info['tech']));
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type array expected by parameter $planet of mrc_get_level(). ( Ignorable by Annotation )

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

183
      $tech_level = intval(mrc_get_level($user, /** @scrutinizer ignore-type */ false, $engine_info['tech']));
Loading history...
184
      if (empty($ship_data) || $tech_level >= $engine_info['min_level']) {
185
        $ship_data = $engine_info;
186
        $ship_data['tech_level'] = $tech_level;
187
      }
188
    }
189
    $ship_data = get_engine_data($user, $ship_data);
190
    $ship_data['capacity'] = get_unit_param($ship_id, 'capacity');
191
  }
192
193
  return $ship_data;
194
}
195
196
/**
197
 * Get unit info by unit's SN ID
198
 *
199
 * @param int $unitSnId
200
 *
201
 * @return mixed
202
 */
203
function getUnitInfo($unitSnId) {
204
  return get_unit_param($unitSnId);
205
}
206
207
function get_unit_param($unit_id, $param_name = null, $user = null, $planet = null) {
208
  $result = null;
209
210
  return sn_function_call('get_unit_param', array($unit_id, $param_name, $user, $planet, &$result));
211
}
212
213
function sn_get_unit_param($unit_id, $param_name = null, $user = null, $planet = null, &$result) {
214
  global $sn_data;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
215
216
  $result = isset($sn_data[$unit_id])
217
    ? ($param_name === null
218
      ? $sn_data[$unit_id]
219
      : (isset($sn_data[$unit_id][$param_name]) ? $sn_data[$unit_id][$param_name] : $result)
220
    )
221
    : $result;
222
223
  return $result;
224
}
225
226
/**
227
 * @param string|string[] $groups
228
 *
229
 * @return array|array[]
230
 */
231
function sn_get_groups($groups) {
232
  $result = null;
233
234
  return sn_function_call('sn_get_groups', array($groups, &$result));
235
}
236
237
function sn_sn_get_groups($groups, &$result) {
238
  $result = is_array($result) ? $result : array();
239
  foreach ($groups = is_array($groups) ? $groups : array($groups) as $group_name) {
0 ignored issues
show
Unused Code introduced by
The assignment to $groups is dead and can be removed.
Loading history...
240
    $result += is_array($a_group = get_unit_param(UNIT_GROUP, $group_name)) ? $a_group : array();
241
  }
242
243
  return $result;
244
}
245
246
247
function unit_requirements_render($user, $planetrow, $unit_id, $field = P_REQUIRE) {
248
  $result = null;
249
250
  return sn_function_call('unit_requirements_render', array($user, $planetrow, $unit_id, $field, &$result));
251
}
252
253
function sn_unit_requirements_render($user, $planetrow, $unit_id, $field = P_REQUIRE, &$result) {
254
  global $lang, $config;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
255
256
  $sn_data_unit = get_unit_param($unit_id);
257
258
  $result = is_array($result) ? $result : array();
259
  if ($sn_data_unit[$field] && !($sn_data_unit[P_UNIT_TYPE] == UNIT_MERCENARIES && SN::$config->empire_mercenary_temporary)) {
260
    foreach ($sn_data_unit[$field] as $require_id => $require_level) {
261
      $level_got = mrc_get_level($user, $planetrow, $require_id);
262
      $level_basic = mrc_get_level($user, $planetrow, $require_id, false, true);
263
      $result[] = array(
264
        'NAME'             => $lang['tech'][$require_id],
265
        //'CLASS' => $require_level > $level_got ? 'negative' : ($require_level == $level_got ? 'zero' : 'positive'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
266
        'REQUEREMENTS_MET' => intval($require_level <= $level_got ? REQUIRE_MET : REQUIRE_MET_NOT),
267
        'LEVEL_REQUIRE'    => $require_level,
268
        'LEVEL'            => $level_got,
269
        'LEVEL_BASIC'      => $level_basic,
270
        'LEVEL_BONUS'      => max(0, $level_got - $level_basic),
271
        'ID'               => $require_id,
272
      );
273
    }
274
  }
275
276
  return $result;
277
}
278
279
/**
280
 * @param array $cost        - [(int)resourceId => (float)unitAmount] => [RES_CRYSTAL => 100]
281
 * @param int   $in_resource - RES_METAL...
282
 *
283
 * @return float|int
284
 */
285
function get_unit_cost_in($cost, $in_resource = RES_METAL) {
286
  static $rates;
287
288
  if (!$rates) {
289
    $rates = SN::$gc->economicHelper->getResourcesExchange();
290
  }
291
292
  unset($cost[P_FACTOR]);
293
294
  $mainResourceExchange = !empty($rates[$in_resource]) ? $rates[$in_resource] : 1;
295
  $metal_cost = 0;
296
  foreach ($cost as $resource_id => $resource_value) {
297
    if (empty($rates[$resource_id])) {
298
      continue;
299
    }
300
301
    $metal_cost += $rates[$resource_id] / $mainResourceExchange * $resource_value;
302
  }
303
304
  return $metal_cost;
305
}
306
307
/**
308
 * Calculates cost of STACKABLE unit in specified resource
309
 *
310
 * @param int|float[] $units - unit ID or array [unitId => unitAmount]
311
 * @param int         $costResourceId
312
 *
313
 * @return float|int
314
 */
315
function getStackableUnitsCost($units, $costResourceId = RES_METAL) {
316
  static $costCache;
317
318
  $result = 0;
319
320
  if (!is_array($units)) {
321
    $units = [$units => 1];
322
  }
323
324
  foreach ($units as $unitId => $unitAmount) {
325
    if (!isset($costCache[$unitId][$costResourceId])) {
326
      $unitInfo = get_unit_param($unitId);
327
328
      $costCache[$unitId][$costResourceId] = !empty($unitInfo[P_COST]) ? get_unit_cost_in($unitInfo[P_COST], $costResourceId) : 0;
329
    }
330
331
    $result += $costCache[$unitId][$costResourceId] * $unitAmount;
332
  }
333
334
  return $result;
335
}
336