|
1
|
|
|
/** |
|
2
|
|
|
redox |
|
3
|
|
|
Component that handles reduction/oxidation and ions. |
|
4
|
|
|
|
|
5
|
|
|
@namespace Components |
|
6
|
|
|
*/ |
|
7
|
|
|
'use strict'; |
|
8
|
|
|
|
|
9
|
|
|
angular.module('game').component('redox', { |
|
10
|
|
|
templateUrl: 'views/redox.html', |
|
11
|
|
|
controller: 'ct_redox', |
|
12
|
|
|
controllerAs: 'ct' |
|
13
|
|
|
}); |
|
14
|
|
|
|
|
15
|
|
|
angular.module('game').controller('ct_redox', ['state', 'data', 'visibility', 'util', 'format', 'reaction', 'upgrade', |
|
16
|
|
|
function (state, data, visibility, util, format, reaction, upgradeService) { |
|
17
|
|
|
let ct = this; |
|
18
|
|
|
ct.state = state; |
|
19
|
|
|
ct.data = data; |
|
20
|
|
|
ct.util = util; |
|
21
|
|
|
ct.format = format; |
|
22
|
|
|
ct.reaction = reaction; |
|
23
|
|
|
ct.upgradeService = upgradeService; |
|
24
|
|
|
ct.adjustAmount = [1, 10, 25, 100]; |
|
25
|
|
|
|
|
26
|
|
|
ct.update = function(player) { |
|
27
|
|
|
processRedox(player); |
|
28
|
|
|
processElectronegativity(player); |
|
29
|
|
|
}; |
|
30
|
|
|
|
|
31
|
|
|
function processRedox(player){ |
|
32
|
|
|
for(let slot of player.element_slots){ |
|
33
|
|
|
if(!slot){ |
|
34
|
|
|
continue; |
|
35
|
|
|
} |
|
36
|
|
|
for (let redox of slot.redoxes) { |
|
37
|
|
|
if (!redox.resource || !redox.active || redox.from === redox.to) { |
|
38
|
|
|
continue; |
|
39
|
|
|
} |
|
40
|
|
|
|
|
41
|
|
|
let reactant = ct.generateName(redox.element, redox.from); |
|
42
|
|
|
let power = util.calculateValue(data.global_upgrades.redox_bandwidth.power.base, |
|
43
|
|
|
data.global_upgrades.redox_bandwidth.power, |
|
44
|
|
|
player.global_upgrades_current.redox_bandwidth); |
|
45
|
|
|
let number = Math.min(power, player.resources[reactant].number); |
|
46
|
|
|
let react = ct.redoxReaction(redox); |
|
47
|
|
|
|
|
48
|
|
|
ct.reaction.react(number, react, player); |
|
49
|
|
|
} |
|
50
|
|
|
} |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
function processElectronegativity(player){ |
|
54
|
|
|
for(let key in data.elements){ |
|
55
|
|
|
let element = data.elements[key]; |
|
56
|
|
|
if(element.electronegativity === 0){ |
|
57
|
|
|
continue; |
|
58
|
|
|
} |
|
59
|
|
|
let ions = element.anions.concat(element.cations); |
|
60
|
|
|
ions.push(element.main); |
|
61
|
|
|
for(let resource of ions){ |
|
62
|
|
|
if(player.resources[resource].number === 0){ |
|
63
|
|
|
continue; |
|
64
|
|
|
} |
|
65
|
|
|
let charge = data.resources[resource].charge || 0; |
|
66
|
|
|
let probabilities = probabilityDistribution(key, charge); |
|
67
|
|
|
for(let probKey in probabilities){ |
|
68
|
|
|
if(charge === parseInt(probKey, 10)) continue; |
|
|
|
|
|
|
69
|
|
|
let production = Math.floor(probabilities[probKey]*player.resources[resource].number); |
|
70
|
|
|
if(production === 0){ |
|
71
|
|
|
continue; |
|
72
|
|
|
} |
|
73
|
|
|
let react = ct.redoxReaction({ |
|
74
|
|
|
element: key, |
|
75
|
|
|
from: charge, |
|
76
|
|
|
to: parseInt(probKey, 10) |
|
77
|
|
|
}); |
|
78
|
|
|
// electronegativity is 'for free' |
|
79
|
|
|
react.reactant.eV = 0; |
|
80
|
|
|
// FIXME: starvation should fix this |
|
81
|
|
|
if(react.reactant['e-']){ |
|
82
|
|
|
production = Math.min(production, player.resources['e-'].number); |
|
83
|
|
|
} |
|
84
|
|
|
ct.reaction.react(production, react, player); |
|
85
|
|
|
} |
|
86
|
|
|
} |
|
87
|
|
|
} |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
function probabilityDistribution(element, charge){ |
|
91
|
|
|
let prob = {}; |
|
92
|
|
|
let start = -data.elements[element].electron_affinity.length; |
|
93
|
|
|
let end = charge; |
|
94
|
|
|
// lower than index, affected by negativity |
|
95
|
|
|
rangeProbability(element, prob, start, end, 1, data.elements[element].negative_factor); |
|
96
|
|
|
|
|
97
|
|
|
prob[charge] = 1; |
|
98
|
|
|
|
|
99
|
|
|
start = charge+1; |
|
100
|
|
|
end = data.elements[element].ionization_energy.length+1; |
|
101
|
|
|
// lower than index, affected by positivity |
|
102
|
|
|
rangeProbability(element, prob, start, end, -1, data.elements[element].positive_factor); |
|
103
|
|
|
|
|
104
|
|
|
let sum = 0; |
|
105
|
|
|
for(let i in prob){ |
|
106
|
|
|
sum += prob[i]; |
|
107
|
|
|
} |
|
108
|
|
|
for(let i in prob){ |
|
109
|
|
|
prob[i] /= sum; |
|
110
|
|
|
} |
|
111
|
|
|
return prob; |
|
112
|
|
|
} |
|
113
|
|
|
|
|
114
|
|
|
function rangeProbability(element, prob, start, end, offset, factor){ |
|
115
|
|
|
for(let i = start; i < end; i++){ |
|
116
|
|
|
let difference = data.redox[element][i]-data.redox[element][i+offset]; |
|
117
|
|
|
if(difference <= 0){ |
|
118
|
|
|
difference = -difference; |
|
119
|
|
|
}else{ |
|
120
|
|
|
difference = 1/difference; |
|
121
|
|
|
} |
|
122
|
|
|
prob[i] = Math.pow(data.constants.ELECTRONEGATIVITY_CHANCE,Math.abs(i))*factor*difference; |
|
123
|
|
|
} |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
/* Writes a redox in the form of a reaction so that we can use the reaction |
|
127
|
|
|
service to process it */ |
|
128
|
|
|
ct.redoxReaction = function (redox) { |
|
129
|
|
|
let reactant = ct.generateName(redox.element, redox.from); |
|
130
|
|
|
let product = ct.generateName(redox.element, redox.to); |
|
131
|
|
|
let energy = redoxEnergy(redox.from, redox.to, redox.element); |
|
132
|
|
|
|
|
133
|
|
|
let react = { |
|
134
|
|
|
'reactant': {}, |
|
135
|
|
|
'product': {} |
|
136
|
|
|
}; |
|
137
|
|
|
|
|
138
|
|
|
react.reactant[reactant] = 1; |
|
139
|
|
|
react.product[product] = 1; |
|
140
|
|
|
if (energy > 0) { |
|
141
|
|
|
react.reactant.eV = energy; |
|
142
|
|
|
} else if (energy < 0) { |
|
143
|
|
|
react.product.eV = -energy; |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
let electron = redox.from - redox.to; |
|
147
|
|
|
if (electron > 0) { |
|
148
|
|
|
react.reactant['e-'] = electron; |
|
149
|
|
|
} else if (electron < 0) { |
|
150
|
|
|
react.product['e-'] = -electron; |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
return react; |
|
154
|
|
|
}; |
|
155
|
|
|
|
|
156
|
|
|
/* Calculates how much energy it takes to go from a redox level to another |
|
157
|
|
|
for a given element */ |
|
158
|
|
|
function redoxEnergy(from, to, element) { |
|
159
|
|
|
let energyFrom = data.redox[element][from]; |
|
160
|
|
|
let energyTo = data.redox[element][to]; |
|
161
|
|
|
let energy = energyTo - energyFrom; |
|
162
|
|
|
|
|
163
|
|
|
return energy; |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
/* Generates the name of a ion, e.g. O3+ */ |
|
167
|
|
|
ct.generateName = function (element, i) { |
|
168
|
|
|
if (i === 0) { |
|
169
|
|
|
return data.elements[element].main; |
|
170
|
|
|
} |
|
171
|
|
|
let postfix = ''; |
|
172
|
|
|
if (Math.abs(i) > 1) { |
|
173
|
|
|
postfix = Math.abs(i); |
|
174
|
|
|
} |
|
175
|
|
|
postfix += getSign(i); |
|
176
|
|
|
let name = element + postfix; |
|
177
|
|
|
return name; |
|
178
|
|
|
}; |
|
179
|
|
|
|
|
180
|
|
|
function getSign(number) { |
|
181
|
|
|
return number > 0 ? '+' : '-'; |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
ct.redoxSize = function (player) { |
|
185
|
|
|
let size = 0; |
|
186
|
|
|
for(let slot of player.element_slots){ |
|
187
|
|
|
if(!slot){ |
|
188
|
|
|
continue; |
|
189
|
|
|
} |
|
190
|
|
|
size += slot.redoxes.length; |
|
191
|
|
|
} |
|
192
|
|
|
return size; |
|
193
|
|
|
}; |
|
194
|
|
|
|
|
195
|
|
|
/* Adds a new redox to the player list */ |
|
196
|
|
|
ct.addRedox = function (player, slot) { |
|
197
|
|
|
if(ct.redoxSize(player) >= util.calculateValue(data.global_upgrades.redox_slots.power.base, |
|
198
|
|
|
data.global_upgrades.redox_slots.power, |
|
199
|
|
|
player.global_upgrades.redox_slots)){ |
|
200
|
|
|
return; |
|
201
|
|
|
} |
|
202
|
|
|
slot.redoxes.push({ |
|
203
|
|
|
resource: data.elements[slot.element].main, |
|
204
|
|
|
active: false, |
|
205
|
|
|
element: slot.element, |
|
206
|
|
|
from: 0, |
|
207
|
|
|
to: 1 |
|
208
|
|
|
}); |
|
209
|
|
|
}; |
|
210
|
|
|
|
|
211
|
|
|
ct.removeRedox = function (slot, index) { |
|
212
|
|
|
slot.redoxes.splice(index, 1); |
|
213
|
|
|
}; |
|
214
|
|
|
|
|
215
|
|
|
ct.checkAll = function(slot){ |
|
216
|
|
|
for(let redox of slot.redoxes){ |
|
217
|
|
|
redox.active = slot.active; |
|
218
|
|
|
} |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
ct.visibleRedox = function(slot) { |
|
222
|
|
|
return slot.redoxes; |
|
223
|
|
|
}; |
|
224
|
|
|
|
|
225
|
|
|
ct.adjustLevel = function(player, upgrade, amount){ |
|
226
|
|
|
player.global_upgrades_current[upgrade] += amount; |
|
227
|
|
|
// We cap it between 1 and the current max level |
|
228
|
|
|
player.global_upgrades_current[upgrade] = Math.max(1, Math.min(player.global_upgrades_current[upgrade], player.global_upgrades[upgrade])); |
|
229
|
|
|
}; |
|
230
|
|
|
|
|
231
|
|
|
ct.visibleUpgrades = function() { |
|
232
|
|
|
return visibility.visible(data.global_upgrades, upgradeService.filterByTag('redoxes')); |
|
233
|
|
|
}; |
|
234
|
|
|
|
|
235
|
|
|
state.registerUpdate('redox', ct.update); |
|
236
|
|
|
} |
|
237
|
|
|
]); |
|
238
|
|
|
|
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.
Consider:
If you or someone else later decides to put another statement in, only the first statement will be executed.
In this case the statement
b = 42will always be executed, while the logging statement will be executed conditionally.ensures that the proper code will be executed conditionally no matter how many statements are added or removed.