@schedule1-tools/mixer 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +54 -0
- package/dist/core/effectSet.d.ts +41 -0
- package/dist/core/effectSet.js +137 -0
- package/dist/core/mixer.d.ts +5 -0
- package/dist/core/mixer.js +173 -0
- package/dist/data/effects.d.ts +2 -0
- package/dist/data/effects.js +175 -0
- package/dist/data/products.d.ts +3 -0
- package/dist/data/products.js +39 -0
- package/dist/data/rules.d.ts +2 -0
- package/dist/data/rules.js +152 -0
- package/dist/data/substances.d.ts +2 -0
- package/dist/data/substances.js +101 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +19 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.js +2 -0
- package/dist/utils/encoding.d.ts +9 -0
- package/dist/utils/encoding.js +67 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Schedule1 Tools
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Schedule1 Mixer
|
|
2
|
+
|
|
3
|
+
A package for calculating substance mixes in the game Schedule 1.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @schedule1-tools/mixer
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { mixSubstances, encodeMixState, decodeMixState } from '@schedule1-tools/mixer';
|
|
15
|
+
|
|
16
|
+
// Calculate a mix
|
|
17
|
+
const result = mixSubstances('OG Kush', ['A', 'B', 'C']);
|
|
18
|
+
console.log(result);
|
|
19
|
+
/*
|
|
20
|
+
{
|
|
21
|
+
effects: ['En', 'Se', 'To'],
|
|
22
|
+
cost: 12,
|
|
23
|
+
sellPrice: 42,
|
|
24
|
+
profit: -5,
|
|
25
|
+
profitMargin: -0.119
|
|
26
|
+
}
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// Encode a mix state for sharing
|
|
30
|
+
const encoded = encodeMixState({
|
|
31
|
+
product: 'OG Kush',
|
|
32
|
+
substances: ['A', 'B', 'C'],
|
|
33
|
+
});
|
|
34
|
+
console.log(encoded); // "T0cgS3VzaDpBQkM"
|
|
35
|
+
|
|
36
|
+
// Decode a mix state
|
|
37
|
+
const decoded = decodeMixState('T0cgS3VzaDpBQkM');
|
|
38
|
+
console.log(decoded);
|
|
39
|
+
/*
|
|
40
|
+
{
|
|
41
|
+
product: 'OG Kush',
|
|
42
|
+
substances: ['A', 'B', 'C']
|
|
43
|
+
}
|
|
44
|
+
*/
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Exports
|
|
48
|
+
|
|
49
|
+
The package also exports the following data objects:
|
|
50
|
+
|
|
51
|
+
- `effects`: Information about all effects
|
|
52
|
+
- `products`: Information about all products
|
|
53
|
+
- `substances`: Information about all substances
|
|
54
|
+
- `effectRulesBySubstance`: Rules for how substances transform effects
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { EffectCode } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* A class for efficiently managing a set of effects using a bitset
|
|
4
|
+
*/
|
|
5
|
+
export declare class EffectSet {
|
|
6
|
+
private static readonly effectToIndex;
|
|
7
|
+
private static readonly indexToEffect;
|
|
8
|
+
private static initialized;
|
|
9
|
+
private bits;
|
|
10
|
+
/**
|
|
11
|
+
* Initialize the static mapping between effect codes and bit positions
|
|
12
|
+
*/
|
|
13
|
+
private static initialize;
|
|
14
|
+
constructor(initialEffects?: EffectCode[]);
|
|
15
|
+
/**
|
|
16
|
+
* Add an effect to the set
|
|
17
|
+
* @returns true if the effect was added, false if it was already present
|
|
18
|
+
*/
|
|
19
|
+
add(effect: EffectCode): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Remove an effect from the set
|
|
22
|
+
* @returns true if the effect was removed, false if it wasn't present
|
|
23
|
+
*/
|
|
24
|
+
remove(effect: EffectCode): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Check if an effect is in the set
|
|
27
|
+
*/
|
|
28
|
+
has(effect: EffectCode): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Convert the set to an array of effect codes
|
|
31
|
+
*/
|
|
32
|
+
toArray(): EffectCode[];
|
|
33
|
+
/**
|
|
34
|
+
* Get the number of effects in the set
|
|
35
|
+
*/
|
|
36
|
+
size(): number;
|
|
37
|
+
/**
|
|
38
|
+
* Create a copy of this effect set
|
|
39
|
+
*/
|
|
40
|
+
clone(): EffectSet;
|
|
41
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EffectSet = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A class for efficiently managing a set of effects using a bitset
|
|
6
|
+
*/
|
|
7
|
+
class EffectSet {
|
|
8
|
+
/**
|
|
9
|
+
* Initialize the static mapping between effect codes and bit positions
|
|
10
|
+
*/
|
|
11
|
+
static initialize() {
|
|
12
|
+
if (this.initialized)
|
|
13
|
+
return;
|
|
14
|
+
const effects = [
|
|
15
|
+
'Ag',
|
|
16
|
+
'At',
|
|
17
|
+
'Ba',
|
|
18
|
+
'Be',
|
|
19
|
+
'Ca',
|
|
20
|
+
'Cd',
|
|
21
|
+
'Cy',
|
|
22
|
+
'Di',
|
|
23
|
+
'El',
|
|
24
|
+
'En',
|
|
25
|
+
'Eu',
|
|
26
|
+
'Ex',
|
|
27
|
+
'Fc',
|
|
28
|
+
'Fo',
|
|
29
|
+
'Gi',
|
|
30
|
+
'Gl',
|
|
31
|
+
'Je',
|
|
32
|
+
'La',
|
|
33
|
+
'Lf',
|
|
34
|
+
'Mu',
|
|
35
|
+
'Pa',
|
|
36
|
+
'Re',
|
|
37
|
+
'Sc',
|
|
38
|
+
'Se',
|
|
39
|
+
'Sh',
|
|
40
|
+
'Si',
|
|
41
|
+
'Sl',
|
|
42
|
+
'Sm',
|
|
43
|
+
'Sn',
|
|
44
|
+
'Sp',
|
|
45
|
+
'To',
|
|
46
|
+
'Tp',
|
|
47
|
+
'Tt',
|
|
48
|
+
'Zo',
|
|
49
|
+
];
|
|
50
|
+
effects.forEach((effect, index) => {
|
|
51
|
+
this.effectToIndex.set(effect, index);
|
|
52
|
+
this.indexToEffect.set(index, effect);
|
|
53
|
+
});
|
|
54
|
+
this.initialized = true;
|
|
55
|
+
}
|
|
56
|
+
constructor(initialEffects = []) {
|
|
57
|
+
this.bits = 0;
|
|
58
|
+
EffectSet.initialize();
|
|
59
|
+
for (const effect of initialEffects) {
|
|
60
|
+
this.add(effect);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Add an effect to the set
|
|
65
|
+
* @returns true if the effect was added, false if it was already present
|
|
66
|
+
*/
|
|
67
|
+
add(effect) {
|
|
68
|
+
const index = EffectSet.effectToIndex.get(effect);
|
|
69
|
+
if (index === undefined)
|
|
70
|
+
return false;
|
|
71
|
+
const mask = 1 << index;
|
|
72
|
+
const alreadyExists = (this.bits & mask) !== 0;
|
|
73
|
+
this.bits |= mask;
|
|
74
|
+
return !alreadyExists;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Remove an effect from the set
|
|
78
|
+
* @returns true if the effect was removed, false if it wasn't present
|
|
79
|
+
*/
|
|
80
|
+
remove(effect) {
|
|
81
|
+
const index = EffectSet.effectToIndex.get(effect);
|
|
82
|
+
if (index === undefined)
|
|
83
|
+
return false;
|
|
84
|
+
const mask = 1 << index;
|
|
85
|
+
const existed = (this.bits & mask) !== 0;
|
|
86
|
+
this.bits &= ~mask;
|
|
87
|
+
return existed;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if an effect is in the set
|
|
91
|
+
*/
|
|
92
|
+
has(effect) {
|
|
93
|
+
const index = EffectSet.effectToIndex.get(effect);
|
|
94
|
+
if (index === undefined)
|
|
95
|
+
return false;
|
|
96
|
+
return (this.bits & (1 << index)) !== 0;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Convert the set to an array of effect codes
|
|
100
|
+
*/
|
|
101
|
+
toArray() {
|
|
102
|
+
const result = [];
|
|
103
|
+
for (let i = 0; i < 34; i++) {
|
|
104
|
+
if ((this.bits & (1 << i)) !== 0) {
|
|
105
|
+
const effect = EffectSet.indexToEffect.get(i);
|
|
106
|
+
if (effect)
|
|
107
|
+
result.push(effect);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get the number of effects in the set
|
|
114
|
+
*/
|
|
115
|
+
size() {
|
|
116
|
+
// Count the number of set bits using Brian Kernighan's algorithm
|
|
117
|
+
let count = 0;
|
|
118
|
+
let n = this.bits;
|
|
119
|
+
while (n) {
|
|
120
|
+
n &= n - 1;
|
|
121
|
+
count++;
|
|
122
|
+
}
|
|
123
|
+
return count;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Create a copy of this effect set
|
|
127
|
+
*/
|
|
128
|
+
clone() {
|
|
129
|
+
const clone = new EffectSet();
|
|
130
|
+
clone.bits = this.bits;
|
|
131
|
+
return clone;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
exports.EffectSet = EffectSet;
|
|
135
|
+
EffectSet.effectToIndex = new Map();
|
|
136
|
+
EffectSet.indexToEffect = new Map();
|
|
137
|
+
EffectSet.initialized = false;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mixSubstances = mixSubstances;
|
|
4
|
+
const effects_1 = require("../data/effects");
|
|
5
|
+
const products_1 = require("../data/products");
|
|
6
|
+
const substances_1 = require("../data/substances");
|
|
7
|
+
const rules_1 = require("../data/rules");
|
|
8
|
+
const effectSet_1 = require("./effectSet");
|
|
9
|
+
const MAX_EFFECTS = 8;
|
|
10
|
+
/**
|
|
11
|
+
* Calculate the result of mixing substances with a product
|
|
12
|
+
*/
|
|
13
|
+
function mixSubstances(product, substanceCodes) {
|
|
14
|
+
if (!products_1.products[product]) {
|
|
15
|
+
throw new Error(`Unknown product: ${product}`);
|
|
16
|
+
}
|
|
17
|
+
const productInfo = products_1.products[product];
|
|
18
|
+
const effectsSet = new effectSet_1.EffectSet(productInfo.effects);
|
|
19
|
+
const processedEffects = new effectSet_1.EffectSet();
|
|
20
|
+
const removedEffects = new effectSet_1.EffectSet();
|
|
21
|
+
let totalCost = 0;
|
|
22
|
+
for (const code of substanceCodes) {
|
|
23
|
+
const substance = substances_1.substances[code];
|
|
24
|
+
if (!substance)
|
|
25
|
+
continue;
|
|
26
|
+
totalCost += substance.price;
|
|
27
|
+
applySubstanceRules(code, effectsSet, processedEffects, removedEffects);
|
|
28
|
+
if (effectsSet.size() < MAX_EFFECTS) {
|
|
29
|
+
for (const effect of substance.effect) {
|
|
30
|
+
if (!effectsSet.has(effect)) {
|
|
31
|
+
effectsSet.add(effect);
|
|
32
|
+
if (effectsSet.size() >= MAX_EFFECTS)
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const finalEffects = effectsSet.toArray().slice(0, MAX_EFFECTS);
|
|
39
|
+
const effectValue = calculateEffectValue(finalEffects);
|
|
40
|
+
const productPrice = productInfo.price;
|
|
41
|
+
const sellPrice = Math.round(productPrice * (1 + effectValue));
|
|
42
|
+
const profit = sellPrice - totalCost - productPrice;
|
|
43
|
+
const profitMargin = Math.round((profit / sellPrice) * 100) / 100;
|
|
44
|
+
return {
|
|
45
|
+
effects: finalEffects,
|
|
46
|
+
cost: totalCost,
|
|
47
|
+
sellPrice,
|
|
48
|
+
profit,
|
|
49
|
+
profitMargin,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Apply the rules for a substance to the current effect set
|
|
54
|
+
*/
|
|
55
|
+
function applySubstanceRules(substanceCode, effectsSet, processedEffects, removedEffects) {
|
|
56
|
+
const rules = rules_1.effectRulesBySubstance[substanceCode];
|
|
57
|
+
if (!rules || rules.length === 0)
|
|
58
|
+
return;
|
|
59
|
+
const initialEffects = effectsSet.clone();
|
|
60
|
+
const appliedRules = new Set();
|
|
61
|
+
// Phase 1: Apply rules where conditions are met in the initial state
|
|
62
|
+
for (let i = 0; i < rules.length; i++) {
|
|
63
|
+
const rule = rules[i];
|
|
64
|
+
if (checkRulePreconditions(rule, initialEffects)) {
|
|
65
|
+
applyReplaceEffects(rule.replace, initialEffects, effectsSet, processedEffects, removedEffects);
|
|
66
|
+
appliedRules.add(i);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Phase 2: Apply rules where conditions are met after phase 1
|
|
70
|
+
for (let i = 0; i < rules.length; i++) {
|
|
71
|
+
if (appliedRules.has(i))
|
|
72
|
+
continue;
|
|
73
|
+
const rule = rules[i];
|
|
74
|
+
if (meetsPhaseTwo(rule, initialEffects, effectsSet, removedEffects)) {
|
|
75
|
+
if (canApplyTransformation(rule.replace, effectsSet)) {
|
|
76
|
+
applyTransformations(rule.replace, effectsSet, processedEffects);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Check if a rule's preconditions are met
|
|
83
|
+
*/
|
|
84
|
+
function checkRulePreconditions(rule, initialEffects) {
|
|
85
|
+
// Check if all required effects are present
|
|
86
|
+
for (const effect of rule.ifPresent) {
|
|
87
|
+
if (!initialEffects.has(effect))
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
// Check if all forbidden effects are absent
|
|
91
|
+
for (const effect of rule.ifNotPresent) {
|
|
92
|
+
if (initialEffects.has(effect))
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
// Check if at least one replaceable effect is present
|
|
96
|
+
for (const oldEffect of Object.keys(rule.replace)) {
|
|
97
|
+
if (initialEffects.has(oldEffect))
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Check if a rule meets phase two conditions
|
|
104
|
+
*/
|
|
105
|
+
function meetsPhaseTwo(rule, initialEffects, currentEffects, removedEffects) {
|
|
106
|
+
// All required effects must have been initially present
|
|
107
|
+
for (const effect of rule.ifPresent) {
|
|
108
|
+
if (!initialEffects.has(effect))
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
// At least one forbidden effect must have been removed
|
|
112
|
+
let hasRemovedForbidden = false;
|
|
113
|
+
for (const effect of rule.ifNotPresent) {
|
|
114
|
+
if (removedEffects.has(effect)) {
|
|
115
|
+
hasRemovedForbidden = true;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!hasRemovedForbidden)
|
|
120
|
+
return false;
|
|
121
|
+
// All forbidden effects must be absent from current set
|
|
122
|
+
for (const effect of rule.ifNotPresent) {
|
|
123
|
+
if (currentEffects.has(effect))
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Check if a transformation can be applied
|
|
130
|
+
*/
|
|
131
|
+
function canApplyTransformation(replace, effectsSet) {
|
|
132
|
+
for (const oldEffect of Object.keys(replace)) {
|
|
133
|
+
if (effectsSet.has(oldEffect))
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Apply effect replacements
|
|
140
|
+
*/
|
|
141
|
+
function applyReplaceEffects(replace, initialEffects, effectsSet, processedEffects, removedEffects) {
|
|
142
|
+
for (const [oldEffect, newEffect] of Object.entries(replace)) {
|
|
143
|
+
if (initialEffects.has(oldEffect)) {
|
|
144
|
+
effectsSet.remove(oldEffect);
|
|
145
|
+
effectsSet.add(newEffect);
|
|
146
|
+
processedEffects.add(oldEffect);
|
|
147
|
+
removedEffects.add(oldEffect);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Apply transformations to effects
|
|
153
|
+
*/
|
|
154
|
+
function applyTransformations(replace, effectsSet, processedEffects) {
|
|
155
|
+
for (const [oldEffect, newEffect] of Object.entries(replace)) {
|
|
156
|
+
if (effectsSet.has(oldEffect)) {
|
|
157
|
+
effectsSet.remove(oldEffect);
|
|
158
|
+
effectsSet.add(newEffect);
|
|
159
|
+
processedEffects.add(oldEffect);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Calculate the total value multiplier from effects
|
|
165
|
+
*/
|
|
166
|
+
function calculateEffectValue(effectCodes) {
|
|
167
|
+
var _a;
|
|
168
|
+
let value = 0;
|
|
169
|
+
for (const code of effectCodes) {
|
|
170
|
+
value += ((_a = effects_1.effects[code]) === null || _a === void 0 ? void 0 : _a.price) || 0;
|
|
171
|
+
}
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.effects = void 0;
|
|
4
|
+
exports.effects = {
|
|
5
|
+
Ca: {
|
|
6
|
+
name: 'Calming',
|
|
7
|
+
price: 0.1,
|
|
8
|
+
color: '#fdba74',
|
|
9
|
+
},
|
|
10
|
+
Re: {
|
|
11
|
+
name: 'Refreshing',
|
|
12
|
+
price: 0.14,
|
|
13
|
+
color: '#bef264',
|
|
14
|
+
},
|
|
15
|
+
En: {
|
|
16
|
+
name: 'Energizing',
|
|
17
|
+
price: 0.22,
|
|
18
|
+
color: '#a3e635',
|
|
19
|
+
},
|
|
20
|
+
Se: {
|
|
21
|
+
name: 'Sedating',
|
|
22
|
+
price: 0.26,
|
|
23
|
+
color: '#818cf8',
|
|
24
|
+
},
|
|
25
|
+
Be: {
|
|
26
|
+
name: 'Bright-Eyed',
|
|
27
|
+
price: 0.4,
|
|
28
|
+
color: '#67e8f9',
|
|
29
|
+
},
|
|
30
|
+
Cd: {
|
|
31
|
+
name: 'Calorie-Dense',
|
|
32
|
+
price: 0.28,
|
|
33
|
+
color: '#e879f9',
|
|
34
|
+
},
|
|
35
|
+
Eu: {
|
|
36
|
+
name: 'Euphoric',
|
|
37
|
+
price: 0.18,
|
|
38
|
+
color: '#fde68a',
|
|
39
|
+
},
|
|
40
|
+
To: {
|
|
41
|
+
name: 'Toxic',
|
|
42
|
+
price: 0,
|
|
43
|
+
color: '#a3e635',
|
|
44
|
+
},
|
|
45
|
+
At: {
|
|
46
|
+
name: 'Athletic',
|
|
47
|
+
price: 0.32,
|
|
48
|
+
color: '#7dd3fc',
|
|
49
|
+
},
|
|
50
|
+
Ba: {
|
|
51
|
+
name: 'Balding',
|
|
52
|
+
price: 0.3,
|
|
53
|
+
color: '#c79232',
|
|
54
|
+
},
|
|
55
|
+
Ag: {
|
|
56
|
+
name: 'Anti-Gravity',
|
|
57
|
+
price: 0.54,
|
|
58
|
+
color: '#3b82f6',
|
|
59
|
+
},
|
|
60
|
+
Mu: {
|
|
61
|
+
name: 'Munchies',
|
|
62
|
+
price: 0.12,
|
|
63
|
+
color: '#C96E57',
|
|
64
|
+
},
|
|
65
|
+
Sl: {
|
|
66
|
+
name: 'Slippery',
|
|
67
|
+
price: 0.34,
|
|
68
|
+
color: '#7dd3fc',
|
|
69
|
+
},
|
|
70
|
+
Gi: {
|
|
71
|
+
name: 'Gingeritis',
|
|
72
|
+
price: 0.2,
|
|
73
|
+
color: '#fb923c',
|
|
74
|
+
},
|
|
75
|
+
Sn: {
|
|
76
|
+
name: 'Sneaky',
|
|
77
|
+
price: 0.24,
|
|
78
|
+
color: '#a8a29e',
|
|
79
|
+
},
|
|
80
|
+
Tp: {
|
|
81
|
+
name: 'Thought-Provoking',
|
|
82
|
+
price: 0.44,
|
|
83
|
+
color: '#f9a8d4',
|
|
84
|
+
},
|
|
85
|
+
Sp: {
|
|
86
|
+
name: 'Spicy',
|
|
87
|
+
price: 0.38,
|
|
88
|
+
color: '#f87171',
|
|
89
|
+
},
|
|
90
|
+
Pa: {
|
|
91
|
+
name: 'Paranoia',
|
|
92
|
+
price: 0,
|
|
93
|
+
color: '#f87171',
|
|
94
|
+
},
|
|
95
|
+
Tt: {
|
|
96
|
+
name: 'Tropic Thunder',
|
|
97
|
+
price: 0.46,
|
|
98
|
+
color: '#fdba74',
|
|
99
|
+
},
|
|
100
|
+
Gl: {
|
|
101
|
+
name: 'Glowing',
|
|
102
|
+
price: 0.48,
|
|
103
|
+
color: '#85E459',
|
|
104
|
+
},
|
|
105
|
+
Cy: {
|
|
106
|
+
name: 'Cyclopean',
|
|
107
|
+
price: 0.56,
|
|
108
|
+
color: '#FEC174',
|
|
109
|
+
},
|
|
110
|
+
Fo: {
|
|
111
|
+
name: 'Foggy',
|
|
112
|
+
price: 0.36,
|
|
113
|
+
color: '#94a3b8',
|
|
114
|
+
},
|
|
115
|
+
Ex: {
|
|
116
|
+
name: 'Explosive',
|
|
117
|
+
price: 0,
|
|
118
|
+
color: '#ef4444',
|
|
119
|
+
},
|
|
120
|
+
La: {
|
|
121
|
+
name: 'Laxative',
|
|
122
|
+
price: 0,
|
|
123
|
+
color: '#a16207',
|
|
124
|
+
},
|
|
125
|
+
Lf: {
|
|
126
|
+
name: 'Long Faced',
|
|
127
|
+
price: 0.52,
|
|
128
|
+
color: '#fde047',
|
|
129
|
+
},
|
|
130
|
+
Je: {
|
|
131
|
+
name: 'Jennerising',
|
|
132
|
+
price: 0.42,
|
|
133
|
+
color: '#e879f9',
|
|
134
|
+
},
|
|
135
|
+
El: {
|
|
136
|
+
name: 'Electrifying',
|
|
137
|
+
price: 0.5,
|
|
138
|
+
color: '#22d3ee',
|
|
139
|
+
},
|
|
140
|
+
Di: {
|
|
141
|
+
name: 'Disorienting',
|
|
142
|
+
price: 0,
|
|
143
|
+
color: '#FE7551',
|
|
144
|
+
},
|
|
145
|
+
Sc: {
|
|
146
|
+
name: 'Schizophrenia',
|
|
147
|
+
price: 0,
|
|
148
|
+
color: '#645AFD',
|
|
149
|
+
},
|
|
150
|
+
Si: {
|
|
151
|
+
name: 'Seizure-Inducing',
|
|
152
|
+
price: 0,
|
|
153
|
+
color: '#FEE900',
|
|
154
|
+
},
|
|
155
|
+
Zo: {
|
|
156
|
+
name: 'Zombifying',
|
|
157
|
+
price: 0.58,
|
|
158
|
+
color: '#71AB5D',
|
|
159
|
+
},
|
|
160
|
+
Fc: {
|
|
161
|
+
name: 'Focused',
|
|
162
|
+
price: 0.16,
|
|
163
|
+
color: '#75F1FD',
|
|
164
|
+
},
|
|
165
|
+
Sm: {
|
|
166
|
+
name: 'Smelly',
|
|
167
|
+
price: 0,
|
|
168
|
+
color: '#84cc16',
|
|
169
|
+
},
|
|
170
|
+
Sh: {
|
|
171
|
+
name: 'Shrinking',
|
|
172
|
+
price: 0.6,
|
|
173
|
+
color: '#B6FEDA',
|
|
174
|
+
},
|
|
175
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.productAbbreviations = exports.products = void 0;
|
|
4
|
+
exports.products = {
|
|
5
|
+
'OG Kush': {
|
|
6
|
+
price: 35,
|
|
7
|
+
effects: ['Ca'],
|
|
8
|
+
abbreviation: 'OH',
|
|
9
|
+
},
|
|
10
|
+
'Sour Diesel': {
|
|
11
|
+
price: 35,
|
|
12
|
+
effects: ['Re'],
|
|
13
|
+
abbreviation: 'SL',
|
|
14
|
+
},
|
|
15
|
+
'Green Crack': {
|
|
16
|
+
price: 35,
|
|
17
|
+
effects: ['En'],
|
|
18
|
+
abbreviation: 'GK',
|
|
19
|
+
},
|
|
20
|
+
'Grandaddy Purple': {
|
|
21
|
+
price: 35,
|
|
22
|
+
effects: ['Se'],
|
|
23
|
+
abbreviation: 'GE',
|
|
24
|
+
},
|
|
25
|
+
Cocaine: {
|
|
26
|
+
price: 150,
|
|
27
|
+
effects: [],
|
|
28
|
+
abbreviation: 'CE',
|
|
29
|
+
},
|
|
30
|
+
Meth: {
|
|
31
|
+
price: 70,
|
|
32
|
+
effects: [],
|
|
33
|
+
abbreviation: 'MH',
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
exports.productAbbreviations = Object.entries(exports.products).reduce((acc, [product, data]) => {
|
|
37
|
+
acc[data.abbreviation] = product;
|
|
38
|
+
return acc;
|
|
39
|
+
}, {});
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.effectRulesBySubstance = void 0;
|
|
4
|
+
exports.effectRulesBySubstance = {
|
|
5
|
+
A: [
|
|
6
|
+
{ ifPresent: ['Eu'], ifNotPresent: ['La'], replace: { Eu: 'La' } },
|
|
7
|
+
{ ifPresent: ['Fo'], ifNotPresent: ['Cy'], replace: { Fo: 'Cy' } },
|
|
8
|
+
{ ifPresent: ['Gi'], ifNotPresent: ['Tp'], replace: { Gi: 'Tp' } },
|
|
9
|
+
{ ifPresent: ['Mu'], ifNotPresent: ['At'], replace: { Mu: 'At' } },
|
|
10
|
+
{ ifPresent: ['Sl'], ifNotPresent: ['Mu'], replace: { Sl: 'Mu' } },
|
|
11
|
+
{ ifPresent: ['Sn'], ifNotPresent: ['Pa'], replace: { Sn: 'Pa' } },
|
|
12
|
+
{ ifPresent: ['To'], ifNotPresent: ['Eu'], replace: { To: 'Eu' } },
|
|
13
|
+
],
|
|
14
|
+
B: [
|
|
15
|
+
{ ifPresent: ['At'], ifNotPresent: ['Mu'], replace: { At: 'Mu' } },
|
|
16
|
+
{ ifPresent: ['Ca'], ifNotPresent: ['Be'], replace: { Ca: 'Be' } },
|
|
17
|
+
{ ifPresent: ['Cy'], ifNotPresent: ['Fo'], replace: { Cy: 'Fo' } },
|
|
18
|
+
{ ifPresent: ['El'], ifNotPresent: ['Re'], replace: { El: 'Re' } },
|
|
19
|
+
{ ifPresent: ['Eu'], ifNotPresent: ['To'], replace: { Eu: 'To' } },
|
|
20
|
+
{ ifPresent: ['Fc'], ifNotPresent: ['Ca'], replace: { Fc: 'Ca' } },
|
|
21
|
+
{ ifPresent: ['La'], ifNotPresent: ['Eu'], replace: { La: 'Eu' } },
|
|
22
|
+
{ ifPresent: ['Mu'], ifNotPresent: ['Sl'], replace: { Mu: 'Sl' } },
|
|
23
|
+
{ ifPresent: ['Sh'], ifNotPresent: ['Pa'], replace: { Sh: 'Pa' } },
|
|
24
|
+
{ ifPresent: ['Tp'], ifNotPresent: ['Gi'], replace: { Tp: 'Gi' } },
|
|
25
|
+
],
|
|
26
|
+
C: [
|
|
27
|
+
{ ifPresent: ['Di'], ifNotPresent: ['Gl'], replace: { Di: 'Gl' } },
|
|
28
|
+
{ ifPresent: ['El'], ifNotPresent: ['Di'], replace: { El: 'Di' } },
|
|
29
|
+
{ ifPresent: ['En'], ifNotPresent: ['Eu'], replace: { En: 'Eu' } },
|
|
30
|
+
{ ifPresent: ['Eu'], ifNotPresent: ['Sp'], replace: { Eu: 'Sp' } },
|
|
31
|
+
{ ifPresent: ['Gi'], ifNotPresent: ['Sm'], replace: { Gi: 'Sm' } },
|
|
32
|
+
{ ifPresent: ['Je'], ifNotPresent: ['Sn'], replace: { Je: 'Sn' } },
|
|
33
|
+
{ ifPresent: ['La'], ifNotPresent: ['Fo'], replace: { La: 'Fo' } },
|
|
34
|
+
{ ifPresent: ['Mu'], ifNotPresent: ['Se'], replace: { Mu: 'Se' } },
|
|
35
|
+
{ ifPresent: ['Pa'], ifNotPresent: ['Ca'], replace: { Pa: 'Ca' } },
|
|
36
|
+
{ ifPresent: ['Sh'], ifNotPresent: ['Fc'], replace: { Sh: 'Fc' } },
|
|
37
|
+
{ ifPresent: ['Sn'], ifNotPresent: ['Tt'], replace: { Sn: 'Tt' } },
|
|
38
|
+
],
|
|
39
|
+
D: [
|
|
40
|
+
{ ifPresent: ['Ag'], ifNotPresent: ['Sl'], replace: { Ag: 'Sl' } },
|
|
41
|
+
{ ifPresent: ['Ba'], ifNotPresent: ['Sn'], replace: { Ba: 'Sn' } },
|
|
42
|
+
{ ifPresent: ['Cd'], ifNotPresent: ['Ex'], replace: { Cd: 'Ex' } },
|
|
43
|
+
{ ifPresent: ['Fc'], ifNotPresent: ['Eu'], replace: { Fc: 'Eu' } },
|
|
44
|
+
{ ifPresent: ['Je'], ifNotPresent: ['Gi'], replace: { Je: 'Gi' } },
|
|
45
|
+
{ ifPresent: ['Mu'], ifNotPresent: ['Ca'], replace: { Mu: 'Ca' } },
|
|
46
|
+
{ ifPresent: ['Sh'], ifNotPresent: ['En'], replace: { Sh: 'En' } },
|
|
47
|
+
],
|
|
48
|
+
E: [
|
|
49
|
+
{ ifPresent: ['Di'], ifNotPresent: ['El'], replace: { Di: 'El' } },
|
|
50
|
+
{ ifPresent: ['Eu'], ifNotPresent: ['En'], replace: { Eu: 'En' } },
|
|
51
|
+
{ ifPresent: ['Fc'], ifNotPresent: ['Sh'], replace: { Fc: 'Sh' } },
|
|
52
|
+
{ ifPresent: ['Fo'], ifNotPresent: ['La'], replace: { Fo: 'La' } },
|
|
53
|
+
{ ifPresent: ['Gl'], ifNotPresent: ['Di'], replace: { Gl: 'Di' } },
|
|
54
|
+
{ ifPresent: ['Sc'], ifNotPresent: ['Ba'], replace: { Sc: 'Ba' } },
|
|
55
|
+
{ ifPresent: ['Se'], ifNotPresent: ['Mu'], replace: { Se: 'Mu' } },
|
|
56
|
+
{ ifPresent: ['Sp'], ifNotPresent: ['Eu'], replace: { Sp: 'Eu' } },
|
|
57
|
+
{ ifPresent: ['Tt'], ifNotPresent: ['Sn'], replace: { Tt: 'Sn' } },
|
|
58
|
+
],
|
|
59
|
+
F: [
|
|
60
|
+
{ ifPresent: ['Ca'], ifNotPresent: ['Ag'], replace: { Ca: 'Ag' } },
|
|
61
|
+
{ ifPresent: ['Cd'], ifNotPresent: ['Sn'], replace: { Cd: 'Sn' } },
|
|
62
|
+
{ ifPresent: ['Ex'], ifNotPresent: ['Se'], replace: { Ex: 'Se' } },
|
|
63
|
+
{ ifPresent: ['Fc'], ifNotPresent: ['Je'], replace: { Fc: 'Je' } },
|
|
64
|
+
],
|
|
65
|
+
G: [
|
|
66
|
+
{ ifPresent: ['En'], ifNotPresent: ['Mu'], replace: { En: 'Mu' } },
|
|
67
|
+
{ ifPresent: ['Eu'], ifNotPresent: ['Se'], replace: { Eu: 'Se' } },
|
|
68
|
+
{ ifPresent: ['Fo'], ifNotPresent: ['To'], replace: { Fo: 'To' } },
|
|
69
|
+
{ ifPresent: ['Mu'], ifNotPresent: ['Sc'], replace: { Mu: 'Sc' } },
|
|
70
|
+
{ ifPresent: ['Pa'], ifNotPresent: ['Ag'], replace: { Pa: 'Ag' } },
|
|
71
|
+
],
|
|
72
|
+
H: [
|
|
73
|
+
{ ifPresent: ['Ca'], ifNotPresent: ['Sn'], replace: { Ca: 'Sn' } },
|
|
74
|
+
{ ifPresent: ['Cy'], ifNotPresent: ['En'], replace: { Cy: 'En' } },
|
|
75
|
+
{ ifPresent: ['Di'], ifNotPresent: ['Fc'], replace: { Di: 'Fc' } },
|
|
76
|
+
{ ifPresent: ['En'], ifNotPresent: ['Tp'], replace: { En: 'Tp' } },
|
|
77
|
+
{ ifPresent: ['Fc'], ifNotPresent: ['Si'], replace: { Fc: 'Si' } },
|
|
78
|
+
{ ifPresent: ['Lf'], ifNotPresent: ['Re'], replace: { Lf: 'Re' } },
|
|
79
|
+
{ ifPresent: ['Pa'], ifNotPresent: ['Je'], replace: { Pa: 'Je' } },
|
|
80
|
+
{ ifPresent: ['Sm'], ifNotPresent: ['Ag'], replace: { Sm: 'Ag' } },
|
|
81
|
+
{ ifPresent: ['To'], ifNotPresent: ['Sm'], replace: { To: 'Sm' } },
|
|
82
|
+
],
|
|
83
|
+
I: [
|
|
84
|
+
{ ifPresent: ['Ag'], ifNotPresent: ['Tt'], replace: { Ag: 'Tt' } },
|
|
85
|
+
{ ifPresent: ['At'], ifNotPresent: ['Eu'], replace: { At: 'Eu' } },
|
|
86
|
+
{ ifPresent: ['La'], ifNotPresent: ['Lf'], replace: { La: 'Lf' } },
|
|
87
|
+
{ ifPresent: ['Mu'], ifNotPresent: ['To'], replace: { Mu: 'To' } },
|
|
88
|
+
{ ifPresent: ['Sh'], ifNotPresent: ['Re'], replace: { Sh: 'Re' } },
|
|
89
|
+
{ ifPresent: ['Sn'], ifNotPresent: ['Be'], replace: { Sn: 'Be' } },
|
|
90
|
+
{ ifPresent: ['Tp'], ifNotPresent: ['Fc'], replace: { Tp: 'Fc' } },
|
|
91
|
+
],
|
|
92
|
+
J: [
|
|
93
|
+
{ ifPresent: ['Ca'], ifNotPresent: ['Ba'], replace: { Ca: 'Ba' } },
|
|
94
|
+
{ ifPresent: ['Cd'], ifNotPresent: ['Gi'], replace: { Cd: 'Gi' } },
|
|
95
|
+
{ ifPresent: ['Eu'], ifNotPresent: ['Si'], replace: { Eu: 'Si' } },
|
|
96
|
+
{ ifPresent: ['Fo'], ifNotPresent: ['Pa'], replace: { Fo: 'Pa' } },
|
|
97
|
+
{ ifPresent: ['Re'], ifNotPresent: ['Tp'], replace: { Re: 'Tp' } },
|
|
98
|
+
{ ifPresent: ['To'], ifNotPresent: ['Sn'], replace: { To: 'Sn' } },
|
|
99
|
+
],
|
|
100
|
+
K: [
|
|
101
|
+
{ ifPresent: ['Ca'], ifNotPresent: ['Sl'], replace: { Ca: 'Sl' } },
|
|
102
|
+
{ ifPresent: ['El'], ifNotPresent: ['At'], replace: { El: 'At' } },
|
|
103
|
+
{ ifPresent: ['En'], ifNotPresent: ['Pa'], replace: { En: 'Pa' } },
|
|
104
|
+
{ ifPresent: ['Fc'], ifNotPresent: ['Gi'], replace: { Fc: 'Gi' } },
|
|
105
|
+
{ ifPresent: ['Fo'], ifNotPresent: ['Ca'], replace: { Fo: 'Ca' } },
|
|
106
|
+
{ ifPresent: ['Gl'], ifNotPresent: ['To'], replace: { Gl: 'To' } },
|
|
107
|
+
{ ifPresent: ['Mu'], ifNotPresent: ['Ag'], replace: { Mu: 'Ag' } },
|
|
108
|
+
{ ifPresent: ['Pa'], ifNotPresent: ['Ba'], replace: { Pa: 'Ba' } },
|
|
109
|
+
{ ifPresent: ['Sp'], ifNotPresent: ['Be'], replace: { Sp: 'Be' } },
|
|
110
|
+
{ ifPresent: ['To'], ifNotPresent: ['Tt'], replace: { To: 'Tt' } },
|
|
111
|
+
],
|
|
112
|
+
L: [
|
|
113
|
+
{ ifPresent: ['At'], ifNotPresent: ['Sn'], replace: { At: 'Sn' } },
|
|
114
|
+
{ ifPresent: ['Di'], ifNotPresent: ['To'], replace: { Di: 'To' } },
|
|
115
|
+
{ ifPresent: ['Eu'], ifNotPresent: ['Be'], replace: { Eu: 'Be' } },
|
|
116
|
+
{ ifPresent: ['La'], ifNotPresent: ['Ca'], replace: { La: 'Ca' } },
|
|
117
|
+
{ ifPresent: ['Sh'], ifNotPresent: ['Gi'], replace: { Sh: 'Gi' } },
|
|
118
|
+
],
|
|
119
|
+
M: [
|
|
120
|
+
{ ifPresent: ['Ag'], ifNotPresent: ['Ca'], replace: { Ag: 'Ca' } },
|
|
121
|
+
{ ifPresent: ['Gi'], ifNotPresent: ['Re'], replace: { Gi: 'Re' } },
|
|
122
|
+
{ ifPresent: ['Si'], ifNotPresent: ['En'], replace: { Si: 'En' } },
|
|
123
|
+
{ ifPresent: ['Tp'], ifNotPresent: ['El'], replace: { Tp: 'El' } },
|
|
124
|
+
],
|
|
125
|
+
N: [
|
|
126
|
+
{ ifPresent: ['At'], ifNotPresent: ['La'], replace: { At: 'La' } },
|
|
127
|
+
{ ifPresent: ['Ca'], ifNotPresent: ['Gl'], replace: { Ca: 'Gl' } },
|
|
128
|
+
{ ifPresent: ['En'], ifNotPresent: ['Cy'], replace: { En: 'Cy' } },
|
|
129
|
+
{ ifPresent: ['Fc'], ifNotPresent: ['Di'], replace: { Fc: 'Di' } },
|
|
130
|
+
{ ifPresent: ['Je'], ifNotPresent: ['Pa'], replace: { Je: 'Pa' } },
|
|
131
|
+
{ ifPresent: ['Si'], ifNotPresent: ['Fc'], replace: { Si: 'Fc' } },
|
|
132
|
+
{ ifPresent: ['Sh'], ifNotPresent: ['El'], replace: { Sh: 'El' } },
|
|
133
|
+
{ ifPresent: ['Sl'], ifNotPresent: ['To'], replace: { Sl: 'To' } },
|
|
134
|
+
{ ifPresent: ['Sn'], ifNotPresent: ['Ca'], replace: { Sn: 'Ca' } },
|
|
135
|
+
{ ifPresent: ['Tp'], ifNotPresent: ['En'], replace: { Tp: 'En' } },
|
|
136
|
+
],
|
|
137
|
+
O: [
|
|
138
|
+
{ ifPresent: ['Ex'], ifNotPresent: ['Eu'], replace: { Ex: 'Eu' } },
|
|
139
|
+
{ ifPresent: ['Fo'], ifNotPresent: ['En'], replace: { Fo: 'En' } },
|
|
140
|
+
{ ifPresent: ['Gl'], ifNotPresent: ['Re'], replace: { Gl: 'Re' } },
|
|
141
|
+
{ ifPresent: ['Lf'], ifNotPresent: ['El'], replace: { Lf: 'El' } },
|
|
142
|
+
{ ifPresent: ['Se'], ifNotPresent: ['Gi'], replace: { Se: 'Gi' } },
|
|
143
|
+
],
|
|
144
|
+
P: [
|
|
145
|
+
{ ifPresent: ['Cy'], ifNotPresent: ['Gl'], replace: { Cy: 'Gl' } },
|
|
146
|
+
{ ifPresent: ['El'], ifNotPresent: ['Eu'], replace: { El: 'Eu' } },
|
|
147
|
+
{ ifPresent: ['Eu'], ifNotPresent: ['Zo'], replace: { Eu: 'Zo' } },
|
|
148
|
+
{ ifPresent: ['La'], ifNotPresent: ['Cd'], replace: { La: 'Cd' } },
|
|
149
|
+
{ ifPresent: ['Mu'], ifNotPresent: ['Tt'], replace: { Mu: 'Tt' } },
|
|
150
|
+
{ ifPresent: ['Sh'], ifNotPresent: ['Mu'], replace: { Sh: 'Mu' } },
|
|
151
|
+
],
|
|
152
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.substances = void 0;
|
|
4
|
+
exports.substances = {
|
|
5
|
+
A: {
|
|
6
|
+
name: 'Cuke',
|
|
7
|
+
rank: '1',
|
|
8
|
+
price: 2,
|
|
9
|
+
effect: ['En'],
|
|
10
|
+
},
|
|
11
|
+
B: {
|
|
12
|
+
name: 'Flu Medicine',
|
|
13
|
+
rank: '4',
|
|
14
|
+
price: 5,
|
|
15
|
+
effect: ['Se'],
|
|
16
|
+
},
|
|
17
|
+
C: {
|
|
18
|
+
name: 'Gasoline',
|
|
19
|
+
rank: '5',
|
|
20
|
+
price: 5,
|
|
21
|
+
effect: ['To'],
|
|
22
|
+
},
|
|
23
|
+
D: {
|
|
24
|
+
name: 'Donut',
|
|
25
|
+
rank: '1',
|
|
26
|
+
price: 3,
|
|
27
|
+
effect: ['Cd'],
|
|
28
|
+
},
|
|
29
|
+
E: {
|
|
30
|
+
name: 'Energy Drink',
|
|
31
|
+
rank: '6',
|
|
32
|
+
price: 6,
|
|
33
|
+
effect: ['At'],
|
|
34
|
+
},
|
|
35
|
+
F: {
|
|
36
|
+
name: 'Mouth Wash',
|
|
37
|
+
rank: '3',
|
|
38
|
+
price: 4,
|
|
39
|
+
effect: ['Ba'],
|
|
40
|
+
},
|
|
41
|
+
G: {
|
|
42
|
+
name: 'Motor Oil',
|
|
43
|
+
rank: '7',
|
|
44
|
+
price: 6,
|
|
45
|
+
effect: ['Sl'],
|
|
46
|
+
},
|
|
47
|
+
H: {
|
|
48
|
+
name: 'Banana',
|
|
49
|
+
rank: '1',
|
|
50
|
+
price: 2,
|
|
51
|
+
effect: ['Gi'],
|
|
52
|
+
},
|
|
53
|
+
I: {
|
|
54
|
+
name: 'Chili',
|
|
55
|
+
rank: '9',
|
|
56
|
+
price: 7,
|
|
57
|
+
effect: ['Sp'],
|
|
58
|
+
},
|
|
59
|
+
J: {
|
|
60
|
+
name: 'Iodine',
|
|
61
|
+
rank: '11',
|
|
62
|
+
price: 8,
|
|
63
|
+
effect: ['Je'],
|
|
64
|
+
},
|
|
65
|
+
K: {
|
|
66
|
+
name: 'Paracetamol',
|
|
67
|
+
rank: '1',
|
|
68
|
+
price: 3,
|
|
69
|
+
effect: ['Sn'],
|
|
70
|
+
},
|
|
71
|
+
L: {
|
|
72
|
+
name: 'Viagra',
|
|
73
|
+
rank: '2',
|
|
74
|
+
price: 4,
|
|
75
|
+
effect: ['Tt'],
|
|
76
|
+
},
|
|
77
|
+
M: {
|
|
78
|
+
name: 'Horse Semen',
|
|
79
|
+
rank: '13',
|
|
80
|
+
price: 9,
|
|
81
|
+
effect: ['Lf'],
|
|
82
|
+
},
|
|
83
|
+
N: {
|
|
84
|
+
name: 'Mega Bean',
|
|
85
|
+
rank: '8',
|
|
86
|
+
price: 7,
|
|
87
|
+
effect: ['Fo'],
|
|
88
|
+
},
|
|
89
|
+
O: {
|
|
90
|
+
name: 'Addy',
|
|
91
|
+
rank: '12',
|
|
92
|
+
price: 9,
|
|
93
|
+
effect: ['Tp'],
|
|
94
|
+
},
|
|
95
|
+
P: {
|
|
96
|
+
name: 'Battery',
|
|
97
|
+
rank: '10',
|
|
98
|
+
price: 8,
|
|
99
|
+
effect: ['Be'],
|
|
100
|
+
},
|
|
101
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { mixSubstances } from './core/mixer';
|
|
2
|
+
export { encodeMixState, decodeMixState } from './utils/encoding';
|
|
3
|
+
export { effects } from './data/effects';
|
|
4
|
+
export { products, productAbbreviations } from './data/products';
|
|
5
|
+
export { substances } from './data/substances';
|
|
6
|
+
export { effectRulesBySubstance } from './data/rules';
|
|
7
|
+
export type { EffectCode, SubstanceCode, ProductType, RankCode, EffectData, SubstanceData, ProductData, EffectRule, MixResult, MixState, } from './types';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.effectRulesBySubstance = exports.substances = exports.productAbbreviations = exports.products = exports.effects = exports.decodeMixState = exports.encodeMixState = exports.mixSubstances = void 0;
|
|
4
|
+
// Main exports
|
|
5
|
+
var mixer_1 = require("./core/mixer");
|
|
6
|
+
Object.defineProperty(exports, "mixSubstances", { enumerable: true, get: function () { return mixer_1.mixSubstances; } });
|
|
7
|
+
var encoding_1 = require("./utils/encoding");
|
|
8
|
+
Object.defineProperty(exports, "encodeMixState", { enumerable: true, get: function () { return encoding_1.encodeMixState; } });
|
|
9
|
+
Object.defineProperty(exports, "decodeMixState", { enumerable: true, get: function () { return encoding_1.decodeMixState; } });
|
|
10
|
+
// Data exports
|
|
11
|
+
var effects_1 = require("./data/effects");
|
|
12
|
+
Object.defineProperty(exports, "effects", { enumerable: true, get: function () { return effects_1.effects; } });
|
|
13
|
+
var products_1 = require("./data/products");
|
|
14
|
+
Object.defineProperty(exports, "products", { enumerable: true, get: function () { return products_1.products; } });
|
|
15
|
+
Object.defineProperty(exports, "productAbbreviations", { enumerable: true, get: function () { return products_1.productAbbreviations; } });
|
|
16
|
+
var substances_1 = require("./data/substances");
|
|
17
|
+
Object.defineProperty(exports, "substances", { enumerable: true, get: function () { return substances_1.substances; } });
|
|
18
|
+
var rules_1 = require("./data/rules");
|
|
19
|
+
Object.defineProperty(exports, "effectRulesBySubstance", { enumerable: true, get: function () { return rules_1.effectRulesBySubstance; } });
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type EffectCode = 'Ag' | 'At' | 'Ba' | 'Be' | 'Ca' | 'Cd' | 'Cy' | 'Di' | 'El' | 'En' | 'Eu' | 'Ex' | 'Fc' | 'Fo' | 'Gi' | 'Gl' | 'Je' | 'La' | 'Lf' | 'Mu' | 'Pa' | 'Re' | 'Sc' | 'Se' | 'Sh' | 'Si' | 'Sl' | 'Sm' | 'Sn' | 'Sp' | 'To' | 'Tp' | 'Tt' | 'Zo';
|
|
2
|
+
export type SubstanceCode = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P';
|
|
3
|
+
export type ProductType = 'OG Kush' | 'Sour Diesel' | 'Green Crack' | 'Grandaddy Purple' | 'Meth' | 'Cocaine';
|
|
4
|
+
export type RankCode = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | '13';
|
|
5
|
+
export interface EffectData {
|
|
6
|
+
name: string;
|
|
7
|
+
price: number;
|
|
8
|
+
color: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SubstanceData {
|
|
11
|
+
name: string;
|
|
12
|
+
rank: RankCode;
|
|
13
|
+
price: number;
|
|
14
|
+
effect: EffectCode[];
|
|
15
|
+
}
|
|
16
|
+
export interface ProductData {
|
|
17
|
+
price: number;
|
|
18
|
+
effects: EffectCode[];
|
|
19
|
+
abbreviation: string;
|
|
20
|
+
}
|
|
21
|
+
export interface EffectRule {
|
|
22
|
+
ifPresent: EffectCode[];
|
|
23
|
+
ifNotPresent: EffectCode[];
|
|
24
|
+
replace: Partial<Record<EffectCode, EffectCode>>;
|
|
25
|
+
}
|
|
26
|
+
export interface MixResult {
|
|
27
|
+
effects: EffectCode[];
|
|
28
|
+
cost: number;
|
|
29
|
+
sellPrice: number;
|
|
30
|
+
profit: number;
|
|
31
|
+
profitMargin: number;
|
|
32
|
+
}
|
|
33
|
+
export interface MixState {
|
|
34
|
+
product: ProductType;
|
|
35
|
+
substances: SubstanceCode[];
|
|
36
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MixState } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Encode a mix state into a URL-safe string
|
|
4
|
+
*/
|
|
5
|
+
export declare function encodeMixState(state: MixState): string;
|
|
6
|
+
/**
|
|
7
|
+
* Decode a mix state from a URL-safe string
|
|
8
|
+
*/
|
|
9
|
+
export declare function decodeMixState(hash: string): MixState | null;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encodeMixState = encodeMixState;
|
|
4
|
+
exports.decodeMixState = decodeMixState;
|
|
5
|
+
const products_1 = require("../data/products");
|
|
6
|
+
const substances_1 = require("../data/substances");
|
|
7
|
+
/**
|
|
8
|
+
* Encode a mix state into a URL-safe string
|
|
9
|
+
*/
|
|
10
|
+
function encodeMixState(state) {
|
|
11
|
+
// Validate inputs
|
|
12
|
+
if (!products_1.products[state.product]) {
|
|
13
|
+
throw new Error('Invalid product type');
|
|
14
|
+
}
|
|
15
|
+
for (const substance of state.substances) {
|
|
16
|
+
if (!substances_1.substances[substance]) {
|
|
17
|
+
throw new Error(`Invalid substance code: ${substance}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const encoded = `${state.product}:${state.substances.join('')}`;
|
|
21
|
+
return toBase64Url(encoded);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Decode a mix state from a URL-safe string
|
|
25
|
+
*/
|
|
26
|
+
function decodeMixState(hash) {
|
|
27
|
+
try {
|
|
28
|
+
const decoded = fromBase64Url(hash);
|
|
29
|
+
const [product, substancesStr] = decoded.split(':');
|
|
30
|
+
if (!product || substancesStr === undefined || !products_1.products[product]) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const substanceCodes = substancesStr.split('');
|
|
34
|
+
// Validate substances
|
|
35
|
+
for (const code of substanceCodes) {
|
|
36
|
+
if (!substances_1.substances[code]) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
product: product,
|
|
42
|
+
substances: substanceCodes,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (_a) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Convert a string to a URL-safe base64 string
|
|
51
|
+
*/
|
|
52
|
+
function toBase64Url(str) {
|
|
53
|
+
return Buffer.from(str, 'binary')
|
|
54
|
+
.toString('base64')
|
|
55
|
+
.replace(/\+/g, '-')
|
|
56
|
+
.replace(/\//g, '_')
|
|
57
|
+
.replace(/=/g, '');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Convert a URL-safe base64 string back to a regular string
|
|
61
|
+
*/
|
|
62
|
+
function fromBase64Url(str) {
|
|
63
|
+
const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
64
|
+
const padding = 4 - (base64.length % 4);
|
|
65
|
+
const padded = padding < 4 ? base64 + '='.repeat(padding) : base64;
|
|
66
|
+
return Buffer.from(padded, 'base64').toString('binary');
|
|
67
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@schedule1-tools/mixer",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "A package for calculating substance mixes in Schedule 1",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"keywords": [
|
|
11
|
+
"schedule1"
|
|
12
|
+
],
|
|
13
|
+
"author": "Schedule1 Tools",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/jest": "^29.5.14",
|
|
17
|
+
"@types/node": "^22.14.1",
|
|
18
|
+
"prettier": "^3.5.3",
|
|
19
|
+
"jest": "^29.7.0",
|
|
20
|
+
"ts-jest": "^29.3.2",
|
|
21
|
+
"typescript": "^5.8.3"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/schedule1-tools/mixer.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/schedule1-tools/mixer/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/schedule1-tools/mixer#readme",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc",
|
|
33
|
+
"test": "jest",
|
|
34
|
+
"test:coverage": "jest --coverage",
|
|
35
|
+
"format": "prettier --write ."
|
|
36
|
+
}
|
|
37
|
+
}
|