Completed
Push — master ( fdd593...5aa3de )
by Andres
30s
created

angular.controller(ꞌct_generatorsꞌ)   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

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