@schedule1-tools/mixer 0.0.1 → 0.1.2

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/README.md CHANGED
@@ -10,12 +10,11 @@ npm install @schedule1-tools/mixer
10
10
 
11
11
  ## Usage
12
12
 
13
- ```typescript
14
- import { decodeMixState, encodeMixState, mixSubstances } from '@schedule1-tools/mixer';
13
+ ### Calculate a mix
15
14
 
16
- // Calculate a mix
15
+ ```typescript
17
16
  const result = mixSubstances('OG Kush', ['Cuke', 'Flu Medicine', 'Gasoline']);
18
- console.log(result);
17
+
19
18
  /*
20
19
  {
21
20
  effects: [ 'Be', 'Eu', 'Se', 'To' ],
@@ -25,17 +24,24 @@ console.log(result);
25
24
  profitMargin: 0.27
26
25
  }
27
26
  */
27
+ ```
28
28
 
29
- // Encode a mix state for sharing
29
+ ### Encode a mix state for sharing
30
+
31
+ ```typescript
30
32
  const encoded = encodeMixState({
31
33
  product: 'OG Kush',
32
34
  substances: ['Cuke', 'Flu Medicine', 'Gasoline'],
33
35
  });
34
- console.log(encoded); // "T0cgS3VzaDpBQkM"
35
36
 
36
- // Decode a mix state
37
+ // "T0cgS3VzaDpBQkM"
38
+ ```
39
+
40
+ ### Decode a mix state
41
+
42
+ ```typescript
37
43
  const decoded = decodeMixState('T0cgS3VzaDpBQkM');
38
- console.log(decoded);
44
+
39
45
  /*
40
46
  {
41
47
  product: 'OG Kush',
@@ -52,3 +58,7 @@ The package also exports the following data objects:
52
58
  - `products`: Information about all products
53
59
  - `substances`: Information about all substances
54
60
  - `effectRulesBySubstance`: Rules for how substances transform effects
61
+
62
+ ## Notice
63
+
64
+ This is a fan-made project and is not affiliated with, authorized, maintained, sponsored, or endorsed by the developers of Schedule I the game. All game-related content, including but not limited to names, trademarks, and copyrights, belong to their respective owners.
@@ -1,38 +1,11 @@
1
1
  import type { EffectCode } from '../types';
2
2
  export declare class EffectSet {
3
- private static readonly effectToIndex;
4
- private static readonly indexToEffect;
5
- private static initialized;
6
- private bits;
7
- /**
8
- * Initialize the static mapping between effect codes and bit positions
9
- */
10
- private static initialize;
3
+ private effects;
11
4
  constructor(initialEffects?: EffectCode[]);
12
- /**
13
- * Add an effect to the set
14
- * @returns true if the effect was added, false if it was already present
15
- */
16
5
  add(effect: EffectCode): boolean;
17
- /**
18
- * Remove an effect from the set
19
- * @returns true if the effect was removed, false if it wasn't present
20
- */
21
6
  remove(effect: EffectCode): boolean;
22
- /**
23
- * Check if an effect is in the set
24
- */
25
7
  has(effect: EffectCode): boolean;
26
- /**
27
- * Convert the set to an array of effect codes
28
- */
29
8
  toArray(): EffectCode[];
30
- /**
31
- * Get the number of effects in the set
32
- */
33
9
  size(): number;
34
- /**
35
- * Create a copy of this effect set
36
- */
37
10
  clone(): EffectSet;
38
11
  }
@@ -2,132 +2,32 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EffectSet = void 0;
4
4
  class EffectSet {
5
- /**
6
- * Initialize the static mapping between effect codes and bit positions
7
- */
8
- static initialize() {
9
- if (this.initialized)
10
- return;
11
- const effects = [
12
- 'Ag',
13
- 'At',
14
- 'Ba',
15
- 'Be',
16
- 'Ca',
17
- 'Cd',
18
- 'Cy',
19
- 'Di',
20
- 'El',
21
- 'En',
22
- 'Eu',
23
- 'Ex',
24
- 'Fc',
25
- 'Fo',
26
- 'Gi',
27
- 'Gl',
28
- 'Je',
29
- 'La',
30
- 'Lf',
31
- 'Mu',
32
- 'Pa',
33
- 'Re',
34
- 'Sc',
35
- 'Se',
36
- 'Sh',
37
- 'Si',
38
- 'Sl',
39
- 'Sm',
40
- 'Sn',
41
- 'Sp',
42
- 'To',
43
- 'Tp',
44
- 'Tt',
45
- 'Zo',
46
- ];
47
- effects.forEach((effect, index) => {
48
- this.effectToIndex.set(effect, index);
49
- this.indexToEffect.set(index, effect);
50
- });
51
- this.initialized = true;
52
- }
53
5
  constructor(initialEffects = []) {
54
- this.bits = 0;
55
- EffectSet.initialize();
56
- for (const effect of initialEffects) {
57
- this.add(effect);
58
- }
6
+ this.effects = new Set(initialEffects);
59
7
  }
60
- /**
61
- * Add an effect to the set
62
- * @returns true if the effect was added, false if it was already present
63
- */
64
8
  add(effect) {
65
- const index = EffectSet.effectToIndex.get(effect);
66
- if (index === undefined)
67
- return false;
68
- const mask = 1 << index;
69
- const alreadyExists = (this.bits & mask) !== 0;
70
- this.bits |= mask;
9
+ const alreadyExists = this.effects.has(effect);
10
+ this.effects.add(effect);
71
11
  return !alreadyExists;
72
12
  }
73
- /**
74
- * Remove an effect from the set
75
- * @returns true if the effect was removed, false if it wasn't present
76
- */
77
13
  remove(effect) {
78
- const index = EffectSet.effectToIndex.get(effect);
79
- if (index === undefined)
80
- return false;
81
- const mask = 1 << index;
82
- const existed = (this.bits & mask) !== 0;
83
- this.bits &= ~mask;
14
+ const existed = this.effects.has(effect);
15
+ this.effects.delete(effect);
84
16
  return existed;
85
17
  }
86
- /**
87
- * Check if an effect is in the set
88
- */
89
18
  has(effect) {
90
- const index = EffectSet.effectToIndex.get(effect);
91
- if (index === undefined)
92
- return false;
93
- return (this.bits & (1 << index)) !== 0;
19
+ return this.effects.has(effect);
94
20
  }
95
- /**
96
- * Convert the set to an array of effect codes
97
- */
98
21
  toArray() {
99
- const result = [];
100
- for (let i = 0; i < 34; i++) {
101
- if ((this.bits & (1 << i)) !== 0) {
102
- const effect = EffectSet.indexToEffect.get(i);
103
- if (effect)
104
- result.push(effect);
105
- }
106
- }
107
- return result;
22
+ return Array.from(this.effects);
108
23
  }
109
- /**
110
- * Get the number of effects in the set
111
- */
112
24
  size() {
113
- let count = 0;
114
- let n = this.bits;
115
- while (n) {
116
- n &= n - 1;
117
- count++;
118
- }
119
- return count;
25
+ return this.effects.size;
120
26
  }
121
- /**
122
- * Create a copy of this effect set
123
- */
124
27
  clone() {
125
28
  const clone = new EffectSet();
126
- clone.bits = this.bits;
29
+ clone.effects = new Set(this.effects);
127
30
  return clone;
128
31
  }
129
32
  }
130
33
  exports.EffectSet = EffectSet;
131
- EffectSet.effectToIndex = new Map();
132
- EffectSet.indexToEffect = new Map();
133
- EffectSet.initialized = false;
@@ -16,16 +16,40 @@ function mixSubstances(product, substanceCodes) {
16
16
  }
17
17
  const productInfo = products_1.products[product];
18
18
  const effectsSet = new effectSet_1.EffectSet(productInfo.effects);
19
- const processedEffects = new effectSet_1.EffectSet();
20
- const removedEffects = new effectSet_1.EffectSet();
21
19
  let totalCost = 0;
22
20
  for (const code of substanceCodes) {
23
21
  const substance = substances_1.substances[code];
24
22
  if (!substance)
25
23
  continue;
26
24
  totalCost += substance.price;
27
- applySubstanceRules(code, effectsSet, processedEffects, removedEffects);
28
- if (effectsSet.size() < MAX_EFFECTS) {
25
+ const rules = rules_1.effectRulesBySubstance[code];
26
+ if (rules && rules.length > 0) {
27
+ const initialEffects = effectsSet.clone();
28
+ const processedEffects = new effectSet_1.EffectSet();
29
+ const removedEffects = new effectSet_1.EffectSet();
30
+ const appliedRules = new Set();
31
+ // Phase 1: Apply rules where conditions are met in the initial state
32
+ for (let i = 0; i < rules.length; i++) {
33
+ const rule = rules[i];
34
+ if (checkRulePreconditions(rule, initialEffects)) {
35
+ applyReplaceEffects(rule.replace, initialEffects, effectsSet, processedEffects, removedEffects);
36
+ appliedRules.add(i);
37
+ }
38
+ }
39
+ // Phase 2: Apply rules where conditions are met after phase 1
40
+ for (let i = 0; i < rules.length; i++) {
41
+ if (appliedRules.has(i))
42
+ continue;
43
+ const rule = rules[i];
44
+ if (meetsPhaseTwo(rule, initialEffects, effectsSet, removedEffects)) {
45
+ if (canApplyTransformation(rule.replace, effectsSet)) {
46
+ applyTransformations(rule.replace, effectsSet, processedEffects);
47
+ }
48
+ }
49
+ }
50
+ }
51
+ // Add substance effects AFTER applying rules
52
+ if (effectsSet.size() < MAX_EFFECTS && substance.effect) {
29
53
  for (const effect of substance.effect) {
30
54
  if (!effectsSet.has(effect)) {
31
55
  effectsSet.add(effect);
@@ -37,9 +61,8 @@ function mixSubstances(product, substanceCodes) {
37
61
  }
38
62
  const finalEffects = effectsSet.toArray().slice(0, MAX_EFFECTS);
39
63
  const effectValue = calculateEffectValue(finalEffects);
40
- const productPrice = productInfo.price;
41
- const sellPrice = Math.round(productPrice * (1 + effectValue));
42
- const profit = sellPrice - totalCost - productPrice;
64
+ const sellPrice = Math.round(productInfo.price * (1 + effectValue));
65
+ const profit = sellPrice - totalCost;
43
66
  const profitMargin = Math.round((profit / sellPrice) * 100) / 100;
44
67
  return {
45
68
  effects: finalEffects,
@@ -49,35 +72,6 @@ function mixSubstances(product, substanceCodes) {
49
72
  profitMargin,
50
73
  };
51
74
  }
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
75
  /**
82
76
  * Check if a rule's preconditions are met
83
77
  */
@@ -125,16 +119,6 @@ function meetsPhaseTwo(rule, initialEffects, currentEffects, removedEffects) {
125
119
  }
126
120
  return true;
127
121
  }
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
122
  /**
139
123
  * Apply effect replacements
140
124
  */
@@ -148,6 +132,16 @@ function applyReplaceEffects(replace, initialEffects, effectsSet, processedEffec
148
132
  }
149
133
  }
150
134
  }
135
+ /**
136
+ * Check if a transformation can be applied
137
+ */
138
+ function canApplyTransformation(replace, effectsSet) {
139
+ for (const oldEffect of Object.keys(replace)) {
140
+ if (effectsSet.has(oldEffect))
141
+ return true;
142
+ }
143
+ return false;
144
+ }
151
145
  /**
152
146
  * Apply transformations to effects
153
147
  */
@@ -22,16 +22,16 @@ exports.products = {
22
22
  effects: ['Se'],
23
23
  abbreviation: 'GE',
24
24
  },
25
- Cocaine: {
26
- price: 150,
27
- effects: [],
28
- abbreviation: 'CE',
29
- },
30
25
  Meth: {
31
26
  price: 70,
32
27
  effects: [],
33
28
  abbreviation: 'MH',
34
29
  },
30
+ Cocaine: {
31
+ price: 150,
32
+ effects: [],
33
+ abbreviation: 'CE',
34
+ },
35
35
  };
36
36
  exports.productAbbreviations = Object.entries(exports.products).reduce((acc, [product, data]) => {
37
37
  acc[data.abbreviation] = product;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schedule1-tools/mixer",
3
- "version": "0.0.1",
3
+ "version": "0.1.2",
4
4
  "description": "A package for calculating substance mixes in Schedule 1",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",