Sonicover

Arky Mart Main

Jan 6th, 2025
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 39.75 KB | None | 0 0
  1. class PokemonMartAdapter
  2. def getMoney
  3. case $currency.downcase
  4. when "money", "gold"
  5. return $player.money
  6. when "coins"
  7. return $player.coins
  8. when "battle points", "bp"
  9. return $player.battle_points
  10. end
  11. end
  12.  
  13. def getMoneyString
  14. case $currency.downcase
  15. when "money", "gold"
  16. return _INTL("Money:\n<r>{1}", pbGetGoldString)
  17. when "coins"
  18. return _INTL("Coins:\n<r>{1}", $player.coins.to_s_formatted)
  19. when "battle points", "bp"
  20. return _INTL("Battle Points:\n<r>{1}", $player.battle_points.to_s_formatted)
  21. end
  22. end
  23.  
  24. def setMoney(value)
  25. case $currency.downcase
  26. when "money", "gold"
  27. return $player.money = value
  28. when "coins"
  29. return $player.coins = value
  30. when "battle points", "bp"
  31. return $player.battle_points = value
  32. end
  33. end
  34.  
  35. def getPrice(item, selling = false, discount = nil)
  36. if selling.is_a?(Numeric)
  37. discount = selling if selling
  38. selling = false
  39. end
  40. gameVar = $game_variables[discount.abs] if discount
  41. disc = 0
  42. if discount && !gameVar.nil? && gameVar >= 0
  43. APMSettings::Discounts.each do |item, var|
  44. if item.is_a?(Symbol) && $bag.has?(item)
  45. disc = var[discount][gameVar] if var.is_a?(Hash) && var.key?(discount)
  46. elsif var.is_a?(Array) || var.is_a?(Numeric)
  47. disc = var[gameVar]
  48. end
  49. end
  50. end
  51. price = GameData::Item.get(item).price.to_f
  52. newPrice = (price * ((100 - disc).to_f / 100)).round(0)
  53. if $game_temp.mart_prices && $game_temp.mart_prices[item]
  54. if selling
  55. return $game_temp.mart_prices[item][1] if $game_temp.mart_prices[item][1] >= 0
  56. elsif $game_temp.mart_prices[item][0] > 0
  57. return $game_temp.mart_prices[item][0]
  58. end
  59. end
  60. return GameData::Item.get(item).sell_price if selling
  61. return newPrice
  62. end
  63.  
  64. def getDisplayPrice(item, selling = false, discount = nil)
  65. price = getPrice(item, selling, discount).to_s_formatted
  66. case $currency.downcase
  67. when "money", "gold"
  68. return _INTL("$ {1}", price)
  69. when "coins"
  70. return _INTL("{1} Coins", price)
  71. when "battle points", "bp"
  72. return _INTL("{1} BP", price)
  73. end
  74. end
  75.  
  76. def getCurrencyPrice(price)
  77. case $currency.downcase
  78. when "money", "gold"
  79. return "$#{price}"
  80. when "coins"
  81. return "#{price} Coins"
  82. when "battle points", "bp"
  83. return "#{price} BP"
  84. end
  85. end
  86.  
  87. def getCurrency
  88. case $currency.downcase
  89. when "money", "gold"
  90. return "Money"
  91. when "coins"
  92. return "Coins"
  93. when "battle points", "bp"
  94. return "Battle Points"
  95. end
  96. end
  97.  
  98. def setChangeMoney(value)
  99. money = getMoney - value
  100. times = money.abs > 50 ? 50 : money.abs
  101. amount = money != 0 ? (money / times).round : 0
  102. $amount = (1..times).map { |step| getMoney - (amount * step) }
  103. end
  104. end
  105.  
  106. class BuyAdapter
  107. def getDisplayPrice(item, discount)
  108. @adapter.getDisplayPrice(item, false, discount)
  109. end
  110. end
  111.  
  112. class PokemonMart_Scene
  113. def pbRefresh
  114. if @subscene
  115. @subscene.pbRefresh
  116. else
  117. itemwindow = @sprites["itemwindow"]
  118. return if itemwindow.nil?
  119. @sprites["icon"].item = itemwindow.item
  120. @sprites["itemtextwindow"].text =
  121. (itemwindow.item) ? @adapter.getDescription(itemwindow.item) : _INTL("Quit shopping.")
  122. @sprites["qtywindow"].visible = !itemwindow.item.nil?
  123. @sprites["qtywindow"].text = _INTL("In Bag:<r>{1}", @adapter.getQuantity(itemwindow.item))
  124. @sprites["qtywindow"].y = Graphics.height - 102 - @sprites["qtywindow"].height
  125. itemwindow.refresh
  126. end
  127. updateCurrencyWindow(@sprites["moneywindow"], @adapter)
  128. end
  129.  
  130. def pbStartBuyOrSellScene(buying, stock, choiceStock, stockByCat, adapter, pokeMartTracker, discount)
  131. # Scroll right before showing screen
  132. pbScrollMap(6, 5, 5)
  133. pbSEPlay("GUI menu open")
  134. @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
  135. @viewport.z = 99999
  136. if choiceStock.nil?
  137. @stock = stock
  138. @stockIndex = 0
  139. else
  140. @stock = stock = choiceStock
  141. @stockIndex = stockByCat.values.index(choiceStock)
  142. @stockByCat = stockByCat
  143. @catName = stockByCat.keys[@stockIndex]
  144. end
  145. @pokeMartTracker = pokeMartTracker
  146. @discount = discount
  147. @adapter = adapter
  148. @sprites = {}
  149. @sprites["background"] = IconSprite.new(0, 0, @viewport)
  150. if Essentials::VERSION.include?("21")
  151. @sprites["background"].setBitmap("Graphics/UI/Mart/bg")
  152. else
  153. @sprites["background"].setBitmap("Graphics/Pictures/martScreen")
  154. end
  155. @sprites["icon"] = ItemIconSprite.new(36, Graphics.height - 50, nil, @viewport)
  156. @winAdapter = buying ? BuyAdapter.new(adapter) : SellAdapter.new(adapter)
  157. @sprites["category"] = BitmapSprite.new(Graphics.width, Graphics.height, @viewport)
  158. @sprites["category"].visible = true
  159. pbSetSystemFont(@sprites["category"].bitmap)
  160. pbDrawTextPositions(@sprites["category"].bitmap, [
  161. [@catName, Graphics.width - 300, 30, 0, Color.new(88, 88, 80), Color.new(168, 184, 184)],
  162. ["Page #{@stockIndex + 1}/#{@stockByCat.length}", 490, 30, 1, Color.new(88, 88, 80), Color.new(168, 184, 184)],
  163. ["-----------------------", Graphics.width - 300, 46, 0, Color.new(88, 88, 80), Color.new(168, 184, 184)]
  164. ])
  165. yMin = 42
  166. yMax = 156
  167. else
  168. yMin = 10
  169. yMax = 128
  170. end
  171. @sprites["itemwindow"] = Window_PokemonMart.new(
  172. stock, @winAdapter, Graphics.width - 316 - 16, yMin, 330 + 16, Graphics.height - yMax, nil, @pokeMartTracker, @discount
  173. )
  174. @sprites["itemwindow"].viewport = @viewport
  175. @sprites["itemwindow"].index = 0
  176. @sprites["itemwindow"].refresh
  177. @sprites["itemtextwindow"] = Window_UnformattedTextPokemon.newWithSize(
  178. "", 64, Graphics.height - 96 - 16, Graphics.width - 64, 128, @viewport
  179. )
  180. pbPrepareWindow(@sprites["itemtextwindow"])
  181. @sprites["itemtextwindow"].baseColor = Color.new(248, 248, 248)
  182. @sprites["itemtextwindow"].shadowColor = Color.black
  183. @sprites["itemtextwindow"].windowskin = nil
  184. @sprites["helpwindow"] = Window_AdvancedTextPokemon.new("")
  185. pbPrepareWindow(@sprites["helpwindow"])
  186. @sprites["helpwindow"].visible = false
  187. @sprites["helpwindow"].viewport = @viewport
  188. pbBottomLeftLines(@sprites["helpwindow"], 1)
  189. @sprites["moneywindow"] = Window_AdvancedTextPokemon.new("")
  190. pbPrepareWindow(@sprites["moneywindow"])
  191. @sprites["moneywindow"].setSkin("Graphics/Windowskins/goldskin")
  192. @sprites["moneywindow"].visible = true
  193. @sprites["moneywindow"].viewport = @viewport
  194. @sprites["moneywindow"].x = 0
  195. @sprites["moneywindow"].y = 0
  196. @sprites["moneywindow"].width = 190
  197. @sprites["moneywindow"].height = 96
  198. @sprites["moneywindow"].baseColor = Color.new(88, 88, 80)
  199. @sprites["moneywindow"].shadowColor = Color.new(168, 184, 184)
  200. @sprites["qtywindow"] = Window_AdvancedTextPokemon.new("")
  201. pbPrepareWindow(@sprites["qtywindow"])
  202. @sprites["qtywindow"].setSkin("Graphics/Windowskins/goldskin")
  203. @sprites["qtywindow"].viewport = @viewport
  204. @sprites["qtywindow"].width = 190
  205. @sprites["qtywindow"].height = 64
  206. @sprites["qtywindow"].baseColor = Color.new(88, 88, 80)
  207. @sprites["qtywindow"].shadowColor = Color.new(168, 184, 184)
  208. @sprites["qtywindow"].text = _INTL("In Bag:<r>{1}", @adapter.getQuantity(@sprites["itemwindow"].item))
  209. @sprites["qtywindow"].y = Graphics.height - 102 - @sprites["qtywindow"].height
  210. pbDeactivateWindows(@sprites)
  211. @buying = buying
  212. pbRefresh
  213. Graphics.frame_reset
  214. end
  215.  
  216. def pbStartBuyScene(stock, choiceStock, stockByCat, adapter, pokeMartTracker, discount)
  217. pbStartBuyOrSellScene(true, stock, choiceStock, stockByCat, adapter, pokeMartTracker, discount)
  218. end
  219.  
  220. def pbChooseBuyItem
  221. itemwindow = @sprites["itemwindow"]
  222. @sprites["helpwindow"].visible = false
  223. pbActivateWindow(@sprites, "itemwindow") do
  224. pbRefresh
  225. loop do
  226. Graphics.update
  227. Input.update
  228. olditem = itemwindow.item
  229. self.update
  230. pbRefresh if itemwindow.item != olditem
  231. if Input.trigger?(Input::LEFT) && [email protected]?
  232. pbSEPlay("GUI naming tab swap start")
  233. @stockIndex -= 1
  234. @stockIndex = @stockByCat.length - 1 if @stockIndex < 0
  235. updateStock
  236. itemwindow = @sprites["itemwindow"]
  237. pbRefresh
  238. next
  239. elsif Input.trigger?(Input::RIGHT) && [email protected]?
  240. pbSEPlay("GUI naming tab swap start")
  241. @stockIndex += 1
  242. @stockIndex = 0 if @stockIndex > @stockByCat.length - 1
  243. pbPlayCursorSE
  244. updateStock
  245. itemwindow = @sprites["itemwindow"]
  246. pbRefresh
  247. next
  248. elsif Input.trigger?(Input::BACK)
  249. pbPlayCloseMenuSE
  250. return nil
  251. elsif Input.trigger?(Input::USE)
  252. if itemwindow.index < @stock.length
  253. pbRefresh
  254. return @stock[itemwindow.index]
  255. else
  256. return nil
  257. end
  258. end
  259. end
  260. end
  261. end
  262.  
  263. def updateStock
  264. @stock = @stockByCat.values[@stockIndex]
  265. if @sprites["category"]
  266. @sprites["category"].bitmap.clear
  267. @catName = @stockByCat.keys[@stockIndex]
  268. pbDrawTextPositions(@sprites["category"].bitmap, [
  269. [@catName, Graphics.width - 300, 30, 0, Color.new(88, 88, 80), Color.new(168, 184, 184)],
  270. ["Page #{@stockIndex + 1}/#{@stockByCat.length}", 490, 30, 1, Color.new(88, 88, 80), Color.new(168, 184, 184)],
  271. ["-----------------------", Graphics.width - 300, 46, 0, Color.new(88, 88, 80), Color.new(168, 184, 184)]
  272. ])
  273. yMin = 42
  274. yMax = 156
  275. else
  276. yMin = 10
  277. yMax = 124
  278. end
  279. @sprites["itemwindow"].dispose
  280. @sprites["itemwindow"] = Window_PokemonMart.new(
  281. @stock, @winAdapter, Graphics.width - 316 - 16, yMin, 330 + 16, Graphics.height - yMax, nil, @pokeMartTracker, @discount
  282. )
  283. @sprites["itemwindow"].viewport = @viewport
  284. @sprites["itemwindow"].index = 0
  285. @sprites["itemwindow"].refresh
  286. end
  287.  
  288. def pbChooseNumber(helptext, item, maximum, minimum = 1, quantity = 1)
  289. curnumber = quantity || 1
  290. ret = 0
  291. helpwindow = @sprites["helpwindow"]
  292. itemprice = @adapter.getPrice(item, !@buying, @discount)
  293. pbDisplay(helptext, true)
  294. using(numwindow = Window_AdvancedTextPokemon.new("")) do # Showing number of items
  295. pbPrepareWindow(numwindow)
  296. numwindow.viewport = @viewport
  297. numwindow.width = 224
  298. numwindow.height = 64
  299. numwindow.baseColor = Color.new(88, 88, 80)
  300. numwindow.shadowColor = Color.new(168, 184, 184)
  301. numwindow.text = _INTL("x{1}<r>$ {2}", curnumber, (curnumber * itemprice).to_s_formatted)
  302. pbBottomRight(numwindow)
  303. numwindow.y -= helpwindow.height
  304. loop do
  305. Graphics.update
  306. Input.update
  307. numwindow.update
  308. update
  309. oldnumber = curnumber
  310. if Input.repeat?(Input::LEFT)
  311. curnumber -= 10
  312. curnumber = minimum if curnumber < minimum
  313. if curnumber != oldnumber
  314. numwindow.text = _INTL("x{1}<r>$ {2}", curnumber, (curnumber * itemprice).to_s_formatted)
  315. pbPlayCursorSE
  316. end
  317. elsif Input.repeat?(Input::RIGHT)
  318. curnumber += 10
  319. curnumber = maximum if curnumber > maximum
  320. if curnumber != oldnumber
  321. numwindow.text = _INTL("x{1}<r>$ {2}", curnumber, (curnumber * itemprice).to_s_formatted)
  322. pbPlayCursorSE
  323. end
  324. elsif Input.repeat?(Input::UP)
  325. curnumber += 1
  326. curnumber = minimum if curnumber > maximum
  327. if curnumber != oldnumber
  328. numwindow.text = _INTL("x{1}<r>$ {2}", curnumber, (curnumber * itemprice).to_s_formatted)
  329. pbPlayCursorSE
  330. end
  331. elsif Input.repeat?(Input::DOWN)
  332. curnumber -= 1
  333. curnumber = maximum if curnumber < minimum
  334. if curnumber != oldnumber
  335. numwindow.text = _INTL("x{1}<r>$ {2}", curnumber, (curnumber * itemprice).to_s_formatted)
  336. pbPlayCursorSE
  337. end
  338. elsif Input.trigger?(Input::USE)
  339. ret = curnumber
  340. break
  341. elsif Input.trigger?(Input::BACK)
  342. pbPlayCancelSE
  343. ret = quantity > 1 ? quantity : 0
  344. break
  345. end
  346. end
  347. end
  348. helpwindow.visible = false
  349. return ret
  350. end
  351. end
  352.  
  353. class PokemonMartScreen
  354. def initialize(scene, stock, speech = nil, choiceStock = nil, stockByCat = nil, pokeMartTracker = nil, discount = nil)
  355. @scene = scene
  356. @stock = stock
  357. @discount = discount
  358. @getSpeech = speech
  359. @choiceStock = choiceStock
  360. @stockByCat = stockByCat
  361. $pokeMartTracker = pokeMartTracker
  362. @adapter = PokemonMartAdapter.new
  363. end
  364.  
  365. def pbBuyScreen
  366. @scene.pbStartBuyScene(@stock, @choiceStock, @stockByCat, @adapter, $pokeMartTracker, @discount)
  367. item = nil
  368. loop do
  369. item = @scene.pbChooseBuyItem
  370. break if !item
  371. quantity = 0
  372. itemname = @adapter.getDisplayName(item)
  373. itemnameplural = @adapter.getDisplayNamePlural(item)
  374. price = @adapter.getPrice(item, @discount)
  375. if @adapter.getMoney < price
  376. pbDisplayPaused(_INTL(@getSpeech[:NotEnoughMoney]&.sample || "You don't have enough money."))
  377. next
  378. end
  379. if GameData::Item.get(item).is_important?
  380. next if !pbConfirm(_INTL(@getSpeech[:BuyItemImportant]&.sample || "So you want {1}?\nIt'll be {2}. All right?", itemname, @adapter.getCurrencyPrice(price.to_s_formatted)))
  381. quantity = 1
  382. else
  383. totAddItems = getMaxAddableItems(item)
  384. maxafford = (price <= 0) ? Settings::BAG_MAX_PER_SLOT : @adapter.getMoney / price
  385. maxafford = Settings::BAG_MAX_PER_SLOT if maxafford > Settings::BAG_MAX_PER_SLOT
  386. maxafford = totAddItems if Settings::BAG_MAX_PER_SLOT > totAddItems && totAddItems > 0
  387. entry = $pokeMartTracker[:items].find { |entry| entry[:name] == item } if $pokeMartTracker.key?(:items)
  388. maxafford = entry[:limit] if !entry.nil? && entry[:limit] < maxafford && entry[:limit] <= Settings::BAG_MAX_PER_SLOT
  389. if [email protected]? && $game_variables[@discount] > 0
  390. oldPrice = @adapter.getPrice(item, nil)
  391. if price != oldPrice
  392. if price < oldPrice
  393. quantity = @scene.pbChooseNumber(
  394. _INTL(@getSpeech[:BuyItemAmountDiscount]&.sample || "So how many {1}?", itemnameplural, @adapter.getCurrencyPrice(price), @adapter.getCurrencyPrice(oldPrice)),
  395. item, maxafford) unless maxafford == 0
  396. elsif price > oldPrice
  397. quantity = @scene.pbChooseNumber(
  398. _INTL(@getSpeech[:BuyItemAmountOvercharge]&.sample || "So how many {1}?", itemnameplural, @adapter.getCurrencyPrice(price), @adapter.getCurrencyPrice(oldPrice)),
  399. item, maxafford) unless maxafford == 0
  400. end
  401. else
  402. Console.echoln_li _INTL("Please check the value of game variable #{@discount}, it's too high according to it's Discounts values")
  403. end
  404. else
  405. quantity = @scene.pbChooseNumber(
  406. _INTL(@getSpeech[:BuyItemAmount]&.sample || "So how many {1}?", itemnameplural),
  407. item, maxafford) unless maxafford == 0
  408. end
  409. if !entry.nil? && entry[:limit] == 0
  410. quantity = 0
  411. pbDisplayPaused(_INTL(@getSpeech[:BuyOutOfStock]&.sample || "I'm sorry, we are currently out of {1}. Come back {2}.", itemnameplural, $pokeMartTracker[:refresh]))
  412. end
  413. if quantity == 0
  414. pbDisplayPaused(_INTL(@getSpeech[:NoRoomInBag]&.sample || "You have no room in your Bag.")) if totAddItems == 0
  415. next
  416. end
  417. price *= quantity
  418. if quantity > 1
  419. next if !pbConfirm(_INTL(@getSpeech[:BuyItemMult]&.sample || "So you want {1} {2}?\nThey'll be {3}. All right?", quantity, itemnameplural, @adapter.getCurrencyPrice(price.to_s_formatted)))
  420. elsif quantity > 0
  421. next if !pbConfirm(_INTL(@getSpeech[:BuyItem]&.sample || "So you want {1} {2}?\nIt'll be {3}. All right?", quantity, itemname, @adapter.getCurrencyPrice(price.to_s_formatted)))
  422. end
  423. end
  424. if @adapter.getMoney < price
  425. pbDisplayPaused(_INTL(@getSpeech[:NotEnoughMoney]&.sample || "You don't have enough {1}.", @adapter.getCurrency))
  426. next
  427. end
  428. entry[:limit] -= quantity if !entry.nil? && quantity != 0
  429. added = 0
  430. quantity.times do
  431. break if [email protected](item)
  432. added += 1
  433. end
  434. if added == quantity
  435. $stats.money_spent_at_marts += price
  436. $stats.mart_items_bought += quantity
  437. @adapter.setChangeMoney(@adapter.getMoney - price)
  438. @stock.delete_if { |item| GameData::Item.get(item).is_important? && $bag.has?(item) }
  439. @stockByCat.each do |key, values|
  440. values.delete_if do |item|
  441. GameData::Item.get(item).is_important? && $bag.has?(item)
  442. end
  443. if values.empty?
  444. @stockByCat.delete(key)
  445. end
  446. end
  447. end
  448. pbDisplayPaused(_INTL(@getSpeech[:BuyThanks]&.sample || "Here you are! Thank you!")) { pbSEPlay("Mart buy item") }
  449. Achievements.setProgress("ITEMS_BOUGHT",$stats.mart_items_bought) if PluginManager.installed?("Mega MewThree's Achievement System")
  450. getBonusItems(item, @adapter, quantity, @getSpeech)
  451. else
  452. added.times do
  453. raise _INTL("Failed to delete stored items")
  454. end
  455. end
  456. pbDisplayPaused(_INTL(@getSpeech[:NoRoomInBag]&.sample || "You have no room in your Bag."))
  457. end
  458. end
  459. @scene.pbEndBuyScene
  460. end
  461.  
  462. def getMaxAddableItems(item)
  463. pocket = GameData::Item.get(item).pocket
  464. list = $bag.pockets[pocket]
  465. maxPocketSize = Settings::BAG_MAX_POCKET_SIZE[pocket - 1]
  466. return maxPocketSize if maxPocketSize < 0
  467. maxPerSlot = Settings::BAG_MAX_PER_SLOT
  468. currItems = list.select { |slot| slot[0] == item }
  469. totCurrItems = currItems.sum { |slot| slot[1] }
  470. avSpaceInSlot = currItems.sum { |slot| maxPerSlot - slot[1] }
  471. avSlots = maxPocketSize - list.size
  472. totAddItems = avSpaceInSlot + (avSlots * maxPerSlot)
  473. return totAddItems
  474. end
  475.  
  476. def pbSellScreen
  477. item = @scene.pbStartSellScene(@adapter.getInventory, @adapter)
  478. loop do
  479. item = @scene.pbChooseSellItem
  480. break if !item
  481. itemname = @adapter.getDisplayName(item)
  482. itemnameplural = @adapter.getDisplayNamePlural(item)
  483. if [email protected]?(item)
  484. pbDisplayPaused(_INTL(@getSpeech[:CantSellItem]&.sample || "Oh, no. I can't buy {1}.", itemnameplural))
  485. next
  486. end
  487. price = @adapter.getPrice(item, true, @discount)
  488. qty = @adapter.getQuantity(item)
  489. next if qty == 0
  490. @scene.pbShowMoney
  491. if qty > 1
  492. qty = @scene.pbChooseNumber(
  493. _INTL(@getSpeech[:SellItemAmount]&.sample || "How many {1} would you like to sell?", itemnameplural), item, qty
  494. )
  495. end
  496. if qty == 0
  497. @scene.pbHideMoney
  498. next
  499. end
  500. price *= qty
  501. if pbConfirm(_INTL(@getSpeech[:SellItem]&.sample || "I can pay {1}.\nWould that be OK?", @adapter.getCurrencyPrice(price.to_s_formatted)))
  502. old_money = @adapter.getMoney
  503. @adapter.setChangeMoney(@adapter.getMoney + price)
  504. $stats.money_earned_at_marts += @adapter.getMoney - old_money
  505. qty.times { @adapter.removeItem(item) }
  506. Achievements.incrementProgress("ITEMS_SOLD",qty) if PluginManager.installed?("Mega MewThree's Achievement System")
  507. sold_item_name = (qty > 1) ? itemnameplural : itemname
  508. pbDisplayPaused(_INTL("You turned over the {1} and got {2}.",
  509. sold_item_name, @adapter.getCurrencyPrice(price.to_s_formatted))) { pbSEPlay("Mart buy item") }
  510. @scene.pbRefresh
  511. end
  512. @scene.pbHideMoney
  513. end
  514. @scene.pbEndSellScene
  515. end
  516. end
  517.  
  518. def forcePokemonMartRefresh
  519. return if $ArckyGlobal.pokeMartTracker.empty?
  520. $ArckyGlobal.pokeMartTracker.each do |mapID, events|
  521. events.each do |eventID, values|
  522. next if values[:refresh] == "never"
  523. $ArckyGlobal.pokeMartTracker[mapID][eventID] = nil
  524. end
  525. end
  526. end
  527.  
  528. def pbShelfMart(stockWithLimit, speech: nil, useCat: false, discount: nil, currency: "money")
  529. setCurrency(currency)
  530. refreshRate, stock = extractStock(stockWithLimit)
  531. pokeMartTracker = createPokeMartTracker(stockWithLimit, refreshRate)
  532. stock = editStockBadgeOrImportant(stock)
  533. getSpeech = getChosenSpeech(speech)
  534. pbMessage(_INTL(getSpeech[:IntroShelf]&.sample || "Is there anything catching your eye?"))
  535. scene = PokemonMart_Scene.new
  536. screen = PokemonMartScreen.new(scene, stock, getSpeech, nil, nil, pokeMartTracker, discount)
  537. screen.pbShelfScreen
  538. $ArckyGlobal.pokeMartTracker[@map_id][@event_id] = $pokeMartTracker unless $pokeMartTracker&.empty?
  539. $ArckyGlobal.pokeMartTracker[@map_id][@event_id][:bill] = $bill
  540. $game_temp.clear_mart_prices
  541. end
  542.  
  543. def pbPokemonMart(stockWithLimit, speech: nil, useCat: false, discount: nil, currency: "money", cantSell: false)
  544. setCurrency(currency)
  545. refreshRate, stock = extractStock(stockWithLimit)
  546. # no speech given (optional useCat, discount, currency and cantSell):
  547. pokeMartTracker = createPokeMartTracker(stockWithLimit, refreshRate)
  548. stock = editStockBadgeOrImportant(stock)
  549. getSpeech = getChosenSpeech(speech)
  550. commands, cmdBuy, cmdSell, cmdBill, cmdQuit = setCommands(cantSell)
  551. introText = getTimeOfDay(getSpeech, "Intro")
  552. cmd = pbMessage(_INTL(introText&.sample || "Welcome! How may I help you?"), commands, cmdQuit + 1)
  553. loop do
  554. catStock = []
  555. if cmdBuy >= 0 && cmd == cmdBuy
  556. if useCat
  557. stockByCat = convertStockByCategories(stockByCat, stock)
  558. choice = !speech.nil? && !(getSpeech[:CategoryText]&.empty?) ? pbMessage(_INTL(getSpeech[:CategoryText]&.sample), stockByCat.keys << "Go Back", -1) : 0
  559. if choice != -1 && choice != stockByCat.length
  560. choiceStock = stockByCat.values[choice]
  561. pbPlayDecisionSE
  562. end
  563. end
  564. unless choiceStock.nil? && useCat
  565. scene = PokemonMart_Scene.new
  566. screen = PokemonMartScreen.new(scene, stock, getSpeech, choiceStock, stockByCat, pokeMartTracker, discount)
  567. screen.pbBuyScreen
  568. end
  569. elsif cmdSell >= 0 && cmd == cmdSell
  570. scene = PokemonMart_Scene.new
  571. screen = PokemonMartScreen.new(scene, stock, getSpeech)
  572. screen.pbSellScreen
  573. elsif cmdBill >= 0 && cmd == cmdBill
  574. payBill(getSpeech)
  575. $game_switches[APMSettings::BillSwitch] = false
  576. commands, cmdBuy, cmdSell, cmdBill, cmdQuit = setCommands(cantSell)
  577. else
  578. outroText = getTimeOfDay(getSpeech, "Outro")
  579. pbMessage(_INTL(outroText&.sample || "Do come again!"))
  580. break
  581. end
  582. cmd = pbMessage(_INTL(getSpeech[:MenuReturnText]&.sample || "Is there anything else I can do for you?"), commands, cmdQuit + 1)
  583. end
  584. $ArckyGlobal.pokeMartTracker[@map_id][@event_id] = $pokeMartTracker unless $pokeMartTracker&.empty?
  585. $game_temp.clear_mart_prices
  586. end
  587.  
  588. def setCurrency(currency)
  589. if ["money", "gold", "coins", "battle points", "bp"].any? { |value| value == currency.downcase }
  590. $currency = currency
  591. else
  592. $currency = "money"
  593. Console.echoln_li _INTL("#{currency} is an invalid Currency!")
  594. end
  595. end
  596.  
  597. def setCommands(cantSell)
  598. commands = []
  599. cmdBuy = -1
  600. cmdSell = -1
  601. cmdBill = -1
  602. cmdQuit = -1
  603. commands[cmdBuy = commands.length] = _INTL("I'm here to buy") if !$game_switches[APMSettings::BillSwitch]
  604. commands[cmdSell = commands.length] = _INTL("I'm here to sell") if !cantSell && !$game_switches[APMSettings::BillSwitch]
  605. commands[cmdBill = commands.length] = _INTL("I'm here to checkout") if $game_switches[APMSettings::BillSwitch]
  606. commands[cmdQuit = commands.length] = _INTL("No, thanks")
  607. return commands, cmdBuy, cmdSell, cmdBill, cmdQuit
  608. end
  609. =begin
  610. def createPokeMartTracker(stockWithLimit, refreshRate)
  611. date = pbGetTimeNow.strftime("%Y-%m-%d")
  612. $ArckyGlobal.pokeMartTracker ||= {}
  613. $ArckyGlobal.pokeMartTracker[@map_id] ||= {}
  614. $ArckyGlobal.pokeMartTracker[@map_id][@event_id] ||= {}
  615. pokeMartTracker = $ArckyGlobal.pokeMartTracker[@map_id][@event_id]
  616. $ArckyGlobal.pokeMartTracker[@map_id][@event_id][:bill] ||= {}
  617. $bill = $ArckyGlobal.pokeMartTracker[@map_id][@event_id][:bill]
  618. $bill = { :total => 0, :basket => {}, :currency => $currency, :event => @event_id } if $bill.empty?
  619. if stockWithLimit.any? {|item| item.is_a?(Array) }
  620. # get the days between the day that one item was out of stock and the day of checking again
  621. daysDiff = getPreviousRefreshDate(date)
  622. timeInDays = convertDays(refreshRate, daysDiff)
  623. if timeInDays.nil? && refreshRate != "never"
  624. $ArckyGlobal.pokeMartTracker[@map_id][@event_id] = {}
  625. daysDiff = getPreviousRefreshDate(date)
  626. timeInDays = convertDays(refreshRate, daysDiff)
  627. end
  628. # canRefresh is true if the daysDiff is equal to the refreshRate day requirement.
  629. pokeMartTracker = { :date => date, :refresh => timeInDays, :items => getItemList(stockWithLimit.drop(1)) } if pokeMartTracker.empty? || pokeMartTracker.length <= 1
  630. pokeMartTracker[:refresh] = timeInDays if !pokeMartTracker.empty?
  631. end
  632. return pokeMartTracker
  633. end
  634. =end
  635.  
  636. # Helper method to convert a date string into a "day count" value (number of days since a reference date)
  637. def convert_to_day_count(date_str)
  638. # Split the date string into year, month, day
  639. year, month, day = date_str.split("-").map(&:to_i)
  640.  
  641. # Calculate the total days since the reference date (using a simplified approach)
  642. # This example assumes 365 days in a year and doesn't account for leap years
  643. (year * 365) + (month * 30) + day # This is a rough estimate
  644. end
  645.  
  646. def createPokeMartTracker(stockWithLimit, refreshRate)
  647. # Get the current date in string format
  648. current_date = pbGetTimeNow
  649. current_date_str = current_date.strftime("%Y-%m-%d")
  650.  
  651. # Ensure PokeMart tracker structure exists
  652. $ArckyGlobal.pokeMartTracker ||= {}
  653. $ArckyGlobal.pokeMartTracker[@map_id] ||= {}
  654. $ArckyGlobal.pokeMartTracker[@map_id][@event_id] ||= {}
  655. pokeMartTracker = $ArckyGlobal.pokeMartTracker[@map_id][@event_id]
  656.  
  657. # Initialize bill if not set
  658. $bill = pokeMartTracker[:bill] || {}
  659. $bill = { :total => 0, :basket => {}, :currency => $currency, :event => @event_id } if $bill.empty?
  660.  
  661. if stockWithLimit.any? { |item| item.is_a?(Array) }
  662. # Retrieve or initialize the previous date from the tracker
  663. previous_date_str = pokeMartTracker[:date] || current_date_str
  664.  
  665. current_date_value = convert_to_day_count(current_date_str)
  666. previous_date_value = convert_to_day_count(pokeMartTracker[:date] || current_date_str)
  667. # Calculate the days difference
  668. daysDiff = current_date_value - previous_date_value
  669.  
  670. # Convert days difference into a refresh time
  671. timeInDays = convertDays(refreshRate, daysDiff)
  672. puts "Time in Days 1: #{timeInDays}"
  673.  
  674. # Handle refresh logic
  675. if timeInDays.nil? && refreshRate != "never"
  676. $ArckyGlobal.pokeMartTracker[@map_id][@event_id] = {}
  677. previous_date_str = pokeMartTracker[:date] || current_date_str # Fallback
  678. daysDiff = current_date_value - previous_date_value#getPreviousRefreshDate(previous_date_str)
  679. timeInDays = convertDays(refreshRate, daysDiff)
  680. puts "Time in Days 2: #{timeInDays}"
  681. end
  682.  
  683. # Update the tracker if it's empty or needs to be refreshed
  684. if pokeMartTracker.empty? || pokeMartTracker.length <= 1
  685. pokeMartTracker[:date] = current_date_str
  686. pokeMartTracker[:refresh] = timeInDays
  687. pokeMartTracker[:items] = getItemList(stockWithLimit.drop(1))
  688. else
  689. pokeMartTracker[:refresh] = timeInDays
  690. end
  691. end
  692.  
  693. # Logging for debugging
  694. puts "Current Date: #{current_date_str}"
  695. puts "Previous Tracker Date: #{pokeMartTracker[:date]}"
  696. puts "Days Difference: #{daysDiff}"
  697. puts "Time in Days (before printing): #{timeInDays.inspect}"
  698. puts "Time in Days3: #{timeInDays}"
  699. puts "PokeMart Tracker: #{pokeMartTracker}"
  700. return pokeMartTracker
  701. end
  702.  
  703.  
  704. def editStockBadgeOrImportant(stock)
  705. APMSettings::BadgesForItems.each do |badgeCount, badgeItems|
  706. if badgeCount > $player.badge_count
  707. badgeItems.each do |item|
  708. stock.delete(item)
  709. end
  710. end
  711. end
  712. stock.delete_if { |item| GameData::Item.get(item).is_important? && $bag.has?(item) }
  713. return stock
  714. end
  715.  
  716. def getChosenSpeech(speech)
  717. unless speech.nil?
  718. getSpeech = APMSettings.const_get(speech.gsub(" ", "")) if APMSettings.const_defined?(speech.gsub(" ", ""))
  719. else
  720. getSpeech = {}
  721. end
  722. end
  723.  
  724. def convertStockByCategories(stockByCat, stock)
  725. stockByCat = Hash.new { |hash, key| hash[key] = [] }
  726. categoryHash = {}
  727. APMSettings::CategoryNames.each_with_index do |name, index|
  728. order = (index + 1) * 10
  729. categoryHash[name] = { order: order }
  730. end
  731. stock.each do |item|
  732. pocketName = APMSettings::CustomCategoryNames.find { |category, list| list[:items].include?(item) }&.first
  733. if pocketName.nil?
  734. pocketID = GameData::Item.get(item).pocket
  735. pocketName = APMSettings::CategoryNames[pocketID-1]
  736. end
  737. stockByCat[pocketName] << item
  738. end
  739. stockByCat = stockByCat.sort_by do |key, _|
  740. order = categoryHash[key]&.dig(:order) || APMSettings::CustomCategoryNames[key]&.dig(:order)
  741. order || Float::INFINITY
  742. end.to_h
  743. return stockByCat
  744. end
  745.  
  746.  
  747. def getPreviousRefreshDate(date)
  748. pokeMartTracker = $ArckyGlobal.pokeMartTracker[@map_id][@event_id]
  749. return 0 if pokeMartTracker.empty? || pokeMartTracker.length <= 1
  750. return (getDateFromString(date) - getDateFromString(pokeMartTracker[:date].to_s)) / (24 * 60 * 60)
  751. end
  752.  
  753.  
  754. def convertDays(refreshRate, daysDiff)
  755. puts "daysDiff: #{daysDiff.inspect}"
  756. puts "refreshRate: #{refreshRate.inspect}"
  757. if refreshRate.nil?
  758. Console.echoln_li _INTL("No refresh rate was set for the items with a limit.")
  759. return -1
  760. end
  761. case refreshRate.downcase
  762. when "daily"
  763. days = 1
  764. when "2daily"
  765. days = 2
  766. when "weekly"
  767. days = 7
  768. when "random"
  769. unless $ArckyGlobal.pokeMartTracker[@map_id][@event_id].empty?
  770. refresh = $ArckyGlobal.pokeMartTracker[@map_id][@event_id][:refresh]
  771. case refresh
  772. when "in a week"
  773. days = 7
  774. when /in (\d+) days/
  775. days = refresh[/\d+/].to_i
  776. when "tomorrow"
  777. days = 1
  778. end
  779. else
  780. days = rand(1..7)
  781. end
  782. else
  783. days = -1
  784. end
  785. puts "daysDiff: #{daysDiff.inspect}"
  786. puts "time to substract: #{days}"
  787. time = days - daysDiff
  788. time = 0 if time < 0
  789. puts "Calculated Time (inside convertDays): #{time}"
  790. case time
  791. when 1
  792. return "tomorrow"
  793. when 2..6
  794. return "in #{time.to_i} days"
  795. when 7
  796. return "in a week"
  797. when 0
  798. return nil
  799. else
  800. return "never"
  801. end
  802. end
  803.  
  804. def getItemList(stock)
  805. itemList = []
  806. newStock = stock.select { |item| item.is_a?(Array) && !item[1].nil? }
  807. newStock.each do |item|
  808. item[2] = item[1] if item[2].nil?
  809. if item[1] > item[2]
  810. Console.echoln_li _INTL("The min limit can't be bigger than the max limit for :#{item[0]}")
  811. next
  812. end
  813. entry = { :name => item[0], :limit => rand(item[1]..item[2])}
  814. itemList << entry
  815. end
  816. return itemList
  817. end
  818.  
  819. def extractStock(stock)
  820. if stock[0].is_a?(String)
  821. refreshRate = stock[0]
  822. stock = stock.drop(1)
  823. end
  824. extractedStock = stock.map do |item|
  825. if item.is_a?(Array)
  826. item[0]
  827. else
  828. item
  829. end
  830. end
  831. return refreshRate, extractedStock
  832. end
  833.  
  834. def getTimeOfDay(getSpeech, text)
  835. return if getSpeech.empty?
  836. weekDay = pbGetTimeNow.wday
  837. day = %w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday][weekDay]
  838. part = (weekDay == 0 || weekDay == 6) ? "Weekend" : "Week"
  839. time = if PBDayNight.isMorning?
  840. "Morning"
  841. elsif PBDayNight.isAfternoon?
  842. "Afternoon"
  843. elsif PBDayNight.isEvening?
  844. "Evening"
  845. elsif PBDayNight.isDay?
  846. "Day"
  847. elsif PBDayNight.isNight?
  848. "Night"
  849. end
  850. output = "#{text}#{day}#{time}".to_sym
  851. fallback = {
  852. "Morning" => ["#{text}TextMorning#{day}".to_sym, "#{text}TextDay#{day}".to_sym, "#{text}Text#{day}".to_sym, "#{text}TextMorning#{part}".to_sym, "#{text}TextDay#{part}".to_sym, "#{text}Text#{part}".to_sym, "#{text}TextMorning".to_sym, "#{text}TextDay".to_sym, "#{text}Text".to_sym],
  853. "Day" => ["#{text}TextDay#{day}".to_sym, "#{text}Text#{day}".to_sym, "#{text}TextDay#{part}".to_sym, "#{text}Text#{part}".to_sym, "#{text}TextDay".to_sym, "#{text}Text".to_sym],
  854. "Afternoon" => ["#{text}TextAfternoon#{day}".to_sym, "#{text}TextDay#{day}".to_sym, "#{text}Text#{day}".to_sym, "#{text}TextAfternoon#{part}".to_sym, "#{text}TextDay#{part}".to_sym, "#{text}Text#{part}".to_sym, "#{text}TextAfternoon".to_sym, "#{text}TextDay".to_sym, "#{text}Text".to_sym],
  855. "Evening" => ["#{text}TextEvening#{day}".to_sym, "#{text}TextDay#{day}".to_sym, "#{text}Text#{day}".to_sym, "#{text}TextEvening#{part}".to_sym, "#{text}TextDay#{part}".to_sym, "#{text}Text#{part}".to_sym, "#{text}TextEvening".to_sym, "#{text}TextDay".to_sym, "#{text}Text".to_sym],
  856. "Night" => ["#{text}TextNight#{day}".to_sym, "#{text}Text#{day}".to_sym, "#{text}TextNight#{part}".to_sym, "#{text}Text#{part}".to_sym, "#{text}TextNight".to_sym, "#{text}Text".to_sym]
  857. }
  858. fallbackOptions = fallback[time] || []
  859. fallbackOptions.each do |fallbackOption|
  860. return getSpeech[fallbackOption] unless getSpeech[fallbackOption]&.empty? || getSpeech[fallbackOption].nil?
  861. end
  862. return getSpeech[text.to_sym]
  863. end
  864.  
  865. def getBonusItems(item, adapter, quantity, speech = nil, retBonus = false)
  866. bonus = APMSettings::BonusItems[item]
  867. item = :POKEBALL if !bonus && GameData::Item.get(item).is_poke_ball?
  868. if bonus
  869. if quantity && bonus[:amount]
  870. if quantity >= bonus[:amount]
  871. bonusItem = []
  872. bItem = nil
  873. itemsWithChance = 0
  874. totalChance = 0
  875. if bonus[:item].is_a?(Array) || bonus[:item].is_a?(Hash)
  876. bonus[:item].each do |item, prop|
  877. next unless prop && (prop.is_a?(Numeric) || (prop.is_a?(Hash) && prop.key?(:chance)))
  878. if prop.is_a?(Hash)
  879. totalChance += prop[:chance]
  880. else
  881. totalChance += prop
  882. end
  883. itemsWithChance += 1
  884. end
  885. if itemsWithChance == bonus[:item].length
  886. if totalChance != 100
  887. factor = 100.0 / totalChance
  888. if bonus[:item].is_a?(Array) || bonus[:item].is_a?(Hash)
  889. array = bonus[:item].map do |key, value|
  890. if value.is_a?(Numeric)
  891. [key, value * factor]
  892. elsif value.is_a?(Hash)
  893. [key, value[:chance] * factor, value[:amount] || 1]
  894. end
  895. end
  896. bonus[:item] = array
  897. end
  898. end
  899. else
  900. remChance = 100 - totalChance
  901. itemsWithoutChance = bonus[:item].length - itemsWithChance
  902. if itemsWithoutChance > 0
  903. indChance = remChance.to_f / itemsWithoutChance
  904. array = bonus[:item].map do |key, value|
  905. if !value
  906. [key, indChance]
  907. elsif value.is_a?(Hash)
  908. [key, value[:chance] || indChance, value[:amount] || 1]
  909. else
  910. item
  911. end
  912. end
  913. bonus[:item] = array
  914. end
  915. end
  916. bonusArray = []
  917. numb = 0
  918. bonus[:item].each do |item, chance|
  919. numb += chance
  920. bonusArray << [item, numb]
  921. end
  922. end
  923. qty = 1
  924. counter = 0
  925. (quantity / bonus[:amount]).times do
  926. if bonus[:item].is_a?(Array) || bonus[:item].is_a?(Hash)
  927. ranChance = rand(1..1000).to_f / 10
  928. bItem = bonusArray.find { |item, chance| chance.to_f >= ranChance }[0]
  929. qty = bonus[:item].find {|itm| itm[0] == bItem }[2] || 1
  930. else
  931. bItem = bonus[:item]
  932. end
  933. counter += qty
  934. qty.times do
  935. break if !adapter.addItem(bItem)
  936. bonusItem << bItem
  937. end
  938. end
  939. tallyItems = bonusItem.tally.map do |item, amount|
  940. name = GameData::Item.get(item).name
  941. name = GameData::Item.get(item).name_plural if amount > 1
  942. "#{amount} #{name}"
  943. end
  944. added = [counter == bonusItem.length, counter > bonusItem.length]
  945. return tallyItems, added if retBonus
  946. string = mergeArrayToString(tallyItems)
  947. outputString = getBonusItemsString(added, string, speech)
  948. pbDisplayPaused(outputString)
  949. end
  950. else
  951. Console.echoln_li _INTL("There's no :amount defined for :#{item} in BonusItems.")
  952. end
  953. else
  954. Console.echoln_li _INTL(":#{item} has no bonus item(s) defined in BonusItems (ignore if intented).")
  955. end
  956. end
  957.  
  958. def getBonusItemsString(added, string, speech)
  959. if added[0] && !string.nil? # All bonus Items were added.
  960. return _INTL(speech[:BuyBonus]&.sample || "And have {1} on the house!", string)
  961. elsif added[1] && !string.nil? # not all bonus Items were added.
  962. return _INTL("And have {1} on the house! (Not all bonus items were added, not enough room in your bag.)", string)
  963. else
  964. return _INTL("You have not enough room in your bag for the bonus items.")
  965. end
  966. end
  967.  
  968. class Window_PokemonMart < Window_DrawableCommand
  969. def initialize(stock, adapter, x, y, width, height, viewport = nil, pokeMartTracker = nil, discount)
  970. @stock = stock
  971. @adapter = adapter
  972. @pokeMartTracker = pokeMartTracker
  973. @discount = discount
  974. super(x, y, width, height, viewport)
  975. if Essentials::VERSION.include?("21")
  976. @selarrow = AnimatedBitmap.new("Graphics/UI/Mart/cursor")
  977. else
  978. @selarrow = AnimatedBitmap.new("Graphics/Pictures/martSel")
  979. end
  980. @baseColor = Color.new(88, 88, 80)
  981. @shadowColor = Color.new(168, 184, 184)
  982. @baseColor2 = Color.new(160, 160, 168)
  983. @shadowColor2 = Color.new(208, 208, 216)
  984. self.windowskin = nil
  985. end
  986.  
  987. def itemCount
  988. return @stock.length + 1
  989. end
  990.  
  991. def item
  992. return (self.index >= @stock.length) ? nil : @stock[self.index]
  993. end
  994.  
  995. def drawItem(index, count, rect)
  996. textpos = []
  997. rect = drawCursor(index, rect)
  998. ypos = rect.y
  999. if index == count - 1
  1000. textpos.push([_INTL("CANCEL"), rect.x, ypos + 2, :left, self.baseColor, self.shadowColor])
  1001. else
  1002. item = @stock[index]
  1003. itemname = @adapter.getDisplayName(item)
  1004. qty = @adapter.getDisplayPrice(item, @discount)
  1005. entry = @pokeMartTracker[:items].find { |entry| entry[:name] == item} if @pokeMartTracker.key?(:items)
  1006. #qty = "Out of Stock" if !entry.nil? && entry[:limit] == 0
  1007. # Check stock limit
  1008. if !entry.nil? && entry[:limit] == 0
  1009. qty = "Out of Stock"
  1010. elsif qty == 0
  1011. qty = "" # Blank space for zero price
  1012. end
  1013.  
  1014. baseColor = qty == "Out of Stock" ? @baseColor2 : self.baseColor
  1015. shadowColor = qty == "Out of Stock" ? @shadowColor2 : self.shadowColor
  1016. sizeQty = self.contents.text_size(qty).width
  1017. xQty = rect.x + rect.width - sizeQty - 2 - 16
  1018. textpos.push([itemname, rect.x, ypos + 2, :left, baseColor, self.shadowColor])
  1019. textpos.push([qty, xQty, ypos + 2, :left, baseColor, self.shadowColor])
  1020. end
  1021. pbDrawTextPositions(self.contents, textpos)
  1022. end
  1023. end
  1024.  
Advertisement
Add Comment
Please, Sign In to add comment