Completed
Push — master ( 3d8cea...e34b6f )
by Andres
36s
created

angular.controller(ꞌct_generatorsꞌ)   D

Complexity

Conditions 10
Paths 16

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 16
dl 0
loc 43
rs 4.8196
c 0
b 0
f 0
nop 1

How to fix   Complexity   

Complexity

Complex classes like angular.controller(ꞌct_generatorsꞌ) often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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