bdoap 0.0.1

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.
@@ -0,0 +1,526 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Utils
4
+ class NPCItemIndex
5
+ def self.get_item(id)
6
+ ITEMS.dig(id.to_i)
7
+ end
8
+
9
+ ITEMS = {
10
+ 7313 => {
11
+ name: 'Apple',
12
+ id: 7313,
13
+ price: 1000,
14
+ price_per_one: 1000,
15
+ count: Float::INFINITY,
16
+ is_npc_item: true,
17
+ npc_type: 'fruit',
18
+ main_category: 25,
19
+ sub_category: 3,
20
+ },
21
+ 7316 => {
22
+ name: 'Banana',
23
+ id: 7316,
24
+ price: 1000,
25
+ price_per_one: 1000,
26
+ count: Float::INFINITY,
27
+ is_npc_item: true,
28
+ npc_type: 'fruit',
29
+ main_category: 25,
30
+ sub_category: 3,
31
+ },
32
+ 7314 => {
33
+ name: 'Cherry',
34
+ id: 7314,
35
+ price: 1000,
36
+ price_per_one: 1000,
37
+ count: Float::INFINITY,
38
+ is_npc_item: true,
39
+ npc_type: 'fruit',
40
+ main_category: 25,
41
+ sub_category: 3,
42
+ },
43
+ 7312 => {
44
+ name: 'Paprika',
45
+ id: 7312,
46
+ price: 850,
47
+ price_per_one: 850,
48
+ count: Float::INFINITY,
49
+ is_npc_item: true,
50
+ npc_type: 'fruit',
51
+ main_category: 25,
52
+ sub_category: 3,
53
+ },
54
+ 7315 => {
55
+ name: 'Pear',
56
+ id: 7315,
57
+ price: 1000,
58
+ price_per_one: 1000,
59
+ count: Float::INFINITY,
60
+ is_npc_item: true,
61
+ npc_type: 'fruit',
62
+ main_category: 25,
63
+ sub_category: 3,
64
+ },
65
+ 7317 => {
66
+ name: 'Pineapple',
67
+ id: 7317,
68
+ price: 1000,
69
+ price_per_one: 1000,
70
+ count: Float::INFINITY,
71
+ is_npc_item: true,
72
+ npc_type: 'fruit',
73
+ main_category: 25,
74
+ sub_category: 3,
75
+ },
76
+ 7304 => {
77
+ name: 'Strawberry',
78
+ id: 9008,
79
+ price: 700,
80
+ price_per_one: 700,
81
+ count: Float::INFINITY,
82
+ is_npc_item: true,
83
+ npc_type: 'fruit',
84
+ main_category: 25,
85
+ sub_category: 3,
86
+ },
87
+ 9016 => {
88
+ name: 'Deep Frying Oil',
89
+ id: 9016,
90
+ price: 40,
91
+ price_per_one: 40,
92
+ count: Float::INFINITY,
93
+ is_npc_item: true,
94
+ npc_type: 'cooking',
95
+ },
96
+ 9015 => {
97
+ name: 'Olive Oil',
98
+ id: 9015,
99
+ price: 40,
100
+ price_per_one: 40,
101
+ count: Float::INFINITY,
102
+ is_npc_item: true,
103
+ npc_type: 'cooking',
104
+ },
105
+ 9007 => {
106
+ name: 'Cooking Oil',
107
+ id: 9007,
108
+ price: 20,
109
+ price_per_one: 20,
110
+ count: Float::INFINITY,
111
+ is_npc_item: true,
112
+ npc_type: 'cooking',
113
+ },
114
+ 9008 => {
115
+ name: 'Sun-Dried Salt',
116
+ id: 9008,
117
+ price: 200,
118
+ price_per_one: 200,
119
+ count: Float::INFINITY,
120
+ is_npc_item: true,
121
+ npc_type: 'cooking',
122
+ },
123
+ 9002 => {
124
+ name: 'Sugar',
125
+ id: 9002,
126
+ price: 20,
127
+ price_per_one: 20,
128
+ count: Float::INFINITY,
129
+ is_npc_item: true,
130
+ npc_type: 'cooking',
131
+ },
132
+ 9001 => {
133
+ name: 'Salt',
134
+ id: 9001,
135
+ price: 20,
136
+ price_per_one: 20,
137
+ count: Float::INFINITY,
138
+ is_npc_item: true,
139
+ npc_type: 'cooking',
140
+ },
141
+ 9059 => {
142
+ name: 'Mineral Water',
143
+ id: 9059,
144
+ price: 30,
145
+ price_per_one: 30,
146
+ count: Float::INFINITY,
147
+ is_npc_item: true,
148
+ npc_type: 'cooking',
149
+ },
150
+ 16080 => {
151
+ name: 'Cron Stone',
152
+ id: 16080,
153
+ price: 3_000_000,
154
+ price_per_one: 3_000_000,
155
+ count: Float::INFINITY,
156
+ is_npc_item: true,
157
+ npc_type: 'blacksmith',
158
+ },
159
+ 6656 => {
160
+ name: 'Purified Water',
161
+ id: 6656,
162
+ price: 5000,
163
+ price_per_one: 5000,
164
+ count: Float::INFINITY,
165
+ is_npc_item: true,
166
+ npc_type: 'desert goods',
167
+ main_category: 25,
168
+ sub_category: 8,
169
+ },
170
+ 8041 => {
171
+ name: 'Old Moon Solvent',
172
+ id: 8041,
173
+ price: 100000,
174
+ price_per_one: 100000,
175
+ count: Float::INFINITY,
176
+ is_npc_item: true,
177
+ npc_type: 'old moon',
178
+ },
179
+ 820978 => {
180
+ name: "Dawn\'s Aura",
181
+ id: 820978,
182
+ price: 5_000_000,
183
+ price_per_one: 5_000_000,
184
+ count: Float::INFINITY,
185
+ is_npc_item: true,
186
+ npc_type: 'old moon',
187
+ },
188
+ 820936 => {
189
+ name: 'Spellbound Catalyst',
190
+ id: 820936,
191
+ price: 1000000,
192
+ price_per_one: 1000000,
193
+ count: Float::INFINITY,
194
+ is_npc_item: true,
195
+ npc_type: 'old moon',
196
+ },
197
+ 59378 => {
198
+ name: 'Growth Reagent',
199
+ id: 59378,
200
+ price: 60000000,
201
+ price_per_one: 60000000,
202
+ count: Float::INFINITY,
203
+ is_npc_item: true,
204
+ npc_type: 'old moon',
205
+ },
206
+ 4986 => {
207
+ name: "Ibellab's Essence",
208
+ id: 4986,
209
+ price: 10000,
210
+ price_per_one: 10000,
211
+ count: Float::INFINITY,
212
+ is_npc_item: true,
213
+ npc_type: 'old moon',
214
+ },
215
+ 4916 => {
216
+ name: 'Blue Reagent',
217
+ id: 4916,
218
+ price: 50000,
219
+ price_per_one: 50000,
220
+ count: Float::INFINITY,
221
+ is_npc_item: true,
222
+ npc_type: 'material vendor',
223
+ },
224
+ 4925 => {
225
+ name: 'Tears of the Falling Moon',
226
+ id: 4925,
227
+ price: 10000,
228
+ price_per_one: 10000,
229
+ count: Float::INFINITY,
230
+ is_npc_item: true,
231
+ npc_type: 'old moon',
232
+ },
233
+ 45162 => {
234
+ name: 'Old Moon Alchemy Catalyst',
235
+ id: 45162,
236
+ price: 3500000,
237
+ price_per_one: 3500000,
238
+ count: Float::INFINITY,
239
+ is_npc_item: true,
240
+ npc_type: 'old moon',
241
+ },
242
+ 5408 => {
243
+ name: 'Arrow Mushroom',
244
+ id: 5408,
245
+ price: 1000,
246
+ price_per_one: 1000,
247
+ count: Float::INFINITY,
248
+ is_npc_item: true,
249
+ npc_type: 'mushroom vendor',
250
+ main_category: 25,
251
+ sub_category: 2,
252
+ },
253
+ 5410 => {
254
+ name: 'Cloud Mushroom',
255
+ id: 5410,
256
+ price: 1000,
257
+ price_per_one: 1000,
258
+ count: Float::INFINITY,
259
+ is_npc_item: true,
260
+ npc_type: 'mushroom vendor',
261
+ main_category: 25,
262
+ sub_category: 2,
263
+ },
264
+ 5409 => {
265
+ name: 'Dwarf Mushroom',
266
+ id: 5409,
267
+ price: 950,
268
+ price_per_one: 950,
269
+ count: Float::INFINITY,
270
+ is_npc_item: true,
271
+ npc_type: 'mushroom vendor',
272
+ main_category: 25,
273
+ sub_category: 2,
274
+ },
275
+ 5413 => {
276
+ name: 'Emperor Mushroom',
277
+ id: 5413,
278
+ price: 900,
279
+ price_per_one: 900,
280
+ count: Float::INFINITY,
281
+ is_npc_item: true,
282
+ npc_type: 'mushroom vendor',
283
+ main_category: 25,
284
+ sub_category: 2,
285
+ },
286
+ 5407 => {
287
+ name: 'Fortune Teller Mushroom',
288
+ id: 5407,
289
+ price: 900,
290
+ price_per_one: 900,
291
+ count: Float::INFINITY,
292
+ is_npc_item: true,
293
+ npc_type: 'mushroom vendor',
294
+ main_category: 25,
295
+ sub_category: 2,
296
+ },
297
+ 5414 => {
298
+ name: 'Ghost Mushroom',
299
+ id: 5414,
300
+ price: 1000,
301
+ price_per_one: 1000,
302
+ count: Float::INFINITY,
303
+ is_npc_item: true,
304
+ npc_type: 'mushroom vendor',
305
+ main_category: 25,
306
+ sub_category: 2,
307
+ },
308
+ 5411 => {
309
+ name: 'Sky Mushroom',
310
+ id: 5411,
311
+ price: 950,
312
+ price_per_one: 950,
313
+ count: Float::INFINITY,
314
+ is_npc_item: true,
315
+ npc_type: 'mushroom vendor',
316
+ main_category: 25,
317
+ sub_category: 2,
318
+ },
319
+ 5412 => {
320
+ name: 'Tiger Mushroom',
321
+ id: 5412,
322
+ price: 950,
323
+ price_per_one: 950,
324
+ count: Float::INFINITY,
325
+ is_npc_item: true,
326
+ npc_type: 'mushroom vendor',
327
+ main_category: 25,
328
+ sub_category: 2,
329
+ },
330
+ 5404 => {
331
+ name: 'Dry Mane Grass',
332
+ id: 5404,
333
+ price: 525,
334
+ price_per_one: 525,
335
+ count: Float::INFINITY,
336
+ is_npc_item: true,
337
+ npc_type: 'herb vendor',
338
+ main_category: 25,
339
+ sub_category: 2,
340
+ },
341
+ 5403 => {
342
+ name: 'Fire Flake Flower',
343
+ id: 5403,
344
+ price: 550,
345
+ price_per_one: 550,
346
+ count: Float::INFINITY,
347
+ is_npc_item: true,
348
+ npc_type: 'herb vendor',
349
+ main_category: 25,
350
+ sub_category: 2,
351
+ },
352
+ 5405 => {
353
+ name: 'Silk Honey Grass',
354
+ id: 5405,
355
+ price: 500,
356
+ price_per_one: 500,
357
+ count: Float::INFINITY,
358
+ is_npc_item: true,
359
+ npc_type: 'herb vendor',
360
+ main_category: 25,
361
+ sub_category: 2,
362
+ },
363
+ 5402 => {
364
+ name: 'Silver Azalea',
365
+ id: 5402,
366
+ price: 575,
367
+ price_per_one: 575,
368
+ count: Float::INFINITY,
369
+ is_npc_item: true,
370
+ npc_type: 'herb vendor',
371
+ main_category: 25,
372
+ sub_category: 2,
373
+ },
374
+ 5401 => {
375
+ name: 'Sunrise Herb',
376
+ id: 5401,
377
+ price: 500,
378
+ price_per_one: 500,
379
+ count: Float::INFINITY,
380
+ is_npc_item: true,
381
+ npc_type: 'herb vendor',
382
+ main_category: 25,
383
+ sub_category: 2,
384
+ },
385
+ # 15009 => {
386
+ # name: 'Magic Crystal of Abundance - Healing',
387
+ # id: 15009,
388
+ # price: 30000,
389
+ # price_per_one: 30000,
390
+ # count: Float::INFINITY,
391
+ # is_npc_item: true,
392
+ # npc_type: 'jeweler',
393
+ # },
394
+ # 15001 => {
395
+ # name: 'Magic Crystal of Flame - Precision',
396
+ # id: 15001,
397
+ # price: 30000,
398
+ # price_per_one: 30000,
399
+ # count: Float::INFINITY,
400
+ # is_npc_item: true,
401
+ # npc_type: 'jeweler',
402
+ # },
403
+ # 15020 => {
404
+ # name: 'Magic Crystal of Enchantment - Agility',
405
+ # id: 15020,
406
+ # price: 30000,
407
+ # price_per_one: 30000,
408
+ # count: Float::INFINITY,
409
+ # is_npc_item: true,
410
+ # npc_type: 'jeweler',
411
+ # },
412
+ # 15019 => {
413
+ # name: 'Magic Crystal of Enchantment - Vision',
414
+ # id: 15019,
415
+ # price: 30000,
416
+ # price_per_one: 30000,
417
+ # count: Float::INFINITY,
418
+ # is_npc_item: true,
419
+ # npc_type: 'jeweler',
420
+ # },
421
+ # 15013 => {
422
+ # name: 'Magic Crystal of Nature - Ascension',
423
+ # id: 15013,
424
+ # price: 30000,
425
+ # price_per_one: 30000,
426
+ # count: Float::INFINITY,
427
+ # is_npc_item: true,
428
+ # npc_type: 'jeweler',
429
+ # },
430
+ 4915 => {
431
+ name: 'Manos Stone',
432
+ id: 4915,
433
+ price: 5000000,
434
+ price_per_one: 5000000,
435
+ count: Float::INFINITY,
436
+ is_npc_item: true,
437
+ npc_type: 'jeweler',
438
+ },
439
+ 4903 => {
440
+ name: 'Empty Crystal',
441
+ id: 4903,
442
+ price: 2500,
443
+ price_per_one: 2500,
444
+ count: Float::INFINITY,
445
+ is_npc_item: true,
446
+ npc_type: 'general goods',
447
+ main_category: 25,
448
+ sub_category_: 8,
449
+ },
450
+ 517 => {
451
+ name: 'HP Potion (Small)',
452
+ id: 517,
453
+ price: 80,
454
+ price_per_one: 80,
455
+ count: Float::INFINITY,
456
+ is_npc_item: true,
457
+ npc_type: 'general goods',
458
+ main_category: 35,
459
+ sub_category_: 5,
460
+ },
461
+ 521 => {
462
+ name: 'HP Potion (Medium)',
463
+ id: 517,
464
+ price: 200,
465
+ price_per_one: 200,
466
+ count: Float::INFINITY,
467
+ is_npc_item: true,
468
+ npc_type: 'general goods',
469
+ main_category: 35,
470
+ sub_category_: 5,
471
+ },
472
+ 519 => {
473
+ name: 'HP Potion (Large)',
474
+ id: 517,
475
+ price: 500,
476
+ price_per_one: 500,
477
+ count: Float::INFINITY,
478
+ is_npc_item: true,
479
+ npc_type: 'general goods',
480
+ main_category: 35,
481
+ sub_category_: 5,
482
+ },
483
+ 524 => {
484
+ name: 'HP Potion (Extra Large)',
485
+ id: 524,
486
+ price: 1250,
487
+ price_per_one: 1250,
488
+ count: Float::INFINITY,
489
+ is_npc_item: true,
490
+ npc_type: 'general goods',
491
+ main_category: 35,
492
+ sub_category_: 5,
493
+ },
494
+ 520 => {
495
+ name: 'MP Potion (Small)',
496
+ id: 520,
497
+ price: 80,
498
+ price_per_one: 80,
499
+ count: Float::INFINITY,
500
+ is_npc_item: true,
501
+ npc_type: 'general goods',
502
+ main_category: 35,
503
+ sub_category_: 5,
504
+ },
505
+ 522 => {
506
+ name: 'MP Potion (Large)',
507
+ id: 522,
508
+ price: 500,
509
+ price_per_one: 500,
510
+ count: Float::INFINITY,
511
+ is_npc_item: true,
512
+ npc_type: 'general goods',
513
+ },
514
+ 526 => {
515
+ name: 'MP Potion (Extra Large)',
516
+ id: 526,
517
+ price: 1250,
518
+ price_per_one: 1250,
519
+ count: Float::INFINITY,
520
+ is_npc_item: true,
521
+ npc_type: 'general goods',
522
+ },
523
+ }
524
+
525
+ end
526
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Utils
4
+ class PriceCalculator
5
+ def self.calculate_taxed_price(price, has_value_pack = true, fame_level = 0)
6
+ fame_levels = [1, 1.005, 1.01, 1.015]
7
+ output_price = 0.65 * ((has_value_pack ? 0.3 : 0) + fame_levels[fame_level]) * price
8
+
9
+ return output_price if output_price == Float::INFINITY
10
+ return 0 unless output_price.is_a?(Numeric) && output_price.to_s.downcase != 'nan'
11
+ output_price.floor
12
+ end
13
+
14
+ def self.format_price(price)
15
+ return price.to_s.downcase if price == Float::INFINITY
16
+ return 0 unless price.is_a?(Numeric) && price.to_s.downcase != 'nan'
17
+ "¤#{price.floor.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse}".to_s.downcase
18
+ end
19
+
20
+ def self.format_num(num)
21
+ return num.to_s.downcase if num == Float::INFINITY
22
+ return 0 unless num.is_a?(Numeric) && num.to_s.downcase != 'nan'
23
+ num.floor.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse.to_s.downcase
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Utils
4
+ # log recipe information
5
+ class RecipeLogger
6
+ def initialize(cli)
7
+ @cli = cli
8
+ end
9
+
10
+ def padstr(str, space_around = ' ', len = 32, pad_with = '.')
11
+ padded = "#{str}#{space_around}"
12
+ "#{padded.ljust(len, pad_with)}#{space_around}"
13
+ end
14
+
15
+ def seconds_to_str(seconds)
16
+ return seconds if seconds == Float::INFINITY
17
+ ["#{(seconds / 3600).floor}h", "#{(seconds / 60 % 60).floor}m", "#{(seconds % 60).floor}s"]
18
+ .select { |str| str =~ /[1-9]/ }.join(" ")
19
+ end
20
+
21
+ def log_recipe_data(item, selected_recipe, max_potion_count, item_market_sell_price, total_ingredient_cost, average_procs, total_max_ingredient_cost, raw_max_market_sell_price, max_taxed_sell_profit_after_procs, raw_profit_with_procs, taxed_sell_profit_after_procs)
22
+ stock_counts = []
23
+
24
+ selected_recipe.each do |ingredient|
25
+ amount_required_for_max_potions = max_potion_count * ingredient[:quant]
26
+ ingredient_market_sell_price = ingredient[:price].to_i
27
+
28
+ next if (amount_required_for_max_potions * ingredient_market_sell_price) < 0
29
+
30
+ raw_max_ingredient_sell_price = ingredient[:price] * max_potion_count
31
+ formatted_price = @cli.yellow PriceCalculator.format_price ingredient_market_sell_price
32
+ formatted_max_price = @cli.yellow PriceCalculator.format_price raw_max_ingredient_sell_price
33
+ formatted_potion_amount = @cli.yellow PriceCalculator.format_num(ingredient[:quant]).rjust(4, ' ')
34
+ formatted_max_potion_amount = @cli.yellow PriceCalculator.format_num max_potion_count * ingredient[:quant]
35
+ formatted_stock_count = @cli.yellow PriceCalculator.format_num ingredient[:total_in_stock]
36
+ formatted_npc_information = ingredient[:is_npc_item] ? @cli.yellow(" (sold by #{ingredient[:npc_type]} npcs)") : ''
37
+
38
+ stock_counts.push "#{formatted_potion_amount} [max: #{formatted_max_potion_amount}] [#{ingredient[:id]}] #{@cli.yellow "#{ingredient[:name].downcase}: #{formatted_stock_count}"} in stock#{formatted_npc_information}. price: #{formatted_price} [for max: #{formatted_max_price}]"
39
+ end
40
+
41
+ market_stock_string = item[:total_in_stock] > 2000 ? @cli.red(PriceCalculator.format_num(item[:total_in_stock])) : @cli.green(PriceCalculator.format_num(item[:total_in_stock]))
42
+
43
+ trade_count_string = item[:total_trade_count] < 10_000_000 ? @cli.red(PriceCalculator.format_num(item[:total_trade_count])) : @cli.green(PriceCalculator.format_num(item[:total_trade_count]))
44
+
45
+ estimated_craft_time = 1.2
46
+ calculated_time = max_potion_count * estimated_craft_time
47
+ crafting_time_string = calculated_time > 21600 ? @cli.red((seconds_to_str(calculated_time))) : @cli.green((seconds_to_str(calculated_time)))
48
+ silver_per_hour = max_taxed_sell_profit_after_procs.to_f / (calculated_time.to_f / 3600)
49
+
50
+ information = " #{@cli.yellow "[#{item[:id]}] [#{item[:name].downcase}], recipe id: #{selected_recipe[0][:for_recipe_id]}"}
51
+
52
+ #{padstr("market price of item")}#{@cli.yellow PriceCalculator.format_price item_market_sell_price}
53
+ #{padstr("market stock of item")}#{market_stock_string}
54
+ #{padstr("total trades of item")}#{trade_count_string}
55
+ #{padstr("you can craft")}#{@cli.yellow PriceCalculator.format_num max_potion_count}
56
+ #{padstr("theoretical max output")}#{@cli.yellow PriceCalculator.format_num(max_potion_count * average_procs)}
57
+ #{padstr("cost of ingredients")}#{@cli.yellow PriceCalculator.format_price total_ingredient_cost} (accounting for average #{average_procs} / craft)
58
+ #{padstr("max cost of ingredients")}#{@cli.yellow PriceCalculator.format_price total_max_ingredient_cost} (accounting for average #{average_procs} / craft)
59
+ #{padstr("time to craft max")}#{crafting_time_string} (accounting for average #{estimated_craft_time}s / craft due to typical server delay)
60
+
61
+ \t#{stock_counts.join "\n\t"}
62
+
63
+ total income for max items before cost subtraction #{@cli.green PriceCalculator.format_price raw_max_market_sell_price}
64
+ #{padstr("total taxed silver per hour")}#{@cli.green PriceCalculator.format_price(silver_per_hour) } silver / hour
65
+ #{padstr("total untaxed profit")}#{@cli.green PriceCalculator.format_price raw_profit_with_procs} [max: #{@cli.green PriceCalculator.format_price(raw_profit_with_procs * max_potion_count)}]
66
+ #{padstr("total taxed profit")}#{@cli.green PriceCalculator.format_price taxed_sell_profit_after_procs} [max: #{@cli.green PriceCalculator.format_price(max_taxed_sell_profit_after_procs)}]
67
+ "
68
+ { recipe_info: information, silver_per_hour: silver_per_hour }
69
+ end
70
+ end
71
+ end