src/scripts/component/generators.js   B
last analyzed

Complexity

Total Complexity 38
Complexity/F 2.53

Size

Lines of Code 212
Function Count 15

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 0
wmc 38
nc 4
mnd 5
bc 36
fnc 15
dl 0
loc 212
rs 8.3999
bpm 2.4
cpm 2.5333
noi 1
c 3
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B angular.controller(ꞌct_generatorsꞌ) 0 202 1
1
/**
2
 generators
3
 Component that handles generators, resource creation, isotopes and decay.
4
5
 @namespace Components
6
 */
7
'use strict';
8
9
angular.module('game').component('generators', {
10
  templateUrl: 'views/generators.html',
11
  controller: 'ct_generators',
12
  controllerAs: 'ct'
13
});
14
15
angular.module('game').controller('ct_generators', ['state', 'visibility', 'data', 'util', 'reaction', 'upgrade',
16
  function (state, visibility, data, util, reaction, upgrade) {
17
    let ct = this;
18
    ct.state = state;
19
    ct.data = data;
20
    ct.util = util;
21
    ct.buyAmount = [1, 10, 25, 100, 'max'];
22
23
    /* Proceses the decay of radiactive isotopes. It uses a random draw based on the
24
    half life to decide how many atoms decay, and then spreads them over different
25
    decay forms proportionally. */
26
    function processDecay(player) {
27
      // for each radiactive isotope
28
      for (let i = 0; i < data.radioisotopes.length; i++) {
29
        let resource = data.radioisotopes[i];
30
        if (player.resources[resource] !== null) {
31
          let number = player.resources[resource];
32
          let decay = data.resources[resource].decay;
33
          let halfLife = decay.half_life;
34
          let decayRate = Math.log(2)/halfLife;
35
          let totalProduction = number * decayRate;
36
          let remaining = Math.floor(totalProduction);
37
          // and decay products
38
          let highestRatio;
39
          for (let key in decay.decay_types) {
40
            let type = decay.decay_types[key];
41
            if(!highestRatio || highestRatio.ratio < type.ratio){
42
              highestRatio = type;
43
            }
44
            let production = totalProduction * type.ratio;
45
            // if production is less than one, do a random draw
46
            if(production < 1){
47
              let draw = Math.random();
48
              if(draw < production){
49
                production = 1;
50
              }
51
            }
52
            production = Math.floor(production);
53
54
            // FIXME: this is a hack to fix decay not working if the number of
55
            // neutrons is lower than the decay amount. Fixing starvation
56
            // should fix this one as well
57
            if (type.reaction.reactant && type.reaction.reactant.n) {
58
              production = Math.min(production, player.resources.n);
59
            }
60
            state.reactions.push({number: production, reaction:type.reaction});
61
            remaining -= production;
62
          }
63
          state.reactions.push({number: remaining, reaction: highestRatio.reaction});
0 ignored issues
show
Bug introduced by
The variable highestRatio seems to not be initialized for all possible execution paths.
Loading history...
64
        }
65
      }
66
    }
67
68
    /* Proceses the generation for each element. It generates isotopes with a random
69
    draw proportionally to their probability. */
70
    function processGenerators(player) {
71
      // we will simulate the production of isotopes proportional to their ratio
72
      for (let slot of player.element_slots) {
73
        if(!slot){
74
          continue;
75
        }
76
        let totalProduction = ct.elementProduction(player, slot);
77
        let remaining = totalProduction;
78
        // for each isotope
79
        for (let key in data.elements[slot.element].isotopes) {
80
          let isotope = data.elements[slot.element].isotopes[key];
81
          // we calculate the production proportion
82
          let production = isotope.ratio * totalProduction;
83
          // if production is less than one, do a random draw
84
          if(production < 1){
85
            let draw = Math.random();
86
            if(draw < production){
87
              production = 1;
88
            }
89
          }
90
91
          production = Math.floor(production);
92
93
          // assign the player the produced isotope
94
          util.addResource(player, [slot.element], key, production, state);
95
96
          // keep track of the remaining production
97
          remaining -= production;
98
        }
99
        // if there is remaining production, we assign it to the main isotope
100
        let main = data.elements[slot.element].main;
101
        // we don't want negative remaining
102
        remaining = Math.max(0, remaining);
103
        util.addResource(player, [slot.element], main, remaining, state);
104
      }
105
    }
106
107
    function update(player) {
108
      processDecay(player);
109
      processGenerators(player);
110
    }
111
112
    function generatorPrice(name, level) {
113
      return data.generators[name].price * Math.pow(data.generators[name].price_exp, level);
114
    }
115
116
    ct.maxCanBuy = function (player, name, slot) {
117
      let level = slot.generators[name];
118
      let i = 0;
119
      let currency = data.elements[slot.element].main;
120
      let price = generatorPrice(name, level);
121
      // we need a loop since we use the ceil operator
122
      while (player.resources[currency] >= price) {
123
        i++;
124
        price += generatorPrice(name, level + i);
125
      }
126
      return i;
127
    };
128
129
    ct.generatorTotalPrice = function (player, name, slot, number) {
130
      if (number === 'max') {
131
        number = ct.maxCanBuy(player, name, slot);
132
      }
133
      number = Math.max(number, 1);
134
135
      let level = slot.generators[name];
136
      let totalPrice = 0;
137
      for (let i = 0; i < number; i++) {
138
        let price = generatorPrice(name, level + i);
139
        totalPrice += Math.ceil(price);
140
      }
141
      return totalPrice;
142
    };
143
144
    ct.buyGenerators = function (player, name, slot, number) {
145
      if (number === 'max') {
146
        number = ct.maxCanBuy(player, name, slot);
147
      }
148
      let price = this.generatorTotalPrice(player, name, slot, number);
149
      let currency = data.elements[slot.element].main;
150
      if (ct.canBuy(player, slot, price)) {
151
        player.resources[currency] -= price;
152
        slot.generators[name] += number;
153
      }
154
    };
155
156
    ct.canBuy = function (player, slot, price) {
157
      let currency = data.elements[slot.element].main;
158
      if (price > player.resources[currency]) {
159
        return false;
160
      }
161
      return true;
162
    };
163
164
    ct.generatorProduction = function (player, name, slot) {
165
      let baseProduction = data.generators[name].power;
166
      return upgradedProduction(player, baseProduction, name, slot);
167
    };
168
169
    ct.tierProduction = function (player, name, slot) {
170
      let baseProduction = data.generators[name].power *
171
        slot.generators[name];
172
      return upgradedProduction(player, baseProduction, name, slot);
173
    };
174
175
    /* Upgraded production includes upgrades, exotic matter and dark matter. */
176
    function upgradedProduction(player, production, name, slot) {
177
      let args = {
178
        production: production,
179
        slot: slot
180
      };
181
182
      upgrade.executeAll(data.upgrades, slot.upgrades, [name, 'production'], args);
183
184
      // extract back the value from applying the upgrades
185
      let newProduction = args.production;
186
187
      let exotic = data.elements[slot.element].exotic;
188
      newProduction *= (1 + player.resources[exotic] * data.constants.EXOTIC_POWER) *
189
        (1 + player.resources.dark_matter * data.constants.DARK_POWER);
190
      return Math.floor(newProduction);
191
    }
192
193
    ct.elementProduction = function (player, slot) {
194
      let total = 0;
195
      for (let tier in data.generators) {
196
        total += ct.tierProduction(player, tier, slot);
197
      }
198
      return total;
199
    };
200
201
    ct.visibleGenerators = function (slot) {
202
      return visibility.visible(data.generators, isGeneratorVisible, slot);
203
    };
204
205
    function isGeneratorVisible(name, slot) {
206
      let generator = data.generators[name];
207
      for (let dep of generator.deps) {
208
        if (slot.generators[dep] === 0) {
209
          return false;
210
        }
211
      }
212
213
      return true;
214
    }
215
216
    state.registerUpdate('generators', update);
217
  }
218
]);
219